話の発端
元のご相談簡単なソースコードをいただきました
↓
https://github.com/motoyasu-yamada/egret-unity-demo
Before
下記のようにすべてのオブジェクトに egret.startTick
を設定していました
class CreateImage extends egret.DisplayObjectContainer {
:
public constructor() {
super();
this.once(egret.Event.ADDED_TO_STAGE, this.generateEgretImage, this);
}
:
public generateEgretImage(event:egret.Event): void {
// 画像の生成
this.egretImage = this.createBitmapByName("egret_icon_png");
this.egretMoveFlag = true;
//Enable touchEvent
this.egretImage.touchEnabled =true;
//this.egretImage.pixelHitTest = true;
this.addChild(this.egretImage);
this.egretImage.x = 100;
this.egretImage.y = 100 + Math.floor( Math.random() * 300 );
//画面にタッチした瞬間にtouchMethodを実行
this.egretImage.addEventListener( egret.TouchEvent.TOUCH_BEGIN, this.egretTouch, this );
egret.startTick(this.moveEgret, this);
}
:
}
After
MonoBehaviour
という共通なクラスを作ってあげて
export class MonoBehaviour<T extends egret.DisplayObject>
{
private started : boolean = false;
protected $egretDisplayObject : T;
isStarted(): boolean {
return this.started;
}
setStarted() : void {
if(this.started !== false) {
throw new Error("MonoBehaviour has been started already");
}
this.started = true;
}
egretDisplayObject() : T {
return this.$egretDisplayObject;
}
async Start() : Promise<void> {};
Update() : void {}
}
多数のオブジェクト(MonoBehaviourクラスを継承した)を管理するScene
クラスに引き渡してScene
クラスで一括管理します。
Main.ts
private createAndStart() {
const scene = new Scene(this);
scene.add(new MyImageObject());
フレーム呼び出しは以下の一回だけ設定
Main.ts
private createAndStart() {
:
egret.startTick(() => { scene.doFrame(); return true; }, this);
}
SceneクラスでMonobehaviourクラスの初期化(Start呼び出し)と、フレーム毎の更新処理(Update呼び出し)を行います。
Scene.ts
import { MonoBehaviour } from "./MonoBehaviour";
export class Scene {
private egretDisplayObjectContainer : egret.DisplayObjectContainer;
private monoBehaviours: MonoBehaviour<egret.DisplayObject>[] = [];
constructor(egretDisplayObjectContainer: egret.DisplayObjectContainer) {
this.egretDisplayObjectContainer = egretDisplayObjectContainer;
}
public remove(o : MonoBehaviour<egret.DisplayObject>) {
this.egretDisplayObjectContainer.removeChild(o.egretDisplayObject());
this.monoBehaviours = this.monoBehaviours.filter (e => e !== o);
}
public add(o: MonoBehaviour<egret.DisplayObject>) {
this.egretDisplayObjectContainer.addChild(o.egretDisplayObject());
this.monoBehaviours.push(o);
}
public doFrame() {
const toBeStarted = this.monoBehaviours.filter(e => !e.isStarted());
Promise.all(toBeStarted.map(e => e.Start()));
toBeStarted.forEach(e => e.setStarted());
this.monoBehaviours.forEach(e => e.Update());
}
}
おまけ
物理エンジンp2
とゲームエンジンの表示エンジンをまとめて管理するための上記とは別な例はこちらです
GameObject
とGameWorld
とPhysicsObject
クラスをご自由にお使いください。
こんな風に使います
GameMain.ts
const BASKET_SIZE_METER = 0.15;
const BALL_SIZE_METER = 0.6;
const FPS = 60;
class GameMain
{
public static destroy()
{
GameWorld.destroy();
}
public static start(stage:egret.Stage, onGameOver:()=>void)
{
const ballPixel = egret.MainContext.instance.stage.stageWidth / 10;
GameWorld.init(ballPixel / BALL_SIZE_METER, stage);
new Sky();
new Ground();
new TimeGauge(30);
new ScoreUi();
const ball = new Ball();
stage.addEventListener(egret.TouchEvent.TOUCH_BEGIN, (e: egret.TouchEvent) => ball.up(), this);
const basketManager = new BasketManager();
GameWorld.on("gameover",() => {
SoundManager.playGameOver();
GameWorld.pause();
onGameOver();
});
GameWorld.start();
}
}