【江鸟中原】贪吃蛇小游戏(鸿蒙)
本项目是基于鸿蒙操作系统(HarmonyOS)开发的经典贪吃蛇游戏,采用 ArkTS 编程语言实现。游戏不仅包含贪吃蛇移动、吃食物增长、碰撞检测等核心功能,还新增了随机生成的特殊食物系统,同时支持多种游戏模式和皮肤自定义,适合鸿蒙初学者学习组件开发、状态管理、定时器使用等基础技能。
鸿蒙贪吃蛇游戏项目设计文档
一.项目概述
1. 项目简介
本项目是基于鸿蒙操作系统(HarmonyOS)开发的经典贪吃蛇游戏,采用 ArkTS 编程语言实现。游戏不仅包含贪吃蛇移动、吃食物增长、碰撞检测等核心功能,还新增了随机生成的特殊食物系统,同时支持多种游戏模式和皮肤自定义,适合鸿蒙初学者学习组件开发、状态管理、定时器使用等基础技能。
2. 技术栈
开发语言:ArkTS(TypeScript的超集)
开发框架:HarmonyOS 3.0+
UI框架:ArkUI声明式开发范式
开发工具:DevEco Studio
3. 核心功能
基础功能:蛇的移动控制、食物生成、得分计算、碰撞检测(撞墙、撞自身、撞障碍物)。
扩展功能:4种游戏模式(极简/普通(默认)/困难/炼狱)、多种皮肤选择、特殊食物系统(4种特殊效果)、最高分持久化存储。
交互功能:开始/暂停/重新开始/返回主页、方向键控制、弹窗选择模式和皮肤、Toast 提示反馈。
二.需求设计
1. 功能需求
|
功能模块 |
具体需求 |
|
游戏初始化 |
蛇初始位置居中、网格数据初始化、得分重置 |
|
蛇的控制 |
上下左右方向移动、防止反向移动、防快速变向 |
|
食物系统 |
普通食物随机生成(不重叠蛇身/障碍物)、特殊食物随机生成(高难度模式生效) |
|
特殊食物 |
4种类型(金色/粉色/青色/紫色),对应不同得分或蛇身变化效果 |
|
游戏模式 |
不同模式对应不同速度、网格大小、障碍物数量 |
|
皮肤系统 |
自定义蛇头/蛇身/食物颜色及食物图标 |
|
碰撞检测 |
撞墙、撞自身、撞障碍物判定,触发游戏结束 |
|
数据存储 |
最高分持久化(使用@StorageLink) |
|
交互反馈 |
模式/皮肤选择弹窗、操作Toast提示、倒计时显示 |
- 用户交互流程
(1)启动游戏→进入开始界面(显示最高分、当前模式/皮肤)。
(2)选择游戏模式/皮肤→点击“开始游戏”进入游戏界面。
(3)游戏中:通过方向键控制蛇移动,吃食物得分,触发特殊食物效果。
(4)游戏控制:支持暂停/继续、重新开始、返回主页。
(5)游戏结束:Toast提示结束原因和得分,自动返回开始界面。
三.项目架构设计
1. 核心数据结构设计
1.1 基础数据结构
interface Position { // 坐标位置接口
x: number; // 行坐标
y: number; // 列坐标
}
type Direction = 'up' | 'down' | 'left' | 'right'; // 移动方向类型
1.2 游戏模式配置
interface GameMode {
name: string; // 模式名称
speed: number; // 移动速度
gridSize: number; // 网格大小
obstacleCount: number; // 障碍物数量
}
1.3 皮肤系统设计
interface Skin {
name: string; // 皮肤名称
snakeHead: string; // 蛇头颜色
snakeBody: string; // 蛇身颜色
food: string; // 食物颜色
foodIcon: string; // 食物图标
}
1.4 特殊食物设计
enum SpecialFoodType {
NONE = 'none', // 无特殊食物
GOLDEN = 'golden', // 金色小球 +25分
PINK = 'pink', // 粉色小球 分数翻倍
CYAN = 'cyan', // 青色小球 +20分
PURPLE = 'purple' // 紫色小球 减一节
}
interface SpecialFood {
x: number; // 横坐标
y: number; // 纵坐标
type: SpecialFoodType; // 食物类型
spawnTime: number; // 生成时间戳
duration: number; // 持续时间
active: boolean; // 是否激活
}
四.核心功能实现详解
1. 游戏初始化流程
1.1 游戏初始化(initSnake 方法)
蛇的初始长度为2,位置在网格中心,符合用户视觉习惯。初始化时会清空之前的定时器和特殊食物,避免残留状态影响新游戏。updateGrid()方法用于刷新网格中蛇、食物、障碍物的显示。
initSnake(): void {
const mid = Math.floor(this.selectedMode.gridSize / 2); // 计算网格中心位置
this.snake = [ // 初始化蛇身(初始两节:蛇头和蛇身)
{ x: mid, y: mid + 1 }, // 蛇头
{ x: mid, y: mid } // 蛇身
];
this.currentDirection = 'right'; // 初始方向向右
this.score = 0; // 得分重置
this.obstacles = []; // 清空障碍物
this.updateGrid(); // 更新网格数据
if (this.specialFoodTimer !== -1) { // 清空特殊食物相关资源
clearInterval(this.specialFoodTimer);
this.specialFoodTimer = -1;
}
this.specialFood = null;
}
1.2 网格数据更新(updateGrid 方法)
网格是二维数组gridData,每个元素代表一个单元格的类型(0 = 空白,1 = 蛇身,2 = 普通食物,3 = 蛇头,4 = 障碍物,5 = 特殊食物)。通过遍历蛇身、食物、障碍物的坐标,更新二维数组的值,后续 UI 根据这些值渲染不同的样式。
updateGrid(): void { // 创建空白网格
this.gridData = Array(this.selectedMode.gridSize)
.fill(0)
.map(() => Array(this.selectedMode.gridSize).fill(0));
this.obstacles.forEach((obs: Position) => {
this.gridData[obs.x][obs.y] = 4; // 标记障碍物位置(值:4)
});
this.snake.forEach((seg: Position, index: number) => {
this.gridData[seg.x][seg.y] = index === 0 ? 3 : 1; // 标记蛇身位置(蛇头:3,蛇身:1)
});
if (this.foodPos.x !== -1) {
this.gridData[this.foodPos.x][this.foodPos.y] = 2; // 标记食物位置(值:2)
}
if (this.specialFood && this.specialFood.active) { // 标记特殊食物位置(值:5)
this.gridData[this.specialFood.x][this.specialFood.y] = 5;
}
}
2. 食物生成系统
2.1 普通食物生成(generateFood 方法)
使用Math.random()随机生成 x/y 坐标,范围是 0 到网格大小 - 1。
do-while循环确保食物不重叠:通过some方法判断坐标是否已被蛇身或障碍物占用。
加入maxAttempts防止极端情况下(格子快满)无限循环。
generateFood(): void {
const maxCells = this.selectedMode.gridSize * this.selectedMode.gridSize;
if (this.snake.length >= maxCells - 1) return; // 检查网格是否已满
let newFood: Position;
let attempts = 0;
const maxAttempts = 100;
do { // 随机生成食物位置,确保不在蛇身或障碍物上
newFood = {
x: Math.floor(Math.random() * this.selectedMode.gridSize),
y: Math.floor(Math.random() * this.selectedMode.gridSize)
};
attempts++;
} while (this.isPositionOccupied(newFood) && attempts < maxAttempts);
this.foodPos = newFood;
this.maybeGenerateSpecialFood(); // 尝试生成特殊食物
}
2.2 特殊食物生成方法(maybeGenerateSpecialFood 方法)
普通模式特殊食物规则
|
食物类型 |
生成概率 |
效果 |
持续时间 |
|
金色(GOLDEN) |
5% |
+25分 |
20秒 |
|
粉色(PINK) |
1% |
分数翻倍(最高+100) |
10秒 |
|
青色(CYAN) |
5% |
+20分 |
20秒 |
|
紫色(PURPLE) |
2% |
蛇身减1(长度<3时+30分) |
15秒 |
maybeGenerateSpecialFood(): void {
const allowedModes = ['普通模式', '困难模式', '炼狱模式']; // 检查是否支持特殊食物的模式
if (!allowedModes.includes(this.selectedMode.name)) return;
if (this.specialFood && this.specialFood.active) return; //检查是否已有特殊食物
const rand = Math.random() * 100;
let newSpecialFood: SpecialFood | null = null;
// 根据不同模式设置不同的生成概率
if (this.selectedMode.name === '普通模式') {
if (rand < 5) { // 5% 概率生成金色食物
newSpecialFood=this.createSpecialFood(SpecialFoodType.GOLDEN, 20000);
} // 其他类型概率...
}
if (newSpecialFood) { // 其他模式概率设置...
this.specialFood = newSpecialFood;
this.startSpecialFoodCountdown(); // 启动倒计时
}
2.3 特殊食物类型效果
通过switch判断食物类型,执行对应的得分或蛇身修改逻辑,并用promptAction.showToast显示操作反馈,提升用户体验。
handleSpecialFood(type: SpecialFoodType): void {
let message = '';
switch (type) {
case SpecialFoodType.GOLDEN:
this.score += 25;
message = '获得奖牌!+25分';
break;
case SpecialFoodType.PINK:
if (this.score > 100) {
this.score += 100;
message = '获得爱心!分数已达上限,+100分';
} else {
this.score *= 2;
message = '获得爱心!分数翻倍!';
}
break;
case SpecialFoodType.CYAN:
this.score += 20;
message = '获得钻石!+20分';
break;
case SpecialFoodType.PURPLE:
if (this.snake.length > 3) {
this.snake.pop();
message = '获得紫水晶球!蛇身缩短一节!';
} else {
this.score += 30;
message = '蛇身太短,获得30分!';
}
break;
}
// 显示效果提示
promptAction.showToast({ message, duration: 2000 });
}
3. 蛇的移动与方向控制
3.1 蛇的移动(moveSnake 方法)
移动原理:复制蛇头→更新蛇头位置→添加新蛇头→移除尾部(没吃到食物时)。
碰撞检测:先判断蛇头是否超出网格(撞墙)、是否与蛇身重叠(撞自己)、是否与障碍物重叠(撞障碍),触发任意一种则游戏结束。
吃食物逻辑:普通食物增长蛇身,特殊食物不增长但有额外效果。
moveSnake(): void {
// 复制当前蛇头作为新头部
const head: Position = { x: this.snake[0].x, y: this.snake[0].y };
switch (this.currentDirection) { // 根据方向移动头部
case 'up': head.x--; break;
case 'down': head.x++; break;
case 'left': head.y--; break;
case 'right': head.y++; break;
}
// 碰撞检测(撞墙、撞自身、撞障碍物)
if (head.x < 0 || head.x >= this.selectedMode.gridSize ||
head.y < 0 || head.y >= this.selectedMode.gridSize) {
this.gameOverReason = '撞墙了!';
this.gameOver(true);
return;
}
if (this.snake.some(seg => seg.x === head.x && seg.y === head.y)) {
this.gameOverReason = '撞到自己了!';
this.gameOver(true);
return;
}
if (this.obstacles.some(obs => obs.x === head.x && obs.y === head.y)) {
this.gameOverReason = '撞到障碍物了!';
this.gameOver(true);
return;
}
// 吃普通食物判断:吃到后得分+5,生成新食物,蛇身增长(不移除尾部)
let ateFood = false;
if (head.x === this.foodPos.x && head.y === this.foodPos.y) {
this.score += 5;
this.generateFood();
ateFood = true;
// 更新最高分
if (this.score > this.highScore) {
this.highScore = this.score;
}
}
// 吃特殊食物判断:触发对应效果,不移除蛇尾(蛇身长度不变)
if (this.specialFood && this.specialFood.active &&
head.x === this.specialFood.x && head.y === this.specialFood.y) {
this.handleSpecialFood(this.specialFood.type); // 处理特殊效果
this.removeSpecialFood('eaten'); // 移除已吃的特殊食物
ateFood = false;
}
this.snake.unshift(head); // 新增蛇头到数组头部
if (!ateFood) { // 没吃到食物则移除尾部(蛇身长度不变)
this.snake.pop();
}
this.updateGrid(); // 刷新网格显示}
3.2 方向控制(changeDirection 方法)
加入了“防快速变向”和“防反向”逻辑,避免游戏操作失误,提升体验。
Direction是之前定义的类型('up'|'down'|'left'|'right'),确保传入的方向合法。
changeDirection(newDir: Direction): void {
if (!this.isPlaying) return; // 游戏暂停时不允许改方向
const now = Date.now();
// 100ms内不允许再次改方向,防止快速操作导致蛇反向
if (now - this.lastDirectionTime < this.directionChangeDelay) {
return;
}
// 定义反向映射:不允许直接掉头(如向上时不能直接向下)
const oppositeDirs: Record<Direction, Direction> = {
'up': 'down', 'down': 'up', 'left': 'right', 'right': 'left'
};
if (oppositeDirs[this.currentDirection] !== newDir) {
this.currentDirection = newDir;
this.lastDirectionTime = now;
}
}
4.游戏结束(gameOver 方法)
游戏结束时必须清除所有定时器,避免内存泄漏;通过Toast提示结束原因和得分,1 秒后自动返回开始界面,流程更友好。
gameOver(isWallCollision: boolean): void {
this.isPlaying = false;
// 清除所有定时器(移动、特殊食物倒计时、特殊食物消失)
if (this.gameTimer !== -1) {
clearInterval(this.gameTimer);
this.gameTimer = -1;
}
this.stopSpecialFoodCountdown();
if (this.specialFoodTimer !== -1) {
clearInterval(this.specialFoodTimer);
this.specialFoodTimer = -1;
}
this.specialFood = null; // 清空特殊食物
this.showSpecialFoodTimer = false;
promptAction.showToast({ // 显示游戏结束提示
message: `${this.gameOverReason} 游戏结束!得分: ${this.score}`,
duration: 3000
});
setTimeout(() => { // 1秒后返回开始界面
if (isWallCollision) {
this.returnToStartScreen();
}
}, 1000);
}
五.用户界面设计
1. 开始界面设计
// 开始界面(gameStarted为false时显示)
if (!this.gameStarted) {
Column() {
Text('贪吃蛇游戏').fontSize(30).margin(30)
Text(`历史最高分: ${this.highScore}`).fontSize(20).margin(20)
Button('选择模式').onClick(() => this.showModeDialog = true)
Button('选择皮肤').onClick(() => this.showSkinDialog = true)
Button('开始游戏').onClick(() => this.startGame())
}
.justifyContent(FlexAlign.Center)
}
- 游戏界面设计
网格渲染:使用Grid+ForEach循环渲染二维数组gridData,每个单元格根据cell值渲染对应元素(蛇头、蛇身、食物等)。
条件渲染:特殊食物倒计时、弹窗等通过if-else控制是否显示。
样式自定义:蛇的颜色、食物图标等通过selectedSkin状态获取,实现皮肤切换功能。
2.1 游戏状态显示区
// 顶部信息栏(模式、得分、特殊食物倒计时)
Row() {
Text(`当前模式: ${this.selectedMode.name}`)
Text(`当前得分: ${this.score}`)
// 特殊食物倒计时(条件渲染)
if (this.showSpecialFoodTimer && this.specialFood) {
Text(`${this.getSpecialFoodName(this.specialFood.type)}: ${this.specialFoodRemainingSeconds}秒`)
.fontColor(this.getSpecialFoodColor(this.specialFood.type))
}
}
2.2 游戏网格渲染
Grid() {
ForEach(this.gridData, (row: number[], rowIndex: number) => {
ForEach(row, (cell: number, colIndex: number) => {
GridItem() {
this.renderGridCell(rowIndex, colIndex);
}
})
})
}
.columnsTemplate(`1fr `.repeat(this.selectedMode.gridSize))
.rowsTemplate(`1fr `.repeat(this.selectedMode.gridSize))
2.3 网格单元格渲染逻辑
private renderGridCell(rowIndex: number, colIndex: number): void {
const cellValue = this.gridData[rowIndex][colIndex];
switch (cellValue) {
case 5: // 特殊食物
Text(this.getSpecialFoodIcon(this.specialFood!.type))
.fontSize(this.getFoodIconSize())
.fontColor(this.getSpecialFoodColor(this.specialFood!.type))
break;
case 2: // 普通食物
Text(this.selectedSkin.foodIcon)
.fontSize(this.getFoodIconSize())
break;
case 3: // 蛇头
Column() { Blank() }
.backgroundColor(this.selectedSkin.snakeHead)
.borderRadius(10)
break;
case 1: // 蛇身
Column() { Blank() }
.backgroundColor(this.selectedSkin.snakeBody)
.borderRadius(8)
break;
case 4: // 障碍物
Text('✵')
.fontSize(this.getObstacleIconSize())
break;
default: // 空白格子
Column() { Blank() }
.backgroundColor('#F8F8F8')
}
}
2.4 控制区域设计
Column() {
Row() { // 功能按钮行
Button('重新开始').onClick(() => this.startGame())
Button(this.isPlaying ? '暂 ⏸ 停' : '继 ⏯️ 续').onClick(() => {
if (this.isPlaying) {
clearInterval(this.gameTimer); // 暂停:清除移动定时器
} else {
this.startGameTimer(); // 继续:重启移动定时器
}
this.isPlaying = !this.isPlaying;
})
Button('返回主页').onClick(() => this.returnToStartScreen())
}
Column() { // 方向控制按钮
Button('↑').onClick(() => this.changeDirection('up'))
Row() {
Button('←').onClick(() => this.changeDirection('left'))
Button('→').onClick(() => this.changeDirection('right'))
}
Button('↓').onClick(() => this.changeDirection('down'))
}
}
- 游戏配置系统
- 游戏模式选择
1.1 模式配置详情
模式数组中每个元素对应一种游戏难度,通过修改speed(移动速度)、gridSize(网格大小)、obstacleCount(障碍物数量)实现难度梯度。
private gameModes: GameMode[] = [
{ name: '极简模式', speed: 2, gridSize: 10, obstacleCount: 0 }, // 速度慢、网格小、无障碍物
{ name: '普通模式', speed: 3, gridSize: 15, obstacleCount: 0 }, // 默认模式
{ name: '困难模式', speed: 4, gridSize: 15, obstacleCount: 3 }, // 速度快、有3个障碍物
{ name: '炼狱模式', speed: 5, gridSize: 20, obstacleCount: 6 } // 速度最快、网格大、6个障碍物
];
1.2 模式选择实现
selectMode(mode: GameMode): void {
this.selectedMode = mode;
this.showModeDialog = false;
promptAction.showToast({ message: `已选择${mode.name}`, duration: 1500 });
}
- 皮肤选择系统
2.1. 皮肤配置选项
private skinOptions: Skin[] = [
{ name: '经典绿', snakeHead: '#2E8B57', snakeBody: '#3CB371', food: '#32CD32', foodIcon: '��' },
{ name: '沙漠黄', snakeHead: '#8B4513', snakeBody: '#F4A460', food: '#32CD32', foodIcon: '��' }, // 其他皮肤(代码略)...
];
2.2 皮肤应用实现
selectSkin(skin: Skin): void {
this.selectedSkin = skin;
this.showSkinDialog = false;
this.updateGrid(); // 立即更新界面显示
promptAction.showToast({
message: `已选择${skin.name}皮肤`,
duration: 1500
});
}
七.性能优化策略
1. 渲染优化
条件渲染:使用if语句控制UI元素的显示
局部更新:只更新变化的网格单元格
轻量组件:优化组件层级结构
2. 内存管理
定时器清理:及时清除不再需要的定时器
对象复用:避免频繁创建和销毁对象
状态管理:合理使用@State装饰器
3. 响应式设计
// 自适应图标大小
getFoodIconSize(): number {
const baseSize = 25;
const gridSize = this.selectedMode.gridSize;
// 根据网格大小调整图标尺寸
if (gridSize <= 10) return 22;
else if (gridSize <= 15) return 18;
else return 14;
}
八. 项目总结与学习要点
1. 技术要点总结
1. ArkTS基础语法:接口、枚举、类的使用
2. HarmonyOS状态管理:@State、@StorageLink装饰器
3. ArkUI声明式开发:组件化、响应式UI构建
4. 游戏逻辑设计:碰撞检测、食物生成、移动算法
5. 性能优化:定时器管理、内存优化、渲染优化
2. 扩展学习方向
1. 多人在线对战:利用分布式能力实现联机对战
2. AI对手:实现智能AI算法
3. 关卡系统:设计不同的游戏关卡
4. 成就系统:添加游戏成就和奖励机制
5. 新增音效功能:吃食物、游戏结束时播放音效(使用鸿蒙audio组件)。
更多推荐



所有评论(0)