EgretEngineでRPGマップはどう実現するか？(2) 表示処理が呼び出されるまで

# ソースコードをおう

## 初期化処理
1. `Main::constructor`で `this.addEventListener(egret.Event.ADDED_TO_STAGE, this.onAddToStage, this);`
2. コールバックされた`Main::onAddToStage`から`Main::loadResConfig`を呼び出す
3. `Main::loadResConfig`から`App.ResourceUtils.loadConfig(this.onConfigComplete, this);`
4. コールバックされた`Main::onConfigComplete`から`theme.addEventListener(eui.UIEvent.COMPLETE, this.onThemeLoadComplete, this);`
5. コールバックされた`Main::onThemeLoadComplete`にて以下の処理

```ts:Main.ts
class Main extends egret.DisplayObjectContainer {
:
    private onThemeLoadComplete(): void {
        this.initModule();
        App.SceneManager.runScene(SceneConsts.LOADING);
        new RpgTest();
        new ProtoBufTest();
    }
:
}
```
## RpgTest

`RpgTest`クラスは、`src/example/test`にある

![image.png](https://qiita-image-store.s3.amazonaws.com/0/302078/c8ce4fba-3b0c-66bf-8236-0a44e98f291a.png)


コンストラクタでマップリソースの初期化メソッド`initMapResource`を呼び出す。


```ts:RpgTest
    public constructor() {
        :
        this.mapId = 1193;
        this.mapGroupKey = "map_" + this.mapId;
        this.initMapResource();
        :
    }
```

`initMapResource`はマップ情報を読み込んでいるわけではなく、マップ情報を読み込むたむのリソース定義情報を動的に生成しています。
今回のサンプルではマップ(mapId=1193)が1つしかありませんので、この処理は無駄に見えます。
しかし多数ある場合はこのように読み込むほうがいいですね。

```ts:RpgTest.ts
    private initMapResource(): void {
        var mapResPath: string = "resource/assets/rpgGame/map/" + this.mapId + "/";
        var mapResKey: string = this.mapGroupKey + "_";
        var mapResKeys: string[] = [];
        var mapRes: any[] = [
            {
                name: "data.json",
                type: "json"
            },
            {
                name: "mini.jpg",
                type: "image"
            }
        ];
        mapRes.forEach(function (res) {
            var resKey: string = mapResKey + res.name;
            App.ResourceUtils.createResource(resKey, res.type, mapResPath + res.name);
            mapResKeys.push(resKey);
        })

        App.ResourceUtils.createGroup(this.mapGroupKey, mapResKeys);
    }
```


リソース定義に記載がある`mini.png`は以下のようなミニマップの一枚絵の画像です

![mini.jpg](https://qiita-image-store.s3.amazonaws.com/0/302078/f540e128-a305-9593-ed85-cb42e0c4c49f.jpeg)

マップの定義ファイル`data.json`はこのようになっています

0と1しか値があらわれませんのでこちらは移動可能・不可能情報のみかもしれません

```json:data.json
{
 "path":"/map/1193/",
 "width": 3200,
 "height": 2400,
 "blocks":[
  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
  [0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
  
:
:

[0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0],
  [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
 ]
}
```

`data.json`と`mini.png`が含まれるリソースが読み込み開始されます

```ts:RpgTest.ts
  constructor() {
  :
    App.ResourceUtils.loadGroups(groupName, subGroups, this.onResourceLoadComplete, this.onResourceLoadProgress, this);
  }
```

読み込みが終わった後は、各種モジュールがの読み込みや初期化が行われ、`SceneConsts.RpgGame` シーンが起動します。

```ts:RpgTest.ts
    private onResourceLoadComplete(): void {
        this.initModule();
        App.Init();

        App.SoundManager.setBgOn(true);
        App.SoundManager.setEffectOn(true);

        App.SceneManager.runScene(SceneConsts.RpgGame, this.mapId);
    }
```

# RpgGameScene

`SceneConsts.RpgGame` シーンは、`Main.ts`クラスの初期化時に、`RpgGameScene`クラスにバインドされています。

```ts:Main.ts
private initScene(): void {
:
App.SceneManager.register(SceneConsts.RpgGame, new RpgGameScene());
}
```

また`App.SceneManager.runsScene`を呼び出すと、新しいシーンの`onEnter`が呼び出されますので、`RpgGameScene.onEnter`を確認します。

```
    public runScene(key: number, ...param: any[]): void {
        var nowScene: BaseScene = this._scenes[key];
        :
        var oldScene: BaseScene = this._scenes[this._currScene];
        if (oldScene) {
            oldScene.onExit();
        }

        nowScene.onEnter.apply(nowScene, param);
        this._currScene = key;
    }
```

シーンから実際に処理をする`ControllerConst.RpgGame`という名前？のコントローラを呼び出しています。

```ts:src/example/module/RpgGameScene.ts

class RpgGameScene extends BaseScene{
:
    public onEnter(...param:any[]):void{
:
        var mapId:number = param[0];
:
        App.ControllerManager.applyFunc(ControllerConst.RpgGame, RpgGameConst.GameInit, mapId);
:
    }
}
```

実際には、`RpgTest.ts`にて、`ControllerConst.RpgGame`という名前は、`RpgGameController`というクラスにバインドされています。

```ts:RpgTest.ts
App.ControllerManager.register(ControllerConst.RpgGame, new RpgGameController());
```


`ControllerManager.applyFunc`の定義を見ると、`RpgGameController`というクラスが呼び出されていることがわかります。

```ts:ControllerManager.ts
    public applyFunc(controllerD: number, key: number, ...param: any[]): any {
        var manager: BaseController = this._modules[controllerD];
        if (manager) {
            var params = [];
            for (var i = 1; i < arguments.length; i++) {
                params[i - 1] = arguments[i];
            }
            return manager.applyFunc.apply(manager, params);
        } else {
            Log.warn("模块" + controllerD + "不存在");
            return null;
        }
    }
```

`BaseController.applyFunc`では、第一引数をメソッド名と解釈しています。

つまり、`App.ControllerManager.applyFunc(ControllerConst.RpgGame, RpgGameConst.GameInit, mapId);`は、`RpgGameController.GameInit(mapId)`という呼び出しになります。

正確にはこの`RpgGameController`は`RpgGameController`のインスタンスという意味です。

```ts:BaseController
    public applyFunc(key: any, ...param: any[]): any {
        var listen: any = this._messages[key];
        if (listen) {
            return listen[0].apply(listen[1], param);
        } else {
            Log.warn("消息" + key + "不存在侦听");
            return null;
        }
    }
```


# RpgGameController

コントローラーからは`ViewConst.RpgGame`ビューを開きます。

```ts:RpgGameController.ts
    private gameInit(mapId: number) {
        this.gameModel.mapId = mapId;
        :
        App.ViewManager.open(ViewConst.RpgGame, this.gameModel);
    }
```

コンストラクターにて`ViewConst.RpgGame`は`RpgGameView`にバインドされています。

```ts:RpgGameController.ts
        this.gameView = new RpgGameView(this, LayerManager.Game_Main);
        App.ViewManager.register(ViewConst.RpgGame, this.gameView);
```

# RpgGameView

ViewManagerにて、Viewの初期化処理が行われます。

また`open`メソッドでは`RpgGameView`の`loadResource`メソッドを呼び出しリソースを読み込みます。

次に、`initUI`と`initData`で初期化を行い、

最後に`open`メソッドを呼び出し、

そのあとに`setVisible(true);`が呼び出され表示されます。

```ts:ViewManager.ts
    public open(key: number, ...param: any[]): IBaseView {
        var view: IBaseView = this.getView(key);
        :
            App.EasyLoading.showLoading();
            view.loadResource(function () {
                view.setVisible(false);
                view.addToParent();
                App.EasyLoading.hideLoading();
            }.bind(this), function () {
                view.initUI();
                view.initData();
                view.open(...param);
                view.setVisible(true);
            }.bind(this));
         :
    }
```

# しめ

いったん長くなりましたので今日はここまで。

次回は`RpgGameView`以降のソースコードを読み解いていきます。