从0开始的Oasis Engine学习笔记(七) —— 脚本与控制

从0开始的Oasis Engine学习笔记(七) —— 脚本与控制

这是我参与更文挑战的第7天,活动详情查看: 更文挑战

在之前已经介绍了如何布置一个游戏场景,今天就让里面的角色动起来

在Oasis里,除了内置组件之外,Oasis 引擎还提供强大的脚本系统。脚本系统是衔接引擎能力和游戏逻辑的纽带,脚本扩展自 Script 基类,用户可以通过它来扩展引擎的功能,也可以脚本组件提供的生命周期钩子函数中编写自己的游戏逻辑代码。

组件生命周期函数

Oasis 为用户提供了丰富的生命周期回调函数,用户只要定义特定的回调函数,Oasis 就会在特定的时期自动执行相关脚本,用户不需要手工调用它们。目前提供给用户的生命周期回调函数如下: image.png

这里主要介绍两个常用的生命周期

onAwake()

onAwake: 组件第一次触发为激活状态时调用, 一般可以在这里做一些初始化的事情,比如初始化组件的一些状态、添加事件监听等。

onUPdata ()

onupdata: 引擎主循环的回调,一般每帧需要更新的内容可以放这里,比如可以在这里实现组件的移动。由于这里的回调为每帧,所以建议不要在此处创建新的对象。

示例

我们以此为例,来一步一步讲解如何让角色动起来

CPT2106271501-1103x706.gif

引入Script组件

import { Script } from 'oasis-engine'

创建一个名为moveScript的类来继承Script

class moveScript extends Script {
    onAwake () {}
    onUpdata () {}
}
复制代码

然后将这个组将绑定到角色的实体上

roleEntity.addComponent(moveScript)

声明一些参数

class moveScript extends Script {
    // 用来缓存中间某个时间点的位置
    static tempPos: Vector3 = new Vector3()
    // 用来角色起始位置
    static startPos: Vector3 = new Vector3()

    // 当前总移动时长
    private _totalTime!: number
    // 移动速度
    private _speed!: number
    // 跳跃时间与高度
    private _jumpTime!: number
    private _jumpHeight!: number
    // 方向判断
    private _isRight!: boolean
    private _isLeft!: boolean
    private _isJump!: boolean
    // 移动距离
    private _moveX!: number
    private _moveY!: number
    // 屏幕范围
    private _screenLeft!: number
    private _screenRight!: number
    
    // 生命周期函数
    onAwake () {}
    onUpdata () {}
}
复制代码

在onAwake()里初始化参数

    onAwake () {
      // 初始化参数
      this._totalTime = 0 // 移动总时长,初始为0
      this._speed = 30 // 设置的移动速度,可以根据自己需求调整
      this._moveX = 0 // X方向上的移动量,初始为0
      this._moveY = 0 // Y方向上的移动量,初始为0
      this._jumpTime = 0 // 跳起来的总时间,初始为0
      this._jumpHeight = -4 // 起跳的最高高度,根据需求调整
      moveScript.tempPos.setValue(0, 0, 0) // 初始化位置

      // 计算角色初始化位置
      const roleX = groundTexture.height * scaleTimes * 5
      const roleY = canvasY - groundTexture.height * scaleTimes * 2 - (roleTexture.height * rolescale) / 2
      const rolepoint = new Vector3(roleX, roleY)
      const roleout = new Vector3()
      // 初始化角色位置
      moveScript.startPos = cameramash.screenToWorldPoint(rolepoint, roleout)

      // 计算屏幕左侧坐标
      const screemLeft = new Vector3((roleTexture.height * rolescale) / 2, 0)
      const leftout = new Vector3()
      cameramash.screenToWorldPoint(screemLeft, leftout)
      // 初始化屏幕左边框位置
      this._screenLeft = leftout.x

      // 计算屏幕右侧坐标
      const screenRight = new Vector3(canvasX, 0)
      const rightout = new Vector3()
      cameramash.screenToWorldPoint(screenRight, rightout)
      // 初始化屏幕右边框位置
      this._screenRight = rightout.x

      // 键盘事件监听
      window.addEventListener('keydown', e => {
        if (e.key === 'ArrowRight') {
            // 使用.flipX 来改变精灵方向为右
          roleRenderer.flipX = false
          this._isRight = true
        }
        if (e.key === 'ArrowLeft') {
            // 使用.flipX 来改变精灵方向为左
          roleRenderer.flipX = true
          this._isLeft = true
        }
        // 注意空格键的key码不为空,是空格‘ ’
        if (e.key === ' ') {
          this._isJump = true
        }
      })
      window.addEventListener('keyup', e => {
        if (e.key === 'ArrowRight') {
          this._isRight = false
        }
        if (e.key === 'ArrowLeft') {
          this._isLeft = false
        }
      })
    }
复制代码

在onUpdata()里实现移动

deltaTime

在updata()里有一个deltaTime参数

我们先来看一下deltaTime是什么

onUpdate (deltaTime: number): void {
      console.log(deltaTime)
    }
复制代码

image.png 是一个在100左右波动的数字,基于朴素的猜测,deltaTime为帧数。也就是说,Updata()会在1秒内执行deltaTime此,所以我们可以得到每帧的时间 1 / deltaTime

至此,我们有了时间和速度,运用小学二年级就学过的方程 x = t*v 就可得到位移

理论结束,代码如下

    onUpdate (deltaTime: number): void {
        // 当按下右键时,时间增加,
        // 用总时间*速度求出位移距离
        // 用Math.min()使向右最远到屏幕右侧
      if (this._isRight) {
        if (moveScript.tempPos.x !== this._screenRight) {
          this._totalTime += 1 / deltaTime
        }
        this._moveX = Math.min(this._totalTime * this._speed, -moveScript.startPos.x + this._screenRight)
      }
      
         // 当按下左键时,时间减少加,
        // 用总时间*速度求出位移距离
        // 用Math.max()使向左最远到屏幕左侧
      if (this._isLeft) {
        if (moveScript.tempPos.x !== this._screenLeft) {
          this._totalTime -= 1 / deltaTime
        }
        this._moveX = Math.max(this._totalTime * this._speed, -moveScript.startPos.x + this._screenLeft)
      }
      
        // 当按下空格键时,跳跃时间增加,
        // 用总时间*速度求出位移距离
        // 到跳跃最高点后,跳跃时间减少
        // 用总时间*速度求出位移距离
        // 使用Math.max()限制最低点
      if (this._isJump) {
        this._jumpTime += 1 / deltaTime
        this._moveY = this._jumpTime * this._speed
        if (moveScript.tempPos.y >= this._jumpHeight) {
          this._isJump = false
        }
      } else if (this._isJump === false && moveScript.tempPos.y > moveScript.startPos.y) {
        this._jumpTime -= 1 / deltaTime
        this._moveY = Math.max(this._jumpTime * this._speed, 0)
      }
      
      // 用startPos.x 加上位移this._moveX得到某个时刻tempPos.x 的值
      moveScript.tempPos.x = moveScript.startPos.x + this._moveX
      // 用startPos.y 加上位移this._moveY得到某个时刻tempPos.y 的值
      moveScript.tempPos.y = moveScript.startPos.y + this._moveY
      // 将temppos坐标复制给使用transform.position
      this.entity.transform.position = moveScript.tempPos
    }
复制代码

end

这里可以看到已经可以控制角色移动了。但在移动时,角色并没移动的动画。下一篇会介绍让他动起来。 如果可以的话,可以点个小小的赞 image.png

respect by myself

分类:
前端
标签: