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

时间:2017-05-15 17:00:10

标签: node.js unity3d socket.io

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

考虑到这是我第一次尝试这样的壮举,我已经能够同步运动员的运动,他们的健康状况和旋转以及精灵的翻转。

然而现在我冒险在这台服务器上制作怪物,我遇到了一个问题,我没有同步玩家。我这样做的方法是让播放器控制器将信息中继到后端服务器,然后后端服务器广播给其他玩家。但是对于NPC,我只是简单地将一个控制器附加到生成的暴徒身上,然后在服务器"上执行操作。客户端然后转发给所有客户,以确保每个人都同意"在发生什么事情和什么时候发生

如果只有1个怪物,这似乎工作得非常好,但是第二个我添加了2个或更多,他们显然是在冲突他们的信息。所以我看到我不能像玩家那样做。为此,如果可能的话,我需要一些反馈。

信号发送如下:

命令产生怪物用于测试目的:

    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);

返回服务器并转发给spawner:

    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);
}
到目前为止一切顺利。一切都很好,客户在正确的时间看到了正确的位置。

Monster在攻击玩家后移动了他的位置:

  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();
}

现在这一切对于只有1个怪物来说非常有效,但是2个地狱全部破裂了,他们开始看起来像是站在同一个地方,一次只能看到1个在它们之间来回跳跃。这让我觉得服务器一次一个地移动,不能同时无缝地完成它们。即使命令promt显示他们的数据每秒发送10次也很好。

我不确定为什么会发生这种情况,我想知道我是否可能从根本上误解了某些事情。也许我需要重新设计与服务器的通信。

任何反馈都很精彩,而且我对这一切都相对较新,但是我已经用一些tuturials建立了所有这些,然后我自己就在那里展开,所以如果这看起来像业余的话请放轻松小时在阿波罗=(

感谢阅读。

我已经缩小了问题范围,让客户能够看到所有产生的怪物及其位置。但是当移动同样的事情发生时。我相信这个问题是因为我存储了各个怪物的识别号错误并且发送错误的数据。我不知道正确的方法,所以我在这里链接我的服务器代码希望有人这样做,并可以指出似乎导致它的原因:

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----------');

1 个答案:

答案 0 :(得分:0)

灵感来自Jolmos&#39;输入我已经解决了这个问题。我没有提到他提到的信息,但我决定在主客户端上创建各个怪物的标识,并将其发送到服务器一个第一个产卵。

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);
}

现在我正在尝试优化运动,所以我不必在网络上发送太多数据,因为每个怪物每秒发送它们的位置20次。我太相信了。

谢谢大家的意见。