# 框架开发

小游戏框架整体采用类ECS架构,开发者可以开发自定义component脚本,来操纵游戏实体(Entity),从而实现游戏逻辑。

# 创建Script Component脚本。

游戏的节点树由实体Entity组成,每一个Entity都可以挂载不同的组件Component,用于实现不同的能力。比如内置的MeshRenderer Component用于渲染。开发者也可以实现自己的脚本组件,继承于engine.Script。在脚本中定义组件的生命周期的回调函数,就可以去实现游戏逻辑,或是修改其他组件的属性。

开发者可以自己使用代码编辑器创建脚本,也可以通过小游戏工具的Project窗口右键新建 >> script来创建默认模版。文件名将会默认作为你的脚本组件的类名。右键这个脚本文件就可以选择使用内置编辑器,或是系统默认软件打开。

# 脚本组件的结构

新建的脚本一般如下,包含了一个类。每当被添加到一个Entity上面的时候都会生成这个类新的实例。

import engine from "engine";

@engine.decorators.serialize("Move")
export default class Move extends engine.Script {
  @engine.decorators.property({
    type: 'string'
  })
  public name: string = "myname"
  
  public onAwake() {

  }
  public onUpdate(dt) {

  }
  public onDestroy() {

  }
}

这个类有几部分组成。

  • 脚本组件是一个继承于engine.Script的类,engine.Script本身继承于engine.Component。
  • 对于这个类有一个serialize装饰器,是用标示这个类型是一个可序列化的类。装饰器的入参应该保证是一个唯一值。
  • 对于属性可以使用property装饰器来标示,可以用于序列化落地以及UI可视化,具体可以在后面序列化系统章节中查看。
  • onAwake/onUpdate等生命周期,这些注册的回调会在组件生命周期被执行,用于开发游戏逻辑。比如onUpdate就是在游戏每一帧调用的,可以用来实现位置移动等能力。生命周期具体有哪些,可以在后面的生命周期章节中查看。

# 添加到Entity上

有两种方式将你的脚本添加到Entity上。

  1. 在编辑态添加。在Project窗口中,拖动一个脚本组件文件到Hierarchy窗口的对应entity上即可绑定。或是打开编辑一个Scene或是Prefab,选中Hierarchy的对应Entity,然后在inspector中最下面可以点击添加组件。除了内置的组件外,还有Script分类,开发者可以找到添加刚刚自己创建的脚本名称,名称是serialize装饰器的名称。添加到Entity后保存Scene或Prefab,序列化系统会把属性当前的值也保存进去,这样后续就不需要每次动态添加。

  2. 在脚本运行的时候添加。开发者可以使用entity.addComponent(Move)来动态按需添加一个组件。

# 获取与修改属性

组件中在回调函数里面可以使用this.entity来获取当前的Entity,并且可以直接对它进行修改。也可以通过getComponent来获取其他组件。

public onUpdate(dt) {
  // 改变3D节点位置
  this.entity.transform.position.x++
  // 获取其他组件
  const mr = this.entity.getComponent(engine.MeshRenderer)
}

# 2D/3D 事件通信

小游戏框架将Scene和Prefab区分为2D和3D两种,但是很多情况下两者需要互相调用通信,比如使用2D的操纵杆来移动3D的人物。小游戏框架内部提供了事件系统engine.game.customEventEmitter来实现通信。

// 3D组件
onAwake() {
  engine.game.customEventEmitter.on('TOUCH_MOVE', (direction) => {
    ...
  });
}
// 2D组件
onTouchMove() {
  engine.game.customEventEmitter.emit('TOUCH_MOVE', direction)
}

# 生命周期

组件以及框架本身有对应的生命周期可以使用,比如onAwake,onUpdate等。可以查看生命周期章节查看