Posted at

EgretEngineでRPGマップはどう実現するか?(4) カメラ回り

updateCameraPosを呼び出しているのはCameraComponent .dealBgCameraメソッドです


CameraComponent.ts

class CameraComponent extends Component {

:
public dealBgCamera(): void {
this.background.updateCameraPos(this.playerX, this.playerY);
}
}

CameraComponent.dealBgCameraを呼び出しているのは、同じくCameraComponentのupdateメソッドです。


CameraComponent.ts

class CameraComponent {

:
public update(advancedTime: number): void {
super.update(advancedTime);

if (this.playerPosChange()) {
this.playerX = this.entity.x;
this.playerY = this.entity.y;

this.dealMoveObjs();
}

if (this.playerCellChange()) {
this.playerCol = this.entity.col;
this.playerRow = this.entity.row;

this.dealBgCamera();
}
}


では、CameraComponentはどこで生成されて、だれがCameraComponent.updateを呼び出しているのかを調べていきます。

結論から言うとRpgPlayerクラスの初期化時(initメソッド)のaddComponentです。


RpgPlayer.ts

class RpgPlayer extends RpgGameObject {

:
public init(data: any): void {
:
this.addComponent(ComponentType.Camera);

addComponentが定義されているのは親クラスのRpgGameObjectです。

下記のように、まずオブジェクトプールObjectPoolからすでに存在している場合はそのオブジェクト取得して、存在していない場合は新規作成をします。

そのオブジェクトをコンポーネントの管理クラスComponentSystemaddComponentで管理対象として追加されます。


RpgGameObject.ts

    public addComponent(componentName: string): void {

if (this._components[componentName]) {
return;
}

var component: Component = ObjectPool.pop(componentName);
component.type = componentName;
component.entity = this;
component.start();

ComponentSystem.addComponent(component);

this._components[componentName] = component;
}


ComponentSystem.addComponentでは、コンポネント種別毎に生成されたコンポーネントが管理されます。


ComponentSystem.ts

    public static addComponent(component: Component): void {

if (!this._Components[component.type]) {
this._Components[component.type] = [];
}
this._Components[component.type].push(component);
}

そしてフレーム毎に呼び出されるComponentSystem.onEnterFrameで各コンポーネントのupdateメソッドが呼び出されます。


ComponentSystem.ts

    private static onEnterFrame(advancedTime: number): void {

:
this.dealComponents(this._Components[ComponentType.Camera], advancedTime);
:
}

private static dealComponents(arr: Component[], advancedTime: number): void {
if (!arr) {
return;
}
arr.forEach(function (component: Component) {
if (!component.isRuning) {
return;
}

component.dealTime += advancedTime;
if (component.dealTime >= component.dealInterval) {
component.dealTime = 0;
component.update(advancedTime);
}
})
}


つまり

1. 各フレーム毎に、ComponentSystem.onEnterFrameが呼ばれ

2. すべてのコンポーネントのupdateが呼びされた結果CameraComponent.updateが呼ばれ

3. CameraComponent.dealMoveObjsでカメラ位置に応じてすべてのオブジェクトの位置がされて

4. CameraComponent.dealBgObjsでカメラの可視範囲に応じてマップタイルが破棄されたり生成されたりします


CameraComponent

    public dealMoveObjs(): void {

var left: number = Math.max(this.playerX - App.StageUtils.getWidth() * 0.5, 0);
var top: number = Math.max(this.playerY - App.StageUtils.getHeight() * 0.5, 0);

left = Math.min(this.background.mapWidth - App.StageUtils.getWidth(), left);
top = Math.min(this.background.mapHeight - App.StageUtils.getHeight(), top);

this.moveObjs.forEach(function (obj: egret.DisplayObject) {
obj.x = -left;
obj.y = -top;
})
}


このようにBackgroundは、moveObjsでもありbackgroundでもあります。


CameraComponent

    public start(): void {

:
this.moveObjs.push(this.entity.gameView.getBackground());

this.background = this.entity.gameView.getBackground();
}