在游戏中同步NPC行为。 使用socket.io/node.js。 Unity2D

我正在制作3D元素游戏统一的2D自上而下。 这是一个多人游戏,我设置它的方式是通过一个主客户端(服务器)通过socket.io/ node.js将信息传递到后端服务器。

考虑到这是我第一次尝试这样一个壮举,我已经能够同步玩家,他们的生命线和旋转棋子的移动,以及他们的精灵翻转。

但是现在我冒险在这台服务器上制造怪物,而且我碰到了一个我没有同步玩家的问题。 我做他们的方式是让玩家控制器将信息传递给后端服务器,然后将其传播给其他玩家。 但是对于NPC,我只是简单地把一个控制器连接到产生的怪物上,在“服务器”客户端执行操作,然后转发给所有的客户端,以确保每个人都“同意”正在发生的事情和时间。

如果只有1个怪物,这似乎工作得很好,但是如果第二个我加上2个或更多,他们显然与他们的信息相冲突。 所以我看到我不能和球员做的一样。 为此,如果可能的话,我需要一些反馈。

信号发送如下:

命令产生怪物出于testing目的:

void CreateMonster() { var selectedSpawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)]; var spawnedEnemy = Instantiate(Enemy[Random.Range(0, Enemy.Length)], selectedSpawnPoint.transform.position, selectedSpawnPoint.transform.rotation); Debug.Log("im at " + spawnedEnemy.transform.position); socket.Emit("enemySpawned", Network.VectorToJson(spawnedEnemy.transform.position)); } 

服务器收到该信号:

 socket.on('enemySpawned', function(data){ var thisEnemyId = shortid.generate(); var currentTarget = ''; var Enemy = { id: thisEnemyId, x:0, y:0, target:currentTarget, }; Enemies[thisEnemyId] = Enemy; Enemy.x = data.x; Enemy.y = data.y; data.id = thisEnemyId; console.log("enemySpawned position: ", data); socket.broadcast.emit('enemySpawned', data); 

回到服务器并转发给产生者:

  public void SpawnEnemy(SocketIOEvent e) { var id = e.data["id"].str; var spawnPosition = new Vector3(e.data["x"].n, e.data["y"].n, 0); var enemy = Instantiate(orcShaman, spawnPosition, Quaternion.identity) as GameObject; enemy.name = "Enemy " + id; enemies.Add(id, enemy); } 

到现在为止还挺好。 一切工作正常,客户在正确的时间正确地看到了暴徒。

怪物在攻击玩家后移动他的位置:

  void Start () { InvokeRepeating("CheckForMove", 1.0f, 0.1f); } void CheckForMove() { if (lastPos != transform.position) { socket.Emit("enemyMove", Network.VectorToJson(transform.position)); lastPos = transform.position; } } 

服务器接收信息移动:

  socket.on('enemyMove', function(data){ Enemy.x = data.x; Enemy.y = data.y; data.id = thisEnemyId; console.log('enemy is moving', data); socket.broadcast.emit('enemyMove', data); }); 

游戏接收数据:

  private void OnEnemyMove(SocketIOEvent e) { var position = new Vector3(e.data["x"].n, e.data["y"].n, 0); var enemy = enemySpawner.FindEnemy(e.data["id"].str); var enemyNavigator = enemy.GetComponent<EnemyNavigator>(); enemyNavigator.MoveThisEnemy(position); } 

个人怪物现在应该收到信息移动到所述位置:

  public void MoveThisEnemy(Vector3 position) { rigid.MovePosition(position); anim.SetBool("walk", true); CheckFacingDirection(); } 

现在这只怪怪的只有一个怪物,但是有两个地狱破裂,他们开始看起来像是站在同一个地方,只有一个显示在他们之间跳来跳去。 这使我认为服务器一次只能移动一个,不能同时无缝地完成它们。 即使这个命令promt显示他们的数据发送非常好,每秒10次。

林不知道为什么会发生这种情况,我想知道如果我有可能从根本上误解了一些东西。 也许我需要重新devise与服务器的通信。

任何反馈都会很棒,而且我对这些都比较陌生,但是我已经把所有这一切都build立起来了,只需要几个tuturials,然后从我自己那里翩然而至,所以如果这看起来像是业余时间, apollo =(

谢谢阅读。


我已经缩小了问题的范围,让客户能够看到所有产生的小怪和他们的位置。 但是,当移动相同的事情发生。 我对这个问题非常有信心,因为我为每个怪物存储了错误的识别号码,并且发送了错误的数据。 我不知道正确的方法来做到这一点,所以我在这里链接我的服务器代码,希望有人做,并可以指出什么似乎造成它:

 var express = require('express'); var app = express(); var http = require('http').Server(app); var io = require('socket.io')(http); var shortid = require('shortid'); app.use(express.static(__dirname)); var players = []; io.on('connection', function(socket){ var thisPlayerId = shortid.generate(); var maxHealthValue = 0; var currentHealthValue = 10; var player = { id: thisPlayerId, x:0, y:0, currentHealth:currentHealthValue, maxHealth: maxHealthValue, UpSideDown:0 }; players[thisPlayerId] = player; console.log('client connected', thisPlayerId); console.log('list of current players: ', players); socket.emit('register', { id: thisPlayerId }); socket.broadcast.emit('otherPlayerConnected', player); for(var everyoneButMe in players){ if(everyoneButMe == thisPlayerId) // for everyone but me continue; console.log('not a main player joining'); socket.emit('otherPlayerConnected', players[everyoneButMe]); socket.emit('register', { id: thisPlayerId }); socket.broadcast.emit('requestData'); } for(var mainPlayer in players){ if(mainPlayer == thisPlayerId){ // for me console.log('main player joining'); socket.emit('spawn', player); } }; // bunch of functions for the players which work very well removed to make this more viser friendly // Section for Enemy logic from Master Client // This is where the problems arrise var Enemies = []; // Array to store Enemies var currentTarget = ''; var Enemy = { id: thisEnemyId, x:0, y:0, target:currentTarget, }; var thisEnemyId = 0; socket.on('enemySpawned', function(data){ thisEnemyId = Enemies.length ++ Enemies[thisEnemyId] = Enemy; Enemy.x = data.x; Enemy.y = data.y; data.id = thisEnemyId; console.log("enemySpawned position: ", data, thisEnemyId); socket.broadcast.emit('enemySpawned', data); }); socket.on('enemyMove', function(data){ Enemy.x = data.x; Enemy.y = data.y; data.id = thisEnemyId; console.log('enemy is moving', data); socket.broadcast.emit('enemyMove', data); }); }); http.listen(process.env.PORT || 3000, function(){; console.log('listening on *:3000'); }); console.log('-----------server started----------'); 

受Jolmos投入的启发,我解决了这个问题。 我没有提到他提到的信息,但我决定在主客户端上创build个别怪物的标识,并将其发送给服务器。

 void CreateMonster() { var random = new Random(); var selectedSpawnPoint = spawnPoints[Random.Range(0, spawnPoints.Length)]; selectedSpawnPoint.transform.position = new Vector3(Random.Range(0, 10), Random.Range(0,10), 0); var spawnedEnemy = Instantiate(Enemy[Random.Range(0, Enemy.Length)], selectedSpawnPoint.transform.position, selectedSpawnPoint.transform.rotation); spawnedEnemy.name = GetInstanceID().ToString() + Time.deltaTime.ToString(); socket.Emit("enemyRegister", Network.MobIdAndLocationToJson(spawnedEnemy.name, spawnedEnemy.transform.position)); } 

这发送这个信息:

  public static JSONObject MobIdAndLocationToJson(string id, Vector3 vector) { JSONObject j = new JSONObject(JSONObject.Type.OBJECT); j.AddField("id", id); j.AddField("x", vector.x); j.AddField("y", vector.y); return j; } 

登陆服务器:

  socket.on('enemyRegister', function(data){ var thisEnemyId = data.id; var enemy = { id: thisEnemyId, x:0, y:0, }; enemies[thisEnemyId] = enemy; enemy.x = data.x; enemy.y = data.y; socket.broadcast.emit('enemyRegister', data); 

回到客户:

  if (!enemies.ContainsKey(e.data["id"].str)) //TODO this works but for some reason it wants to spawn everyone from the list not only new one. { var id = e.data["id"].str; var spawnPosition = new Vector3(e.data["x"].n, e.data["y"].n, 0); var enemy = Instantiate(orcShaman, spawnPosition, Quaternion.identity) as GameObject; enemy.name = "Enemy " + id; enemies.Add(id, enemy); } 

现在意味着我的结果和以前一样,在正确的位置产卵,但是这次他们有独特的认同。 所以搬家实际工作:

  void CheckForMove() { if (lastPos != transform.position) { socket.Emit("enemyMove", Network.MobIdAndLocationToJson(gameObject.name, transform.position)); lastPos = transform.position; } } 

和服务器:

  socket.on('enemyMove', function(data){ Enemy.x = data.x; Enemy.y = data.y; console.log('enemy is moving', data); socket.broadcast.emit('enemyMove', data); }); 

到移动敌人的脚本:

  public void MoveThisEnemy(Vector3 position) { rigid.position = Vector3.MoveTowards(transform.position, position, speed * Time.deltaTime); } 

现在我正在试着去调整这个动作,所以我不需要在networking上发送太多的数据,因为现在每个怪物每秒发送一次他们的位置20次。 我太相信那个了。

谢谢大家的意见。