# 开发小游戏
# 小游戏能力快速引导
以下可能是你在开发小游戏过程中较为常用的一些能力,完整的能力列表可以查阅 开发小游戏。
服务端
# 开发小游戏示例解析
# 小游戏项目结构
├── game.js
├── game.json
game.js是游戏执行逻辑的入口文件。
game.json是游戏的配置文件,是游戏运行时的配置。
# game.json 的文件内容为一个 JSON 对象,包含以下属性:
属性 | 类型 | 必填 | 默认值 | 描述 |
---|---|---|---|---|
deviceOrientation | String | 否 | 'portrait' | 屏幕选择方向 |
workers | String | 否 | - | 在 game.json 中可配置 Worker 代码放置的目录,目录下的所有 JS 代码最终将被打包成一个 JS 文件 |
subpackages | Object Array | 否 | 'portrait' | 分包结构配置 |
iOSHighPerformance | Boolean | 否 | true | 是否开启 iOS 高性能模式。默认开启,当前不支持关闭 |
# 学习贪吃蛇游戏示例
贪吃蛇小游戏的初始项目结构如下:
├── game.js
├── game.json
├── js
│ │── food.js // 食物类
│ │── snake.js // 贪吃蛇类
│ │── main.js // 游戏入口函数
│ │── gameInfo.js // 绘制游戏信息
# 初始化Canvas
// 创建画布
this.canvas = tap.createCanvas()
this.ctx = this.canvas.getContext('2d')
# 开始游戏
通过模块导入语句引入了游戏中使用的不同模块,包括 贪吃蛇、食物、游戏信息。 在初始化Main类时,我们主要做了以下工作: 创建一块画布,初始化游戏对象,绑定触摸事件,使用户可以与游戏进行交互,开始游戏。
import Snake from './snake'
import Food from './food'
import GameInfo from './gameinfo'
export default class Main {
constructor() {
// 创建画布
this.canvas = tap.createCanvas()
this.ctx = this.canvas.getContext('2d')
...
// 初始化游戏对象
this.snake = new Snake(this)
this.food = new Food(this)
this.gameInfo = new GameInfo(this)
// 绑定触摸事件
this.bindEvent()
// 开始游戏循环
this.startGameLoop()
}
// 开始游戏循环
startGameLoop() {
this.lastTime = Date.now()
this.loop()
}
}
# 游戏循环
包含了游戏的核心玩法逻辑。
loop() {
const now = Date.now()
const dt = now - this.lastTime
// 清除画布
this.ctx.clearRect(0, 0, this.width, this.height)
// 更新游戏状态
if (!this.gameOver && dt > this.speed) {
this.direction = this.nextDirection
this.snake.move(this.direction)
// 检查是否吃到食物
if (this.snake.checkEat(this.food)) {
this.food.reset()
this.score += 10
// 每得100分加速一次
if (this.score % 100 === 0 && this.speed > 50) {
this.speed -= 10
}
}
// 检查是否游戏结束
if (this.snake.checkCollision()) {
this.gameOver = true
console.log('游戏结束,得分:', this.score)
}
this.lastTime = now
}
// 绘制游戏画面
this.drawBackground()
this.food.draw()
this.snake.draw()
this.gameInfo.draw()
// 继续下一帧
requestAnimationFrame(this.loop.bind(this))
}
# 绘制背景
绘制游戏的画面背景。
drawBackground() {
this.ctx.fillStyle = '#f3f3f3'
this.ctx.fillRect(0, 0, this.width, this.height)
// 绘制网格
this.ctx.strokeStyle = '#e0e0e0'
this.ctx.lineWidth = 0.5
// 绘制竖线
for (let x = 0; x <= this.width; x += this.gridSize) {
this.ctx.beginPath()
this.ctx.moveTo(x, 0)
this.ctx.lineTo(x, this.height)
this.ctx.stroke()
}
// 绘制横线
for (let y = 0; y <= this.height; y += this.gridSize) {
this.ctx.beginPath()
this.ctx.moveTo(0, y)
this.ctx.lineTo(this.width, y)
this.ctx.stroke()
}
}
# 绑定触摸事件
绑定事件,使用户可以通过触摸滑动来与游戏交互。
bindEvent() {
// 触摸开始位置
let startX = 0
let startY = 0
tap.onTouchStart(e => {
if (this.gameOver) {
// 游戏结束时,点击重新开始
this.restart()
return
}
startX = e.touches[0].clientX
startY = e.touches[0].clientY
})
tap.onTouchEnd(e => {
if (this.gameOver) return
const endX = e.changedTouches[0].clientX
const endY = e.changedTouches[0].clientY
const dx = endX - startX
const dy = endY - startY
// 判断滑动方向
if (Math.abs(dx) > Math.abs(dy)) {
// 水平方向
if (dx > 0 && this.direction !== 'left') {
this.nextDirection = 'right'
} else if (dx < 0 && this.direction !== 'right') {
this.nextDirection = 'left'
}
} else {
// 垂直方向
if (dy > 0 && this.direction !== 'up') {
this.nextDirection = 'down'
} else if (dy < 0 && this.direction !== 'down') {
this.nextDirection = 'up'
}
}
})
}