鸿蒙HarmonyOS NEXT开发:简易贪吃蛇小游戏的实现(撞墙、吃到自己、方向控制、吃到东西长大判断等)

时间:2025-04-06 08:38:45
  • @Entry
  • @Component
  • struct Page2 {
  • // 二维数组 表示运动区域
  • @State area:number[][] = []
  • // 当前运动方向
  • @State directions: 'up'| 'down'| 'left'| 'right' = 'right'
  • // 控制方向
  • @State tryDirections: 'up'| 'down'| 'left'| 'right' = 'right'
  • // 历史位置 用于蛇移动时更新蛇头和蛇尾
  • @State historyPosition:number[][]=[]
  • // 头部坐标
  • @State headX:number = 0
  • @State headY:number = 0
  • // 蛇的长度
  • @State length:number = 0
  • // 颜色 不同的表示渲染不同等等颜色
  • @State colors:ResourceColor[]=[, , ]
  • //结束提示
  • @State end:string=''
  • // 初始化
  • initArea(){
  • // 25 * 25 初始化地图
  • this.area = []
  • for(let i=0;i<25;i++){
  • this.area.push([])
  • for(let j=0;j<25;j++){
  • this.area[i].push(0)
  • }
  • }
  • // 对蛇初始化
  • this.area[4][6]=1
  • this.area[4][7]=1
  • this.area[4][8]=1
  • this.area[4][9]=1
  • this.area[4][10]=1
  • // 初始化历史位置
  • =[]
  • ([6,4])
  • ([7,4])
  • ([8,4])
  • ([9,4])
  • ([10,4])
  • // 初始化头部位置
  • = 10
  • = 4
  • // 初始化蛇的长度
  • this.length = 5
  • // 初始化 结束提示
  • this.end=''
  • // 初始化方向以及想尝试的方向 为右
  • = 'right'
  • = 'right'
  • }
  • aboutToAppear(): void {
  • // 初始化
  • a()
  • // 随机生成能量的位置
  • let foodX:number = (Math.random()*this.area[0].length)
  • let foodY:number = (Math.random()*this.area[0].length)
  • // 控制蛇的移动(更新坐标)
  • setInterval(()=>{
  • // 游戏结束后不做操作
  • if(!this.end){
  • // 上一个还没吃到 或 蛇的长度占满全屏 不用生成
  • if(this.area[foodY][foodX]!=2&&this.length<25*25){
  • while(true){
  • // 生成的随机坐标为0时即为空位置时才生成能量退出循环
  • if(this.area[foodY][foodX]==0){
  • this.area[foodY][foodX]=2
  • break
  • }
  • // 继续生成
  • foodX = (Math.random()*this.area[0].length)
  • foodY = (Math.random()*this.area[0].length)
  • }
  • }
  • // 移动后头部的新位置
  • let newHeadY:number
  • let newHeadX:number
  • // 当控制方向和当前移动的方向满足条件时 才改变当前位置 避免蛇头往身后走
  • if( == 'right' && != 'left') = 'right'
  • else if( == 'left' && != 'right') = 'left'
  • else if( == 'up' && != 'down') = 'up'
  • else if( == 'down' && != 'up') = 'down'
  • // 不同的方向更新不同的头部
  • if( == 'right'){
  • newHeadY =
  • newHeadX = +1
  • }else if( == 'up'){
  • newHeadY = -1
  • newHeadX =
  • }else if( == 'down'){
  • newHeadY = +1
  • newHeadX =
  • }else{
  • newHeadY =
  • newHeadX = -1
  • }
  • // 判断是否撞墙
  • if(newHeadY>=0 && newHeadY<this.area.length && newHeadX>=0 && newHeadX<this.area[0].length){
  • // 未撞墙
  • // 头部撞到自己
  • if(this.area[newHeadY][newHeadX]==1){
  • this.end = '吃到自己了 游戏结束!'
  • } // 未撞到
  • else{
  • // 是否吃到能量
  • let eat:boolean = false
  • // 如果头碰到2 则视为吃到能量
  • if(this.area[newHeadY][newHeadX] == 2) eat = true
  • // 将头的位置放入历史位置中
  • ([newHeadX,newHeadY])
  • // 获取头部的那一行
  • let newRowHead = this.area[newHeadY]
  • // 将头部的位置置为1 即变为蛇的一部分
  • newRowHead[newHeadX] = 1
  • // 更新蛇头的位置
  • = newHeadY
  • = newHeadX
  • // 更新蛇头的那一行
  • this.area.splice(newHeadY,1,newRowHead)
  • // 吃到了能量 无需更新尾巴 长度加一
  • if(!eat){
  • // 没吃到能量 更新尾巴的那一行
  • // 获取尾巴的位置
  • let tailX = [0][0]
  • let tailY = [0][1]
  • // 移除尾巴
  • ()
  • // 获取旧的尾巴的那一行
  • let pastRowTail = this.area[tailY]
  • // 将旧尾巴的位置置为0 表示尾巴移动
  • pastRowTail[tailX] = 0
  • // 更新旧的尾巴的那一行
  • this.area.splice(tailY,1,pastRowTail)
  • }else {
  • // 吃到了 长度加一即可
  • this.length++
  • }
  • }
  • } //跑出边界 即为撞墙
  • else this.end='撞墙了 游戏结束!'
  • }
  • },200) //200ms动一次
  • }
  • build() {
  • Column() {
  • Stack(){
  • // 区域
  • Column(){
  • // 遍历每一行
  • ForEach(this.area,(itemR:number[], indexR:number)=>{
  • Row(){
  • // 遍历每行的每一个位置
  • ForEach(itemR,(itemC:number, indexC:number)=>{
  • // 对每一个位置进行渲染 0:空位置 1:蛇的部位 2:能量 以及是否为蛇头
  • Text(indexR == && indexC == ?'·' : '')
  • .textAlign()
  • .fontSize(12)
  • .fontWeight(900)
  • .fontColor()
  • .width(12)
  • .aspectRatio(1)
  • .backgroundColor([.length-1][0] == indexC &&
  • [.length-1][1] == indexR?
  • : [this.area[indexR][indexC]])
  • })
  • }
  • })
  • }
  • .borderWidth(2)
  • .borderColor()
  • // 结束时展示提示
  • Column({space:10}){
  • Text(this.end)
  • .fontSize(20)
  • .fontColor()
  • Text(this.end?'重新开始':'')
  • .fontSize(22)
  • .fontColor()
  • .onClick(()=>{
  • a()
  • })
  • }
  • .zIndex(this.end?1:-1) //结束时置z轴为1 展示出来
  • }
  • // 控制键
  • Stack(){
  • // 上、下、左、右 逻辑一样 以"上"操作为例
  • Button('上')
  • .fontSize(20)
  • .height(50)
  • .width(80)
  • .position({top:0, left:'50%'})
  • .translate({x:'-50%'})
  • .onClick(()=>{
  • = 'up'
  • })
  • Button('下')
  • .fontSize(20)
  • .height(50)
  • .width(80)
  • .position({bottom:0, left:'50%'})
  • .translate({x:'-50%'})
  • .onClick(()=>{
  • = 'down'
  • })
  • Button('左')
  • .fontSize(20)
  • .height(50)
  • .width(70)
  • .position({left:0, top:'50%'})
  • .translate({y:'-50%'})
  • .offset({left:0})
  • .onClick(()=>{
  • = 'left'
  • })
  • Button('右')
  • .fontSize(20)
  • .height(50)
  • .width(70)
  • .position({right:0, top:'50%'})
  • .translate({y:'-50%'})
  • .onClick(()=>{
  • = 'right'
  • })
  • }
  • .enabled(this.end?false:true) // 游戏结束时为禁用态 按钮失效
  • .width('45%')
  • .aspectRatio(1)
  • }
  • .height('100%')
  • .width('100%')
  • }
  • }