【鸿蒙实战】20分钟手把手教你开发骰子模拟器
【鸿蒙实战】20分钟手把手教你开发骰子模拟器
保姆级教程!从零开始,带你用 HarmonyOS NEXT 和 ArkTS 实现一个功能完整的骰子模拟器应用。
一、项目预览
先看看我们要做什么:
- 🎲 点击投掷骰子,显示 1-6 点
- ⚡ 流畅的翻滚动画效果
- 🎨 5 种主题配色可选
- 📊 自动记录投掷历史
- 💡 支持点击骰子或按钮两种操作
二、准备工作
2.1 环境要求
| 工具 | 版本 |
|---|---|
| DevEco Studio | 5.0+ |
| HarmonyOS SDK | API 23+ |
| Node.js | 14.19.1+ |
2.2 创建项目
步骤 1:打开 DevEco Studio,点击File → New → Create Project
步骤 2:选择Empty Ability模板
步骤 3:填写项目信息:
- Bundle name:
com.example.myapplication - Save location:
D:\harmonyos\project\project11\MyApplication
步骤 4:点击 Finish,等待项目初始化
2.3 项目结构
MyApplication/ ├── entry/ │ └── src/main/ │ ├── ets/ │ │ ├── entryability/ │ │ │ └── EntryAbility.ets │ │ └── pages/ │ │ └── Index.ets ⭐ 主页面 │ └── resources/ └── build-profile.json5我们主要编辑Index.ets文件。
三、代码实现
3.1 定义数据模型
步骤 1:打开Index.ets,定义两个接口:
// 投掷记录interfaceDiceRecord{value:number;// 点数:1-6time:string;// 时间:HH:MM:SS}// 主题配置interfaceDiceTheme{name:string;// 主题名称bg:string;// 背景色dot:string;// 点数色border:string;// 边框色}3.2 创建组件和状态
步骤 2:定义组件和状态变量:
@Entry@Componentstruct Index{// ========== 状态变量 ==========@StatecurrentValue:number=1;// 当前点数@StateisRolling:boolean=false;// 是否在滚动@StatetotalRolls:number=0;// 总投掷次数@Statehistory:DiceRecord[]=[];// 历史记录@StatediceColor:string='#FFFFFF';// 骰子背景色@StatedotColor:string='#1C1C1E';// 点数颜色// ========== 主题数据 ==========readonlydiceColors:DiceTheme[]=[{name:'经典白',bg:'#FFFFFF',dot:'#1C1C1E',border:'#D1D1D6'},{name:'复古红',bg:'#FF3B30',dot:'#FFFFFF',border:'#C41A1A'},{name:'深邃蓝',bg:'#007AFF',dot:'#FFFFFF',border:'#0040DD'},{name:'翡翠绿',bg:'#34C759',dot:'#FFFFFF',border:'#248A3D'},{name:'暗夜黑',bg:'#1C1C1E',dot:'#FFFFFF',border:'#000000'},];}说明:
@State:状态变量,变化时 UI 自动更新readonly:常量数组,不需要响应式
3.3 实现投掷逻辑
步骤 3:添加投掷方法:
rollDice():void{// 1. 防止重复触发if(this.isRolling)return;this.isRolling=true;// 2. 快速切换数字产生动画letframe=0;constinterval=setInterval(()=>{this.currentValue=Math.floor(Math.random()*6)+1;frame++;// 3. 8 帧后停止if(frame>=8){clearInterval(interval);constfinalValue=Math.floor(Math.random()*6)+1;this.currentValue=finalValue;this.isRolling=false;this.totalRolls++;// 4. 记录历史this.addToHistory(finalValue);}},60);}步骤 4:添加记录历史的方法:
addToHistory(value:number):void{constnow=newDate();consttimeStr=`${now.getHours().toString().padStart(2,'0')}:`+`${now.getMinutes().toString().padStart(2,'0')}:`+`${now.getSeconds().toString().padStart(2,'0')}`;constnewRecord:DiceRecord={value:value,time:timeStr};// 插入到数组开头consttemp=[newRecord];for(leti=0;i<this.history.length;i++){temp.push(this.history[i]);}this.history=temp;// 限制 10 条if(this.history.length>10){consttemp2=[];for(leti=0;i<10;i++){temp2.push(this.history[i]);}this.history=temp2;}}3.4 绘制骰子点数
步骤 5:使用@Builder定义可复用的 UI:
@BuilderbuildDiceFace(){Column(){if(this.currentValue===1){Text('●').fontSize(48).fontColor(this.dotColor)}elseif(this.currentValue===2){Row(){Column(){Text('●').fontSize(24).fontColor(this.dotColor)}.width('50%')Column(){Text('●').fontSize(24).fontColor(this.dotColor)}.width('50%')}.width(120).justifyContent(FlexAlign.SpaceAround)}elseif(this.currentValue===3){Row(){Column(){Text('●').fontSize(20).fontColor(this.dotColor)}.width('33%')Column(){Text('●').fontSize(24).fontColor(this.dotColor)}.width('33%')Column(){Text('●').fontSize(20).fontColor(this.dotColor)}.width('33%')}.width(140).justifyContent(FlexAlign.SpaceAround)}elseif(this.currentValue===4){Column({space:12}){Row({space:24}){Text('●').fontSize(24).fontColor(this.dotColor)Text('●').fontSize(24).fontColor(this.dotColor)}Row({space:24}){Text('●').fontSize(24).fontColor(this.dotColor)Text('●').fontSize(24).fontColor(this.dotColor)}}}elseif(this.currentValue===5){Column({space:10}){Row({space:18}){Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)}Row({space:18}){Text('').fontSize(20)Text('●').fontSize(24).fontColor(this.dotColor)Text('').fontSize(20)}Row({space:18}){Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)}}}else{Column({space:8}){Row({space:14}){Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)}Row({space:14}){Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)}Row({space:14}){Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)Text('●').fontSize(20).fontColor(this.dotColor)}}}}.width(160).height(160).justifyContent(FlexAlign.Center)}3.5 构建界面
步骤 6:在build()方法中组装 UI:
build(){Column(){// 标题Text('🎲 骰子模拟器').fontSize(26).fontWeight(FontWeight.Bold).margin({top:30,bottom:4})Text(`已投掷${this.totalRolls}次`).fontSize(14).fontColor('#8E8E93').margin({bottom:20})// 骰子Column(){this.buildDiceFace()}.width(180).height(180).backgroundColor(this.diceColor).borderRadius(24).border({width:3,color:'#D1D1D6'}).shadow({radius:12,color:'#20000000',offsetY:4}).opacity(this.isRolling?0.7:1.0).onClick(()=>{this.rollDice();})// 按钮Button(this.isRolling?'🎲 投掷中...':'🎲 掷骰子').type(ButtonType.Capsule).width(200).height(50).backgroundColor('#007AFF').margin({top:24}).enabled(!this.isRolling).onClick(()=>{this.rollDice();})// 主题Text('选择主题').fontSize(14).fontColor('#8E8E93').margin({top:20,bottom:8})Row({space:10}){ForEach(this.diceColors,(theme:DiceTheme)=>{Row(){Text(theme.name).fontSize(11).fontColor(theme.bg==='#1C1C1E'?'#FFFFFF':'#1C1C1E')}.width(60).height(28).backgroundColor(theme.bg).borderRadius(14).border({width:this.diceColor===theme.bg?2:1,color:this.diceColor===theme.bg?'#007AFF':theme.border}).justifyContent(FlexAlign.Center).onClick(()=>{this.diceColor=theme.bg;this.dotColor=theme.dot;})})}// 历史if(this.history.length>0){Row(){Text('📋 投掷记录').fontSize(16).fontWeight(FontWeight.Bold)Blank()Text('清空').fontSize(13).fontColor('#FF3B30').onClick(()=>{this.history=[];this.totalRolls=0;})}.width('100%').margin({top:20,bottom:8})Column({space:4}){ForEach(this.history,(record:DiceRecord)=>{Row(){Text(`🎲${record.value}`).fontSize(18).fontWeight(FontWeight.Bold)Blank()Text(record.time).fontSize(12).fontColor('#8E8E93')}.width('100%').padding(10).backgroundColor('#F2F2F7').borderRadius(10)})}.width('100%')}}.width('100%').height('100%').backgroundColor('#FFFFFF').padding(20)}四、运行测试
五、功能演示
5.1 投掷骰子
点击骰子或按钮,骰子快速翻滚 8 次后停下。
5.2 切换主题
点击主题按钮,骰子颜色立即切换。
| 主题 | 颜色 |
|---|---|
| 经典白 | 白底黑点 |
| 复古红 | 红底白点 |
| 深邃蓝 | 蓝底白点 |
| 翡翠绿 | 绿底白点 |
| 暗夜黑 | 黑底白点 |
5.3 查看历史
自动记录最近 10 次投掷,显示点数和时间。
六、常见问题
Q1: 点击没反应?
A:检查isRolling状态,确保动画结束后才能再次点击。
Q2: 历史记录不显示?
A:检查history.length > 0条件,确保有数据。
Q3: 主题切换不生效?
A:检查diceColor和dotColor是否都更新了。
Q4: 如何修改动画速度?
A:调整setInterval的间隔时间:
- 更快:改小间隔(如 40ms)
- 更慢:改大间隔(如 100ms)
Q5: 如何添加更多主题?
A:在diceColors数组中添加:
{name:'紫罗兰',bg:'#AF52DE',dot:'#FFFFFF',border:'#8B3AA8'}七、项目总结
核心知识点
| 知识点 | 说明 |
|---|---|
| @State | 状态管理 |
| @Builder | UI 复用 |
| setInterval | 动画实现 |
| ForEach | 列表渲染 |
| if | 条件渲染 |
项目信息:
- SDK:API 23
- 开发工具:DevEco Studio 5.0+
