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

前言:

该篇对NPC进行了升级,这里可以投入多个NPC,且互不影响,npc之间不会触发eat,只和玩家触发eat,且每个NPC有自己的属性,他们的等级在他们的头顶

1、放置多个NPC

我们放置多个NPC就要把NPC属性抽离出来,这里很复杂,又牵扯到了知识点《状态管理》,在鸿蒙中分为了多种状态管理

这里感兴趣的话,可以去看看官方文档,我是觉得咋一看挺复杂的,用起来确实不简单。这里我就简单说一下我用到的,就是鸿蒙开发都是按照组件来组建的,一个titleview,一个小鱼等都可以封装成一个组件

@Component

用这个修饰。在主组件中定义的变量我们如果传递到子组件,可以让他只读也可以让他修改,这就用到了状态管理,子组件中如果改变了变量,在主组件中做出了相应改变就说明是父子双向同步。

下面开始写npc属性

@Observed
export default class NpcInfo {
  //NPC
  public npcSpeed: number = 3
  public npcFishX: number = 200
  public npcFishY: number = 200
  public npcAngle: number = 0
  public npcSin: number = 1
  public npcCos: number = 1
  public npcLevel: number = 2

  constructor(npcSpeed: number
              , npcFishX: number
              , npcFishY: number
              , npcAngle: number
              , npcLevel: number
              , npcCos: number
              , npcSin: number) {
    this.npcSpeed = npcSpeed
    this.npcFishX = npcFishX
    this.npcFishY = npcFishY
    this.npcAngle = npcAngle
    this.npcLevel = npcLevel
    this.npcCos = npcCos
    this.npcSin = npcSin
  }
}

单独使用@Observed是没有任何作用的,需要搭配@ObjectLink或者@Prop使用。

@Component
struct npcView {
  @ObjectLink item: NpcInfo;

  build() {
    Column() {
      Text(this.item.npcLevel + "")
        .fontColor('#f11')
        .fontSize(12)
      Image($r("app.media.icon_npc_2"))
        .objectFit(ImageFit.ScaleDown)
        .width(40)
        .height(40)
    }.position({
      x: this.item.npcFishX - 40,
      y: this.item.npcFishY - 40
    })
    .rotate({ angle: this.item.npcAngle, centerX: '50%', centerY: '50%' })

  }
}

@ObjectLink 同样也不能在@Entry修饰的组件中使用。这里面有几个需要注意的点就是npcInfo需要用@ObjectLink修饰,而且也需要单独写一个npcView组件,这样npcList数据发生改变,组件才会监控到,和咱们平常安卓是不是不一样,我刚开始的写法是直接在主组件中写,如下

ForEach(
  this.npcList,
  (item: NpcInfo, index) => {
      //错误写法
     Column() {
      Text(item.npcLevel + "")
        .fontColor('#f11')
        .fontSize(12)
      Image($r("app.media.icon_npc_2"))
        .objectFit(ImageFit.ScaleDown)
        .width(40)
        .height(40)
    }.position({
      x: item.npcFishX - 40,
      y: item.npcFishY - 40
    })
    .rotate({ angle: item.npcAngle, centerX: '50%', centerY: '50%' })
  }
)

这样写也可以创建出来npc,但是小鱼不会动,我看日志npc(x,y)坐标是改变的,但就是view不动,后来查资料发现需要双向数据同步,不然就是单向数据问题。正确写法是

@Component
struct npcView {
  @ObjectLink item: NpcInfo;

  build() {
    Column() {
      Text(this.item.npcLevel + "")
        .fontColor('#f11')
        .fontSize(12)
      Image($r("app.media.icon_npc_2"))
        .objectFit(ImageFit.ScaleDown)
        .width(40)
        .height(40)
    }.position({
      x: this.item.npcFishX - 40,
      y: this.item.npcFishY - 40
    })
    .rotate({ angle: this.item.npcAngle, centerX: '50%', centerY: '50%' })

  }
}

主组件中

ForEach(
  this.npcList,
  (item1: NpcInfo, index) => {
    npcView({ item: item1 })
  }
)

这样写就可以了,那多条小鱼在处理坐标问题时应该如何操作呢,我这里是用数组的形式,用for循环动态设置所有npc的小鱼坐标。如果有其他的方式请给我留言。

if (this.isBegin == false) {
  Button('开始游戏')
    .backgroundColor('#36d')
    .onClick(() => {
      this.isBegin = true
      clearInterval(this.intervalIdNPC_1)
      this.intervalIdNPC_1 = setInterval(() => {

        for (let i = 0; i < this.npcList.length; i++) {

          //6、设置小鱼的移动位置,
          this.npcList[i].npcFishX += this.npcList[i].npcSpeed * this.npcList[i].npcCos
          this.npcList[i].npcFishY += this.npcList[i].npcSpeed * this.npcList[i].npcSin


          this.npcList[i].npcFishX = this.getNPCBorderX(i, this.npcList[i].npcFishX)
          this.npcList[i].npcFishY = this.getNPCBorderY(i, this.npcList[i].npcFishY)

          console.log("小鱼走了吗" + i + "   " + this.npcList[i].npcFishX)
        }


      }, 40)

    })
}

这里需要注意的是,多个npc之间是没有关联的,只有当npc碰到屏幕边缘或者某个点的时候掉头,其他npc不受影响。这里对getNPCBorderX,Y()方法做了修改,。

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

getNPCBorderY(i: number, y: number) {
  if (y <= this.fishRadius) {
    y = this.fishRadius + 10
    this.getRandom(i)
  }
  if (y > this.screenHeight - this.fishRadius) {
    y = this.screenHeight - this.fishRadius - 10
    this.getRandom(i)
  }
  return y
}

  /*随机获取一个角度*/
  getRandom(i: number) {
    this.npcList[i].npcAngle = this.selectFrom(0, 359)
    // let angle = Math.random()+Math.random()+Math.random()
    // this.npcAngle = angle * 180 / Math.PI
    //这是是求弧度,弧度 = 角度 * π / 180


    this.npcList[i].npcSin = Math.sin(this.npcList[i].npcAngle * Math.PI / 180)
    this.npcList[i].npcCos = Math.cos(this.npcList[i].npcAngle * Math.PI / 180)

  }

好了,到这多个NPC就已经放置完成了,并且已经动起来了。哦,对了还需要初始化

onPageShow() {
    //                         速度,x,y   角度/等级/cos/sin
  this.npcList.push(new NpcInfo(3, 300, 200, 0, 2, 1, 1))
  this.npcList.push(new NpcInfo(3, 300, 100, 0, 3, 1, 1))
  this.npcList.push(new NpcInfo(3, 200, 200, 0, 2, 1, 1))
  this.npcList.push(new NpcInfo(1, 200, 200, 0, 1, 1, 1))
}

2、互吃逻辑

竟然要pk,就要有血量或者等级,这里暂时写等级

//等级
@State level: number = 3

只要玩家碰到NPC了就要判断level是否相等,如果大就要吃掉NPC,npcList就要减去一个,如果小于NPC等级就是被吃,游戏结束。

//互吃逻辑
eatFish(){
  for (let i = 0; i < this.npcList.length; i++) {

    let vx =  this.xFish - this.npcList[i].npcFishX;
    let vy =  this.yFish - this.npcList[i].npcFishY;

    let distance = Math.sqrt(vx * vx + vy * vy)
    if(distance >0 && distance<20){
      if(this.level >= this.npcList[i].npcLevel){
          this.level+=1;
          this.npcList.splice(i,1)
      }else{
        //游戏结束
      }
    }
  }

}

使用地方

handleTouchEvent(event: TouchEvent) {
  switch (event.type) {
    case TouchType.Down:
      this.intervalId = setInterval(() => {
        //6、设置小鱼的移动位置,
        this.xFish += this.speed * this.cos
        this.yFish += this.speed * this.sin

        //目的是触碰到边缘时不溢出
        this.xFish = this.getBorderX(this.xFish)
        //还原角度
        // this.angle = 0

         //互吃逻辑
        this.eatFish()
      }, 40)
      break
    case TouchType.Move:
      this.setMovePosition(event)
      break
    case TouchType.Up:
      clearInterval(this.intervalId)
    //恢复摇杆位置
      animateTo({
        curve: curves.springMotion()
      }, () => {
        this.positionX = this.centerX
        this.positionY = this.centerY
      })

      this.speed = 0
      break
  }


}

最后,有很多小伙伴不知道学习哪些鸿蒙开发技术?不知道需要重点掌握哪些鸿蒙应用开发知识点?而且学习时频繁踩坑,最终浪费大量时间。所以有一份实用的鸿蒙(Harmony NEXT)资料用来跟着学习是非常有必要的。 

这份鸿蒙(Harmony NEXT)资料包含了鸿蒙开发必掌握的核心知识要点,内容包含了ArkTS、ArkUI开发组件、Stage模型、多端部署、分布式应用开发、音频、视频、WebGL、OpenHarmony多媒体技术、Napi组件、OpenHarmony内核、Harmony南向开发、鸿蒙项目实战等等)鸿蒙(Harmony NEXT)技术知识点。

希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,限时开源,先到先得~无套路领取!!

如果你是一名有经验的资深Android移动开发、Java开发、前端开发、对鸿蒙感兴趣以及转行人员,可以直接领取这份资料

 获取这份完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

鸿蒙(Harmony NEXT)最新学习路线

  •  HarmonOS基础技能

  • HarmonOS就业必备技能 
  •  HarmonOS多媒体技术

  • 鸿蒙NaPi组件进阶

  • HarmonOS高级技能

  • 初识HarmonOS内核 
  • 实战就业级设备开发

 有了路线图,怎么能没有学习资料呢,小编也准备了一份联合鸿蒙官方发布笔记整理收纳的一套系统性的鸿蒙(OpenHarmony )学习手册(共计1236页)鸿蒙(OpenHarmony )开发入门教学视频,内容包含:ArkTS、ArkUI、Web开发、应用模型、资源分类…等知识点。

获取以上完整版高清学习路线,请点击→纯血版全套鸿蒙HarmonyOS学习资料

《鸿蒙 (OpenHarmony)开发入门教学视频》

《鸿蒙生态应用开发V2.0白皮书》

图片

《鸿蒙 (OpenHarmony)开发基础到实战手册》

OpenHarmony北向、南向开发环境搭建

图片

 《鸿蒙开发基础》

  • ArkTS语言
  • 安装DevEco Studio
  • 运用你的第一个ArkTS应用
  • ArkUI声明式UI开发
  • .……

图片

 《鸿蒙开发进阶》

  • Stage模型入门
  • 网络管理
  • 数据管理
  • 电话服务
  • 分布式应用开发
  • 通知与窗口管理
  • 多媒体技术
  • 安全技能
  • 任务管理
  • WebGL
  • 国际化开发
  • 应用测试
  • DFX面向未来设计
  • 鸿蒙系统移植和裁剪定制
  • ……

图片

《鸿蒙进阶实战》

  • ArkTS实践
  • UIAbility应用
  • 网络案例
  • ……

图片

 获取以上完整鸿蒙HarmonyOS学习资料,请点击→纯血版全套鸿蒙HarmonyOS学习资料

总结

总的来说,华为鸿蒙不再兼容安卓,对中年程序员来说是一个挑战,也是一个机会。只有积极应对变化,不断学习和提升自己,他们才能在这个变革的时代中立于不败之地。 

  • 24
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
大鱼吃小鱼》是一款简单而有趣的游戏,适合初学者学习Java游戏开发。下面我将手把手教你如何用Java开发这款游戏,并提供相应的源码。 步骤一:创建游戏窗口和游戏主类 首先,我们需要创建游戏的窗口,可以使用Java提供的Swing框架来实现。创建一个GameWindow类,继承JFrame类,并在构造方法中设置窗口的基本属性。 步骤二:添加游戏画布 在GameWindow类中,创建一个GameCanvas类,继承JPanel类,并重写paintComponent()方法,在此方法中实现游戏场景的绘制,包括大鱼、小鱼和其他游戏元素。 步骤三:添加游戏逻辑 在GameWindow类中,添加游戏逻辑的处理方法,包括大鱼的移动、小鱼的生成和碰撞检测等。 步骤:添加游戏控制 在GameWindow类中,添加游戏控制的方法,包括键盘事件的处理和游戏状态的切换等。 步骤五:运行游戏 在GameWindow类中,添加一个main()方法,创建游戏窗口对象,并启动游戏循环。 以上是《大鱼吃小鱼游戏的基本开发步骤,下面提供相应的源码供参考: ```java import javax.swing.*; import java.awt.*; import java.awt.event.KeyEvent; import java.awt.event.KeyListener; public class GameWindow extends JFrame implements KeyListener{ private GameCanvas gameCanvas; private boolean isRunning; public GameWindow(){ super("大鱼吃小鱼"); setSize(800, 600); setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setLocationRelativeTo(null); addKeyListener(this); gameCanvas = new GameCanvas(); add(gameCanvas, BorderLayout.CENTER); isRunning = true; } public void start(){ while(isRunning){ update(); gameCanvas.repaint(); try{ Thread.sleep(10); }catch(InterruptedException e){ e.printStackTrace(); } } } public void update(){ // 游戏逻辑更新 } public void keyPressed(KeyEvent e){ // 键盘按下事件处理 } public void keyReleased(KeyEvent e){ // 键盘释放事件处理 } public void keyTyped(KeyEvent e){ // 键盘输入事件处理 } public static void main(String[] args){ GameWindow gameWindow = new GameWindow(); gameWindow.setVisible(true); gameWindow.start(); } } class GameCanvas extends JPanel{ protected void paintComponent(Graphics g){ super.paintComponent(g); // 游戏场景绘制 } } ``` 通过以上源码和步骤,我们可以实现《大鱼吃小鱼游戏的基本开发,通过添加更多的游戏逻辑和个性化设计,可以进一步完善这款游戏。希望对您有所帮助!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值