1、案例效果

在这里插入图片描述

2、案例实现

1、代码实现

代码如下(示例):

import router from '@ohos.router'
import { ResizeDirection } from '@ohos.UiTest'
import curves from '@ohos.curves'

@Entry
@Component
struct AnimateFishPage {
  //游戏中鱼的图片
  @State fishImage: Resource = $r('app.media.fish_Right')
  //小鱼起始的坐标
  @State fishX: number = 300
  @State fishY: number = 140
  //小鱼图片角度
  @State fishAngle: number = 0
  //游戏状态
  @State isStartGame: boolean = false

  //摇杆中心区域坐标
  private centerX: number = 120
  private centerY: number = 120

  //大小半径
  private maxRadius: number = 100
  private radius: number = 20

  //摇杆小圆球位置
  @State positionX: number = this.centerX;
  @State positionY: number = this.centerY;

  //摇杆角度正弦、余弦
  sin: number = 0
  cos: number = 0

  //小鱼速度
  speed: number = 0
  // 任务id
  taskedId = -1

  build() {
    Row() {
      Stack() {
        //返回按钮
        Button('返回')
          .position({ x: 0, y: 0 })
          .backgroundColor('#20101010')
          .onClick(() => {
            //返回上一页
            router.back()
          })
        if (!this.isStartGame) {
          //显示开始按钮
          Button('开始游戏')
            .onClick(() => {
              animateTo(
                { duration: 1000 },
                () => {
                  //开始游戏后加载小鱼
                  this.isStartGame = true
                })
            })
        }
        else {
          //小鱼图片
          Image(this.fishImage)
            .position({ x: this.fishX - 20, y: this.fishY - 20 })
            .rotate({ angle: this.fishAngle, centerX: '50%', centerY: '50%' })
            .width(60)
            .height(40)
            .transition({
              type: TransitionType.Insert,
              opacity: 0,
              translate: { x: -250 }
            })
        }
        //操作按钮区域
        Row() {
          /* Button('⬅').backgroundColor('#20101010')
             .onClick(() => {
               animateTo(
                 { duration: 500 },
                 () => {
                   this.fishX -= 20
                   this.fishImage = $r('app.media.fish_Left')
                 }
               )
             })
           Column({ space: 40 }) {
             Button('⬆').backgroundColor('#20101010')
               .onClick(() => {
                 animateTo(
                   { duration: 500 },
                   () => {
                     this.fishY -= 20
                   }
                 )
               })
             Button('⬇').backgroundColor('#20101010')
               .onClick(() => {
                 animateTo(
                   { duration: 500 },
                   () => {
                     this.fishY += 20
                   }
                 )
               })
           }

           Button('➡').backgroundColor('#20101010')
             .onClick(() => {
               animateTo(
                 { duration: 500 },
                 () => {
                   this.fishX += 20
                   this.fishImage = $r('app.media.fish_Right')
                 }
               )
             })*/

          //遥杆

          Circle({ width: this.maxRadius * 2, height: this.maxRadius * 2 })
            .fill('#cb393737')
            .position({ x: this.centerX - this.maxRadius, y: this.centerY - this.maxRadius })
          Circle({ width: this.radius * 2, height: this.radius * 2 })
            .fill('#a3211d1d')
            .position({ x: this.positionX - this.radius, y: this.positionY - this.radius })

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

  //处理手指移动事件
  handleTouchEvent(event: TouchEvent) {

    switch (event.type) {
      case TouchType.Up:
        animateTo(
          { curve: curves.springMotion() },
          () => {
            //摇杆中心位置复位
            this.positionX = this.centerX
            this.positionY = this.centerY

            this.fishAngle = 0
          })
        this.speed = 0
      //取消定时任务
        clearInterval(this.taskedId)
        break
      case TouchType.Down:
      //开始一个定时任务
        this.taskedId = setInterval(() => {
          //6、修改小鱼的坐标
          this.fishX += this.speed * this.cos
          this.fishY += this.speed * this.sin
        }, 40)
        break
      case TouchType.Move:
      //1、获取手指位置坐标
        let x = event.touches[0].x
        let y = event.touches[0].y
      //2、手指与中心点坐标差值
        let vx = x - this.centerX
        let vy = y - this.centerY

      //3、计算手指与中心点连线和x轴正半轴的夹角,角度为弧度
        let angleH = Math.atan2(vy, vx)
      //4、计算手指与中心点距离
        let distance = this.getDistance(vx, vy)

        this.sin = Math.sin(angleH)
        this.cos = Math.cos(angleH)

        animateTo(
          { curve: curves.responsiveSpringMotion() },
          () => {
            //5、计算摇杆小球坐标
            this.positionX = this.centerX + distance * this.cos
            this.positionY = this.centerY + distance * this.sin

            //修改小鱼速度和角度

            if (Math.abs(angleH * 2) < Math.PI) {
              this.fishImage = $r('app.media.fish_Right')
            } else {
              this.fishImage = $r('app.media.fish_Left')
              angleH = angleH < 0 ? angleH + Math.PI : angleH - Math.PI
            }

            this.fishAngle = angleH * 180 / Math.PI
            this.speed = 10
          })
        break
    }
  }

  getDistance(x: number, y: number) {
    let d = Math.sqrt(x * x + y * y)
    return Math.min(d, this.maxRadius)
  }
}

2、代码解释

构建UI

  • 使用Row和Stack布局来组织界面元素。
  • 包含一个返回按钮,点击时返回上一级页面。
  • 显示一个开始游戏按钮,点击后设置游戏开始状态并加载小鱼。
  • 加载小鱼图片,并根据游戏状态设置其位置和旋转角度。
  • 实现了一个摇杆,由两个圆形组成,一个大圆表示摇杆范围,一个小圆表示摇杆手柄的位置。
  • 设置了触摸事件处理器handleTouchEvent,用于处理用户的触摸操作。

触摸事件处理

  • TouchType.Up: 当手指离开屏幕时,将摇杆复位,并停止小鱼移动的定时任务。
  • TouchType.Down: 当手指按下屏幕时,启动一个定时任务,使小鱼根据摇杆的方向移动。
  • TouchType.Move: 当手指在屏幕上移动时:
    1、计算手指相对于摇杆中心的偏移量。
    2、计算手指与中心点连线和x轴正半轴的夹角。
    3、计算手指与中心点的距离,并确保不超过最大半径。
    4、更新摇杆小球的位置。
    5、根据摇杆的方向更新小鱼的速度和旋转角度。

辅助方法

  • getDistance(x: number, y: number): 计算两点之间的距离,并确保不超过最大半径。

4、总结

本节代码展示了如何在HarmonyOS应用中实现一个简单的游戏界面,包括基本的UI布局、状态管理以及触摸事件处理。最后实现用摇杆控制游戏物体移动的功能。

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐