纯血HarmonyOS NETX 打造小游戏实践:大鱼吃小鱼(附源文件)
2025-06-29 09:46:57
109次阅读
0个评论
一、游戏整体架构设计
这款基于ArkUI的鱼类捕食游戏采用了经典的MVC架构思想,将游戏逻辑与UI渲染分离,主要包含以下核心模块:
- 模型层(Model):
Fish
基类及其子类定义游戏实体 - 视图层(View):
play_6
组件负责UI渲染 - 控制层(Controller):游戏循环、交互逻辑与AI控制
这种架构使代码具有良好的可维护性和扩展性,下面我们将逐模块解析核心代码。
二、Fish基类与继承体系
1. 基类核心属性与功能
class Fish {
size: number = 0; // 体型决定捕食关系,数值越大越能捕食小鱼
speed: number = 0; // 移动速度,与体型负相关
positionX: number = 0; // 笛卡尔坐标系X轴位置
positionY: number = 0; // 笛卡尔坐标系Y轴位置
health: number = 100; // 生命值系统,被大鱼攻击会减少
scoreValue: number = 0; // 被吃掉时提供的分数,与体型正相关
direction: number = 1; // 移动方向(1:右,-1:左)
constructor(
size: number, speed: number, x: number, y: number,
isPlayer: boolean, name: string, direction: number
) {
this.size = size;
this.speed = speed;
this.positionX = x;
this.positionY = y;
// 分数价值 = 体型*1.5并取整,体现体型与价值的线性关系
this.scoreValue = Math.floor(size * 1.5);
this.direction = direction;
}
}
设计亮点:
- 通过
size
属性构建捕食关系链,形成游戏核心玩法 scoreValue
与size
的线性关系设计,使游戏进度与视觉反馈一致- 统一的坐标系统为碰撞检测和移动逻辑提供基础
2. 玩家鱼PlayerFish实现
export class PlayerFish extends Fish {
private isDragging: boolean = false; // 拖拽状态标记
constructor(size: number, speed: number, x: number, y: number) {
super(size, speed, x, y, true, "Player");
}
// 边界检测核心逻辑
checkBoundary() {
const displayClass = display.getDefaultDisplaySync();
const screenWidth = displayClass.width / displayClass.densityPixels;
const screenHeight = displayClass.height / displayClass.densityPixels;
// 四个方向的边界限制,确保玩家鱼不会移出屏幕
if (this.positionX < 0) this.positionX = 0;
if (this.positionY < 0) this.positionY = 0;
if (this.positionX > screenWidth - this.size * 2) {
this.positionX = screenWidth - this.size * 2;
}
if (this.positionY > screenHeight - this.size * 2) {
this.positionY = screenHeight - this.size * 2;
}
}
}
交互逻辑解析:
checkBoundary
方法通过获取屏幕实际尺寸,实现玩家鱼的边界限制- 边界计算考虑了鱼的体型大小(
size * 2
),避免鱼体超出屏幕显示范围 - 拖拽控制通过
isDragging
状态标记与偏移量计算实现精准操作
3. NPC鱼智能行为NPCFish
class NPCFish extends Fish {
private directionX: number = 0; // X轴移动方向分量
private directionY: number = 0; // Y轴移动方向分量
private lastDirectionChange: number = 0; // 上次改变方向的时间戳
private playerFish: PlayerFish | null = null; // 玩家鱼引用
constructor(
size: number, speed: number, x: number, y: number,
playerFish: PlayerFish, direction: number
) {
super(size, speed, x, y, false, `NPC-${Math.random() * 1000}`, direction);
this.playerFish = playerFish;
this.resetDirection(); // 初始化移动方向
}
// 随机重置移动方向
private resetDirection() {
// X方向根据初始方向确定基本趋势,添加随机扰动
this.directionX = this.direction * (Math.random() * 0.5 + 0.3);
// Y方向完全随机,模拟鱼类自然游动
this.directionY = (Math.random() > 0.5 ? 1 : -1) * (Math.random() * 0.3);
this.lastDirectionChange = Date.now();
}
}
AI行为核心:
resetDirection
方法通过随机数生成扰动向量,使NPC鱼移动更自然lastDirectionChange
时间戳控制方向变化频率,避免NPC鱼行为过于规律- 方向向量的X分量与初始方向关联,Y分量完全随机,形成"定向游动+随机摆动"的效果
三、游戏核心循环与逻辑控制
1. 游戏主循环机制
private gameLoop() {
if (this.gameOver) return;
// 更新所有NPC鱼状态
this.npcFishes.forEach(npc => {
npc.autoMove();
});
// 检测碰撞与生存状态
this.checkCollisions();
this.checkPlayerSurvival();
// 下一帧循环(30ms约33FPS)
setTimeout(() => {
this.gameLoop();
}, 30);
}
循环逻辑解析:
- 采用
setTimeout
实现递归循环,控制游戏更新频率 - 先更新NPC鱼状态,再进行碰撞检测,确保逻辑顺序正确
gameOver
状态标记可暂停循环,优化资源占用
2. 碰撞检测与捕食逻辑
// 核心碰撞检测算法
private isColliding(fish1: Fish, fish2: Fish): boolean {
const dx = fish1.positionX - fish2.positionX;
const dy = fish1.positionY - fish2.positionY;
const distance = Math.sqrt(dx * dx + dy * dy);
// 碰撞判定:两鱼中心距离小于体型半径和
return distance < (fish1.size + fish2.size) / 2;
}
// 捕食逻辑实现
private checkCollisions() {
const toRemove: number[] = [];
for (let i = 0; i < this.npcFishes.length; i++) {
const npc = this.npcFishes[i];
// 玩家鱼捕食NPC鱼的条件:玩家鱼更大且发生碰撞
if (this.playerFish.size > npc.size && this.isColliding(this.playerFish, npc)) {
// 玩家鱼成长:体型增加NPC鱼体型的15%
this.playerFish.size += npc.size * 0.15;
// 分数增加:获取NPC鱼的scoreValue
this.score += npc.scoreValue;
// 速度调整:体型越大速度越慢,最小速度为1
this.playerFish.speed = Math.max(1, 3 - this.playerFish.size / 20);
// 标记NPC鱼为移除
toRemove.push(i);
}
}
// 从后往前移除,避免索引错误
for (let i = toRemove.length - 1; i >= 0; i--) {
this.npcFishes.splice(toRemove[i], 1);
}
}
算法关键点:
- 碰撞检测采用欧几里得距离计算,时间复杂度O(n)
- 捕食后玩家鱼的成长比例(15%)与速度衰减公式(
3 - size/20
)经过平衡设计 toRemove
数组收集待移除索引,避免遍历时修改数组导致的逻辑错误
3. NPC鱼智能反应逻辑
autoMove() {
// 定期改变方向(1000-3000ms随机间隔)
if (Date.now() - this.lastDirectionChange > 1000 + Math.random() * 2000) {
this.resetDirection();
}
// 基础移动:方向向量*速度
this.positionX += this.directionX * this.speed;
this.positionY += this.directionY * this.speed;
// 边界循环机制
if (this.positionX < -this.size * 2) {
// 从左侧消失,右侧重新生成
this.positionX = this.screenWidth + this.size * 2;
this.positionY = Math.random() * (this.screenHeight - 100) + 50;
} else if (this.positionX > this.screenWidth + this.size * 2) {
// 从右侧消失,左侧重新生成
this.positionX = -this.size * 2;
this.positionY = Math.random() * (this.screenHeight - 100) + 50;
}
// 对玩家鱼的智能反应
if (this.playerFish) {
const playerDistX = this.playerFish.positionX - this.positionX;
const playerDistY = this.playerFish.positionY - this.positionY;
const dist = Math.sqrt(playerDistX * playerDistX + playerDistY * playerDistY);
if (this.playerFish.size > this.size && dist < 200) {
// 玩家鱼更大时,NPC鱼躲避(向远离玩家鱼的方向移动)
this.directionX = -playerDistX / dist * 0.3;
this.directionY = -playerDistY / dist * 0.3;
} else if (this.size > this.playerFish.size && dist < 300) {
// NPC鱼更大时,追逐玩家鱼(向玩家鱼方向移动)
this.directionX = playerDistX / dist * 0.3;
this.directionY = playerDistY / dist * 0.3;
}
}
}
AI策略解析:
- 边界循环机制实现NPC鱼从屏幕一侧消失后从另一侧出现,形成持续流动感
200
和300
作为触发躲避/追逐的距离阈值,经过游戏平衡设计- 向量归一化处理(
playerDistX/dist
)确保方向向量长度为1,避免速度突变
四、UI渲染与用户交互
1. 组件渲染核心逻辑
build() {
Stack() {
// 背景层
Row().backgroundColor('#e2e9ef').width('100%').height('100%')
// 信息显示层
Text(`分数: ${this.score}`).fontSize(24).fontColor('#FFFFFF')
Text(`生命值: ${this.playerFish.health}`)
.backgroundColor('rgba(0, 0, 0, 0.5)')
// 玩家鱼渲染(红色图标,可拖拽)
Text('🐟')
.fontSize(this.playerFish.size)
.backgroundColor('#FF0000')
.gesture(
PanGesture()
.onActionStart((event) => {
// 计算拖拽偏移量,确保手势起点精准
this.dragOffsetX = event.offsetX - (this.playerFish.positionX - (this.playerFish.size * 2) / 2);
this.dragOffsetY = event.offsetY - (this.playerFish.positionY - (this.playerFish.size * 2) / 2);
})
)
// NPC鱼列表渲染(蓝色图标,方向动态变化)
ForEach(this.npcFishes, (npc) => {
Text(npc.direction > 0 ? '🐠' : '🐟')
.fontSize(npc.size)
.backgroundColor('#ADD8E6')
})
// 游戏结束层(半透明遮罩)
if (this.gameOver) {
Column()
.backgroundColor('rgba(0, 0, 0, 0.7)')
.children([
Text('游戏结束!'),
Button('重新开始').onClick(() => {
// 重置游戏状态
})
])
}
}
}
UI设计关键点:
Stack
布局实现多层叠加效果,背景层、信息层、鱼群层、结束层有序排列ForEach
组件实现NPC鱼列表的动态渲染,每条鱼根据direction
属性显示不同图标- 半透明遮罩(
rgba(0,0,0,0.7)
)在游戏结束时覆盖整个屏幕,突出显示结束信息
2. 屏幕适配与动态生成
// 屏幕尺寸获取与初始化
aboutToAppear() {
try {
const displayClass = display.getDefaultDisplaySync();
this.screenWidth = displayClass.width / displayClass.densityPixels;
this.screenHeight = displayClass.height / displayClass.densityPixels;
console.info(`屏幕尺寸: ${this.screenWidth}x${this.screenHeight}`);
} catch (error) {
// 异常处理:获取失败时使用默认值
console.error("获取屏幕尺寸失败", error);
}
// 初始化8条NPC鱼
this.initNPCFishes(8);
// 启动游戏循环
this.gameLoop();
// 每1000ms生成新鱼
setInterval(() => {
this.spawnRandomFish();
}, 1000);
}
// NPC鱼动态生成
private spawnRandomFish() {
const size = Math.floor(Math.random() * 25) + 10; // 10-35的随机体型
const speed = 3 - size / 10; // 速度与体型负相关
// 随机从左侧或右侧生成
const fromLeft = Math.random() > 0.5;
let x = fromLeft ? -size * 2 : this.screenWidth + size * 2;
const direction = fromLeft ? 1 : -1;
// Y坐标限制在屏幕中间区域(70-430,假设屏幕高度500)
const y = Math.floor(Math.random() * (500 - 70)) + 70;
this.npcFishes.push(new NPCFish(size, speed, x, y, this.playerFish, direction));
console.info(`生成NPC鱼: 位置(${x},${y}), 方向${direction}, 大小${size}`);
}
适配与生成逻辑:
aboutToAppear
生命周期钩子中获取屏幕尺寸,确保UI元素正确布局- 动态生成频率(1000ms)与初始数量(8条)经过游戏节奏设计
- Y坐标限制在中间区域(
70-430
),避免NPC鱼生成在屏幕边缘
五、附:源代码
import { display } from "@kit.ArkUI";
// 优化后的Fish基类(增加生命值、分数等属性)
class Fish {
size: number = 0; // 体型(决定捕食关系)
speed: number = 0; // 移动速度
positionX: number = 0; // X坐标
positionY: number = 0; // Y坐标
isPlayer: boolean = false; // 是否为玩家控制
name: string = ""; // 角色标识
health: number = 100; // 生命值(可被大鱼攻击扣除)
scoreValue: number = 0; // 被吃掉时提供的分数
direction: number = 1; // 移动方向(1:右, -1:左)
constructor(
size: number,
speed: number,
x: number,
y: number,
isPlayer: boolean,
name: string,
direction: number = 1
) {
this.size = size;
this.speed = speed;
this.positionX = x;
this.positionY = y;
this.isPlayer = isPlayer;
this.name = name;
this.scoreValue = Math.floor(size * 1.5); // 体型越大分数越高
this.direction = direction;
}
}
// 玩家鱼(增加拖拽控制逻辑)
export class PlayerFish extends Fish {
private isDragging: boolean = false; // 是否正在拖拽
constructor(size: number, speed: number, x: number, y: number) {
super(size, speed, x, y, true, "Player");
}
// 设置拖拽状态
setDragging(isDragging: boolean) {
this.isDragging = isDragging;
}
// 获取拖拽状态
getIsDragging(): boolean {
return this.isDragging;
}
// 边界检测(优化版)
checkBoundary() {
let displayClass: display.Display = display.getDefaultDisplaySync();
const screenWidth = displayClass.width / displayClass.densityPixels;
const screenHeight = displayClass.height / displayClass.densityPixels;
if (this.positionX < 0) this.positionX = 0;
if (this.positionY < 0) this.positionY = 0;
if (this.positionX > screenWidth - this.size * 2) {
this.positionX = screenWidth - this.size * 2;
}
if (this.positionY > screenHeight - this.size * 2) {
this.positionY = screenHeight - this.size * 2;
}
}
}
// NPC鱼(增加AI行为策略)
class NPCFish extends Fish {
private directionX: number = 0;
private directionY: number = 0;
private lastDirectionChange: number = 0;
private playerFish: PlayerFish | null = null;
constructor(
size: number,
speed: number,
x: number,
y: number,
playerFish: PlayerFish,
direction: number
) {
super(size, speed, x, y, false, `NPC-${Math.floor(Math.random() * 1000)}`, direction);
this.playerFish = playerFish;
this.resetDirection();
}
// 重置移动方向(随机生成)
private resetDirection() {
// 根据初始方向设置基础X方向
this.directionX = this.direction * (Math.random() * 0.5 + 0.3); // 增大X方向速度范围
// 随机Y方向
this.directionY = (Math.random() > 0.5 ? 1 : -1) * (Math.random() * 0.3);
this.lastDirectionChange = Date.now();
}
// AI自动移动(包含躲避与追逐逻辑)
autoMove() {
// 定期改变移动方向(模拟自然游动)
if (Date.now() - this.lastDirectionChange > 1000 + Math.random() * 2000) {
this.resetDirection();
}
// 基础移动
this.positionX += this.directionX * this.speed;
this.positionY += this.directionY * this.speed;
// 边界检测(优化为从一侧消失后从另一侧出现)
let displayClass: display.Display = display.getDefaultDisplaySync();
const screenWidth = displayClass.width / displayClass.densityPixels;
const screenHeight = displayClass.height / displayClass.densityPixels;
// 确保鱼在屏幕内生成和移动
if (this.positionX < -this.size * 2) {
// 从左侧消失,重新出现在右侧
this.positionX = screenWidth + this.size * 2;
this.positionY = Math.random() * (screenHeight - 100) + 50;
} else if (this.positionX > screenWidth + this.size * 2) {
// 从右侧消失,重新出现在左侧
this.positionX = -this.size * 2;
this.positionY = Math.random() * (screenHeight - 100) + 50;
}
if (this.positionY < 0) {
this.directionY *= -1;
} else if (this.positionY > screenHeight) {
this.directionY *= -1;
}
// 特殊行为:NPC鱼对玩家鱼的反应
if (this.playerFish && this.playerFish.size > this.size) {
// 玩家鱼更大时,NPC鱼尝试躲避
const playerDistX = this.playerFish.positionX - this.positionX;
const playerDistY = this.playerFish.positionY - this.positionY;
const dist = Math.sqrt(playerDistX * playerDistX + playerDistY * playerDistY);
if (dist < 200) { // 当玩家鱼靠近时
// 向远离玩家鱼的方向移动
this.directionX = -playerDistX / dist * 0.3;
this.directionY = -playerDistY / dist * 0.3;
}
} else if (this.playerFish && this.size > this.playerFish.size) {
// NPC鱼更大时,尝试追逐玩家鱼
const playerDistX = this.playerFish.positionX - this.positionX;
const playerDistY = this.playerFish.positionY - this.positionY;
const dist = Math.sqrt(playerDistX * playerDistX + playerDistY * playerDistY);
if (dist < 300) { // 当玩家鱼在范围内时
// 向玩家鱼方向移动
this.directionX = playerDistX / dist * 0.3;
this.directionY = playerDistY / dist * 0.3;
}
}
}
}
@Component
export struct play_6 {
@State playerFish: PlayerFish = new PlayerFish(30, 3, 150, 300); // 玩家鱼初始位置
@State npcFishes: Array<NPCFish> = [];
@State score: number = 0;
@State gameOver: boolean = false;
@State isDragging: boolean = false; // 拖拽状态
@State dragOffsetX: number = 0; // 拖拽偏移量X
@State dragOffsetY: number = 0; // 拖拽偏移量Y
@State screenWidth: number = 800; // 屏幕宽度
@State screenHeight: number = 400; // 屏幕高度
// 初始化游戏
aboutToAppear() {
console.info("游戏初始化,玩家鱼位置: " + this.playerFish.positionX + ", " + this.playerFish.positionY);
// 获取屏幕尺寸
try {
let displayClass: display.Display = display.getDefaultDisplaySync();
this.screenWidth = displayClass.width / displayClass.densityPixels;
this.screenHeight = displayClass.height / displayClass.densityPixels;
console.info(`屏幕尺寸: ${this.screenWidth}x${this.screenHeight}`);
} catch (error) {
console.error("获取屏幕尺寸失败,使用默认值", error);
}
this.initNPCFishes(8);
this.gameLoop(); // 启动游戏循环
// 定时生成新鱼
setInterval(() => {
this.spawnRandomFish();
}, 1000);
}
// 初始化NPC鱼
private initNPCFishes(count: number) {
for (let i = 0; i < count; i++) {
this.spawnRandomFish();
}
}
// 随机生成NPC鱼(从左右两侧)
private spawnRandomFish() {
const size = Math.floor(Math.random() * 25) + 10;
const speed = 3 - size / 10;
// 随机决定从左侧还是右侧生成
const fromLeft = Math.random() > 0.5;
let x: number, direction: number;
if (fromLeft) {
// 从左侧生成,向右移动
x = -size * 2; // 左侧屏幕外
direction = 1;
} else {
// 从右侧生成,向左移动
x = this.screenWidth + size * 2; // 右侧屏幕外
direction = -1;
}
// 确保Y坐标在屏幕中间区域
const y = Math.floor(Math.random() * (500 - 70)) + 70;
this.npcFishes.push(new NPCFish(size, speed, x, y, this.playerFish, direction));
console.info(`生成NPC鱼: 位置(${x},${y}), 方向${direction}, 大小${size}`);
}
// 游戏主循环
private gameLoop() {
if (this.gameOver) return;
// 更新NPC鱼状态
this.npcFishes.forEach(npc => {
npc.autoMove();
// 调试:输出NPC鱼位置
console.info(`NPC鱼位置: ${npc.positionX},${npc.positionY}`);
});
// 检查碰撞和生存状态
this.checkCollisions();
this.checkPlayerSurvival();
// 下一帧
setTimeout(() => {
this.gameLoop();
}, 30);
}
// 碰撞检测与捕食逻辑
private checkCollisions() {
const toRemove: number[] = [];
for (let i = 0; i < this.npcFishes.length; i++) {
const npc = this.npcFishes[i];
// 玩家鱼捕食NPC鱼
if (this.playerFish.size > npc.size && this.isColliding(this.playerFish, npc)) {
// 玩家鱼成长
this.playerFish.size += npc.size * 0.15;
this.score += npc.scoreValue;
// 更新玩家鱼速度(体型越大速度越慢)
this.playerFish.speed = Math.max(1, 3 - this.playerFish.size / 20);
// 标记NPC鱼为移除
toRemove.push(i);
}
}
// 从后往前移除,避免索引问题
for (let i = toRemove.length - 1; i >= 0; i--) {
this.npcFishes.splice(toRemove[i], 1);
}
}
// 检测玩家鱼是否被吃掉
private checkPlayerSurvival() {
for (const npc of this.npcFishes) {
if (npc.size > this.playerFish.size && this.isColliding(this.playerFish, npc)) {
// 玩家鱼生命值减少
this.playerFish.health -= 20;
if (this.playerFish.health <= 0) {
// 游戏结束
this.gameOver = true;
}
}
}
}
// 碰撞检测函数
private isColliding(fish1: Fish, fish2: Fish): boolean {
const dx = fish1.positionX - fish2.positionX;
const dy = fish1.positionY - fish2.positionY;
const distance = Math.sqrt(dx * dx + dy * dy);
return distance < (fish1.size + fish2.size) / 2;
}
build() {
Stack() {
// 背景
Row()
.backgroundColor('#e2e9ef')
.width('100%')
.height('100%')
// 分数显示
Text(`分数: ${this.score}`)
.fontSize(24)
.fontColor('#FFFFFF')
.position({ x: 20, y: 20 })
// 玩家鱼(拖拽控制)
Text('🐟')
.fontSize(this.playerFish.size)
.width(this.playerFish.size * 2)
.height(this.playerFish.size * 2)
.borderRadius(this.playerFish.size)
.backgroundColor('#FF0000')
.position({
x: this.playerFish.positionX - (this.playerFish.size * 2) / 2,
y: this.playerFish.positionY - (this.playerFish.size * 2) / 2
})
.gesture(
PanGesture()
.onActionStart((event: GestureEvent) => {
// 开始拖拽,计算偏移量
this.isDragging = true;
this.dragOffsetX = event.offsetX - (this.playerFish.positionX - (this.playerFish.size * 2) / 2);
this.dragOffsetY = event.offsetY - (this.playerFish.positionY - (this.playerFish.size * 2) / 2);
})
.onActionUpdate((event: GestureEvent) => {
// 拖拽中更新位置
if (this.isDragging) {
this.playerFish.positionX = event.offsetX - this.dragOffsetX;
this.playerFish.positionY = event.offsetY - this.dragOffsetY;
this.playerFish.checkBoundary();
}
})
.onActionEnd(() => {
// 拖拽结束
this.isDragging = false;
})
)
// NPC鱼(修复显示问题)
ForEach(this.npcFishes, (npc: NPCFish) => {
Text(npc.direction > 0 ? '🐠' : '🐟')
.fontSize(npc.size)
.width(npc.size * 1.5)
.height(npc.size * 1.5)
.borderRadius(npc.size * 0.75)
.backgroundColor('#ADD8E6')
.position({
x: npc.positionX - (npc.size * 1.5) / 2,
y: npc.positionY - (npc.size * 1.5) / 2
})
})
// 游戏结束提示
if (this.gameOver) {
Column() {
Text('游戏结束!')
.fontSize(48)
.fontWeight(FontWeight.Bold)
.fontColor('#FF0000')
Text(`最终分数: ${this.score}`)
.fontSize(32)
.fontColor('#FFFFFF')
Button('重新开始')
.onClick(() => {
this.playerFish = new PlayerFish(30, 3, 150, 300);
this.npcFishes = [];
this.score = 0;
this.gameOver = false;
this.initNPCFishes(8);
})
}
.width('80%')
.height('30%')
.backgroundColor('rgba(0, 0, 0, 0.7)')
.borderRadius(20)
.justifyContent(FlexAlign.Center)
.alignItems(HorizontalAlign.Center)
.position({
x: (this.screenWidth - this.screenWidth * 0.8) / 2,
y: (this.screenHeight - this.screenHeight * 0.3) / 2
})
}
}
.width('100%')
.height('100%')
}
}
00
- 0回答
- 0粉丝
- 0关注
相关话题
- 纯血Harmony NETX 5小游戏实践:2048(附源文件)
- 纯血Harmony NETX 5小游戏实践:电子木鱼(附源文件)
- 纯血Harmony NETX 5小游戏实践:趣味三消游戏(附源文件)
- 纯血HarmonyOS5 打造小游戏实践:扫雷(附源文件)
- 纯血Harmony NETX 5小游戏实践:贪吃蛇(附源文件)
- 纯血HarmonyOS5 打造小游戏实践:绘画板(附源文件)
- 纯血HarmonyOS 5 ArKTS 打造小游戏实践:狼人杀(介绍版(附源文件)
- 纯血Harmony NETX 5 打造趣味五子棋:(附源文件)
- HarmonyOS 5ArkUI-X打造数字猜谜游戏:(附源文件)
- 鸿蒙HarmonyOS 5小游戏实践:打砖块游戏(附:源代码)
- 鸿蒙HarmonyOS 5小游戏实践:记忆翻牌(附:源代码)
- 鸿蒙HarmonyOS 5小游戏实践:数字记忆挑战(附:源代码)
- 鸿蒙HarmonyOS 5 小游戏实践:数字华容道(附:源代码)
- 鸿蒙HarmonyOS 5小游戏实践:动物连连看(附:源代码)
- 真正的纯血鸿蒙开发者是怎样开发应用的?纯血鸿蒙到底”纯“在哪里?