仓库源码地址:https://gitcode.com/feng8403000/math_app_study
一、项目概述
本项目是一个基于HarmonyOS ArkTS框架开发的数字能力训练应用,包含10款数字能力训练游戏和1款九宫数独终极挑战游戏。应用采用深色主题设计,通过关卡制度实现难度递进,为用户提供系统的数字能力训练体验。
1.1 技术栈
| 技术 | 版本 | 说明 |
|---|---|---|
| HarmonyOS | API 24 | 操作系统基础 |
| ArkTS | 3.0+ | 应用开发语言 |
| ArkUI | 3.0+ | UI框架 |
| Hvigor | 3.0+ | 构建工具 |
1.2 项目结构
entry/src/main/ets/ ├── managers/ # 管理器层 │ ├── AppState.ets # 全局状态管理 │ ├── GameManager.ets # 游戏逻辑管理 │ ├── SudokuGenerator.ets # 数独生成器 │ └── ... ├── models/ # 数据模型层 │ ├── GameState.ets # 游戏状态模型 │ ├── CellData.ets # 单元格数据模型 │ └── ... ├── pages/ # 页面层 │ ├── Index.ets # 首页 │ ├── NumberConnectPage.ets # 数字连线 │ ├── SudokuPage.ets # 九宫数独 │ └── ... └── resources/ # 资源文件 ├── base/ └── ...二、架构设计
2.1 分层架构
采用经典的三层架构模式,将应用分为表示层、业务逻辑层和数据模型层:
┌─────────────────────────────────────────────────┐ │ 表示层 (Pages) │ │ Index.ets | GamePages | LevelPages | UI组件 │ ├─────────────────────────────────────────────────┤ │ 业务逻辑层 (Managers) │ │ AppState | GameManager | SudokuGenerator │ ├─────────────────────────────────────────────────┤ │ 数据模型层 (Models) │ │ GameState | CellData | LevelInfo | Category │ └─────────────────────────────────────────────────┘2.1.1 表示层
表示层负责UI展示和用户交互,包含以下核心页面:
- Index.ets:应用首页,展示游戏列表和分类
- 关卡选择页面:每个游戏对应一个关卡选择页面,如
NumberConnectLevelPage.ets - 游戏页面:每个游戏的核心玩法页面,如
NumberConnectPage.ets
页面设计遵循以下原则:
@Entry@Componentstruct GamePage{@StateisPlaying:boolean=false;@Statescore:number=0;@StatetimerSeconds:number=0;build(){Column(){// 顶部导航栏Row(){...}// 游戏主体区域if(!this.isPlaying){// 开始界面Button('开始游戏').onClick(()=>this.startGame())}else{// 游戏界面Grid(){...}}}}}2.1.2 业务逻辑层
业务逻辑层处理游戏核心逻辑,包含以下管理器:
AppState- 全局状态管理器
采用单例模式设计,管理所有游戏的进度和配置:
exportclassAppState{privatestaticinstance:AppState|null=null;// 各游戏的关卡进度numberConnectCompletedLevels:Array<number>=[];numberConnectLevelTimes:Array<number>=[];findDifferentCompletedLevels:Array<number>=[];// ... 其他游戏进度staticgetInstance():AppState{if(AppState.instance===null){AppState.instance=newAppState();}returnAppState.instance;}}exportconstappState:AppState=AppState.getInstance();SudokuGenerator- 数独生成器
负责生成有效的数独谜题,包含回溯算法实现:
classSudokuGenerator{generate(size:number):Array<number>{// 生成完整的数独解letsolution:Array<number>=[];// 回溯算法填充this.fillBoard(solution,size);returnsolution;}generatePuzzle(solution:Array<number>,difficulty:Difficulty,size:number):Array<number>{// 根据难度挖空letpuzzle:Array<number>=[...solution];letremoveCount:number=this.getRemoveCount(difficulty,size);this.removeCells(puzzle,removeCount,size);returnpuzzle;}}2.1.3 数据模型层
数据模型层定义应用的数据结构:
GameState- 游戏状态模型
classGameState{size:number=9;board:Board=newBoard();solution:Array<number>=[];difficulty:Difficulty=Difficulty.EASY;level:number=1;history:Array<HistoryRecord>=[];historyIndex:number=-1;isCompleted:boolean=false;}CellData- 单元格数据模型
classCellData{value:number=0;isOriginal:boolean=false;isSelected:boolean=false;isHighlighted:boolean=false;isError:boolean=false;constructor(value:number,isOriginal:boolean){this.value=value;this.isOriginal=isOriginal;}}三、核心设计模式
3.1 单例模式
应用中多处使用单例模式,确保全局状态的唯一性:
exportclassAppState{privatestaticinstance:AppState|null=null;privateconstructor(){// 私有构造函数,防止外部实例化}staticgetInstance():AppState{if(AppState.instance===null){AppState.instance=newAppState();}returnAppState.instance;}}3.2 观察者模式
通过@State装饰器实现状态驱动的UI更新:
@Statescore:number=0;// 状态变化自动触发UI更新this.score+=10;3.3 策略模式
不同游戏采用不同的难度策略:
// 数字炸弹的难度策略privategetRangeByLevel(level:number):{min:number,max:number}{if(level<=5)return{min:1,max:10000};if(level<=10)return{min:1,max:1000000};if(level<=15)return{min:1,max:21000000000};return{min:10000000000,max:31000000000};}// 找不同数字的难度策略privategetGridSizeByLevel(level:number):number{if(level<=5)return4;if(level<=10)return6;if(level<=15)return8;return10;}四、路由与导航
4.1 路由配置
在main_pages.json中配置所有页面路由:
{"src":["pages/SplashPage","pages/Index","pages/NumberConnectLevelPage","pages/NumberConnectPage","pages/SudokuLevelPage","pages/SudokuPage",// ... 其他页面]}4.2 页面跳转
使用router.pushUrl进行页面跳转:
router.pushUrl({url:'pages/NumberConnectPage',params:{level:1,gridSize:4}});4.3 参数传递
通过router.getParams()获取路由参数:
interfaceRouteParams{level:number;gridSize:number;}aboutToAppear():void{letparams:RouteParams=router.getParams()asRouteParams;if(params!==undefined){this.currentLevel=params.level;this.gridSize=params.gridSize;}}五、关卡系统设计
5.1 关卡配置
每个游戏包含20个关卡,分为4个难度等级:
classLevelInfo{level:number=0;gridSize:number=0;label:string='';minNum?:number=1;constructor(level:number,gridSize:number,label:string,minNum?:number){this.level=level;this.gridSize=gridSize;this.label=label;if(minNum!==undefined){this.minNum=minNum;}}}classCategory{name:string='';description:string='';color:string='';levels:Array<LevelInfo>=[];constructor(name:string,description:string,color:string){this.name=name;this.description=description;this.color=color;}}5.2 关卡解锁逻辑
只有完成前一关才能解锁下一关:
privateisLevelUnlocked(level:number):boolean{letcompletedLevels:Array<number>=appState.numberConnectCompletedLevels;if(level===1)returntrue;for(leti=0;i<completedLevels.length;i++){if(completedLevels[i]>=level-1){returntrue;}}returnfalse;}5.3 进度保存
完成关卡后保存进度和最佳时间:
privatesaveProgress():void{letcompletedLevels:Array<number>=appState.numberConnectCompletedLevels;letexists:boolean=false;for(leti=0;i<completedLevels.length;i++){if(completedLevels[i]===this.currentLevel){exists=true;break;}}if(!exists){completedLevels.push(this.currentLevel);completedLevels.sort((a:number,b:number)=>a-b);appState.numberConnectCompletedLevels=completedLevels;}letlevelTimes:Array<number>=appState.numberConnectLevelTimes;while(levelTimes.length<=this.currentLevel){levelTimes.push(0);}if(levelTimes[this.currentLevel]===0||this.timerSeconds<levelTimes[this.currentLevel]){levelTimes[this.currentLevel]=this.timerSeconds;appState.numberConnectLevelTimes=levelTimes;}}六、计时系统
6.1 计时器实现
使用setTimeout实现精确计时:
privatetimerId:number=0;privatestartTimer():void{this.timerId=1;this.tick();}privatetick():void{if(this.timerId!==0){this.timerSeconds++;setTimeout(()=>{this.tick();},1000);}}privatestopTimer():void{if(this.timerId!==0){clearInterval(this.timerId);this.timerId=0;}}privateformatTime(seconds:number):string{letmins:number=Math.floor(seconds/60);letsecs:number=seconds%60;return`${mins.toString().padStart(2,'0')}:${secs.toString().padStart(2,'0')}`;}6.2 最佳时间记录
每个关卡独立记录最佳时间:
@StatebestTime:number=0;aboutToAppear():void{letlevelTimes:Array<number>=appState.numberConnectLevelTimes;if(levelTimes.length>this.currentLevel&&levelTimes[this.currentLevel]>0){this.bestTime=levelTimes[this.currentLevel];}}七、UI设计规范
7.1 深色主题
应用采用深色主题设计,主色调为深蓝黑色:
.build(){Column(){// ...}.width('100%').height('100%').backgroundColor('#0A192F')}7.2 配色方案
| 用途 | 颜色 | 代码 |
|---|---|---|
| 主背景 | 深蓝黑 | #0A192F |
| 强调色 | 金色 | #FFD700 |
| 文字色 | 白色 | #FFFFFF |
| 提示色 | 天蓝色 | #87CEEB |
| 成功色 | 绿色 | #32CD32 |
| 错误色 | 红色 | #FF6B6B |
7.3 布局组件
使用 ArkUI 的布局组件构建界面:
Column({space:16}){Row({space:12}){Text('标题').fontSize(24).fontColor('#FFD700')Text('副标题').fontSize(14).fontColor('#87CEEB')}Grid(){ForEach(items,(item)=>{GridItem(){Button(item).width('100%').height('100%')}})}.columnsTemplate('1fr 1fr 1fr').rowsTemplate('1fr 1fr')}八、开发注意事项
8.1 ArkTS语法约束
开发过程中需要注意 ArkTS 的语法限制:
// 不支持解构赋值// let { a, b } = obj; // 错误lettemp:number=obj.a;lettemp2:number=obj.b;// 不支持函数表达式// let fn = function() {}; // 错误letfn=()=>{};// 不支持any和unknown类型// let x: any; // 错误letx:number=0;// 所有import必须在文件开头import{router}from'@kit.ArkUI';import{appState}from'../managers/AppState';8.2 状态管理最佳实践
使用@State管理组件状态,避免不必要的状态更新:
@StateisPlaying:boolean=false;@StateisGameWon:boolean=false;@Statescore:number=0;// 正确:状态变化后UI自动更新this.isGameWon=true;// 错误:直接修改数组元素不会触发更新// this.grid[0] = 1;// 正确:重新赋值触发更新this.grid=[...this.grid.slice(0,0),1,...this.grid.slice(1)];8.3 性能优化
- 使用
renderGroup(true)优化复杂组件渲染 - 避免在循环中创建新对象
- 合理使用懒加载和条件渲染
九、总结
本项目采用分层架构设计,通过单例模式管理全局状态,使用路由系统实现页面导航,通过关卡制度实现难度递进。项目充分利用了 HarmonyOS ArkTS 的声明式UI特性和状态管理机制,为用户提供了流畅的数字能力训练体验。
在后续的博客中,我们将深入探讨每个游戏的实现细节,包括算法设计、布局技巧和交互优化等方面。