用holastudio实现多人在线游戏 - Holaverse/holastudio-demos GitHub Wiki
多人在线游戏是很复杂的,直到最近看到agar.io,原来多人在线游戏也可以这么简单(至少实现一个DEMO不难)。趁过年期间有点空隙,花了两个小时写个DEMO,供有兴趣的朋友参考。
为了简化起见,服务器端完全用Pomelo的DEMO了。服务器我们不做任何修改,用聊天的消息作为同步游戏状态的载体。
1.先实现登录界面。这个很简单,放三个编辑器,分别用来输入服务器、聊天室和用户名,再放一个按钮用来登录就行了。
var hostname = this.win.getValueOf("hostname");
var roomname = this.win.getValueOf("roomname");
var username = this.win.getValueOf("username");
if(!username || !roomname || !hostname) {
return;
}
var initData = {
roomname:roomname,
username:username
};
function onLogin(data) {
initData.data = data;
this.openWindow("win-main", null, true, initData);
}
ChatClient.login(hostname, username, roomname, onLogin.bind(this));
2.实现游戏场景。这里只是一个空的场景,每个玩家进入后可以通过虚拟摇杆移动自己。虚拟摇杆的实现请参考https://github.com/Holaverse/holastudio-components/tree/master/joystick。
创建一个js文件main-scene.js,把公共代码放到里面:
function MainScene() {
}
//玩家离开时,把Ta场景中删除。
MainScene.onUserLeft = function(data) {
var win = MainScene.win;
var figure = win.find(data.user);
if(figure) {
figure.remove(true, true);
}
}
//其他玩家加入时,在自己的场景中创建新玩家的角色,同时在新玩家的场景中更新自己的位置。
MainScene.onUserEnter = function(data) {
var win = MainScene.win;
var newPlayer = win.dupChild("figure");
newPlayer.setPosition(0, 0).setText(data.user).setName(data.user);
var figure = MainScene.figure;
MainScene.update(figure.x, figure.y, figure.getRotation());
}
//其他玩家位置移动时,更新该玩家在自己的场景中的位置。
MainScene.onMessage = function(data) {
var win = MainScene.win;
var figureState = JSON.parse(data.msg);
if(figureState.type === "update-state") {
var figure = win.find(figureState.name);
if(figure) {
figure.setPosition(figureState.x, figureState.y).setRotation(figureState.angle);
}
}
}
//自己的位置有变化时,通知其它玩家更新。
MainScene.update = function(x, y, angle) {
var figureState = {type:"update-state", name:MainScene.username, x:x, y:y, angle:angle};
ChatClient.send("*", JSON.stringify(figureState), function(username, target, msage) {});
return;
}
//通过虚拟摇杆移动自己的位置。
MainScene.onJoyStickKeyPressed = function(args) {
var dx = args.dx*2;
var dy = args.dy*2;
var angle = args.angle*Math.PI/180;
var x = MainScene.figure.x + dx;
var y = MainScene.figure.y + dy;
MainScene.update(x, y, angle);
}
//初始化时,创建自己和场景中已经有的玩家。
MainScene.init = function(win, initData) {
MainScene.win = win;
MainScene.username = initData.username;
MainScene.roomname = initData.roomname;
MainScene.figure = win.dupChild("figure");
MainScene.figure.setName(MainScene.username).setText(MainScene.username);
pomelo.on('onChat', MainScene.onMessage.bind(MainScene));
pomelo.on('onAdd', MainScene.onUserEnter.bind(MainScene));
pomelo.on('onLeave', MainScene.onUserLeft.bind(MainScene));
var users = initData.data.users;
for(var i = 0; i < users.length; i++) {
var name = users[i];
if(name === MainScene.username) continue;
var figure = win.dupChild("figure");
figure.setName(name).setText(name);
}
MainScene.update(0, 0, 0);
return;
}
在场景的onOpen函数中:
MainScene.init(this, initData);
在摇杆的onKeyPressed事件中:
MainScene.onJoyStickKeyPressed(args);
还有几个对pomelo的包装函数,放到client.js中:
function ChatClient() {
}
ChatClient.queryEntry = function(uid, callback) {
var route = 'gate.gateHandler.queryEntry';
pomelo.init({
host: ChatClient.hostname,
port: 3014,
log: true
}, function() {
pomelo.request(route, {
uid: uid
}, function(data) {
pomelo.disconnect();
if(data.code === 500) {
return;
}
callback(data.host, data.port);
});
});
}
ChatClient.login = function(hostname, username, rid, callback) {
ChatClient.hostname = hostname;
ChatClient.queryEntry(username, function(host, port) {
pomelo.init({
host: host,
port: port,
log: true
}, function() {
var route = "connector.entryHandler.enter";
pomelo.request(route, {
username: username,
rid: rid
}, function(data) {
if(data.error) {
return;
}
callback(data);
ChatClient.rid = rid;
ChatClient.username = username;
});
});
});
}
ChatClient.send = function(target, msg, callback) {
var rid = ChatClient.rid;
var username = ChatClient.username;
var route = "chat.chatHandler.send";
pomelo.request(route, {
rid: rid,
content: msg,
from: username,
target: target
}, function(data) {
if(target != '*' && target != username) {
callback(username, target, msg);
}
});
}
require('boot');
3.最后还要在项目中引用pomelo的库,它的位置取决于pomelo服务器的名称了,我的pomelo安装在本机: http://192.168.168.108:3001/js/lib/build/build.js