概述#
官方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 不支持await及promisesJavaScript功能。如果想要使用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));
});
