Я потерял много времени, пытаясь найти решение — как осуществить обмен данными между vue.js и Phaser. Этот вопрос заинтересовал меня, т.к. все что не касается игровой механики, намного удобнее и быстрее делать вне игрового движка, например: авторизация и вывод игровой статистики.

Поскольку у меня есть некоторый опыт работы с Vue.js, то я решил использовать его для этих целей.

Поскольку Phaser работает как отдельное приложение, то вы не можете передавать или извлекать информацию из него, для этого вам потребуется немного пофантазировать.

Я не мог найти, как передать какую-то переменную в Phaser через процесс инициализации игры или как достучаться из него во Vue. Казалось бы, у обоих инструментов есть большие комьюнити, но я нашел лишь много подобных вопросов на форумах или под видео на YouTube — и все они либо без ответа, либо содержат не рабочие или не полноценные ответы. Я решил написать эту короткую статью, потому что надеюсь помочь другим энтузиастам, которые находятся в самом начале пути.


Для того чтобы Phaser в целом запустить внутри Vue, я использовал проект -ion-phaser(статья).

Далее пошаговая инструкция:

  1. Создаем пустой проект. (Начнем с нуля, для того чтоб мы были на одной странице)

vue create my-awesome-project
cd my-awesome-project
yarn add phaser vuex @ion-phaser/core
  1. Настраиваем Phaser

Нужно добавить 2 строчки в main.js

import { defineCustomElements as defineIonPhaser } from '@ion-phaser/core/loader'

defineIonPhaser(window);

Также нужно задать конфигурацию загрузки ассетов в файле /vue.config.js.

  1. Создаем файл хранилища - vuex.

Разместим его в - /src/store/index.js

Подключаем его в приложение Vue:

// /src/main.js
import store from './store'
....
....
createApp(App)
  .use(store)
  .mount('#app');
  1. Добавим игровую логику:

Для примера я взял код с официального сайта Phaser.

Подключаем и конфигурируем игру в компоненте Vue - /src/game/Game.vue

В этом файле стоит обратить внимание на строки 44-51. Именно тут происходит прослушивание изменений состояния переменной count.

Само же изменение значения мы произведем внутри игровой логики. Будем начислять очки за каждую собранную звезду)

Разместим код игрового уровня в файле - /src/game/scenes/PlayScene.js

Файл довольно длинный и содержит лишь адаптированную копию кода, поэтому рассмотрим лишь отрывок который добавил автор:

import store from "@/store";

/*********/

collectStar(player, star) {
  star.disableBody(true, true);
  store.commit('increment');
}

Первая строка внедряет vuex в игровой код.

На строке 6 - мы производим вызов мутирующего метода - increment. Собрали звезду - добавили очко.

  1. Протестируем то что мы накодили.

Запускаем приложение:

yarn serve

На экране мы должны увидеть следующую картинку:

Игровой персонаж ударяясь головой об платформу вызывает появление звездочек, после того как он соберет 5ть - будет выведено сообщение о выигрыше средствами Vue.js.


Подводя итоги. В статье были рассмотрено следующее:

  • Интеграция Phaser во Vue.js

  • Подключение и настройка хранилища Vuex

  • Обмен состоянием между Vue.js и Phaser в обе стороны.

Ссылка на репозиторий с исходным кодом.


PS: Мой основной язык РНР, но для общего развития последнее время изучаю и серверный javascript. Самым веселым способом изучения, мне показалось - создать многопользовательскую сетевую игру. Если вам также интересна данная тема - буду рад пообщаться и покодить вместе :-)

Комментарии (10)


  1. Vadiok
    24.07.2022 02:28
    +1

    1-й момент: вместо того, чтобы следить за $store.state.count лучше использовать computed свойство.

    {
    	computed: {
    		starsCollected() {
    			return $store.state.count;
    		},
    	},
    	watch: {
    		starsCollected(value) {
    			if (value >= 5) {
    				// Странное решение для отображения победы, но ладно
    				alert('...');
    				window.location.reload();
    			}
    		},
    	},
    }
    

    2-й момент: вы параметры игры передаете из data, делая их реактивными, в т.ч. все, что формируется в Scenes. С т.з. производительности очень так себе идея. Если использовать Composition API, то можно избежать реактивности. Либо можно параметры передавать также как computed свойство, тогда Vue вроде как тоже не будет вешать реактивность на все, что внутри объекта.


    1. Desprit
      24.07.2022 09:38
      +1

      В дополнении к этому я бы очень советовал использовать Pinia вместо Vuex. Она на Typescript и помогает избежать багов, связанных с типами данных.


      1. Vadiok
        24.07.2022 13:26

        Да. Но в примере автора можно вообще просто переменную вне компонента через ref создать и с ней работать.


      1. khudyakv
        25.07.2022 16:18

        в pinia еще и мутаций больше нет


    1. Alexandroppolus
      24.07.2022 15:15

      2-й момент: вы параметры игры передаете из data, делая их реактивными, в т.ч. все, что формируется в Scenes

      Чего-то вроде observable.ref (из МобХ) так и не появилось?


      1. Vadiok
        24.07.2022 15:29

        Если говорить о Vue, а не о Vuex, то в composition API аналогом будет shallowRef. Хотя в примере ддя конфига, передаваемого в Phaser даже такая реактивность не требуется.


    1. Yurich_T
      25.07.2022 03:54

      Тут вместо вочера лучше использовать сеттер компьютед переменной.


    1. volkovnd
      25.07.2022 09:39

      На саом деле на счёт computed св-ва не соглашусь, поскольку состояние с количеством хранится внутри store, поэтому было бы логичнее хранить в геттере store св-во isWin, которое расчитывалось исходя от count и уже непосредственно его пробрасывать на компоненты


      1. Vadiok
        25.07.2022 09:49

        Наверное, да. Тут в целом код такой, что вместо того, чтобы его рефакторинг, лучше заново все написать.


        1. VladVerpeta Автор
          25.07.2022 19:50

          Спасибо за комментарии, все они уместные)

          Кто-то даже сделал форк на гитхабе и воплотил все описанные выше комментарии в жизнь)

          ---

          Не думаю что переданный конфиг в data - хоть как то замедлит игровой процесс, так же как и выбор как следить за стораджом(watch или  computed), как по мне это уже больше экономия на спичках и вкусовщина.

          ----

          Напомню что, цель статьи была - показать как легко и просто можно реализовать обмен данными между Vue и игрой на Phaser