例外処理は難しい。
しかし、例外をうまく処理すれば、エラーやバグの原因をすばやく突き止められるはず。
例外はただcatchしておけばよいっていうものでは無く、catchしたあとで誰に宛ててエラーメッセージを表示するかを考慮する必要がありますね。
Missileフレームワークの場合、例外は以下3つに分類されます。
1.ユーザーに宛てる例外
2.スクリプターに宛てる例外
3.プログラマーに宛てる例外
それぞれの名宛人の定義は、
1は、Missileフレームワークで作られたゲームをプレイしている人
2は、Missileスクリプトを記述する人
3は、Missileフレームワークをプログラミングしている人
です。
1は、ユーザーのシステム環境が原因で発生するエラーが主です。
例えば、DirectXのバージョンが古いとか、メモリが足りないなどが考えられます。
2は、スクリプトの記述ミスで発生するエラーです。
例えば、スクリプト中で存在しないファイルを指定した場合などが考えられます。
3は、Missileフレームワークのバグで発生するエラーです。
ぬるぽとかそれ系です。
ApplicationExceptionを継承して、UserExceptionとScriptRuntimeExceptionを用意します。
1は、キャッチして、UserExceptionをthrowします。例外メッセージには、ユーザーが読んで理解できるようなことを入れておきます。
2は、キャッチして、ScriptRuntimeExceptionをthrowします。例外メッセージには、スクリプトのバグの原因を突き止められるような内容を入れておきます。
3は、キャッチしないようにします。その方がVisualStudioでデバックしやすいからです。
そして、UserExceptionとScriptRuntimeExceptionをメイン画面のフォームでキャッチして、例外メッセージをダイアログボックスに表示します。そしてプログラムを終了させます。
こんな感じでいいかと思います。
2007年12月15日土曜日
2007年12月11日火曜日
スコアアタックについて
Missileスクリプトの仕様策定の段階であったのですがスクリプト上簡単にリプレイを作成できるようになっています。
しかし、このリプレイ。
多少の欠点があります。
それは現状バージョンの差異を特定出来ないことです。
リプレイデータはゲーム中でプレイヤーがどのようにキャラを動かしたか、それがMISSILEスクリプトのバーチャルマシン上でどのように反映されるかを保存します。
そのため、スクリプト変更に伴う敵の動きの変更があった場合その動きの差異を拾えきれない事があります。
スクリプト、アップローダ用のスコアを特定する方法はすでに内部で決まってはいるのですが他の同人STGでも過去のリプレイがまともに動く例は少ないようです。
(当たり前といえば当たり前なのですが)
しかし、これを解決したところでステージ構成が違うバージョンでのスコアアタックに意味があるのか。
おそらくは意味がない場合がほとんどなんでしょう。
しかし、このリプレイ。
多少の欠点があります。
それは現状バージョンの差異を特定出来ないことです。
リプレイデータはゲーム中でプレイヤーがどのようにキャラを動かしたか、それがMISSILEスクリプトのバーチャルマシン上でどのように反映されるかを保存します。
そのため、スクリプト変更に伴う敵の動きの変更があった場合その動きの差異を拾えきれない事があります。
スクリプト、アップローダ用のスコアを特定する方法はすでに内部で決まってはいるのですが他の同人STGでも過去のリプレイがまともに動く例は少ないようです。
(当たり前といえば当たり前なのですが)
しかし、これを解決したところでステージ構成が違うバージョンでのスコアアタックに意味があるのか。
おそらくは意味がない場合がほとんどなんでしょう。
2007年12月7日金曜日
Missileスクリプトの優位性について2
つづきです。
Misiileスクリプトを使えば、同じことを以下のように記述できます。
frame命令は、Missileスクリプトの最大の特徴だと思います。
frame命令が実行されるとスクリプトの実行を一時停止して、指定されたフレーム数の間、スクリプトの呼び出し側に処理を返します。
指定されたフレーム数が経過すると、一時停止した所から処理を再開します。
C言語とかの関数の場合は、処理を一時停止して、呼び出し側に戻るっていうことはできません。また、ローカル変数は関数を抜けると開放されてしまうので、キャラクタのコンテキストを関数の外側で保持しておく必要がありました。
Missileスクリプトでは、frame命令で処理を「一時停止」して、その間に他のスクリプトの処理や描画処理などを並列的に実行します。
この仕組みにより、キャラクタのコンテキストをローカル変数に置くことが出来るようになります。また、カウンタなどで時間軸を分割して移動パターンを記述する必要がなくなります。
結果として、直感的に分かりやすいコードになっていると思います。
以下は余談です。
処理を一時停止して、呼び出し側に戻って、その後処理を再開できるルーチンのことを、「コルーチン」と言います。
Lua5.0とかC#2.0にはコルーチンがあります。
でも、C#のコルーチンは、列挙子を記述するための専用構文になっていて汎用的には使えないのが残念です(yield文)。
Misiileスクリプトを使えば、同じことを以下のように記述できます。
main()かなり簡単になりました。
{
texture("enemy1.png");
x = 100;
y = 100;
for (;;)
{
vx = 2;
frame(100);
vy = 2;
frame(100);
vx = -2;
frame(100);
vy = -2;
frame(100);
}
}
frame命令は、Missileスクリプトの最大の特徴だと思います。
frame命令が実行されるとスクリプトの実行を一時停止して、指定されたフレーム数の間、スクリプトの呼び出し側に処理を返します。
指定されたフレーム数が経過すると、一時停止した所から処理を再開します。
C言語とかの関数の場合は、処理を一時停止して、呼び出し側に戻るっていうことはできません。また、ローカル変数は関数を抜けると開放されてしまうので、キャラクタのコンテキストを関数の外側で保持しておく必要がありました。
Missileスクリプトでは、frame命令で処理を「一時停止」して、その間に他のスクリプトの処理や描画処理などを並列的に実行します。
この仕組みにより、キャラクタのコンテキストをローカル変数に置くことが出来るようになります。また、カウンタなどで時間軸を分割して移動パターンを記述する必要がなくなります。
結果として、直感的に分かりやすいコードになっていると思います。
以下は余談です。
処理を一時停止して、呼び出し側に戻って、その後処理を再開できるルーチンのことを、「コルーチン」と言います。
Lua5.0とかC#2.0にはコルーチンがあります。
でも、C#のコルーチンは、列挙子を記述するための専用構文になっていて汎用的には使えないのが残念です(yield文)。
Missileスクリプトの優位性について
Missileスクリプトを使って、ゲームを作る場合の良い点を書いておこうと思います。
Missileスクリプトを使うと、敵の移動パターンを分かりやすく記述できます。これが最大の利点かつ唯一の利点かと思いますw
既存のプログラミング言語でSTGを作った場合の、「よくありそうな」例を以下に挙げます。
C#っぽい言語で書いておきます。
まず、STGに登場するキャラクタの基底クラスを作ります。
敵クラスとか自機クラスとか得点表示クラスは、全てCharacterクラスから派生させるわけです。
キャラクタ基底クラスを継承して、敵1クラスを作ります。この敵の動き方は、
右に1フレーム当り2ドットの速さで100フレームの間、移動
次に、下に1フレーム当り2ドットの速さで100フレームの間、移動
次に、左に1フレーム当り2ドットの速さで100フレームの間、移動
次に、上に1フレーム当り2ドットの速さで100フレームの間、移動
とします。
つまり、正方形の辺を時計回りにたどるように動きます。
そして、最後はメインループです。
多分、OOPっぽくSTGを作ると、たいていこんな構造になると思います。
この例では、いまいちな点が2点ほどあります。
1.Enemy1.Move()ではカウンタの値で分岐して行動パターンを記述しているので、直感的に分かりづらいコードになっていること。
2.インスタンスはメインルーチン内で管理しなければならないこと。
移動パターンを関数に記述したとき、ローカル変数は関数を抜けると開放されるので、位置などの変数は、関数の外で保持してやる必要があります。
上の例のように、クラスを使える言語で書いた場合は、位置などの変数はメンバ変数にします。また、純粋なCで書いた場合は、キャラクタの情報を入れる構造体を作って、それを参照渡しする形になると思います。
上の例では位置x,yは、敵1クラスのメンバ変数になっています。
Enemy1クラスのインスタンスはMain内で生成されています。そのため、Main内で各キャラクタのインスタンスを管理する必要があります。
テクスチャの指定も、Main側から行う形になっています。1つのテクスチャを複数のキャラクタで使う場合がある(というよりは、STGでは同じキャラクタが何個も生成されるので、そのたびにテクスチャをロードするのは無駄がありすぎる)ので、Enemy1クラス内でテクスチャをロードして使うことが出来ないためです。本来ならば、テクスチャの指定といった、キャラクタごとに固有の処理は、各キャラクタクラス内で完結して記述できたほうが良いのは当然です。
ローカル変数だけを使って、行動パターンを記述できないだろうか。
また、各キャラクタに関する処理は、そのキャラクタのソース内で完結して記述できないだろうか。
そういう発想を原点にして、作り始めたのが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");
LinkedListcharacters = 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スクリプトです。
つづく
2007年12月4日火曜日
google-code-prettifyの導入を試験的に行ってみました。
内部で行っていることなので、閲覧者の方には解りづらいかもしれませんが、これで各種言語のコードが解りやすくなると思います。
missileには対応してないので、その辺はご勘弁を。
とりあえず、こんな感じです。
と、言うわけでスタッフの方への業務連絡でした。
missileには対応してないので、その辺はご勘弁を。
とりあえず、こんな感じです。
public void Play(bool loop_flag)
{
loopflag = loop_flag;
try
{
audiodata = new Audio(filename);
audiodata.Play();
audiodata.Ending += new System.EventHandler(this.Loop);
}
catch (Exception e)
{
Console.WriteLine("Not FileSetting", e);
}
}
と、言うわけでスタッフの方への業務連絡でした。
Missileスクリプトエンジン環境下のリソース管理について
Missileスクリプトでは、オーディオデータやグラフィックデータなどのリソースを管理する手間が非常に少なくなる予定です。
普通の環境だと、リソースをファイルからロードしてインスタンス化し、それを実際に使用して、最後に破棄する、という手順が必要になります。
なぜ、ロード、使う、破棄、の3ステップを踏まなければならないかといえば、メモリとハードディスクの特性の違いによるものだと私は考えます。
一般に、メモリは小容量・高速・揮発性で、ハードディスクは大容量・低速・不揮発性という特性を持っています。プログラマはこれらの違いを意識してプログラムを書く必要があります。
もしも、ハードディスク並みに大容量かつ電源を切っても内容が消えないメモリがあり、PCの記憶装置はメインメモリだけということになったら、上記の点に関してプログラマはとても楽をできるはずです。ディスクからロードしたりする手順を踏まなくとも、すべてのリソースに最速でアクセスできるわけです。
Missileスクリプトエンジンでは、擬似的にそのような環境を実現することを目標にしています。スクリプトの記述者は、明示的にリソースをロードしたり破棄したりするコードを書く必要がありません。
それは、Missileスクリプトエンジンにリソースを自動的にキャッシュする仕組みがある為です。
普通の環境だと、リソースをファイルからロードしてインスタンス化し、それを実際に使用して、最後に破棄する、という手順が必要になります。
なぜ、ロード、使う、破棄、の3ステップを踏まなければならないかといえば、メモリとハードディスクの特性の違いによるものだと私は考えます。
一般に、メモリは小容量・高速・揮発性で、ハードディスクは大容量・低速・不揮発性という特性を持っています。プログラマはこれらの違いを意識してプログラムを書く必要があります。
もしも、ハードディスク並みに大容量かつ電源を切っても内容が消えないメモリがあり、PCの記憶装置はメインメモリだけということになったら、上記の点に関してプログラマはとても楽をできるはずです。ディスクからロードしたりする手順を踏まなくとも、すべてのリソースに最速でアクセスできるわけです。
Missileスクリプトエンジンでは、擬似的にそのような環境を実現することを目標にしています。スクリプトの記述者は、明示的にリソースをロードしたり破棄したりするコードを書く必要がありません。
それは、Missileスクリプトエンジンにリソースを自動的にキャッシュする仕組みがある為です。
2007年11月28日水曜日
進捗
スクリプトエンジンは大体完成したってことにする。
あとは、この上に乗っかるゲームエンジンを作らないと。
スクリプトエンジンを弄ってると、あれこれと機能を追加したくなるのだが、我慢することにした。
きりが無いので。
なにげにスクリプトコンパイラ+スクリプトエンジン+IDEのソースを合わせると
1万ステップ弱になる。よく3週間でこれだけ書いたもんだと我ながら思う。
まあ、以前に作ったソースを土台にしてるから、短時間で作れたのはあるが、
VisualStudio2005とC#の生産性は驚異的だと思う。
スクリプト言語仕様に本当は入れたかったが、今回見送ったものは次バージョンの課題としたい。
・配列(ハッシュテーブル)
・switch case break continue defaultなどの制御構文
・型推論
あとは、この上に乗っかるゲームエンジンを作らないと。
スクリプトエンジンを弄ってると、あれこれと機能を追加したくなるのだが、我慢することにした。
きりが無いので。
なにげにスクリプトコンパイラ+スクリプトエンジン+IDEのソースを合わせると
1万ステップ弱になる。よく3週間でこれだけ書いたもんだと我ながら思う。
まあ、以前に作ったソースを土台にしてるから、短時間で作れたのはあるが、
VisualStudio2005とC#の生産性は驚異的だと思う。
スクリプト言語仕様に本当は入れたかったが、今回見送ったものは次バージョンの課題としたい。
・配列(ハッシュテーブル)
・switch case break continue defaultなどの制御構文
・型推論
Missileスクリプトについて
Missileスクリプトの特徴として、変数の型宣言が必要ないことが挙げられます。
変数の型は、実行時に決まります。
JavaScriptなどと同じ、実行時型付けの言語です。
型が実行時に決まるので、上のような記述も出来ます。
この場合、プログラムの実行後に変数aは"4.5hoge"になります。
変数の型は、実行時に決まります。
JavaScriptなどと同じ、実行時型付けの言語です。
main()
{
a = 3; // 3が整数なので、aは整数型になるが、
a *= 1.5; // ここで実数型になり
a += "hoge"; // ここで文字型になる。
}
型が実行時に決まるので、上のような記述も出来ます。
この場合、プログラムの実行後に変数aは"4.5hoge"になります。
Missileスクリプトについて
スクリプトの言語仕様は超簡単です。
新たに覚えなくてはならないことは少ないです。
言語仕様を無理やり一言で説明すると、
C言語から、変数定義とポインタと配列と構造体をとっぱらったのがMissileスクリプトです。
それじゃあ、機能が少なすぎて不便なんじゃないかと思われるかもしれませんが、大丈夫です。
無くても大丈夫なように考慮しました。
ポインタとか配列は、バグを作り込んでしまいがちな部分です。
MissileスクリプトエンジンにSTGに特化した機能を盛り込むことにより、ポインタや配列といった
難しい要素を使わずとも、ゲームを作れるようにすることを目標にしています。
まったくゲームプログラミングとは関係ありませんが、下がスクリプトのサンプルです。
再帰呼び出しで、nの階乗を計算します。
CとかJavaをやったことある人なら、何も説明要らないのが分かると思います。
新たに覚えなくてはならないことは少ないです。
言語仕様を無理やり一言で説明すると、
C言語から、変数定義とポインタと配列と構造体をとっぱらったのがMissileスクリプトです。
それじゃあ、機能が少なすぎて不便なんじゃないかと思われるかもしれませんが、大丈夫です。
無くても大丈夫なように考慮しました。
ポインタとか配列は、バグを作り込んでしまいがちな部分です。
MissileスクリプトエンジンにSTGに特化した機能を盛り込むことにより、ポインタや配列といった
難しい要素を使わずとも、ゲームを作れるようにすることを目標にしています。
まったくゲームプログラミングとは関係ありませんが、下がスクリプトのサンプルです。
再帰呼び出しで、nの階乗を計算します。
main()
{
ans = fact(5);
}
fact(n)
{
if (n == 0)
{
return 1;
}
else
{
return fact(n - 1) * n;
}
}
CとかJavaをやったことある人なら、何も説明要らないのが分かると思います。
2007年11月12日月曜日
METAL BREAKER(仮)について
名前でぴんと来る人もいるかもしれませんが、このソフトはTAITOが1991年に出したMetal Blackという横STGがその大本となっています。
元々シナリオ担当だったoukaさんと話しているときにMetal Blackの世界観、又そこへのリスペクトを込めてタイトルに冠し、シナリオもそれに沿った物になっています。
(とは言っても、シナリオに関してはだいぶ改変されているので言わなければ気づかない、っていう程度の残骸しか残らないかもしれませんが。)
この大まかなシナリオ、世界観に関してはoukaさんが決めたのですが結局文書化ができない、ということなのでその後私が受け持ち、今練り直している最中、ということです。
また、システムにも似ている部分も多々あります。
これはもちろん意図的に似せているのですが。
ですが、その大筋などは大幅に異なる事となると思います。
システムに関しても向こうはストイックな横STG、こっちは弾幕縦STG。
その時点でも変えざるを得ない、というか変えた方が面白い部分が多数有るので。
シナリオに関してはソフトに発表前に有る程度は出す予定です。
ただし、その全てを出すことはおそらくできないでしょう。
私たちが変更したBREAKERの表す意味。
そこを感じてくれれば幸いです。
元々シナリオ担当だったoukaさんと話しているときにMetal Blackの世界観、又そこへのリスペクトを込めてタイトルに冠し、シナリオもそれに沿った物になっています。
(とは言っても、シナリオに関してはだいぶ改変されているので言わなければ気づかない、っていう程度の残骸しか残らないかもしれませんが。)
この大まかなシナリオ、世界観に関してはoukaさんが決めたのですが結局文書化ができない、ということなのでその後私が受け持ち、今練り直している最中、ということです。
また、システムにも似ている部分も多々あります。
これはもちろん意図的に似せているのですが。
ですが、その大筋などは大幅に異なる事となると思います。
システムに関しても向こうはストイックな横STG、こっちは弾幕縦STG。
その時点でも変えざるを得ない、というか変えた方が面白い部分が多数有るので。
シナリオに関してはソフトに発表前に有る程度は出す予定です。
ただし、その全てを出すことはおそらくできないでしょう。
私たちが変更したBREAKERの表す意味。
そこを感じてくれれば幸いです。
2007年11月11日日曜日
STG製作用ツールについて
STG製作用ツールはどんなものが存在しているのかを調べてみました。
Shooting Builder
http://maglog.jp/sb/
SB.wiki
http://www.erc-j.com/sb/
foret
http://www.geocities.jp/flashnetmovie/foretforet.html
シューティングツクール95
http://www.enterbrain.co.jp/digifami/products/stg95v/index.html
ちゃんと中身まで見たわけでは無いですが、Shooting Builderはかなり良さそうな感じですね。
foretは公式サイトが消えてる?
シューティングツクール95は昔、持ってて使ったことがあります。
今となってみると、仕様の古さは否めない感じです。
あの頃から10年経ってるわけかw
上で上げた3つは、GUIでパラメタをポチポチ設定すればSTGが作れる感じっぽいです。
今私が作ってるSTGのエンジンは、スクリプト言語で駆動するのが基本なので、上の3つとは方向性がちょっと違うのですが、やりたいことは一緒なので参考になりそうです。
STGを作ることが目的であって、STG製作ツールを作ることが目的ではないので、ツールとして作り込むことはほどほどにするつもりです。
でも、ほぼ全体をスクリプトで記述するのだから、GUIで設定するツールでは実現できないような表現力は持たせたいところです。
Shooting Builder
http://maglog.jp/sb/
SB.wiki
http://www.erc-j.com/sb/
foret
http://www.geocities.jp/flashnetmovie/foretforet.html
シューティングツクール95
http://www.enterbrain.co.jp/digifami/products/stg95v/index.html
ちゃんと中身まで見たわけでは無いですが、Shooting Builderはかなり良さそうな感じですね。
foretは公式サイトが消えてる?
シューティングツクール95は昔、持ってて使ったことがあります。
今となってみると、仕様の古さは否めない感じです。
あの頃から10年経ってるわけかw
上で上げた3つは、GUIでパラメタをポチポチ設定すればSTGが作れる感じっぽいです。
今私が作ってるSTGのエンジンは、スクリプト言語で駆動するのが基本なので、上の3つとは方向性がちょっと違うのですが、やりたいことは一緒なので参考になりそうです。
STGを作ることが目的であって、STG製作ツールを作ることが目的ではないので、ツールとして作り込むことはほどほどにするつもりです。
でも、ほぼ全体をスクリプトで記述するのだから、GUIで設定するツールでは実現できないような表現力は持たせたいところです。
2007年11月6日火曜日
Staff blogスタートです
とりあえず始まりました。
えーこのページではスタッフが日頃どんな作業をしている、妄想をしている、堕落をしているかをお伝えしていくページです。
現状伝えられる部分と、伝えられない部分、その両方があると思いますがそれは追々…。
えーこのページではスタッフが日頃どんな作業をしている、妄想をしている、堕落をしているかをお伝えしていくページです。
現状伝えられる部分と、伝えられない部分、その両方があると思いますがそれは追々…。