Demo運行以前須要去Matchvs 官網配置遊戲相關信息,以獲取Demo運行所須要的GameID、AppKey、SecretID。如圖:node
獲取到相關遊戲信息以後,運行Demo,便可進入房間,準備開始遊戲,如圖所示:web
在引入SDK以後,在初始化前須要先調用Matchvs.MatchvsEngine.getInstance()獲取一個Matchvs引擎對象實例:緩存
var engine = Matchvs.MatchvsEngine.getInstance();複製代碼
另外咱們須要定義一個對象,該對象定義一些回調方法,用於獲取遊戲中玩家加入、離開房間、數據收發的信息,這些方法在特定的時刻會被SDK調用。bash
var response = {
// 能夠如今定義一些回調方法,也能夠事後再定義。
};複製代碼
爲方便使用,咱們把engine和reponse放到單獨的文件Mvs.js中,使用module.exports將它們做爲全局變量使用:app
var engine = Matchvs.MatchvsEngine.getInstance();
var response = {};
module.exports = {
engine: engine,
response: engine
};
// 文件路徑:assets\scripts\Mvs.js複製代碼
其餘文件能夠用require函數引入engine和reponse:dom
var mvs = require("Mvs");
// 引擎實例:mvs.engine
// 引擎回調實現:mvs.response複製代碼
完成以上步驟後,咱們能夠調用初始化接口創建相關資源。異步
mvs.engine.init(response, channel, platform, gameId);
// 文件路徑:assets\scripts\Lobby.js複製代碼
注意 在整個應用全局,開發者只須要對引擎作一次初始化。函數
接下來,咱們就能夠從Matchvs獲取一個合法的用戶ID,經過該ID鏈接至Matchvs服務端。工具
獲取用戶ID:ui
cc.Class({
onLoad: function() {
mvs.response.registerUserResponse = this.registerUserResponse.bind(this);
mvs.engine.registerUser();
},
registerUserResponse: function(userInfo) {
// 註冊成功,userInfo包含相關用戶信息
},
// ...
})
// 文件路徑:assets\scripts\Lobby.js複製代碼
用戶信息須要保存起來,咱們使用一個類型爲對象的全局變量GLB來存儲:
GLB.userInfo = userInfo;複製代碼
登陸:
cc.Class({
onLoad: function() {
// ...
mvs.engine.login(userInfo.id, userInfo.token, gameId, gameVersion, appKey,
secret, deviceId, gatewayId);
// ...
},
loginResponse: function(loginRsp) {
// 登陸成功,loginRsp包含登陸相關信息
},
// ...
})
// 文件路徑:assets\scripts\Lobby.js複製代碼
成功鏈接至Matchvs後,當即隨機匹配加入一個房間進行遊戲。
代碼以下:
cc.Class({
loginResponse: function() {
// ...
mvs.response.joinRoomResponse = this.joinRoomResponse.bind(this);
mvs.engine.joinRandomRoom(maxPlayer, userProfile);
// ...
},
joinRoomResponse: function(status, userInfoList, roomInfo) {
// 加入房間成功,status表示結果,roomUserInfoList爲房間用戶列表,roomInfo爲房間信息
// ...
},
// ...
})
// 文件路徑:assets\scripts\Lobby.js複製代碼
咱們設定若是有3個玩家匹配成功則知足開始條件且遊戲設計中不提供中途加入,此時需告訴Matchvs不要再向房間里加人。
代碼以下:
cc.Class({
joinRoomResponse: function(status, userInfoList, roomInfo) {
// 加入房間成功,status表示結果,roomUserInfoList爲房間用戶列表,roomInfo爲房間信息
// ...
if (userIds.length >= GLB.MAX_PLAYER_COUNT) {
mvs.response.joinOverResponse = this.joinOverResponse.bind(this); // 關閉房間以後的回調
var result = mvs.engine.joinOver("");
this.labelLog("發出關閉房間的通知");
if (result !== 0) {
this.labelLog("關閉房間失敗,錯誤碼:", result);
}
GLB.playerUserIds = userIds;
}
},
joinOverResponse: function(joinOverRsp) {
if (joinOverRsp.status === 200) {
this.labelLog("關閉房間成功");
// ...
} else {
this.labelLog("關閉房間失敗,回調通知錯誤碼:", joinOverRsp.status);
}
},
})
// 文件路徑:assets\scripts\Lobby.js複製代碼
在這裏須要記下房間的用戶列表,記入到全局變量GLB.playerUserIds中,後面要使用到。
若是收到服務端的房間關閉成功的消息,就能夠通知遊戲開始了。
cc.Class({
// ...
joinOverResponse: function(joinOverRsp) {
if (joinOverRsp.status === 200) {
this.labelLog("關閉房間成功");
this.notifyGameStart();
} else {
this.labelLog("關閉房間失敗,回調通知錯誤碼:", joinOverRsp.status);
}
},
notifyGameStart: function () {
GLB.isRoomOwner = true;
var event = {
action: GLB.GAME_START_EVENT,
userIds: GLB.playerUserIds
}
mvs.response.sendEventResponse = this.sendEventResponse.bind(this); // 設置事件發射以後的回調
mvs.response.sendEventNotify = this.sendEventNotify.bind(this); // 設置事件接收的回調
var result = mvs.engine.sendEvent(JSON.stringify(event));
// ...
// 發送的事件要緩存起來,收到異步回調時用於判斷是哪一個事件發送成功
GLB.events[result.sequence] = event;
},
sendEventResponse: function (info) {
// ... 輸入校驗
var event = GLB.events[info.sequence]
if (event && event.action === GLB.GAME_START_EVENT) {
delete GLB.events[info.sequence]
this.startGame()
}
},
sendEventNotify: function (info) {
if (info
&& info.cpProto
&& info.cpProto.indexOf(GLB.GAME_START_EVENT) >= 0) {
GLB.playerUserIds = [GLB.userInfo.id]
// 經過遊戲開始的玩家會把userIds傳過來,這裏找出全部除本玩家以外的用戶ID,
// 添加到全局變量playerUserIds中
JSON.parse(info.cpProto).userIds.forEach(function(userId) {
if (userId !== GLB.userInfo.id) GLB.playerUserIds.push(userId)
});
this.startGame()
}
},
startGame: function () {
this.labelLog('遊戲即將開始')
cc.director.loadScene('game')
},
})
// 文件路徑:assets\scripts\Lobby.js複製代碼
遊戲進行中在建立星星、玩家進行向左、向右操做時,咱們將這些操做廣播給房間內其餘玩家。界面上同步展現各個玩家的狀態變化。
其中星星是房主建立和展現,而後通知其餘玩家,其餘玩家收到消息後展現,相關的代碼以下:
cc.Class({
onLoad: function() {
mvs.response.sendEventNotify = this.sendEventNotify.bind(this);
// ...
},
sendEventNotify: function (info) {
// ...
if (info.cpProto.indexOf(GLB.NEW_START_EVENT) >= 0) {
// 收到建立星星的消息通知,則根據消息給的座標建立星星
this.createStarNode(JSON.parse(info.cpProto).position)
} /* 其餘else if條件 */
},
// 根據座標位置建立渲染星星節點
createStarNode: function (position) {
// ...
},
// 發送建立星星事件
spawnNewStar: function () {
if (!GLB.isRoomOwner) return; // 只有房主可建立星星
var event = {
action: GLB.NEW_START_EVENT,
position: this.getNewStarPosition()
}
var result = mvs.engine.sendEvent(JSON.stringify(event))
if (!result || result.result !== 0)
return console.error('建立星星事件發送失敗');
this.createStarNode(event.position);
},
// 隨機返回'新的星星'的位置
getNewStarPosition: function () {
// ...
},
// ...
})
// 文件路徑:assets\scripts\Game.js複製代碼
玩家進行向左、向右操做時,這些消息會發送給其餘玩家:
cc.Class({
setInputControl: function () {
var self = this;
cc.eventManager.addListener({
event: cc.EventListener.KEYBOARD,
onKeyPressed: function (keyCode, event) {
var msg = { action: GLB.PLAYER_MOVE_EVENT };
switch (keyCode) {
case cc.KEY.a:
case cc.KEY.left:
msg.accLeft = true;
msg.accRight = false;
break;
case cc.KEY.d:
case cc.KEY.right:
msg.accLeft = false;
msg.accRight = true;
break;
default:
return;
}
var result = mvs.engine.sendEvent(JSON.stringify(msg));
if (result.result !== 0)
return console.error("移動事件發送失敗");
self.accLeft = msg.accLeft;
self.accRight = msg.accRight;
},
onKeyReleased: function (keyCode, event) {
var msg = { action: GLB.PLAYER_MOVE_EVENT };
switch (keyCode) {
case cc.KEY.a:
msg.accLeft = false;
break;
case cc.KEY.d:
msg.accRight = false;
break;
default:
return;
}
var result = mvs.engine.sendEvent(JSON.stringify(msg));
if (result.result !== 0)
return console.error("中止移動事件發送失敗");
if (msg.accLeft !== undefined) self.accLeft = false;
if (msg.accRight !== undefined) self.accRight = false;
}
}, self.node);
},
onLoad: function () {
// ...
this.setInputControl();
}
// ...
})
// 文件路徑:assets\scripts\Player1.js
cc.Class({
sendEventNotify: function (info) {
if (/* ... */) {
// ...
} else if (info.cpProto.indexOf(GLB.PLAYER_MOVE_EVENT) >= 0) {
// 收到其餘玩家移動的消息,根據消息信息修改加速度
this.updatePlayerMoveDirection(info.srcUserId, JSON.parse(info.cpProto))
} /* 更多else if條件*/
},
// 更新每一個玩家的移動方向
updatePlayerMoveDirection: function (userId, event) {
// ...
},
// ...
})
// 文件路徑:assets\scripts\Game.js複製代碼
考慮到數據同步會有延遲,不一樣客戶端收到的數據的延遲也會有差別,若是隻在同步玩家左右移動的操做數據,那麼過一段時間以後,不一樣客戶端的小怪物位置可能會不同,所以每隔一段時間仍是須要再同步一次小怪物的位置、速度和加速度數據:
cc.Class({
onLoad: function () {
// ...
setInterval(() => {
mvs.engine.sendEvent(JSON.stringify({
action: GLB.PLAYER_POSITION_EVENT,
x: this.node.x,
xSpeed: this.xSpeed,
accLeft: this.accLeft,
accRight: this.accRight,
ts: new Date().getTime()
}));
}, 200);
// ..
}
// ...
})
// 文件路徑:assets\scripts\Player1.js
cc.Class({
sendEventNotify: function (info) {
if (/* ... */) {
// ...
} else if (info.cpProto.indexOf(GLB.PLAYER_POSITION_EVENT) >= 0) {
// 收到其餘玩家的位置速度加速度信息,根據消息中的值更新狀態
this.receiveCountValue++;
this.receiveCount.string = "receive msg count: " + this.receiveCountValue;
var cpProto = JSON.parse(info.cpProto);
var player = this.getPlayerByUserId(info.srcUserId);
if (player) {
player.node.x = cpProto.x;
player.xSpeed = cpProto.xSpeed;
player.accLeft = cpProto.accLeft;
player.accRight = cpProto.accRight;
}
// ...
} /* 更多else if條件 */
},
// ...
})
// 文件路徑:assets\scripts\Game.js複製代碼
最終效果以下:
搞定。