文档开发者中心
我的

#HarmonyOS技术训练营第四期#Ark UI 贪食蛇

 这几天学习了HarmonyOS方舟开发框架(Ark UI),尝试了一下自己做了一个贪食蛇的小游戏,第一次尝试,也遇到了很多问题,一边查看API教程,一边不停实践。分享下我的开发和问题。

效果图:

%E5%90%88%E5%B9%B6%E8%A7%86%E9%A2%91.gif

代码结构:

image.png

实现思路:

通过画一个20 * 20 的 Text排列模拟贪食蛇可活动的范围,改变Text的背景色表示生成的食物和模拟蛇的移动。

代码介绍:

1、欢迎页面(index.ets)

animateTo实现Logo图标的渐出和放大效果;闪屏动画播放结束后定格1s,进入游戏页面。设置animateTo的onFinish回调接口,调用定时器Timer的setTimeout接口延时1s后,调用router.replace,显示游戏页面。

image.png

2、游戏页面(game.ets)

a、定义了一个常量用了表示格子不用状态下的背景色

收起
自动换行
深色代码主题
复制

const colors = ['#FFFFFF', '#ff0000', '#000000']

b、初始化格子

收起
自动换行
深色代码主题
复制

initialize() { initialize() { this.gridColorIndex = new Array(); for (let i = 0; i < 20; i++) { this.gridColorIndex.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); } this.headX = 0; this.headY = 0; this.foodX = 0; this.foodY = 0; this.score = 0; this.gameOver = false; this.result = 0; this.times = 0; this.snake = new Array();}Grid() { ForEach(this.rowIndex, (row: number) => { ForEach(this.colIndex, (col: number) => { GridItem() { Text('') .backgroundColor(colors[this.gridColorIndex[row][col]]) .width(17) .height(17) } }, col => col.toString()) }, row => row.toString())}.columnsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr').rowsTemplate('1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr 1fr').rowsGap(2).columnsGap(2).backgroundColor('#C1D0E6').height(355)

c、开始游戏把所有的状态数回归到初始化状态

收起
自动换行
深色代码主题
复制

Button('开始游戏') .height(70) .width(200) .fontSize(35) .fontWeight(FontWeight.Bold) .align(Alignment.Center) .backgroundColor('#4162AA') .fontColor(Color.White) .margin({ left: 5, top: 10, bottom: 5, right: 5 }) .onClick((event: ClickEvent) => { this.initialize() this.initSnake() this.setFood() this.move() })initialize() { this.gridColorIndex = new Array(); for (let i = 0; i < 20; i++) { this.gridColorIndex.push([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); } this.headX = 0; this.headY = 0; this.foodX = 0; this.foodY = 0; this.score = 0; this.gameOver = false; this.result = 0; this.times = 0; this.snake = new Array();}

d、初始化一个只有蛇头的蛇出来,改变蛇头的格子状态数据,设置为黑色,设定默认的移动方向为向右移动

收起
自动换行
深色代码主题
复制

//初始化蛇 initSnake() { this.headX = 0; this.headY = 0; this.snake.push([this.headX, this.headY]); this.gridColorIndex[this.headX][this.headY] = 2; this.dir = 'right'; }

e、随机产生食物

收起
自动换行
深色代码主题
复制

setFood() { do { this.foodX = Math.floor(Math.random() * 20); this.foodY = Math.floor(Math.random() * 20); } while (this.isFoodInSnake()); this.gridColorIndex[this.foodX][this.foodY] = 1; console.info('Tracy setFood foodX = ' + this.foodX + ' foodY = ' + this.foodY); }//判断食物是否在蛇身 isFoodInSnake() { for (var index = 0; index < this.snake.length; index++) { if (this.foodX == this.snake[index][0] && this.foodY == this.snake[index][1]) { return true; } } return false; }

f、设定定时器,让蛇动起来

收起
自动换行
深色代码主题
复制

move() { console.info('Tracy move!!') var inervalID = setInterval(() => { this.times += 1; this.moveSnake() if (this.gameOver) { clearInterval(inervalID) this.dialogController.open(); } }, 500);}//移动蛇 moveSnake() { console.info('Tracy moveSnake!!') let step = 1 if (this.dir == 'left' || this.dir == 'up') { step = -1; } console.info('Tracy moveSnake step = ' + step); let newHead; if (this.dir == 'left' || this.dir == 'right') { this.headY += step; } else if (this.dir == 'up' || this.dir == 'down') { this.headX += step } console.info('Tracy moveSnake headX = ' + this.headX + '; headY = ' + this.headY); this.checkMove(this.headX, this.headY) newHead = [[this.headX, this.headY]]; newHead = newHead.concat(this.snake); this.snake = newHead; this.gridColorIndex[this.headX][this.headY] = 2; //吃到食物 if (this.headX == this.foodX && this.headY == this.foodY) { this.score += 1; this.setFood() //重新产生食物 } else { //没有吃到食物,删除蛇尾 let delItem = this.snake.pop(); console.info('Tracy snake lenght = ' + this.snake.length); console.info('Tracy delete delItemX = ' + delItem[0] + ' delItemY= ' + delItem[1]); this.gridColorIndex[delItem[0]][delItem[1]] = 0; } }checkMove(x, y) { //表示撞墙了 if (x < 0 || y < 0 || x > 19 || y > 19) { this.gameOver = true; this.result = 1; return; } else { for (let index = 0; index < this.snake.length; index++) { if (x == this.snake[index][0] && y == this.snake[index][1]) { this.gameOver = true; this.result = 2; return; } } } if (this.score >= 100) { this.gameOver = true; this.result = 0; return; }}

g、方向按钮改变蛇移动的方向

收起
自动换行
深色代码主题
复制

Row() { setButton({ dirDesc: '↑', dir: 'up', direction: $dir }) setButton({ dirDesc: '←', dir: 'left', direction: $dir }) setButton({ dirDesc: '→', dir: 'right', direction: $dir }) setButton({ dirDesc: '↓', dir: 'down', direction: $dir })}struct setButton { private dirDesc: string private dir: string @Link direction: String build() { Button(this.dirDesc) .height(70) .width(70) .fontSize(35) .fontWeight(FontWeight.Bold) .align(Alignment.Center) .backgroundColor('#4162AA') .fontColor(Color.White) .margin({ left: 5, top: 20, bottom: 5, right: 5 }) .onClick((event: ClickEvent) => { this.direction = this.dir }) }}

h、蛇移动过程中如果撞墙或者撞到自己,弹出提示框,游戏结束。

收起
自动换行
深色代码主题
复制

struct DialogResult { controller: CustomDialogController; @Link result: number @Link score: number build() { Column() { if (this.result == 0) { Text('好厉害,挑战成功!') .fontSize(25) .fontColor(Color.Red) } else if (this.result == 1) { Text('撞墙了!你的分数是:' + this.score + ' 分') .fontSize(25) .fontColor(Color.Green) } else if (this.result == 2) { Text('撞到自己了!你的分数是:' + this.score + ' 分') .fontSize(25) .fontColor(Color.Green) } Button('返回游戏') .onClick(() => { this.controller.close(); }) } }}

在编写代码的过程中我也遇到了几个问题,初学者请教各路大神指点

1、以下代码刚开始我不是这样些的,没有定义常量的colors数组,而是根据this.gridColorIndex[row][col]的值用的条件渲染,但是我发现每次移动改变了背景颜色的格子就会排列到最后,不是在原位置改变颜色,不知道为什么会这样,所以增加了一个colors数组,去掉了if - else的条件判断。

收起
自动换行
深色代码主题
复制

GridItem() { Text('') .backgroundColor(colors[this.gridColorIndex[row][col]]) .width(17) .height(17) }

2、定义的@State gridColorIndex: number[][]= new Array();状态数据改变的时候,UI没有刷新,我试了好多种方式都不刷新,然后我只有同步改变了另一个简单类型的状态数据,UI才刷新的。不知道为什么? 

点赞
6
收藏
5
回复
6
分享
举报
浏览546 编辑于2021-12-19 16:33未知归属地
全部评论
最多点赞
最新发布
最早发布
那就让我依葫芦画个瓢
6楼回复于2022-02-21 06:32 未知归属地
还比较完整,可以
5楼回复于2022-01-04 06:20 未知归属地
不错不错,目前也正在弄扫雷游戏哈哈哈
4楼回复于2021-12-31 06:33 未知归属地
不错哟,代码逻辑清晰
3楼回复于2021-12-22 14:00 未知归属地
厉害👍👍👍👍
2楼回复于2021-12-20 16:44 未知归属地
童年记忆又回来了,楼主666
1楼回复于2021-12-20 11:44 未知归属地
写回答
新增插入模板功能
一键使用模板,快速填写内容,轻松发帖~
知道了
  • 为了保障您的信息安全,请勿上传您的敏感个人信息(如您的密码等信息)和您的敏感资产信息(如关键源代码、签名私钥、调试安装包、业务日志等信息),且您需自行承担由此产生的信息泄露等安全风险。
  • 如您发布的内容为转载内容,请注明内容来源。

我要发帖子

了解社区公约,与您携手共创和谐专业的开发者社区。