Unity
EgretEngine

【Egret無料ご相談室】 EgretのDisplayObjectをちょいUnity Likeにする


話の発端

image.png

元のご相談簡単なソースコードをいただきました

https://github.com/squmari/EgretEngine/tree/master/All_Stop_With_One_Click



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とゲームエンジンの表示エンジンをまとめて管理するための上記とは別な例はこちらです

https://github.com/motoyasu-yamada/BasketBallBoy/tree/master/src

GameObjectGameWorldPhysicsObjectクラスをご自由にお使いください。

こんな風に使います


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();
}

}