2007年12月7日金曜日

Missileスクリプトの優位性について

Missileスクリプトを使って、ゲームを作る場合の良い点を書いておこうと思います。

Missileスクリプトを使うと、敵の移動パターンを分かりやすく記述できます。これが最大の利点かつ唯一の利点かと思いますw

既存のプログラミング言語でSTGを作った場合の、「よくありそうな」例を以下に挙げます。
C#っぽい言語で書いておきます。

まず、STGに登場するキャラクタの基底クラスを作ります。
    public class Character
{
public void Move()
{
}

public void Draw(Graphics graphics)
{
}
}

敵クラスとか自機クラスとか得点表示クラスは、全てCharacterクラスから派生させるわけです。

キャラクタ基底クラスを継承して、敵1クラスを作ります。この敵の動き方は、
  右に1フレーム当り2ドットの速さで100フレームの間、移動
  次に、下に1フレーム当り2ドットの速さで100フレームの間、移動
  次に、左に1フレーム当り2ドットの速さで100フレームの間、移動
  次に、上に1フレーム当り2ドットの速さで100フレームの間、移動
とします。
つまり、正方形の辺を時計回りにたどるように動きます。
    public class Enemy1 : Character
{
private Texture texture;
private int x;
private int y;
private int count;

public Enemy1(Texture texture, int x, int y)
{
this.texture = texture;
this.x = x;
this.y = y;
this.count = 0;
}

public new void Move()
{
if (count < 100)
{
x += 2;
}
else if (count < 200)
{
y += 2;
}
else if (count < 300)
{
x -= 2;
}
else if (count < 400)
{
y -= 2;
}

count++;
if (count >= 400)
{
count = 0;
}
}

public new void Draw(Graphics graphics)
{
graphics.Sprite.Draw2D(texture, x, y);
}
}

そして、最後はメインループです。
        public void Main()
{
Graphics graphics = new Graphics();
Texture texture = TextureLoader.FromFile("enemy1.png");

LinkedList characters = new LinkedList();
characters.AddLast(new Enemy1(texture, 100, 200));

for (; ; )
{
for (int i = 0; i < characters.Count; i++)
{
characters[i].Move();
}

for (int i = 0; i < characters.Count; i++)
{
characters[i].Draw(graphics);
}
}
}

多分、OOPっぽくSTGを作ると、たいていこんな構造になると思います。

この例では、いまいちな点が2点ほどあります。
1.Enemy1.Move()ではカウンタの値で分岐して行動パターンを記述しているので、直感的に分かりづらいコードになっていること。
2.インスタンスはメインルーチン内で管理しなければならないこと。

移動パターンを関数に記述したとき、ローカル変数は関数を抜けると開放されるので、位置などの変数は、関数の外で保持してやる必要があります。

上の例のように、クラスを使える言語で書いた場合は、位置などの変数はメンバ変数にします。また、純粋なCで書いた場合は、キャラクタの情報を入れる構造体を作って、それを参照渡しする形になると思います。
上の例では位置x,yは、敵1クラスのメンバ変数になっています。
Enemy1クラスのインスタンスはMain内で生成されています。そのため、Main内で各キャラクタのインスタンスを管理する必要があります。

テクスチャの指定も、Main側から行う形になっています。1つのテクスチャを複数のキャラクタで使う場合がある(というよりは、STGでは同じキャラクタが何個も生成されるので、そのたびにテクスチャをロードするのは無駄がありすぎる)ので、Enemy1クラス内でテクスチャをロードして使うことが出来ないためです。本来ならば、テクスチャの指定といった、キャラクタごとに固有の処理は、各キャラクタクラス内で完結して記述できたほうが良いのは当然です。

ローカル変数だけを使って、行動パターンを記述できないだろうか。
また、各キャラクタに関する処理は、そのキャラクタのソース内で完結して記述できないだろうか。
そういう発想を原点にして、作り始めたのがMissileスクリプトです。

つづく

0 件のコメント: