Javascript TypeError, не удается получить доступ к методам объекта

Я использую p5.js, node.js и socket.io для создания небольшой многопользовательской игры в браузере. Объект с именем «игрок» передается от одного клиента к другому для синхронизации обоих клиентов. Это прекрасно работает для другого кода, который не полагается на вызовы методов. Но теперь, когда я также хочу получить доступ к методам сохраненных объектов в объекте игрока, это больше не работает.

Это будет объект, в котором хранятся все переменные и массив с объектами между двумя клиентами:

var player = {
  structures: []
};

Теперь, если я добавлю к нему объект с именем костер, вот так:

player.structures.push(new campfire(mouseX,mouseY));

И попробуйте вызвать метод draw() объекта костра, который выглядит так:

class campfire {
constructor(x,y){
    this.scale = 40;
    this.x = x;
    this.y = y;
    this.maxLevel = 3;
    this.button = new button(this.x, this.y+50, this.x-50, this.y-70, upgrade, upgrade_hover, this);
    this.show_upgrade_button = true;
}

draw(){
    switch(player.campfire.level){
        case 1: image(fire, this.x, this.y, this.scale, this.scale);break;
        case 2: image(campfire_2, this.x, this.y, this.scale, this.scale);break;
        case 3: image(campfire_3, this.x, this.y, this.scale, this.scale);break;
        default: console.info("cant upgrade, this shouldn't happen.");
    }
    if (this.show_upgrade_button){
        this.button.draw();
    }
}

trigger(){      
    if (player.campfire.level + 1 <= this.maxLevel && this.show_upgrade_button == true){
        this.button.trigger();
    }
}}

с использованием

player.structures[i].draw();

Консоль (клиента, не помещающего объект "костер" в массив "структуры") выводит следующую ошибку:

gui.js:38 Uncaught TypeError: player.structures[i].draw is not a function

Клиент, который помещает объект костра в массив, может выполнить вызов draw() и не выводить сообщение об ошибке. Однако другой клиент, который не отправил объект в массив, не может использовать этот метод и выводит ошибку, даже если они оба используют один и тот же объект «игрок». Странно то, что тот, кто распечатывает ошибку, по-прежнему может получить доступ ко всем переменным объекта костра, поэтому, похоже, это влияет только на методы.

Единственный ресурс, который я нашел по этому поводу, это статья https://airbrake.io/blog/javascript-error-handling/x-is-not-a-function-typeerror Я попытался переименовать функцию в draw = function(){} и campfire.prototype.draw = function(){}, но для меня это не имеет значения. Я думаю, что функции не объявлены правильно? Это было бы единственным возможным объяснением для меня прямо сейчас.

Спасибо за время, которое вы потратили, чтобы прочитать мой вопрос!

Обновлено: вот ссылка на проект: https://github.com/Mayhoon/Многопользовательская браузерная игра

Вы уверены, что ваш индекс i находится в диапазоне от 0 до player.structures.length - 1?

Dacre Denny 06.04.2019 23:45

Пожалуйста, опубликуйте Минимальный, полный и проверяемый пример

Ele 06.04.2019 23:46

@DacreDenny да, оба клиента знают длину массива, и я могу получить доступ к переменным объектов, например, при использовании player.structures[0].x. Цикл for, который я использую для перебора массива, работает, но только для клиента, который помещает объект в массив.

MayBee 07.04.2019 10:17

Можете ли вы опубликовать больше кода, показывающего, как вы заполняете массив структур, или предоставить ссылку, скажем, на репозиторий github?

Dacre Denny 07.04.2019 10:41

@Ele вот ссылка на проект: github.com/Mayhoon/Многопользовательская браузерная игра . Я использую «nodemon server.js» для запуска сервера на порту 3000. Вам нужно открыть 2 вкладки одновременно. После загрузки обоих нажмите h, нажмите на изображение и нажмите где-нибудь на экране. Предполагается, что значок молотка выполняет часть обновления и синхронизирует процесс с другим клиентом при нажатии. Я включил только необходимые классы.

MayBee 07.04.2019 11:57
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
0
5
71
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

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

Я бы посоветовал только толкать state вперед и назад. У игрока есть молоток? Сколько жизней у игрока? У игрока есть костер? Другими словами, синхронизируйте только те данные, которые постоянно меняются.

Поскольку функциональность костра (функция розыгрыша) одинакова для всех игроков, нет необходимости нажимать этот код туда-сюда каждые несколько секунд! Это совсем неэффективно!

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

В коде, который может выглядеть так (просто идея):

Синхронизация объекта для socket.io

var player = {
  structures: {campfire:true}
};

Код клиента

// create campfire instances, tell the campfire which player it belongs to
if (player.structures.campfire) {
    let cf = new Campfire(player)
    cf.draw()
}

примечание: вполне может быть, что socket.io удаляет исполняемый код

Спасибо за ваш ответ, я уже сделал что-то похожее с индикатором выполнения, который указывает на процесс обновления костра, и задался вопросом, есть ли лучший способ сделать это. Я не был уверен, что это проблема с javascript, потому что сообщение об ошибке предполагало это, поэтому я спросил здесь. Как вы уже писали, возможно, socket.io удаляет все методы, но я не воспользуюсь вашим советом и вместо этого просто использую переменные состояния - ваш ответ мне очень помог, большое спасибо!

MayBee 07.04.2019 14:04

Socket IO сериализует свои объекты. Во время сериализации JSON все методы исчезают, а сохраняются только свойства.

Manos Kounelakis 07.04.2019 14:40

Другие вопросы по теме