生成游戏网格
-
坐标系定义
- 采用**左下角为原点(0,0)**的二维坐标系
- 网格尺寸例如:20行 × 10列
-
网格状态定义
typescript
enum GridStatus {
notUse,
snakeHead,
snakeBody,
food,
}
- 生成游戏网格,默认所有网格的状态是未使用
typescript
generateGrids(){
......
for (let rowIndex=0; rowIndex<this.row; rowIndex++){
this.gridList.push([])
for (let columnIndex=0; columnIndex<this.column; columnIndex++){
let gridData: GridDataInterface = {
name: `Grid-${rowIndex}-${columnIndex}`,
status: GridStatus.notUse,
gridNode: null,
row: rowIndex,
column: columnIndex,
}
this.gridList[rowIndex].push(gridData)
// 生成网格UI节点
......
}
}
}
蛇的初始化
- 定义蛇的当前移动方向往左,蛇的下次移动也往左。
typescript
enum Direction {
UP,
DOWN,
LEFT,
RIGHT
}
public currentDirection = Direction.LEFT
public nextDirection = Direction.LEFT
-
定义蛇的初始位置:行数/2取整、列数/2取整,得到网格居中位置。
-
修改居中位置网格数据,把网格状态改为蛇头,而当前移动方向的反方向设置一定数量的网格状态为蛇身。
typescript
generateSnake(){
// 起始位置
const startRow = Math.floor(this.row / 2)
const startColumn = Math.floor(this.column / 2)
// 蛇头
const headGridData = this.gridList[startRow][startColumn]
headGridData.status = GridStatus.snakeHead
this.snakeGridList.push(headGridData)
// 蛇身
for (
let columnIndex=startColumn+1;
columnIndex<=startColumn+this.startBodyNum;
columnIndex++
){
const nowGridData = this.gridList[startRow][columnIndex]
nowGridData.status = GridStatus.snakeBody
this.snakeGridList.push(nowGridData)
}
// 更新UI显示
this.updateGridsUI()
}
- 如此就把蛇数据定义在了网格数据里。
蛇朝一个方向移动
-
点击开始游戏后,搞一个定时器,如每0.5秒调用一次,作为蛇的移动回调。
-
下次移动方向为向左,那么就让蛇头的列数-1,如果方向往上则让蛇头的行数+1,可得到蛇头新的网格位置。
-
有了新的蛇头网格位置后,就可以让蛇尾巴网格数据换到新蛇头网格位置,巧妙的实现蛇的移动。
typescript
snakeMove(){
if (this.gameStatus !== GameStatus.running) return
const move = {row: 0, column: 0}
if (this.nextDirection === Direction.LEFT){
move.column = -1
}
else if (this.nextDirection === Direction.RIGHT){
move.column = 1
}
else if (this.nextDirection === Direction.UP){
move.row = 1
}
else if (this.nextDirection === Direction.DOWN){
move.row = -1
}
const headGridData = this.snakeGridList[0]
const newHeadGridData = this.gridList[headGridData.row+move.row][headGridData.column+move.column]
// 移动
headGridData.status = GridStatus.snakeBody
newHeadGridData.status = GridStatus.snakeHead
this.snakeGridList.unshift(newHeadGridData)
const tailGridData = this.snakeGridList.pop()
tailGridData.status = GridStatus.notUse
// 更新UI显示
this.updateGridsUI()
// 下次移动
this.snakeMoveSchedule()
}
蛇改变方向移动
-
点击上、下、左、右按键时,记录蛇的下次移动方向。
-
下次移动方向的限制:不能反方向移动。如蛇的当前移动方向是往左,那么下次移动方向就不能往右。
typescript
onBtnClick(event: Event, key: string){
if (key === 'begin' && this.gameStatus === GameStatus.ready){
this.readDifficulty()
this.setGameStauts(GameStatus.running)
this.generateSnake()
this.generateFood()
this.snakeMoveSchedule()
}
......
// 移动方向更改
else if (key === 'left' && this.gameStatus === GameStatus.running && this.currentDirection !== Direction.RIGHT){
this.nextDirection = Direction.LEFT
}
else if (key === 'right' && this.gameStatus === GameStatus.running && this.currentDirection !== Direction.LEFT){
this.nextDirection = Direction.RIGHT
}
else if (key === 'up' && this.gameStatus === GameStatus.running && this.currentDirection !== Direction.DOWN){
this.nextDirection = Direction.UP
}
else if (key === 'down' && this.gameStatus === GameStatus.running && this.currentDirection !== Direction.UP){
this.nextDirection = Direction.DOWN
}
}
- 当记录下次移动方向后,再次进入移动回调时蛇会改变方向移动,但移动后还需把当前移动方向记录为下次移动方向,让用户点击方向按钮时可以进行反方向判断。
生成食物
-
点击开始游戏后,在生成蛇后再生成食物。
-
食物的位置是一个随机位置,遍历网格数据提取出未使用的网格数据,随机一个网格数据,让网格状态改为食物即可。
蛇吃食物
- 在蛇的移动回调中,得到蛇头新的网格位置后,判断网格状态是否是食物,如果是食物,则把食物网格设置为蛇头网格即可(不要再处理蛇尾网格数据),接着再生成新的食物。
游戏结束
- 蛇头出网格边界:在蛇的移动回调中,判断蛇头新的网格位置,是否超出整体网格行数或列数以及小于0。
- 蛇头撞到蛇身:在蛇的移动回调中,判断蛇头新的网格状态是否是蛇身。
游戏成功
- 当蛇吃到食物,改完蛇头网格状态后,当所有网格的状态只有蛇头或蛇身时游戏成功。
加速功能
-
当长按加速按钮时,使蛇的移动速度加快。
-
只需在点击加速时更改蛇移动回调的间隔时间,缩短即可实现加速。
获取完整小游戏源码
-
以上内容是讲述了贪吃蛇的核心逻辑如何实现,可以使用任何编程语言编写,但你如果是为了给别人玩、为了上架小游戏平台,那么就需要使用一个游戏引擎去开发小游戏。
-
在 Cocos商城 里,搜索 zezhou222 ,获取对应小游戏源码学习!