如何将 Phaser 集成到 React 中
How to integrate Phaser into React
我有一个用 create-react-app 创建的 React 应用程序,我也在尝试集成 Phaser 3。我跟着 this guide 开始了。我有 canvas 渲染文本,但在预加载中加载图像似乎不起作用。我得到了默认显示加载失败的纹理图像。
import ExampleScene from "./scenes/ExampleScene";
import * as React from "react";
export default class Game extends React.Component {
componentDidMount() {
const config = {
type: Phaser.AUTO,
parent: "phaser-example",
width: 800,
height: 600,
scene: [ExampleScene]
};
new Phaser.Game(config);
}
shouldComponentUpdate() {
return false;
}
render() {
return <div id="phaser-game" />;
}
}
示例场景:
import Phaser from "phaser";
export default class ExampleScene extends Phaser.Scene {
preload() {
this.load.image("logo", "assets/logo.png");
}
create() {
const text = this.add.text(250, 250, "Phaser", {
backgroundColor: "white",
color: "blue",
fontSize: 48
});
text.setInteractive({ useHandCursor: true });
this.add.image(400, 300, "logo");
text.on("pointerup", () => {
console.log("Hello!");
//store.dispatch({ type: ACTION_TYPE });
});
}
}
我们的想法是创建一个基于简单基因引擎的花朵生长的可视化。因此 Phaser 将从商店获取有关当前状态的说明。
我猜想这与 Phaser 的加载方式有关,并且与 React 的更新方式存在冲突。我正在阻止组件更新,因为我只需要游戏通过收听商店来接收指令
我已经看过这个SO answer and the accompanying wrapper,但它已经过时了。
如何让 Phaser 在 Create-React-App 中加载图像?
代码沙箱:https://codesandbox.io/s/github/nodes777/react-punnett/tree/phaser-game
回购:https://github.com/nodes777/react-punnett/tree/phaser-game
我从头开始创建 my own boilerplate from the phaser 3 template. I wrote about the specific steps to add React to the Phaser 3 template here。
您似乎可以从 Create-React-App 中弹出并从那里添加 Phaser 3,但是不要弹出的警告让我放弃了该解决方案。
其他选项使用 WebComponents 以便能够将 Phaser 与任何其他框架(React、Angular、VueJS等),检查这个 npm 包:https://www.npmjs.com/package/@ion-phaser/core
此外,您可以使用该库的 React 包装器轻松地将 Phaser 与 React 组件一起使用,因此您无需直接操作 WebComponents,示例:
import React from 'react'
import Phaser from 'phaser'
import { IonPhaser } from '@ion-phaser/react'
const game = {
width: "100%",
height: "100%",
type: Phaser.AUTO,
scene: {
init: function() {
this.cameras.main.setBackgroundColor('#24252A')
},
create: function() {
this.helloWorld = this.add.text(
this.cameras.main.centerX,
this.cameras.main.centerY,
"Hello World", {
font: "40px Arial",
fill: "#ffffff"
}
);
this.helloWorld.setOrigin(0.5);
},
update: function() {
this.helloWorld.angle += 1;
}
}
}
const App = () => {
return (
<IonPhaser game={game} />
)
}
export default App;
有关更多详细信息,请查看存储库:https://github.com/proyecto26/ion-phaser/tree/master/react
您需要将图片放入文件夹public!
对我来说,我认为正确使用它们的最佳做法是单独创建相位器项目并使用 firebase 或您喜欢的任何托管服务单独托管它,然后将 link 放入在 iframe 标签里面做出反应。
通过这种方式,您可以有效地管理它们,并且可以以更舒适的方式操作 React 网站,尤其是移动宽度兼容性。
一年前我自己在这里寻找答案。这是应该起作用的模式。
import Phaser from "phaser"
import React, { useEffect, useState } from "react"
/** @tutorial I made this! This answers how you get your image. */
import logoImage from "./path-to-logo.png"
/** @tutorial I made this! Use a functional React component and `useEffect` hook.*/
export const Phaser3GameComponent = ({ someState }) => {
// Optional: useful to delay appearance and avoid canvas flicker.
const [isReady, setReady] = useState(false)
// Just an example... do what you do here.
const dataService = (changedState) => {
// I'm not sure how to use stores, but you'll know better what to do here.
store.dispatch(
{
...someState,
...changedState,
},
{ type: ACTION_TYPE }
)
}
// This is where the fun starts.
useEffect(() => {
const config = {
callbacks: {
preBoot: game => {
// A good way to get data state into the game.
game.registry.merge(someState)
// This is a good way to catch when that data changes.
game.registry.events.on("changedata", (par, key, val, prevVal) => {
// Simply call whatever functions you want outside.
dataService({ [key]: val })
})
},
},
type: Phaser.AUTO,
parent: "phaser-example",
width: 800,
height: 600,
scene: [ExampleScene],
}
let game = new Phaser.Game(config)
// Triggered when game is fully READY.
game.events.on("READY", setReady)
// If you don't do this, you get duplicates of the canvas piling up.
return () => {
setReady(false)
game.destroy(true)
}
}, []) // Keep the empty array otherwise the game will restart on every render.
return (
<div id="phaser-example" className={isReady ? "visible" : "invisible"} />
)
}
export default class ExampleScene extends Phaser.Scene {
preload() {
this.load.image("logo", logoImage)
}
create() {
// You made this!
const text = this.add.text(250, 250, "Phaser")
text.setInteractive({ useHandCursor: true })
this.add.image(400, 300, "logo")
/** @tutorial I made this! */
// Get all that lovely dataState into your scene,
let { clickCount } = this.registry.getAll()
text.on("pointerup", () => {
// This will trigger the "changedata" event handled by the component.
this.registry.merge({ clickCount: clickCount++ })
})
// This will trigger the scene as now being ready.
this.game.events.emit("READY", true)
}
}
我有一个用 create-react-app 创建的 React 应用程序,我也在尝试集成 Phaser 3。我跟着 this guide 开始了。我有 canvas 渲染文本,但在预加载中加载图像似乎不起作用。我得到了默认显示加载失败的纹理图像。
import ExampleScene from "./scenes/ExampleScene";
import * as React from "react";
export default class Game extends React.Component {
componentDidMount() {
const config = {
type: Phaser.AUTO,
parent: "phaser-example",
width: 800,
height: 600,
scene: [ExampleScene]
};
new Phaser.Game(config);
}
shouldComponentUpdate() {
return false;
}
render() {
return <div id="phaser-game" />;
}
}
示例场景:
import Phaser from "phaser";
export default class ExampleScene extends Phaser.Scene {
preload() {
this.load.image("logo", "assets/logo.png");
}
create() {
const text = this.add.text(250, 250, "Phaser", {
backgroundColor: "white",
color: "blue",
fontSize: 48
});
text.setInteractive({ useHandCursor: true });
this.add.image(400, 300, "logo");
text.on("pointerup", () => {
console.log("Hello!");
//store.dispatch({ type: ACTION_TYPE });
});
}
}
我们的想法是创建一个基于简单基因引擎的花朵生长的可视化。因此 Phaser 将从商店获取有关当前状态的说明。
我猜想这与 Phaser 的加载方式有关,并且与 React 的更新方式存在冲突。我正在阻止组件更新,因为我只需要游戏通过收听商店来接收指令
我已经看过这个SO answer and the accompanying wrapper,但它已经过时了。
如何让 Phaser 在 Create-React-App 中加载图像?
代码沙箱:https://codesandbox.io/s/github/nodes777/react-punnett/tree/phaser-game 回购:https://github.com/nodes777/react-punnett/tree/phaser-game
我从头开始创建 my own boilerplate from the phaser 3 template. I wrote about the specific steps to add React to the Phaser 3 template here。
您似乎可以从 Create-React-App 中弹出并从那里添加 Phaser 3,但是不要弹出的警告让我放弃了该解决方案。
其他选项使用 WebComponents 以便能够将 Phaser 与任何其他框架(React、Angular、VueJS等),检查这个 npm 包:https://www.npmjs.com/package/@ion-phaser/core
此外,您可以使用该库的 React 包装器轻松地将 Phaser 与 React 组件一起使用,因此您无需直接操作 WebComponents,示例:
import React from 'react'
import Phaser from 'phaser'
import { IonPhaser } from '@ion-phaser/react'
const game = {
width: "100%",
height: "100%",
type: Phaser.AUTO,
scene: {
init: function() {
this.cameras.main.setBackgroundColor('#24252A')
},
create: function() {
this.helloWorld = this.add.text(
this.cameras.main.centerX,
this.cameras.main.centerY,
"Hello World", {
font: "40px Arial",
fill: "#ffffff"
}
);
this.helloWorld.setOrigin(0.5);
},
update: function() {
this.helloWorld.angle += 1;
}
}
}
const App = () => {
return (
<IonPhaser game={game} />
)
}
export default App;
有关更多详细信息,请查看存储库:https://github.com/proyecto26/ion-phaser/tree/master/react
您需要将图片放入文件夹public!
对我来说,我认为正确使用它们的最佳做法是单独创建相位器项目并使用 firebase 或您喜欢的任何托管服务单独托管它,然后将 link 放入在 iframe 标签里面做出反应。 通过这种方式,您可以有效地管理它们,并且可以以更舒适的方式操作 React 网站,尤其是移动宽度兼容性。
一年前我自己在这里寻找答案。这是应该起作用的模式。
import Phaser from "phaser"
import React, { useEffect, useState } from "react"
/** @tutorial I made this! This answers how you get your image. */
import logoImage from "./path-to-logo.png"
/** @tutorial I made this! Use a functional React component and `useEffect` hook.*/
export const Phaser3GameComponent = ({ someState }) => {
// Optional: useful to delay appearance and avoid canvas flicker.
const [isReady, setReady] = useState(false)
// Just an example... do what you do here.
const dataService = (changedState) => {
// I'm not sure how to use stores, but you'll know better what to do here.
store.dispatch(
{
...someState,
...changedState,
},
{ type: ACTION_TYPE }
)
}
// This is where the fun starts.
useEffect(() => {
const config = {
callbacks: {
preBoot: game => {
// A good way to get data state into the game.
game.registry.merge(someState)
// This is a good way to catch when that data changes.
game.registry.events.on("changedata", (par, key, val, prevVal) => {
// Simply call whatever functions you want outside.
dataService({ [key]: val })
})
},
},
type: Phaser.AUTO,
parent: "phaser-example",
width: 800,
height: 600,
scene: [ExampleScene],
}
let game = new Phaser.Game(config)
// Triggered when game is fully READY.
game.events.on("READY", setReady)
// If you don't do this, you get duplicates of the canvas piling up.
return () => {
setReady(false)
game.destroy(true)
}
}, []) // Keep the empty array otherwise the game will restart on every render.
return (
<div id="phaser-example" className={isReady ? "visible" : "invisible"} />
)
}
export default class ExampleScene extends Phaser.Scene {
preload() {
this.load.image("logo", logoImage)
}
create() {
// You made this!
const text = this.add.text(250, 250, "Phaser")
text.setInteractive({ useHandCursor: true })
this.add.image(400, 300, "logo")
/** @tutorial I made this! */
// Get all that lovely dataState into your scene,
let { clickCount } = this.registry.getAll()
text.on("pointerup", () => {
// This will trigger the "changedata" event handled by the component.
this.registry.merge({ clickCount: clickCount++ })
})
// This will trigger the scene as now being ready.
this.game.events.emit("READY", true)
}
}