• 鸿蒙开发游戏(三)---大鱼吃小鱼(放置NPC)


    效果图

    添加了一个NPC(小红鱼),玩家控制小黄鱼

    鸿蒙开发游戏(一)---大鱼吃小鱼(界面部署

    鸿蒙开发游戏(二)---大鱼吃小鱼(摇杆控制)

    鸿蒙开发游戏(三)---大鱼吃小鱼(放置NPC)

    鸿蒙开发游戏(四)---大鱼吃小鱼(互吃升级)

    鸿蒙开发游戏(五)---大鱼吃小鱼(添加音效)

    鸿蒙开发游戏(六)---大鱼吃小鱼(称霸海洋)

     

    前两篇文章我们做了摇杆控制小鱼移动,这篇将会添加一个NPC,让其自动在海洋里游荡,然后玩家控制吃掉它。在这之前我们想思考一些问题,

    NPC如何生成?NPC有哪些属性?NPC是如何控制的?如何做到随机转方向?

    这是该篇的难点,这里还用到了一些数学知识,包括sin,cos,弧度与角度的计算等,还是比较麻烦的,但是等你看到代码又会发现代码量很少,又会觉得如此简单,好了,看例子。

    1、开始游戏

    这里我们需要添加一个开始游戏按钮,因为只有玩家开始了游戏,我们启动一个计时器才会变得顺理成章,不然的话,上来就启动计时器会很好资源的。

    export struct FishPage {
        @State isBegin: boolean = false
    }

    这里我们默认是false,未启动状态

    build() {
      Row() {
        Stack() {
          // 背景
          Image($r("app.media.bg_fish"))
    
          if (this.isBegin == false) {
            Button('开始游戏')
              .backgroundColor('#36d')
              .onClick(() => {
              //这里把设置成true
                this.isBegin = true
                
              })
          } else {
              //渲染小鱼
          }
        }
    }

     

    2、添加NPC小鱼

    我们在开始之前就已经开始思考了,NPC应该有什么属性,起始位置,方向,速度,等,这里暂时不需要等级,下篇互吃逻辑写。

    //NPC
    @State npcSpeed: number = 3
    @State npcFishX: number = 300
    @State npcFishY: number = 200
    @State npcAngle: number = 0
    @State intervalIdNPC_1: number = 1
    @State npcSin: number = 1
    @State npcCos: number = 1

    npc显示需要写在else里面,也就是点击开始游戏后,isBegin=true时

    if (this.isBegin == false) {
      Button('开始游戏')
        .backgroundColor('#36d')
        .onClick(() => {
          this.isBegin = true
        })
    } else {
      Image($r("app.media.icon_fish_right"))
        .position({ x: this.xFish - this.fishRadius, y: this.yFish - this.fishRadius })
        .rotate({ angle: this.angle, centerX: '50%', centerY: '50%' })
        .width(40)
        .height(40)
    
      Image($r("app.media.icon_npc_2"))
        .position({ x: this.npcFishX - this.fishRadius, y: this.npcFishY - this.fishRadius })
        .rotate({ angle: this.npcAngle, centerX: '50%', centerY: '50%' })
        .objectFit(ImageFit.ScaleDown)
        .width(40)
        .height(40)
        
    }

    ok,第一个image是玩家控制的小鱼,第二个image是NPC。

     

    3、NPC动起来

    问题来了,NPC如何自己动起来了,这就又用到了计时器,这里如果有其他好的方法也评论区打出来哈。当玩家点击开始游戏按钮时启动计时器,

    if (this.isBegin == false) {
      Button('开始游戏')
        .backgroundColor('#36d')
        .onClick(() => {
          this.isBegin = true
          clearInterval(this.intervalIdNPC_1)
          this.intervalIdNPC_1 = setInterval(() => {
    
            //设置小鱼的移动位置,
            this.npcFishX += this.npcSpeed * this.npcCos
            this.npcFishY += this.npcSpeed * this.npcSin
    
            this.npcFishX = this.getNPCBorderX(this.npcFishX)
            this.npcFishY = this.getNPCBorderY(this.npcFishY)
    
    
          }, 40)
    
        })
    }

    这里需要说一下,启动一个计时器,内部是不断地计算npc的位置,getNPCBorderX这个是防止走出屏幕的宽度和高度设置的,当触碰到边框要改变方向。难点也在这

    getNPCBorderX(x: number) {
      if (x <= this.fishRadius) {
        x = this.fishRadius + 10
        this.getRandom()
      }
      if (x > this.screenWidth - this.fishRadius) {
        x = this.screenWidth - this.fishRadius - 15
        this.getRandom()
      }
      return x
    }
    
    getNPCBorderY(y: number) {
      if (y <= this.fishRadius) {
        y = this.fishRadius + 10
        this.getRandom()
      }
      if (y > this.screenHeight - this.fishRadius) {
        y = this.screenHeight - this.fishRadius - 10
        this.getRandom()
      }
      return y
    }

    那一个x方向说吧,当x<=小鱼的半径时说明,小鱼已经贴左边了,大于屏幕宽度时贴右边了,这时我们要改变方向,getRandom()就是改变方向用的,至于x=this.fishRadius +10 这个主要是当贴边后,小鱼还在走,就会触发多次if语句,生成多次方向,也就是说会出现抖动现象,感兴趣去掉赋值可以试试。

    4、NPC方向生成

    这一块是最麻烦的,

    弧度 = 角度 * π / 180
    角度 = 弧度 * 180 / π

    我们认识到的Math.sin,cos,tan等一般都是传入一个弧度,而不是角度(我传入角度老是有问题,这里传入弧度就解决了)

    /*随机获取一个角度*/
    getRandom() {
      this.npcAngle= this.selectFrom(-179,180)
      // let angle = Math.random()+Math.random()+Math.random()
      // this.npcAngle = angle * 180 / Math.PI
      //这是是求弧度,弧度 = 角度 * π / 180
    
      this.npcSin = Math.sin(this.npcAngle * Math.PI /180)
      this.npcCos = Math.cos(this.npcAngle * Math.PI /180)
    
      console.log("角度"+this.npcAngle)
    }
    
    selectFrom(startNumber, endNumber) {
      let choice = endNumber - startNumber + 1;
      return Math.floor(Math.random() * choice + startNumber)
    }

    首先我们需要随机生成一个角度,比如说90度,50度,-120度等

    角度是作为鱼头方向用的,我们按照speed速度去计算该方向的值

    那么x轴上的值就是x = speed * cos值,如下

    this.intervalIdNPC_1 = setInterval(() => {
    
      //设置小鱼的移动位置,
      this.npcFishX += this.npcSpeed * this.npcCos
      this.npcFishY += this.npcSpeed * this.npcSin
    
      this.npcFishX = this.getNPCBorderX(this.npcFishX)
      this.npcFishY = this.getNPCBorderY(this.npcFishY)
    
    
    }, 40)

     

    5、关闭计时器

    onPageHide() {
      clearInterval(this.intervalIdNPC_1)
    }

    记住页面消失时,或者游戏结束时需要关闭计时器

    好了,到这NPC防止就完成了。

     

  • 相关阅读:
    一文读懂TDengine的三种查询功能
    【经验分享】嵌入式C语言开发如何有效地排查内存泄露的疑难问题?
    2022年java开发跑路-真实面试题
    爬虫的三大库
    Mybatis的二级缓存 (ehcache方式)
    Docker搭建Redis集群
    【OBS】Dropped Frames And General Connection Issues
    asp.net mvc 起步
    成都优优聚美团代运营具备专业团队!
    [激光原理与应用-23]:《激光原理与技术》-9- 控制技术-锁模技术
  • 原文地址:https://www.cnblogs.com/cmusketeer/p/18016841