跳过正文
Cocos2d-x JavaScript 客户端指南
  1. 文章/

Cocos2d-x JavaScript 客户端指南

本文翻译自 Nakama 官方文档(Cocos2d-x JavaScript Client Guide)

概述
#

官方Cocos2d JavaScript客户端:支持与服务器的实时通信,实现所有服务器功能,并适用于cocos2d-x js项目。客户端附带类型定义文件,支持TypeScript。

开源地址GitHub。欢迎报告问题和贡献代码以帮助改进。

下载
#

下载最新版本:从GitHub发布页面下载包含Nakama-js模块(UMD模块加载器)和polyfill库的最新版本。

更新提示:在升级前,请查阅CHANGELOG了解更新升级内容。

设置
#

将下载的文件解压到src目录。

project.json中导入以下文件:

"jsList" : [
  ...
  "src/NakamaSDK/ThirdParty/polyfill.js",
  "src/NakamaSDK/nakama-js.umd.js"
]

配置
#

创建客户端对象以执行针对服务器的所有逻辑:

// 默认连接设置
var serverkey = "defaultkey";
var host = "127.0.0.1";
var port = "7350";
var useSSL = false;
var timeout = 7000; // ms

var client = new nakamajs.Client(serverkey, host, port, useSSL, timeout);

Cocos2d 不支持awaitpromisesJavaScript功能。如果想要使用promises,可以选择使用polyfill第三方库。

认证
#

使用客户端对象进行认证。可以注册或登录用户,采用推荐模式编写代码。

const email = "hello@example.com";
const password = "somesupersecretpassword";

client.authenticateEmail(email, password).then(function(session) {
  cc.log("认证成功。用户ID:", session.user_id);
  cc.sys.localStorage.setItem("nakamaToken", session.token);
}, function(error) {
  cc.error("认证失败:", JSON.stringify(error));
});

发送消息
#

用户认证后,使用会话连接服务器并发送各种消息,如添加好友、加入群组、提交排行榜成绩等。你可以通过RPC执行服务器远程代码。服务器同样提供了一个存储引擎来维护用户记录及保存游戏数据,我们将通过存储来介绍如何发送消息。

const objects = [{
  "collection": "collection",
  "key": "key1",
  "value": {"jsonKey": "jsonValue"}
}, {
  "collection": "collection",
  "key": "key2",
  "value": {"jsonKey": "jsonValue"}
}];
client.writeStorageObjects(session, objects)
  .then(function(storageWriteAck) {
        cc.log("Storage成功写入:", JSON.stringify(storageWriteAck));
    },
    function(error) {
        cc.error("Storage写入失败:", JSON.stringify(error));
    });

在文档的其他部分可以找到更多示例代码。

实时数据交换
#

你可以通过WebSocket连接来保持与服务器的实时数据交换,包括接收聊天消息、接收通知匹配进入多玩家比赛。你同样可以通过RPC来执行远程服务器代码。你首先应该和服务器创建一个实时的socker连接:

const useSSL = false;
const verboseLogging = false;
const createStatus = false;    // set `true` to send presence events to subscribed users.
const socket = client.createSocket(useSSL, verboseLogging);
var session = ""; // obtained by authentication.
socket.connect(session, createStatus)
  .then(
        function() {
            cc.log("连接成功");
        },
        function(error) {
            cc.error("连接失败:", JSON.stringify(error));
        }
    );

然后接下来加入一个聊天频道并发送一条消息:

socket.onchannelmessage = function (channelMessage) {
  cc.log("成功接收聊天消息:", JSON.stringify(channelMessage));
};

const channelId = "pineapple-pizza-lovers-room";
const persistence = false;
const hidden = false;

socket.joinChat(channelId, 1, persistence, hidden).then(
      function(response) {
          cc.log("成功加入聊天频道:", response.channel.id);
          sendChatMessage(response.channel.id);
      },
      function(error) {
          cc.error("join channel failed:", JSON.stringify(error));
      }
  );

function sendChatMessage(channelId) {
  socket.writeChatMessage(channelId, {"message": "Pineapple doesn't belong on a pizza!"}).then(
      function(messageAck) {
          cc.log("成功发送聊天消息:", JSON.stringify(messageAck));
      },
      function(error) {
          cc.error("发送聊天消息失败:", JSON.stringify(error));
      }
  );
}

你可以在这里了解更多不同的聊天功能信息。

处理事件
#

客户端的Socket连接拥有事件监听器,这些事件监听器处理从服务器接收到的各种事件。

socket.ondisconnect = function (event) {
  cc.log("与服务器断开连接。事件:", JSON.stringify(event));
};
socket.onnotification = function (notification) {
  cc.log("收到通知:", JSON.stringify(notification));
};
socket.onchannelpresence = function (presence) {
  cc.log("收到存在状态更新:", JSON.stringify(presence));
};
socket.onchannelmessage = function (message) {
  cc.log("收到新的聊天消息:", JSON.stringify(message));
};
socket.onmatchdata = function (matchdata) {
  cc.log("收到匹配数据:", JSON.stringify(matchdata));
};
socket.onmatchpresence = function (matchpresence) {
  cc.log("收到匹配存在状态更新:", JSON.stringify(matchpresence));
};
socket.onmatchmakermatched = function (matchmakerMatched) {
  cc.log("收到匹配器更新:", JSON.stringify(matchmakerMatched));
};
socket.onstatuspresence = function (statusPresence) {
  cc.log("收到状态存在更新:", JSON.stringify(statusPresence));
};
socket.onstreampresence = function (streamPresence) {
  cc.log("收到流存在状态更新:", JSON.stringify(streamPresence));
};
socket.onstreamdata = function (streamdata) {
  cc.log("收到流数据:", JSON.stringify(streamdata));
};

有些事件监听只需要根据您想要使用的功能选择实现。

回调(callbacks)描述(description)
onDisconnect客户端被服务器断开连接
onNotification服务器推送的app通知
onChannelMessage其他用户发送的实时聊天信息
onChannelPresence聊天中加入离开频道事件
onMatchState实时多玩家匹配程序匹配数据
onMatchPresence接收实时多玩家匹配程序加入离开的事件
onMatchmakerMatched匹配程序找到合适匹配
onStatusPresence订阅用户状态源时接收状态更新
onStreamPresence加入离开事件
onStreamState服务器发送的数据

日志和报错
#

服务器和客户端都可以生成日志,来帮助我们debug代码。当你构建一个客户端的时候,为了把该客户端发送的所有消息都打日志,你可以打开verbose

const verboseLogging = true;
const useSSL = false;
var client = new nakamajs.Client("defaultkey");
client.verbose = verboseLogging;
socket = client.createSocket(useSSL, verboseLogging);

完整代码示例
#

一个通过cocos2d-x JavaScript客户端库来管理session的完整代码示例:

var client = new nakamajs.Client("defaultkey");
var currentSession = null;

function storeSession(session) {
  cc.sys.localStorage.setItem("nakamaToken", session.token);
  cc.log("Session存储成功.");
}

function getSessionFromStorage() {
  return cc.sys.localStorage.getItem("nakamaToken");
}

function restoreSessionOrAuthenticate() {
const email = "hello@example.com";
  const password = "somesupersecretpassword";
  var session = null;
  try {
    var sessionString = getSessionFromStorage();
    if (sessionString && sessionString !== "") {
      session = nakamajs.Session.restore(sessionString);
      var currentTimeInSec = new Date() / 1000;
      if (!session.isexpired(currentTimeInSec)) {
        cc.log("Session恢复成功,UserID: ", session.user_id);
        return Promise.resolve(session);
      }
    }

    return new Promise(function(resolve, reject) {
      client.authenticateEmail(email, password)
        .then(function(session) {
            storeSession(session);
            cc.log("认证成功,UserID:", session.user_id);
            resolve(session);
          },
          function(error) {
            cc.error("认证失败:", JSON.stringify(error));
            reject(error);
          });
    });
  } catch(e) {
    cc.log("当尝试恢复Session或者认证的时候,发生错误:", JSON.stringify(e));
    return Promise.reject(e);
  }
}

restoreSessionOrAuthenticate().then(function(session) {
  currentSession = session;
  return client.writeStorageObjects(currentSession, [{
    "collection": "collection",
    "key": "key1",
    "value": {"jsonKey": "jsonValue"}
  }]);
}).then(function(writeAck) {
  cc.log("Storage写成功 - ack:", JSON.stringify(writeAck));
}).catch(function(e) {
  cc.log("发生错误:", JSON.stringify(e));
});