3D堆叠游戏——第二步 控制 控制主角移动以及停止

676 阅读3分钟

上一篇文章中制作了游戏的第一步创建基础 这一篇将制作游戏第二步,控制主角

主角移动主要使用TWEEN 作为动画引擎

因为不是介绍tweenjs所以这里不提基础用法,如果有需要可以留言,专门研究一下

这个是封装好的动画

const TWEEN = require("@tweenjs/tween.js");

export class Animate {
  tween
  constructor(mesh:any, e:any, t:number) {
    this.tween = new TWEEN.Tween(mesh.position)
    this.tween.to(e, t)
    this.tween.start()
  }
}

很简单,从起始vector3向量到结束vector3向量

调用动画还需要在render方法中对动画进行更新

// 渲染
render(): void {
  this.animate()
  this.renderer.render(this.scene, this.camera);
  this.controls.update();
  TWEEN.update();
}

控制主角动画

参数为起始点为主角position 终点为计算后结果,运动时间 T:number = 5000 // 主角运动时间,随着高度增加而衰减

 // 控制主角
leadHandle() {
  // 控制移动
  const lead = this.leadCube
  // 动画起始点
  const start = lead.position
  let ex = lead.position.x
  let ez = lead.position.z
  ex = ex === this.size / 2 ? this.size / 2 : (Math.abs(ex) + this.offset)
  ez = ez === this.size / 2 ? this.size / 2 : (Math.abs(ez) + this.offset)
  // 动画结束点
  const end = new THREE.Vector3(ex, start.y, ez)
  console.log(start, end)
  // 开启主角动画
  // 每增加一层减100毫秒 难度增加
  const t = Math.max(this.T - this.leadCount * 100, 1000)
  this.tween = new Animate(this.leadCube, end, t)
}

操作控制

游戏使用空格控制主角暂停和其他操作

监听一下keydown事件

window.addEventListener('keydown', this.leadStop.bind(this))

主角停止事件

// 主角停止
leadStop(event) {
  // 判断是否点击空格
  if (event.keyCode === 32) {
    if (this.tween) {
      // 暂停动画
      this.tween.tween.stop()
      this.tween = null
      // 生成下一个主角
      this.createlead()
    }
  }
}

目前游戏效果是这样的

目前生成下一个角色只有在点击空格之后,所以还需要一个是主角运动结束 再生成下一个主角

this.tween.tween.onComplete(this.leadOperation.bind(this))

leadOperation方法

// 对主角进行处理,包括生成新的主角,裁切主角,重绘底板等
leadOperation(){
  // 生成下一个主角
  this.createlead()
}

之后的文章会写到裁切功能,自由落体,游戏结束等

initGame目前完整代码

const THREE = require("three");
import { createCube } from '../utils/tools'
import { getSize, getPosition } from '../utils/getBox'
// 引入封装好的动画
import { Animate } from '../utils/animate'

class CreateGame {
  scene: any
  floorCube: any // 初始底板
  floorGroup: any // 底板组
  size: number = 30 // 主角宽度和长度
  leadY: number = 5 // 主角高度
  leadCount: number = 0 // 计数器
  startPoint: number = 60 // 主角起始位置 x或z
  leadInterval: any = null // 循环
  leadCube: any = null // 主角
  tween: any = null // 动画
  offset: number = 40 // 主角起始位置和终点位置偏移量
  T:number = 500 // 主角运动时间,随着高度增加而衰减
  constructor(element: any) {
    this.scene = element.scene
    this.floorGroup = new THREE.Group()
    this.scene.add(this.floorGroup)
    this.initFloor()
    window.addEventListener('keydown', this.leadStop.bind(this))
  }
  initFloor() {
    const w: number = this.size
    const h: number = 50
    const l: number = this.size
    const floorParams = {
      w: w,
      h: h,
      l: l,
      x: w / 2,
      y: h / 2,
      z: l / 2
    }
    this.floorCube = createCube(floorParams)
    this.floorGroup.add(this.floorCube)
    this.floorGroup.updateMatrix()
  }
  createlead() {
    const size = new THREE.Vector3()
    const mesh = this.floorGroup
    // 获取尺寸
    getSize(mesh, size)
    const position = new THREE.Vector3()
    // 获取底板的位置 默认应该都是0
    getPosition(mesh, position)
    const gy = position.y // 底板的Y值
    const y = size.y + gy + this.leadY / 2 // 主角的Y值
    // 设定第奇数个主角从z轴的负方向来,第偶数个主角从X轴方向来 
    // 需要一个主角计数器,同样可以用来计算分数
    // 起始点距离底板30
    // 主角初始位置
    const flag: boolean = this.leadCount % 2 === 0 // 是否是偶数主角
    // x 起始点
    let sx: number = (flag ? -this.startPoint - this.offset : 0) + this.size / 2
    // z 起始点
    let sz: number = (flag ? 0 : -this.startPoint - this.offset) + this.size / 2
    // 创建一个主角
    const leadParam = {
      w: this.size,
      h: this.leadY,
      l: this.size,
      x: sx,
      y,
      z: sz
    }
    this.leadCube = createCube(leadParam)
    this.floorGroup.add(this.leadCube)
    // 创建角色后计数器自增1
    this.leadCount++
    // 开始控制主角
    // const startVector3 = new THREE.Vector3(sx,y,sz)
    this.leadHandle()
  }
  // 控制主角
  leadHandle():void {
    // 控制移动
    const lead = this.leadCube
    // 动画起始点
    const start = lead.position
    let ex = lead.position.x
    let ez = lead.position.z
    ex = ex === this.size / 2 ? this.size / 2 : (Math.abs(ex) + this.offset)
    ez = ez === this.size / 2 ? this.size / 2 : (Math.abs(ez) + this.offset)
    // 动画结束点
    const end = new THREE.Vector3(ex, start.y, ez)
    console.log(start, end)
    // 开启主角动画
    // 每增加一层减100毫秒 难度增加
    const t = Math.max(this.T - this.leadCount * 100, 1000)
    this.tween = new Animate(this.leadCube, end, t)

    if(this.tween) {
      console.log(this.tween.tween)
      this.tween.tween.onComplete(this.leadOperation.bind(this))
    }
  }
  // 主角停止
  leadStop(event):void {
    // 判断是否点击空格
    if (event.keyCode === 32) {
      if (this.tween) {
        // 暂停动画
        this.tween.tween.stop()
        this.tween = null
        this.leadOperation()
      }
    }
  }

  // 对主角进行处理,包括生成新的主角,裁切主角,重绘底板等
  leadOperation(){
    // 生成下一个主角
    this.createlead()
    
  }
}

export { CreateGame }

代码可能有点粗糙,还望指正

3D堆叠游戏——第一步 基础 初始化游戏