1、打开两个窗口,输入名称进行登陆
2、开始聊天
做好三件事:
一、写好cocos的界面
二、搭建本地服务器
三、写好cocos的脚本
一、写好cocos的界面
主要有两个,一个是登陆面板(login节点),一个是聊天面板(chat节点)。
下图是登陆面板。
下图是聊天面板
需要注意一个细节,滑动视图的content要添加垂直布局,不然聊天记录会重叠在一起。
同时还需要将chat--New ScrollView--view--content--item制作成预制。因为后面要不断地产生聊天记录,就是用item来生成的。做成预制之后就可以把item节点给删掉。
这样界面就好了,接下来搭建本地服务器。
二、搭建本地服务器
当你在玩单机游戏的时候,你的电脑会响应你的一切操作,但是如果要玩多人游戏,则需要远程的服务器来同步你和别的玩家的状态。远程服务器是要花钱的,所以我们可以搭建一个简单的本地服务器。这里要用到Node.js,它是一个平台,具体干嘛的我也说不清。先去node官网下载它吧,然后终端检测一下是否安装成功。
node -v
// v12.14.0
接着就开始搭建服务器啦。找一个你喜欢的位置新建文件夹ChatServer,再在这个文件夹下新建文件夹Server,在此目录下运行如下命令
npm install nodejs-websocket
继续在Server目录下新建server.js,写一个每当有客户端连接时就会打印的功能。
// server.js
// 导入模块,使用ws变量接收
var ws = require("nodejs-websocket");
// createServer方法会在每个连接到来时执行一次
// 其中conn参数为到来的连接
var server = ws.createServer(function (conn) {
console.log("一个新的来自客户端的连接!");
}).listen(3000);
我们让这个服务器运行起来,在Server目录下执行命令:
node server
执行了不会有什么反应,但是服务器已经运行起来了。接下来写cocos客户端的脚本,我们会在下面的内容检验客户端能否连上这个正在运行的服务器。
三、写好cocos的脚本
1、连接服务器
在cocos中我们只需要写一个JS脚本,我把它命名为Main,放在scripts目录下,挂到Canvas节点上。在下文中我可能直接把这个脚本说成客户端代码。
学过网络编程的同学都知道,客户端开始运行的时候,要和指定的服务器进行连接,因此start函数写为如下,一旦客户端成功连上服务器端就打印“连接成功”。
// Main.js
cc.Class({
extends: cc.Component,
properties: {
},
start () {
let self = this;
// 进行本地连接,3000 端口
self.ws = new WebSocket("ws://localhost:3000");
self.ws.onopen = function (event) {
console.log("连接成功!");
};
},
});
cocos运行一下,注意这里要确保第二步的服务器正在运行。
可以看到客户端能连上服务器,打印了连接成功。同时服务器也进行了打印。
这样,我们的网络模块就搞通了,接下来要继续完善客户端代码。
2、动态生成item预制体
第一步说了,聊天时需要不断地产生item预制体,这里引用一下官方文档的说法:
在运行时进行节点的创建(
cc.instantiate
)和销毁(node.destroy
)操作是非常耗费性能的,因此我们在比较复杂的场景中,通常只有在场景初始化逻辑(onLoad
)中才会进行节点的创建,在切换场景时才会进行节点的销毁。如果制作有大量敌人或子弹需要反复生成和被消灭的动作类游戏,我们要如何在游戏进行过程中随时创建和销毁节点呢?这里就需要对象池的帮助了。
因此我们的代码onLoad里面需要用到对象池,以降低性能的耗费。所以onLoad函数这么写:
// Main.js
cc.Class({
extends: cc.Component,
properties: {
// item预制体
item: cc.Prefab,
},
onLoad () {
// 初始化对象池,使用 this.pool 变量接收
this.pool = new cc.NodePool();
for (let i = 0; i < 200; i++) {
// 克隆预制体,用 item_prefab 变量接收
let item_prefab = cc.instantiate(this.item);
// 放入对象池中,在需要时使用 get() 方法即可
this.pool.put(item_prefab);
}
},
start () {
let self = this;
// 进行本地连接,3000 端口
self.ws = new WebSocket("ws://localhost:3000");
self.ws.onopen = function (event) {
console.log("连接成功!");
};
},
});
为了测试一下我们能不能动态生成item,在start里面调用新写的createMessage方法。
// Main.js
cc.Class({
extends: cc.Component,
properties: {
// item预制体
item: cc.Prefab,
// 聊天记录的容器
content: cc.Node,
},
onLoad () {
// 初始化对象池,使用 this.pool 变量接收
this.pool = new cc.NodePool();
for (let i = 0; i < 200; i++) {
// 克隆预制体,用 item_prefab 变量接收
let item_prefab = cc.instantiate(this.item);
// 放入对象池中,在需要时使用 get() 方法即可
this.pool.put(item_prefab);
}
},
start () {
// 测试能否动态生成item
this.createMessage('你好');
this.createMessage('我很好');
let self = this;
// 进行本地连接,3000 端口
self.ws = new WebSocket("ws://localhost:3000");
self.ws.onopen = function (event) {
console.log("连接成功!");
};
},
// 创建一个聊天记录,传入参数为字符串
createMessage (str) {
let item_prefab = null;
// 先判断对象池中取没取空
if (this.pool.size() > 0) {
item_prefab = this.pool.get();
} else {
item_prefab = cc.instantiate(this.item);
}
// 为 item_prefab 指定父节点,更改其显示的字符串
item_prefab.parent = this.content;
item_prefab.getComponent(cc.Label).string = str;
},
});
注意把item预制体和content节点拖动关联。
然后运行,就是预期的效果。
3、登陆与聊天的实现