当前位置:首页 > Web开发 > 正文

一起来学习用nodejs和CocosCreator开发网络游戏吧(六)

2024-03-31 Web开发

其实用了很永劫间思考了一下一些数据运算方面放在哪里合适。固然,数值方面的运算必定要放在处事端是正确的,本地的数值计算就会有被改削器改削、数据传输中抓包改包等作弊、外挂的问题存在,不过对付我这个小项目目前开发阶段来说,只涉及到对游戏角色移动操控这块。

在我本身所接触过的网游中,确实存在两种方法来措置惩罚惩罚角色移动数据,一个是发出操纵指令,然后处事器按照操纵指令计算出移动坐标再返给客户端措置惩罚惩罚,一个是本地计算移动距离,再将数据交付给处事器。这两种情况在游戏失线的时候就能有很明显的觉得,前者失线后,角色就无法移动了,做出的任何操纵指令都不会有反馈,后者在失线后,依然可以独霸角色在游戏中勾当。

这两种方法各有利弊,前者可以杜绝各类改削数据的外挂,但是对处事器会有很大的数据计算压力。后者无法制止一些神仙外挂,但是处事器方面计算本钱就会降低很多。

因为自身做过很多年的单机游戏,想学习一下网游的开发理论常识,才决定写这一系列的博客记录学习过程,所以决定使用全处事器措置惩罚惩罚数据的方案,将包孕角色移动的数据计算都放随处事器中进行。

在之前的篇章中,已经做好了摇杆,在场景中摆放了个角色。在这个根本上,接下来扩展一下处事器和客户端代码,让我们可以通过摇杆操纵角色,让处事器运算角色移动后的坐标并返回客户端,在客户端中表示出人物行走。同时,也能撑持多个客户端同时访谒,在客户端中可以看到多个角色的移动。

在确定了方案之后,就需要对处事器和客户端做出不小的窜改。

首先改革一下处事器,因为大部分的数据措置惩罚惩罚都放在处事器来做,那么就需要让处事器来主导数据形式。

因为初阶设计的模式是以舆图为单位来创建处事器,那么每个舆图城市有本身的信息,包孕舆图的名称,舆图中npc的数据以及舆图中玩家的数据。

在Server中创建MapServerModules文件夹,在里面创建mapObject.js文件,编写舆图的类代码。

class MapObject { constructor(mapName) { this.mapName = mapName;//舆图名称 this.npcs = [];//舆图中npc的数组 this.players = [];//舆图中玩家的数组 } //客户端连接完毕,创建玩家的数据信息后将其放入舆图的玩家数组中 addPlayer(player) { for(let i in this.players) { let playerItem = this.players[i]; if(player.getPlayerData().playerId === playerItem.getPlayerData().playerId) { return; } } this.players.push(player); } /** * 监听到玩家分开舆图,要从数组中将玩家信息删除 * 因为玩家分开后,需要通知其他还在连接中的玩家 * 所以延迟从数组中删失,是为了给其他玩家发送舆图玩家数据时符号玩家退出 */ deletePlayer(player) { setTimeout(() => { this.players.splice(this.players.indexOf(player), 1); }, 1000); } //舆图信息,将npc和玩家数据打包成数据集 getMapInfo() { return { npcs: this.npcs.map((item) => {return null}), players: this.players.map((item) => {return item.getPlayerData()}) } } } module.exports = MapObject;

舆图类创建好后,接着创建一个角色类,里面包罗了玩家的一些数据,以及相关的数据计算。固然,这些数据计算日后必定需要抽离出来,但因为此刻是一个简单的demo,暂时放在同一个类中进行措置惩罚惩罚。

在根目录的modules文件夹中,创建playerObject.js,用来编写玩家类的代码。因为本身设想的demo开发流程,还没有到插手数据库的时候,所以在这里,玩家数据初始化都使用了一些随机参数。

class PlayerObject { //结构函数中的相关初始化。 constructor() { this.dt = 1 / 60; //因为游戏的设计帧率是60帧,所以处事器在计算数据的时候,也选择60帧(即每秒进行60次计算) this.update = null; //循环计时器 //角色状态参数,站立,向摆布标的目的行走 this.State = { STATE_STAND: 1, STATE_WALK_LEFT: 2, STATE_WALK_RIGHT: 3 }; //玩家角色数据集,初始化随机的id和随机的名字 this.playerData = { playerId: this.makeUUID(), playerName: "player" + Math.ceil(Math.random() * 100), playerAttribute: { //角色数据 logout: false, //是否退出舆图的标示符 currentState: this.State.STATE_STAND, //角色当前状态 moveSpeed: 150.0, //角色移动速度 position: { //角色在舆图中的坐标 x: -500, y: -460 }, scale: { //角色动画的缩放参数,角色的面向是通过缩放参数来控制的 x: 3, y: 3 } } }; this.connection = null; //角色的websocket连接东西 } //获取到角色的相关数据,用在map中生成数据合集 getPlayerData() { return this.playerData; } addConnection(connection) { this.connection = connection; } makeUUID() { return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function(c) { var r = (Math.random() * 16) | 0, v = c == "x" ? r : (r & 0x3) | 0x8; return v.toString(16); }); } //接收玩家的操纵,目前只有操控移动,所以这里是按照操纵转变角色状态 operation(data) { this.playerData.playerAttribute.currentState = data.state; } /** * 角色在处事器生成后,需要发送动静到客户端 * 客户端进行角色人物动画加载,加载完成后,再通知处事器可以开始角色数据运算 * 这里使用按时器循环计算 */ start() { this.update = setInterval(() => { if (!this.playerData.playerAttribute) { return; } switch (this.playerData.playerAttribute.currentState) { case this.State.STATE_STAND: break; case this.State.STATE_WALK_LEFT: this.walkLeft(); break; case this.State.STATE_WALK_RIGHT: this.walkRight(); break; } //计算完成后,通过websocket的连接东西,连同舆图中全部的npc和角色信息,一并返回给客户端 if (this.connection) { let map = this.connection.map; let mapData = map.getMapInfo(); let data = { /** * 数据格局暂定 * dataType 数据操纵指令 * data 数据 */ dataType: "GAME_PLAYER_DATA", data: mapData }; this.connection.sendText(JSON.stringify(data)); } }, this.dt * 1000); } //符号角色分开舆图,遏制数据计算 end() { this.playerData.playerAttribute.logout = true; clearInterval(this.update); } //计算角色移动后的坐标,和措置惩罚惩罚面向 walkLeft() { let dis = this.playerData.playerAttribute.moveSpeed * this.dt; this.playerData.playerAttribute.position.x = this.playerData.playerAttribute.position.x - dis; this.playerData.playerAttribute.scale.x = Math.abs(this.playerData.playerAttribute.scale.x) * -1; } walkRight() { let dis = this.playerData.playerAttribute.moveSpeed * this.dt; this.playerData.playerAttribute.position.x = this.playerData.playerAttribute.position.x + dis; this.playerData.playerAttribute.scale.x = Math.abs( this.playerData.playerAttribute.scale.x ); } } module.exports = PlayerObject;

如此就创建好了一个简单的舆图类和一个简单的角色类措置惩罚惩罚舆图和角色信息。

接下来创建一下舆图的处事器。在Server目录下,添加mapServer.js。

温馨提示: 本文由Jm博客推荐,转载请保留链接: https://www.jmwww.net/file/web/32997.html