鸿蒙应用开发学习:改进小鱼动画实现按键一直按下时控制小鱼移动和限制小鱼移出屏幕

一、前言

近期我在学习鸿蒙应用开发,跟着B站UP主黑马程序员的视频教程做了一个小鱼动画应用,UP主提供的小鱼动画源代码仅仅实现了移动组件的功能,还存在一些问题,如默认进入页面是竖屏而页面适合横屏显示;真机测试发现手机的状态栏影响到了返回键对按键事件的响应;方向键不能响应一直按着的操作;还有小鱼会移出屏幕范围。

之前已经解决了强制横屏隐藏手机状态栏,这次则是通过一番研究,实现了按键一直按下时控制小鱼移动和限制小鱼移出屏幕这两个功能。

二、实现方法

1. 一直按下方向键时控制小鱼移动

实现这一功能是在方向键下添加onTouch方法,对按键一直按下事件进行响应。在onTouch方法中还需要判断TouchType.Down事件和TouchType.Up事件。在TouchType.Down事件时,添加animateTo方法,实现按键时一直控制小鱼移动(需要通过setInterval方法设置定时任务让animateTo方法定期执行)。在TouchType.Up事件时,通过clearInterval清除定时任务,小鱼就不会一直移动了。以向右按键为例,改造后的代码如下:

Button('→').backgroundColor('#20101010')
            .onClick(() => {              
                animateTo(
                 { duration: 500 },
                 () => {
                   this.src = $r('app.media.fish')
                   this.fishX += this.speed
                 }
               )
            })
            .onTouch((event: TouchEvent) => {
              if (event.type === TouchType.Down) {
                this.taskId = setInterval(() => {
                  animateTo(
                    { duration: 500 },
                    () => {                      
                    this.src = $r('app.media.fish')
                    this.fishX += this.speed
                    }
                  )
                }, 200)
              }
              if (event.type === TouchType.Up) {
                clearInterval(this.taskId)
                this.taskId = -1
              }
            })

        }
        .height(240)
        .width(240)
        .justifyContent(FlexAlign.Center)
        .position({ x: 0, y: 120 })

2.限制小鱼移出屏幕

实现了上面的代码后,一直按下方向键,小鱼终于可以一直移动了,但往一个方向一直移动就会移出屏幕,为让小鱼不移出屏幕,还需要对按键操作事件进行判断,检查当前小鱼的位置,只有小鱼在限制的范围内才能执行animateTo方法移动小鱼。

按下向左方向键:对小鱼的X坐标(this.fishX)进行判断。屏幕左侧边界的X值为0,小鱼的大小为40(this.fishSize)。this.fishX是小鱼图片中心点的坐标,则当小鱼接触到屏幕左侧边界时,小鱼的中心点X坐标值为20。本软件中设置的小鱼的移动速度为20(this.speed),因此,我设置的判断条件是当this.fishX >= this.fishSize时,才能执行animateTo方法。当this.fishX == 40时,再移动一次this.fishX就变成了20,此时小鱼图片的左侧边缘正好接触到屏幕左边界。

按下向上方向键:对小鱼的Y坐标(this.fishY)进行判断。屏幕上边界Y值为0,小鱼大小为40。原理和按下向左方向机一样。我设置的判断条件是当this.fishY >= this.fishSize时,才能执行animateTo方法。

对于屏幕下方的边界和屏幕右侧的边界判断需要导入模块 import display from '@ohos.display' ,并在页面的onPageShow方法获取屏幕的尺寸信息。

onPageShow() {
    // 获取旋转的方向,具体可以查看对应文档
    let orientation = window.Orientation.LANDSCAPE;

    // 获取屏幕尺寸信息
    let promise = display.getAllDisplays()
    promise.then((data) => {
      console.info('设备屏幕信息:' + JSON.stringify(data));
      console.info('testTag', '屏幕宽度px:' + JSON.stringify(data[0].width));
      console.info('testTag', '屏幕高度px:' + JSON.stringify(data[0].height));
      this.screenWidth = px2vp(data[0].width)
      this.screenHeight = px2vp(data[0].height)
      console.info('testTag', '屏幕宽度vp:' + JSON.stringify(this.screenWidth));
      console.info('testTag', '屏幕高度vp:' + JSON.stringify(this.screenHeight));
    }).catch((err) => {
      console.error('错误信息:' + JSON.stringify(err));
    })
  }

按下向右方向机:对小鱼的X坐标(this.fishX)进行判断。屏幕右侧边界的X值为变量this.screenHeight, 则判定语句为 this.fishX <= this.screenHeight - this.fishSize 。只有符合该条件是才执行animateTo方法。

按下向下方向机:对小鱼的Y坐标(this.fishY)进行判断。屏幕右侧边界的Y值为变量this.screenWidth, 则判定语句为 this.fishY <= this.screenWidth - this.fishSize 。只有符合该条件是才执行animateTo方法。

这些判断语句都要添加到方向键的onClick方法和onTouch方法。

三、完整源代码

最后上这个文件的完整源代码:

import router from '@ohos.router';
import window from '@ohos.window'; // 用于强制设为横屏
import display from '@ohos.display'

@Entry
@Component
struct Aquarium1Page {
  onPageShow() {
    // 获取旋转的方向,具体可以查看对应文档
    let orientation = window.Orientation.LANDSCAPE;
    try {
      // 设置屏幕旋转
      globalThis.windowClass.setPreferredOrientation(orientation, (err) => {
        console.log('testTag', `onPageShow函数中setPreferredOrientation方法错误码为${err}`)
      });
    } catch (exception) {
      console.error('设置失败: ' + JSON.stringify(exception));
    }
    // 获取屏幕尺寸信息
    let promise = display.getAllDisplays()
    promise.then((data) => {
      console.info('设备屏幕信息:' + JSON.stringify(data));
      console.info('testTag', '屏幕宽度px:' + JSON.stringify(data[0].width));
      console.info('testTag', '屏幕高度px:' + JSON.stringify(data[0].height));
      this.screenWidth = px2vp(data[0].width)
      this.screenHeight = px2vp(data[0].height)
      console.info('testTag', '屏幕宽度vp:' + JSON.stringify(this.screenWidth));
      console.info('testTag', '屏幕高度vp:' + JSON.stringify(this.screenHeight));
    }).catch((err) => {
      console.error('错误信息:' + JSON.stringify(err));
    })
  }

  onPageHide() {
    // 获取旋转的方向,具体可以查看对应文档
    let orientation = window.Orientation.PORTRAIT;
    try {
      // 设置屏幕旋转
      globalThis.windowClass.setPreferredOrientation(orientation, (err) => {
        console.log('testTag', `onPageHide函数中setPreferredOrientation方法错误码为${err}`)
      });
    } catch (exception) {
      console.error('设置失败: ' + JSON.stringify(exception));
    }
  }

  // 小鱼的位置
  @State fishX: number = 200
  @State fishY: number = 180
  // 小鱼的大小
  fishSize: number = 40
  // 小鱼角度
  @State angle: number = 0
  // 小鱼图片
  @State src: Resource = $r('app.media.fish')
  // 是否开始游戏
  @State isBegin: boolean = false
  // 小鱼的速度
  speed: number = 20
  // 用于控制Interval的id
  taskId: number = -1
  // 屏幕尺寸
  screenWidth: number = px2vp(2000)
  screenHeight: number = px2vp(1080)

  build() {
    Row() {
      Stack() {
        Button('返回')
          .position({ x: 20, y: 20 })
          .backgroundColor('#20101010')
          .onClick(() => {
            router.back()
          })

        if (!this.isBegin) {
          Button('开始游戏')
            .onClick(() => {
              animateTo(
                { duration: 1000 },
                () => {
                  // 点击后显示小鱼
                  this.isBegin = true
                }
              )
            })
        } else {
          // 小鱼图片
          Image(this.src)
            .position({ x: this.fishX - 20, y: this.fishY - 20 })
            .rotate({ angle: this.angle, centerX: '50%', centerY: '50%' })
            .width(this.fishSize)
            .height(this.fishSize)
              //.animation({duration: 500, curve: Curve.Smooth})
            .transition({
              type: TransitionType.Insert,
              opacity: 0,
              translate: { x: -250 }
            })
        }
        // 操作按钮
        Row() {
          // 向左移动,小鱼身体不能超出屏幕范围
          Button('←').backgroundColor('#20101010')
            .onClick(() => {
              if (this.fishX >= this.fishSize) {
                animateTo(
                  { duration: 500 },
                  () => {
                    this.src = $r('app.media.fish_rev')
                    this.fishX -= this.speed
                  }
                )
              }
            })
            .onTouch((event: TouchEvent) => {
              if (event.type === TouchType.Down) {
                this.taskId = setInterval(() => {
                  animateTo(
                    { duration: 500 },
                    () => {
                      if (this.fishX >= this.fishSize) {
                        this.src = $r('app.media.fish_rev')
                        this.fishX -= this.speed
                      }
                    }
                  )
                }, 200)
              }
              if (event.type === TouchType.Up) {
                clearInterval(this.taskId)
                this.taskId = -1
              }
            })

          Column({ space: 40 }) {
            // 向上和向下移动,小鱼的身体均不能超出屏幕范围
            Button('↑').backgroundColor('#20101010')
              .onClick(() => {
                if (this.fishY >= this.fishSize) {
                  animateTo(
                    { duration: 500 },
                    () => {
                      this.fishY -= this.speed
                    }
                  )
                }
              })
              .onTouch((event: TouchEvent) => {
                if (event.type === TouchType.Down) {
                  this.taskId = setInterval(() => {
                    animateTo(
                      { duration: 500 },
                      () => {
                        if (this.fishY >= this.fishSize) {
                          this.fishY -= this.speed
                        }
                      }
                    )
                  }, 200)
                }
                if (event.type === TouchType.Up) {
                  console.log("testTag", `停止向上,当前fishY为:${this.fishY}`)
                  clearInterval(this.taskId)
                  this.taskId = -1
                }
              })
            Button('↓').backgroundColor('#20101010')
              .onClick(() => {
                if (this.fishY <= this.screenWidth - this.fishSize) {
                  animateTo(
                    { duration: 500 },
                    () => {
                      this.fishY += this.speed
                    }
                  )
                }
              })
              .onTouch((event: TouchEvent) => {
                if (event.type === TouchType.Down) {
                  this.taskId = setInterval(() => {
                    animateTo(
                      { duration: 500 },
                      () => {
                        if (this.fishY <= this.screenWidth - this.fishSize) {
                          this.fishY += this.speed
                        }
                      }
                    )
                  }, 200)
                }
                if (event.type === TouchType.Up) {
                  console.log("testTag", `停止向下,当前fishY为:${this.fishY}`)
                  clearInterval(this.taskId)
                  this.taskId = -1
                }
              })
          }

          Button('→').backgroundColor('#20101010')
            .onClick(() => {
              if (this.fishX <= this.screenHeight - this.fishSize) {
                animateTo(
                  { duration: 500 },
                  () => {
                    this.src = $r('app.media.fish')
                    this.fishX += this.speed
                  }
                )
              }
            })
            .onTouch((event: TouchEvent) => {
              if (event.type === TouchType.Down) {
                this.taskId = setInterval(() => {
                  animateTo(
                    { duration: 500 },
                    () => {
                      if (this.fishX <= this.screenHeight - this.fishSize) {
                        this.src = $r('app.media.fish')
                        this.fishX += this.speed
                      }
                    }
                  )
                }, 200)
              }
              if (event.type === TouchType.Up) {
                clearInterval(this.taskId)
                this.taskId = -1
              }
            })

        }
        .height(240)
        .width(240)
        .justifyContent(FlexAlign.Center)
        .position({ x: 0, y: 120 })
      }
      .height('100%').width('100%')
    }
    .width('100%')
    .height('100%')
    .backgroundImage($r('app.media.underwater_cartoon'))
    .backgroundImageSize({ height: '100%', width: '100%' })

  }
}

四、B站视频链接:

鸿蒙应用开发学习:改进小鱼动画实现按键一直按下时控制小鱼移动和限制小鱼移出屏幕-CSDN博客

  • 32
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
### 回答1: 活体小鱼的运动目标检测和跟踪实现通常使用计算机视觉技术。这些技术包括目标检测算法,如基于深度学习的目标检测算法(如YOLO,SSD,Faster R-CNN等)和基于视觉跟踪算法(如KCF,MOSSE,DeepSORT等)。这些算法可以帮助识别并跟踪小鱼在水中的运动,从而提供有关小鱼行为和生态学的信息。 ### 回答2: 活体小鱼的运动目标检测与跟踪实现背景可以从两个方面来解释。 首先,活体小鱼的运动目标检测与跟踪是为了研究小鱼的行为和生理特征而进行的一项实验研究。小鱼在水中的运动行为包括游泳速度、运动方向、身体姿态等,这些行为反映了小鱼的神经系统、感官系统和运动系统的协调性能。通过对小鱼的运动进行目标检测和跟踪,可以了解小鱼在不同环境和刺激下的运动行为变化规律,进而研究小鱼的行为选择、抉择和学习机制。 其次,活体小鱼的运动目标检测与跟踪的实现背景源于计算机视觉和机器学习技术的发展。随着计算机硬件和算法的不断进步,目标检测和跟踪技术在图像和视频处理领域得到了广泛应用。通过使用计算机视觉算法,可以从小鱼的图像或视频序列中提取运动目标的位置、形状和特征等信息,实现小鱼运动行为的自动分析和量化。 综上所述,活体小鱼的运动目标检测与跟踪实现背景既包括对小鱼行为和生理特征的研究需求,也借助了计算机视觉和机器学习技术的发展。通过对小鱼运动行为的观察和分析,我们可以更好地理解小鱼的行为和与环境的交互,以及这些行为的神经机制和行为选择的规律。 ### 回答3: 活体小鱼的运动目标检测与跟踪实现背景可以从以下几个方面进行说明。 首先,活体小鱼是一种具有自主移动能力的仿生机器人,其灵感来源于真实类的运动方式和行为特点。活体小鱼的设计目的是模拟自然水域中的类运动,在水中实现高效的机动性和灵活的行动控制。 其次,活体小鱼的运动目标检测和跟踪是指通过对周围环境的感知和对运动目标进行分析,使机器能够准确地识别、追踪和锁定目标对象。这对于活体小鱼来说至关重要,因为它需要根据检测到的目标信息来做相应的运动决策和行动规划。 第三,实现活体小鱼运动目标检测和跟踪的背景主要是基于计算机视觉和机器学习技术的发展。通过利用摄像头或传感器等设备获取环境信息,结合图像处理、特征提取和目标识别等算法,可以实地对周围环境中的目标进行检测和跟踪。 此外,为了提高目标检测和跟踪的精度和鲁棒性,还可以借鉴深度学习、神经网络和强化学习等技术,通过训练模型和优化算法来实现更精确的目标识别和跟踪效果。这些技术的不断发展和应用为活体小鱼的运动目标检测和跟踪提供了坚实的技术基础。 总之,活体小鱼的运动目标检测与跟踪实现背景是基于计算机视觉和机器学习技术的发展,结合图像处理算法和目标识别技术,实现对周围环境中目标的准确识别和跟踪。通过这些技术的应用,活体小鱼能够更加智能地感知环境、分析目标,并做相应的运动决策和行动规划。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

武陵悭臾

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值