Встраивание игр Phaser3 в функциональные компоненты React 18 с помощью useEffects
5 марта 2023 г.Вот шаблон для встраивания игр Phaser3 в компоненты React.
В самой простой реализации вы можете использовать этот шаблон для добавления игр Phaser3 и обращаться с ними как с GIF-анимацией на стероидах.
В самом сложном случае я покажу вам, как запускать игры Phaser3 внутри (и из других) компонентов React, перехватывать события, происходящие внутри игры, и запускать функции в React. Эти события могут обновлять уведомления о статусе в баннере веб-сайта или отправлять данные во внутренний API вашего веб-сайта, чтобы вести постоянную запись прогресса игрока.
Как и во всех моих сообщениях, я не буду снабжать решения слишком большим количеством фрагментов «сейчас добавь это» и «затем добавь это», а просто покажу вам целые шаблоны кода, которые сработали для меня.
Предпосылки
- Знакомство с React.
- Знакомство с Phaser3.
- Знакомство с JavaScript.
- Склонность нажимать кнопки «Мне нравится этот пост».
Основной шаблон
Как и было обещано, вот основной шаблон, который мы будем использовать:
import Phaser from "phaser"
import React, { useEffect, useState } from "react"
import happyFace from "./happy-face.png"
class HappyFaceScene extends Phaser.Scene {
preload() {
// A convention of mine to avoid `this` confusion with sub classes is to
// give it a better reference name at the top of every function.
let scene = this
scene.load.image("happyFace", happyFace)
}
create(data) {
let scene = this
// Add your game objects and all that other stuff. It's just a simple image.
scene.add.image(0, 0, "happyFace").setOrigin(0, 0).setDisplaySize(480, 142)
// Finally trigger an event so that the scene is now visible. This is optional
// but useful if you want to transition your game's appearance.
scene.game.events.emit("putOnAHappyFace", true)
}
update() {
let scene = this
let { lives, progress } = scene
// For example, monitor the number of lives and exit when
if (!lives) {
// Save the progress.
game.registry.merge(progress)
// Trigger the game end.
scene.game.events.emit("putOnAHappyFace", false)
}
}
}
export const Phaser3GameComponent = () => {
const [isReady, setReady] = useState(false);
useEffect(() => {
// Nothing really special here... Your phaser3 config should work just fine.
let config = {
height: 320,
width: 480,
physics: { default: "arcade" },
scale: {
// Except this should match the ID of your component host element.
parent: "phaser-game",
mode: Phaser.Scale.FIT,
autoCenter: Phaser.Scale.CENTER_HORIZONTALLY,
},
transparent: true,
type: Phaser.AUTO,
}
let game = new Phaser.Game(config)
// Triggered when game is fully visible.
game.events.on('putOnAHappyFace', setReady)
// Add your scene/s here (or in `scene` key of `config`).
game.scene.add("HappyFaceScene", HappyFaceScene, true)
// If you don't do this, you get duplicates of the canvas piling up
// everytime this component renders.
return () => {
setReady(false)
game.destroy(true)
}
// You must have an empty array here otherwise the game restarts every time
// the component renders.
}, [])
// Return the host element where Phaser3 will append the canvas.
return <div id="phaser-game" className={isReady ? "visible" : "invisible"} />
}progress
Вы видите, насколько это просто. React делает то, для чего создан: он реагирует на происходящее в игре.
Оценка
Помимо того, что React обычно перехватывает события, вызванные игрой, его также можно подключить к настройке обратных вызовов
Phaser.
В этом дополнительном фрагменте, который вы должны добавить в часть конфигурации Phaser Game приведенного выше шаблона, мы будем загружать предыдущий прогресс пользователя в «реестр» игры Phaser3 с помощью функции merge
. Мы также можем отслеживать изменения в
...
physics: { default: "arcade" },
callbacks: {
preBoot: (game) => {
game.registry.merge(userProgress)
game.registry.events.on('changedata', function(parent, key, value, previousValue) => {
updateUserProgress(key, value)
})
},
},
...
Где userProgress
выходит из хранилища, а updateUserProgress
изменяет изменения обратно в хранилище.
Это показывает, насколько легко встраивать игры Phaser (либо для отображения неинтерактивной анимации, либо для воспроизведения) в React, а также передавать данные туда и обратно.
Модальный
Наконец, использование div в качестве контейнера идеально подходит, если вы хотите встроить игру в страницу. В реализации, над которой я работаю для клиента, игра отображается в полноэкранном режиме с использованием модального окна Bootstrap-React следующим образом:
return (
<Modal show={isReady} backdrop="static" fullscreen={true} keyboard={false}>
<Modal.Body>{isReady && <div id="PhaserGame" />}</Modal.Body>
</Modal>
)
С этим простым изменением модальное окно начальной загрузки будет всплывать при загрузке игры и исчезать, когда оно закончится.
Оригинал