タワーディフェンスタイプのゲームを作ってみようと思う 2日目

さて論理的な地形が出来た。この地形に敵軍ユニットを配置したいのだがゲーム画面上のどこにユニットを配置すればいいのだろうか?と、ここで地形の空間表現がまだ出来ていない事に気づく。

地形の空間表現のロジックはどこに記述するべきだろうか?今ある地形モデルだろうか、それとも地形ビューだろうか?
言うまでもなく地形の空間表現はビューに密接に関係する。MVCの原則からモデルはビューに関心を持つべきではない。従って地形の空間表現はビューに記述する事になる。しかしこれはなんだか嫌な感じがする。この考え方では敵軍ユニットビューが自身の配置される座標を決定する事になるからだ。これは出来れば避けたい。ビューはなるべく知性を持たない置物のようなオブジェクトであるべきだ。

そこで、以下の用にビューモデル層を導入する事にした。各レイヤーの責務は図に記述してある。

地形のアーキテクチャ

GraphMapperというクラスをビューモデル層に作り、このクラスがグラフの空間表現を行う事にする。

地形マッパーのクラス図

テストとして前回作った簡易地形ビューを使い各ノード間の経路をポイントしてみた。

以下ソースコード
GraphMapper.as

package com.imajuk.tdf
{
    import flash.utils.Dictionary;
    /**
     * @author imajuk
     */
    public class GraphMapper
    {
        private var model : DirectedGraph;
        private var position : Dictionary = new Dictionary(true);

        public function GraphMapper(model : DirectedGraph)
        {
            this.model = model;
            
            // とりあえずノードの座標は簡易ビューのノード座標をハードコーディングする.
            // あとでノードの座標を指定するインターフェイスを考える
            model.crawl(function(node : GraphNode) : void
            {
                position[node] = Vector.([node.depth * 100 + 60, node.childIndex * 60]);
            });
        }

        public function getPosition(begin : GraphNode, end : GraphNode, time : Number) : Vector.
        {
            var v1 : Vector. = position[begin],
                v2 : Vector. = position[end],
                bx : Number = v1[0], by : Number = v1[1],
                ex : Number = v2[0], ey : Number = v2[1];
                
            return Vector.([bx + (ex - bx) * time, by + (ey - by) * time]);
        }
    }
}

Main.as

package com.imajuk.tdf
{
    import flash.display.DisplayObject;
    import flash.display.Sprite;

    public class Main extends Sprite
    {
        private var terrin : DirectedGraph;

        public function Main()
        {
            // テスト用の地形作成
            terrin = new DirectedGraph();
            // 敵軍進軍始点(ノードA)
            var node_A : GraphNode = terrin.begin;
            // ノードAにノードBを追加
            var node_B : GraphNode = node_A.add(3);
            // ノードBにノードCを追加
            var node_C : GraphNode = node_B.add(5);
            // ノードBにノードDを追加
            var node_D : GraphNode = node_B.add(5);
            // ノードCにノードEを追加
            var node_E : GraphNode = node_C.add(5);
            // ノードEに敵軍終点(ノードF)を追加
            var node_F : GraphNode = node_E.add(5);
            // ノードDとノードFを連結
            node_D.connect(node_F);
            
            // テスト用の簡易ビュー
            var view:Sprite = addChild(new GraphView(terrin)) as Sprite;

            // グラフを空間にマップするオブジェクト
            var mapper:GraphMapper = new GraphMapper(terrin);
            
            // ビューの各ノード間の経路をポイント
            var tests:Array = [
                [node_A, node_B,  0], //ノードAからノードBまでの経路上で0%の位置
                [node_B, node_C, .2], //ノードBからノードCまでの経路上で20%の位置
                [node_B, node_D, .4], //ノードBからノードDまでの経路上で40%の位置
                [node_C, node_E, .6], //ノードCからノードEまでの経路上で60%の位置
                [node_D, node_F, .8], //ノードDからノードFまでの経路上で80%の位置
                [node_E, node_F,  1]  //ノードEからノードFまでの経路上で100%の位置
            ];
            tests.forEach(function(a:Array, ...rest) : void
            {
                var v : Vector. = mapper.getPosition(a[0], a[1], a[2]);
                var p : DisplayObject = view.addChild(new TestPoint());
                p.x = v[0];
                p.y = v[1];
            });
        }
    }
}
import flash.display.Shape;

class TestPoint extends Shape
{
    public function TestPoint() {
        graphics.beginFill(0x0000FF, .5);
        graphics.drawCircle(0, 0, 30);
        graphics.endFill();
    }
}

実行結果
経路にポイントをマップ

これで敵軍ユニットを地形に配置する事が出来そうだ。
今日はここまで! 
リビジョンは601fe26dd3

たぶん つづく。

カテゴリー: ActionScript3, towerDefense パーマリンク

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です