Java Script переписывает индексы массива после сращивания - PullRequest
0 голосов
/ 07 июня 2018

У меня проблема, когда кажется, что я перезаписываю индексы массива после объединения, по крайней мере, я так думаю.Это небольшая игра, созданная с использованием Phaser 2. По сути, это всего лишь небольшая многопользовательская игра с прыжками, чтобы получить опыт работы с архитектурой клиент / сервер.Использовали socket.io и express.Кажется, моя проблема на сервере, где, когда клиент отключается, когда его удаляют из списка игроков, другой игрок, все еще находящийся в игре, кажется, перезаписывает индекс игрока, который отключился.Для отладки этого я в основном использовал консольные журналы, используя цикл for, чтобы перебрать список и распечатать идентификаторы сокетов плеера.Так, например, если я присоединяюсь к игроку 1 с идентификатором гнезда 1, присоединяется игрок 2 с идентификатору гнезда 2, а затем игрок 2 уходит, цикл for выводит 1, 1. Если после игрока присоединяется новый игрок 3 с идентификатором гнезда 32 осталось, распечатка идентификаторов игроков выведет 1, 1, 3. Сначала я подумал, что проблема в том, что в функции onNewPlayer (data) у меня возникла проблема с алиасингом, потому что я использовал var currentInfo в двухв разных местах, поэтому я изменил второй объект на var info.Кажется ли, что это какая-то проблема с псевдонимами, или я должен искать эту проблему где-то еще?Я могу предоставить дополнительный код при необходимости, пока все наши обратные вызовы для создания и перемещения игроков работали нормально.Благодарю.

ниже - соответствующий код на стороне сервера

var players[];
//When a new player is made, save it
function onNewPlayer(data) {
  var newPlayer = new Player(data.x, data.y, this.id);

  var currentInfo = {
    x: newPlayer.x,
    y: newPlayer.y,
    id: newPlayer.id,
  };

  for(i = 0; i < players.length; i++) {
    //broadcast the new player out to all the other players in the list  
    this.broadcast.emit("newEnemy", currentInfo);
  }

  //check for if there are already players,
  //if so, send the player's who are already in the game to the new player
  if(players.length > 0) {
    for(i = 0; i < players.length; i++) {
        var info = {
            x: players[i].x,
            y: players[i].y,
            id: players[i].id,
        };
        this.emit("newEnemy", info);
    }
  }

  players.push(newPlayer);
  for(i = 0; i < players.length; i++) {
    console.log(players[i].id);
  }
}

function onDisconnect(){
    console.log("User " + this.id + " disconnected");
    //find the user in the list of players and remove them, then tell the client
    for(i = 0; i < players.length; i++) {
        if(players[i].id === this.id) {
            console.log("removing this player " + this.id);
            //TODO trying a different broadcast
            this.broadcast.emit("playerDisconnect", this.id);
            console.log(players[i].id);
            players.splice(i, 1);
        }
    }
}

ниже - соответствующий код на стороне клиента

//We've lost connection with the server!
function onSocketDisconnect() {
    console.log("Lost connection with server!");
};

//When the server notifies the client an enemy has disconnected,
//search for it in the enemies list and stop rendering it
function onEnemyDisconnect(data) {
    //TODO
    for(i = 0; i < enemies.length; i++) {
        if(enemies[i].id == data) {
            //TODO
            console.log("destroying");
            enemies[i].destroy();
            enemies.splice(i, 1);
        }
    }
}

1 Ответ

0 голосов
/ 07 июня 2018

Вы перебираете массив в прямом направлении с помощью цикла for И удаляете элементы из массива с помощью .splice().Это не будет работать должным образом, потому что когда вы вызываете .splice() для удаления элемента из массива, он копирует более поздние элементы из массива на одну позицию вниз.Но ваш индекс цикла for указывает на следующий элемент в массиве.Конечным результатом является то, что вы пропускаете итерации элементов в массиве.

Существует несколько возможных решений.

  1. Вы можете выполнять итерацию массива назад, а не вперед.При выполнении итерации в обратном порядке элементы .splice(), на которые вы еще не выполнялись, не подвержены влиянию *1011*, и он работает просто отлично.

  2. Вы можете прекратить изменять массив, находясь в for петля.Возможно, вы соберете набор индексов, которые хотите удалить, а затем удалите их задом наперед.

  3. Вы можете использовать .filter(), чтобы создать новый массив, который является подмножествомисходный массив и после выполнения операции .filter() просто назначьте новый массив вашей переменной и используйте его с этого момента.

  4. Вы можете сохранить итерацию такой, какая вы есть, но вернойиндекс цикла for после вызова .splice(), уменьшив его на единицу.

Вот пример обратной итерации массива:

// When the server notifies the client an enemy has disconnected,
// search for it in the enemies list and stop rendering it
function onEnemyDisconnect(data) {
    // use reverse iteration to avoid skipping elements when calling .splice()
    for (i = enemies.length - 1; i >= 0; i--)
        if(enemies[i].id == data) {
            console.log("destroying");
            enemies[i].destroy();
            enemies.splice(i, 1);
        }
    }
}

Вотпример .filter(), который предполагает, что вы можете присвоить enemies, и новый массив навсегда займет свое место:

// When the server notifies the client an enemy has disconnected,
// search for it in the enemies list and stop rendering it
function onEnemyDisconnect(data) {
    enemies = enemies.filter(item => {
        if (item.id === data) {
            console.log("destroying");
            item.destroy();
            return false;    // don't keep this one
        }
        return true;
    });
}
...