一、项目搭建
工欲善其事,必先利其器
模板创建
创建项目,我选择了react + ts
的模版,在不熟悉一个新的游戏框架的情况下,用 ts 会方便许多,可以明显的看到报错。
pnpm create vite@latest
自动格式化
一个好的项目怎么能没有自动格式化
- 安装 prettier 和 eslint 插件
pnpm i prettier
(因为模板里已安装了 eslint 包)- 创建一个
.prettierrc.cjs
文件,写入习惯,此时按快捷键就可以格式化了
// .prettierrc.js
module.exports = {
printWidth: 100, //一行的字符数,如果超过会进行换行,默认为80
singleQuote: true, // 字符串是否使用单引号,默认为 false,使用双引号
semi: false, // 行尾是否使用分号,默认为true
trailingComma: 'none' // 是否使用尾逗号
}
4. 创建 .vscode
文件夹,在其中创建 settings.json
文件,写入
{
"editor.formatOnSave": true, // 自动保存
"editor.defaultFormatter": "esbenp.prettier-vscode" // 按 prettier 格式化
}
注意别忘了从 .ignore
文件里移除 .vscode
的忽略
tailwindcss
这个单纯是习惯了,可以不用,引入可参考www.tailwindcss.cn/docs/guides…
构建成单个html文件
也是个人习惯,把打包好的html拖到手机上测试,不想分成那么多文件。需要配置 vite.config.ts
文件
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import { viteSingleFile } from 'vite-plugin-singlefile'
export default defineConfig({
plugins: [react(), viteSingleFile()]
})
二、游戏主体
无所谓,
我会出手GPT 会出手
- 引入
phaser3
pnpm i phaser
2. 写一个最基本的画布
const App = () => {
useEffect(() => {
// 配置项
const config: Phaser.Types.Core.GameConfig = {
type: Phaser.AUTO,
width: CANVAS_WIDTH,
height: CANVAS_HEIGHT,
backgroundColor: '#f0f0f0',
parent: 'game-container', // 挂载的demo
scene: {
// 游戏核心的三个函数,下文再写
preload: preload,
create: create,
update: update
}
}
// 激活
const game = new Phaser.Game(config)
// 销毁
return () => {
game.destroy(true, true)
}
}, [])
return <div id="game-container"></div>
}
export default App
到这一步就可以看到一个灰色的画布了
- 生成物品
let ball: Phaser.Physics.Arcade.Image
let paddle: Phaser.Physics.Arcade.Image
let bricks: Phaser.Physics.Arcade.StaticGroup
let score = 0
let scoreText: Phaser.GameObjects.Text
function create(this: Phaser.Scene) {
// 创建球
ball = this.physics.add.image(CANVAS_WIDTH / 2, CANVAS_HEIGHT - 50, 'ball')
ball.setCollideWorldBounds(true) // 世界边缘碰撞
ball.setBounce(1, 1)
ball.setVelocityY(BALL_SPEED)
ball.body!.setCircle(ball.width / 2)
ball.setMaxVelocity(BALL_SPEED)
// 创建挡板
paddle = this.physics.add.image(CANVAS_WIDTH / 2, CANVAS_HEIGHT, 'paddle')
paddle.setCollideWorldBounds(true) // 世界边缘碰撞
paddle.setImmovable(true)
paddle.body!.setCircle(paddle.width / 2)
// 创建砖块
bricks = this.physics.add.staticGroup({
key: 'brick',
repeat: Math.floor(CANVAS_WIDTH / 100),
setXY: {
x: BLOCK_WIDTH,
y: 150,
stepX: CANVAS_WIDTH / Math.floor(CANVAS_WIDTH / 100)
}
})
// 将每个砖块转换为圆形
bricks.children.iterate((brick) => {
if (brick.body) {
brick.body.setCircle(BLOCK_WIDTH / 2)
}
})
}
- 增加物理碰撞
在 config 中开启物理引擎
physics: {
default: 'arcade',
arcade: {
debug: true // 碰撞箱辅助线
}
},
在 create 中增加碰撞对象
// 为球和砖块增加碰撞事件
this.physics.add.collider(ball, paddle)
this.physics.add.collider(ball, bricks, (_, brick) => {
brick.destroy()
score += 10
scoreText.setText(`Score: ${score}`)
})
到这一步,就可以看到画布上的游戏雏形了(是的,我没有搞贴图,加图片的话就不能放到一个html了)
- 动起来
- 键盘操控
// 动
function update(this: Phaser.Scene) {
const cursors = this.input.keyboard?.createCursorKeys()
// const cursors = joyStick.createCursorKeys()
if (!cursors) {
return
}
if (cursors.left.isDown) {
paddle.setVelocityX(-PADDLE_SPEED)
} else if (cursors.right.isDown) {
paddle.setVelocityX(PADDLE_SPEED)
} else {
paddle.setVelocityX(0)
}
if (ball.y >= CANVAS_HEIGHT - 20) {
ball.setVelocity(0)
// 显示失败消息
this.add.text(200, 250, 'Game Over', { fontSize: '64px', color: '#FF0000' })
ball.disableBody(true)
// 重新开始游戏
this.time.delayedCall(2000, () => {
window.location.reload()
})
}
if (bricks.countActive() === 0) {
// 显示胜利消息
this.add.text(200, 250, 'You Win!', { fontSize: '64px', color: '#00FF00' })
ball.disableBody(true)
// 重新开始游戏
this.time.delayedCall(2000, () => {
window.location.reload()
})
}
}
- 虚拟方向盘操控(移动端)
引入插件
import VirtualJoystickPlugin from 'phaser3-rex-plugins/plugins/virtualjoystick-plugin.js'
在 config 中加载插件
plugins: {
global: [
{
key: 'rexVirtualJoystick',
plugin: VirtualJoystickPlugin,
start: true
}
]
},
在 create 中激活插件
// 创建摇杆
joyStick = (this.plugins.get('rexVirtualJoystick') as any)?.add(this, {
x: CANVAS_WIDTH / 2,
y: CANVAS_HEIGHT / 2,
radius: JOY_SIZE,
base: this.add.circle(0, 0, JOY_SIZE, 0x888888),
thumb: this.add.circle(0, 0, JOY_SIZE / 2, 0xcccccc)
})
在 update 中监听插件
// const cursors = this.input.keyboard?.createCursorKeys()
const cursors = joyStick.createCursorKeys()
大功告成,效果如下
打包出来就可以
pnpm run build
最终产物只有个html
三、源码
完整源码可查阅 github.com/imoo666/blo… ,感谢看完~
© 版权声明
文章版权归作者所有,未经允许请勿转载,侵权请联系 admin@trc20.tw 删除。
THE END