在ArkTS中,使用@State修饰器,二维数组中的某个数字发生改变时,UI是无法监听到的,导致不能实时渲染,因此定义一个二维的全局变量arr[][]作为"中介",操作时是对arr[][]进行操作,操作后对每一行进行赋值,即可让UI监听到。若要UI监听到二维数组的变化,则需使用@Observed和@ObjectLink配合使用,可参考简易五子棋小游戏的实现https://blog.csdn.net/weixin_63484971/article/details/141223205?spm=1001.2014.3001.5502。
let arr:number[][]=[]
@State row1
到 @State row4
这四个状态变量分别代表了游戏棋盘的四行数字状态。初始时,每行都被初始化为包含四个 0 的数组,表示棋盘上的初始位置均为空。
@State text
用于存储游戏过程中的提示信息,例如“游戏结束”等。
@State colors
定义了不同数字所对应的背景颜色。这样,在游戏界面中,根据数字的大小可以为其显示相应的背景颜色,增强视觉效果。
@State maxScore
用于记录游戏过程中出现的最高分数。
@State totalScore
则用于累计游戏中的总得分。
// 每一行 共四行
@State row1:number[] = [0, 0, 0, 0]
@State row2:number[] = [0, 0, 0, 0]
@State row3:number[] = [0, 0, 0, 0]
@State row4:number[] = [0, 0, 0, 0]
@State text:string = ''
// 背景颜色 不同的数字不同的背景颜色
@State colors:ResourceColor[]=[Color.Transparent,'#fcc307','#e2c027','#806332', '#edc3ae',
'#f43e06', '#12aa9c','#428675','#d2d97a','#8fb2c9',
'#b0d5df','#2e317c','#983680']
// 最大分
@State maxScore:number = 0
// 总分
@State totalScore:number = 0
updateArr
函数的作用是将四个表示行的状态变量组合成一个二维数组 arr
。这样在后续的游戏逻辑处理中,可以更方便地对整个棋盘进行统一的操作和判断。
// 更新全局的arr 用二维数组表示4乘4
updateArr(){
arr=[]
arr.push(this.row1)
arr.push(this.row2)
arr.push(this.row3)
arr.push(this.row4)
}
updateRows
函数的功能与 updateArr
相反,它将全局的二维数组 arr
的内容更新到四个行状态变量中,以实现游戏界面的同步渲染。
// 更新每一行的渲染
updateRows(){
this.row1 = arr[0]
this.row2 = arr[1]
this.row3 = arr[2]
this.row4 = arr[3]
}
haveZeros
函数用于检查 arr
数组中是否还存在值为 0 的元素。通过两层循环遍历整个数组,如果找到任何一个 0 元素,立即返回 true
,表示还有可操作的空间;如果循环结束都没有找到 0 元素,则返回 false
,意味着游戏可能已经无法继续。
// 是否还有0
haveZeros(){
for(let i:number = 0;i<4;i++){
for(let j:number = 0;j<4;j++){
if(arr[i][j]==0) return true
}
}
// 循环完还为发现0 则游戏结束
return false
}
gameOver
函数用于判断游戏是否结束。首先检查是否存在 0 元素,如果有则游戏未结束,返回 false
。然后通过两层循环检查每个位置的数字是否与其相邻位置(上、下、左、右)的数字相同。如果存在相同的情况,游戏也未结束,返回 false
。如果整个循环结束都没有满足上述未结束的条件,则表示游戏结束,返回 true
。
gameOver(){
//还有0或者存相邻的数是一样的 说明游戏未结束
if(this.haveZeros()) return false
for(let i:number = 0;i<4;i++){
for(let j:number = 0;j<4;j++){
// 利用 逻辑中断做判断
if(arr[i][j]==( ((i-1)>=0?1:0) && arr[i-1][j] ) ||
arr[i][j]==( ((i+1)<=3?1:0) && arr[i+1][j] ) ||
arr[i][j]==( ((j-1)>=0?1:0) && arr[i][j-1] ) ||
arr[i][j]==( ((j+1)<=3?1:0) && arr[i][j+1] )
) return false
}
}
// 循环完还为发现0 则游戏结束
return true
}
firstNonZero
函数根据给定的坐标 (x, y)
和移动方向 direction
,查找该方向上的下一个非零数字的坐标和值。例如,当 direction
为 1 表示向上移动时,从给定坐标开始向下查找,直到找到第一个非零数字,并返回其值、横坐标和纵坐标。如果在指定方向上没有找到非零数字,则返回 [-1, 0, 0]
作为标识。
// 坐标x,y的下一个非零的坐标以及值 direction 1、2、3、4 分别为上、下、左、右
firstNonZero(x:number, y:number, direction:number){
// 向上移动则要向下寻找 (反向) 下面同理
if(direction==1){
y++
while(y<=3){
if(arr[y][x]!=0) {
return [arr[y][x],x,y]
}
y++
}
// 没有非零的 返回一个标识
return [-1,0,0]
}
else if(direction==2){
y--
while(y>=0){
if(arr[y][x]!=0) {
return [arr[y][x],x,y]
}
y--
}
return [-1,0,0]
}
else if(direction==3){
x++
while(x<=3){
if(arr[y][x]!=0) {
return [arr[y][x],x,y]
}
x++
}
return [-1,0,0]
}
else if(direction==4){
x--
while(x>=0){
if(arr[y][x]!=0) {
return [arr[y][x],x,y]
}
x--
}
return [-1,0,0]
}
return [-1,0,0]
}
f
函数用于根据指定的方向对某一列或某一行进行处理。以向上移动为例,如果当前位置为 0 ,则与找到的下一个非零数字交换位置,并递归处理当前位置;如果当前位置数字不为 0 且与找到的下一个非零数字相同,则将当前数字乘以 2 ,并将找到的位置置为 0 ,然后继续处理下一个位置。其他方向(下、左、右)的处理逻辑类似。
// 处理每一列或每一行
f(x:number, y:number, direction:number){
// 向上移 以此为例 (下、左、右) 同理
if(direction==1){
// 若找不到坐标x,y的下一个非零的坐标 则说明这一列已处理完成
if(this.firstNonZero(x,y, direction)[0]==-1) return;
// 若找到坐标x,y的下一个非零的坐标 则需要进行处理
// 如果本身为0 则和找到的坐标交换 再在原来的坐标再继续执行 此方法this.f向下处理即可
if(arr[y][x]==0) {
arr[y][x] =