4.プログラミングアーキテクチャ

4.1この章の概要

この章では、より専門的な方向からメトセライズデストラクタを分析します。

 

スポンサーリンク

4.2開発環境

開発に使用した言語を次に示します。

クライアント:ActionScript3

サーバ:Perl

ツール作成:C++(MFC)

 

開発に使用したツールを次に示します。

クライアント:Flex3.0(無料)

サーバ:ActivePerl(無料)

ツール作成:VisualC++ExpressEdition(無料)

エディタ:Sakuraエディタ(無料)

 

クライアントとは、ゲーム本体のことです。

クライアントはブラウザ上のFlashで動作しています。

Flashをプログラミングで作成するために使うのがFlex3.0に入っているActionScript3です。

ActionScript3JavaScriptライクな関数型言語で、簡単にBitmapやネットワークを扱えます。

 

サーバは、文字列処理が主ですので、

正規表現が使えて安定しているPerlを使っています。

サーバ内の通信はUDPを用いています。

 

ツールとなるマップエディタはVisualC++で作成しました。

これは、高校2年の時にADVERITASUNICAというゲームのマップを作るために作ったGUIツールで、

RUINATERRAATULADOとバージョンアップしながら使ってきたツールをさらに拡張し、使用しています。

4.3全体アーキテクチャ

全体のブロック図を次に示します。

メトセライズデストラクタではデータとプログラムを分離しています。

マップや敵のパラメータ等は、コンパイル無しで調整できます。

また、独自のスクリプト言語を導入しており、

敵の行動パターンやイベントを、プログラミング無しで作成できます。

各項目の詳細は後述します。

4.4ネットワークアーキテクチャ

メトセライズデストラクタではP2Pに近いクライアント/サーバモデルを採用しています。

プレイヤの操作などは全てサーバに送信され、サーバを通じて全プレイヤに配信されます。

処理は基本的にクライアントが行いますが、データの管理および送信は全てサーバが行います。

ここで、各PCをクライアントと呼びます。

 

サーバはエイバースのサーバです。

具体的に、Core2duoIntel Mac、一台で全て処理をしています。

ちなみに、オンラインRPGをサービスする場合、自宅サーバがオススメです。

既にインターネットに接続している場合は、固定IPが月1000円、24時間動かしても電気代が月1500円程度でOK。

好き勝手にサービスを作れる上、その経験は将来何倍にもなって返ってくるでしょう。

OSLinuxMacOSXがいいです。

WindowsXPは同時接続できるソケット数に制限がある上、ファイルアクセスが遅いです。

 

クライアントPCとサーバ間は一般にTCPで通信を行いますが、

メトセライズデストラクタは、元々JavaScriptで設計していたため、HTTPを用いています。

HTTPは、ブラウザからサーバにWEBページを要求する標準的なプロトコルです。

 

クライアントからサーバにデータを要求するには次に示す関数を使います。

例えばrequestFile(“send text”,”http://www.abars.biz/receive.cgi”,callbackfunc)とすることで、

”send text”という送信データをサーバのcgiに送り、

サーバからの返却データをcallbackfuncで受信することができます。

 

              function requestFile( data , url_text, func)

              {

                            var urlRequest:URLRequest = new URLRequest(url_text);

                            var urlLoader:URLLoader = new URLLoader();

                            urlLoader.addEventListener(Event.COMPLETE,func);

                            urlLoader.addEventListener(IOErrorEvent.IO_ERROR,ajax_error);

                            urlRequest.contentType = "application/octet-stream";

                            if(!data){

                                          urlRequest.method = URLRequestMethod.GET;

                            }else{

                                          urlRequest.method = URLRequestMethod.POST;

                                          urlRequest.data = data;

                            }

                            urlLoader.load(urlRequest);

              }

 

コールバック関数は次のように記述します。

retにサーバから返却されたデータが入っています。

 

function callback(event:Event){

           var ret=event.target.data;

    }

 

サーバのcgiは次のように書きます。

この例では$bufferにクライアントからの送信データが入り、

”ret”がクライアントへの返却データになります。

 

#!/usr/bin/perl

 

#ヘッダ出力

print "Content-type: text/html\n\n";

 

#クライアントからのデータ

if ($ENV{'REQUEST_METHOD'} eq "POST") {

              read(STDIN, $buffer, $ENV{'CONTENT_LENGTH'});

}else{

              $buffer = $ENV{'QUERY_STRING'};

}

 

#クライアントに返却するデータ

print “ret”;

 

HTTPではサーバからクライアントへのデータの送信は、

クライアントがサーバに要求した場合しか出来ません。

そのため、データが更新されていないかどうか、

クライアントがサーバに定期的に問い合わせます。

これをポーリングといいます。

 

4.5プレイヤアーキテクチャ

メトセライズデストラクタでは、処理は自プレイヤについてのみ行い、

他プレイヤは表示するだけという仕組みを取っています。

 

具体的に、1秒に一回、自プレイヤの位置や状態をサーバに送り、同時に他プレイヤの状態を取得します。

画面では、1秒かけて、前回の他プレイヤの情報から今回の他プレイヤの情報へと遷移させます。

 

例えば、前回の他プレイヤの位置が(x,y)=(0,0)だったとして、

今回の他プレイヤの位置が(x,y)=(2,0)だった場合、

1秒かけて位置を(x,y)=(2,0)へと移動させます。

 

また、HP10から6に減少していた場合、

4ダメージを受けたというエフェクトを表示し、HPを減少させます。

 

具体的に、プレイヤがサーバに送信する情報を次に示します。

 

プレイヤのユニーク番号:プレイヤを識別する一意の番号(ログイン中のプレイヤ0127

位置:プレイヤの位置を情報(x,y)

向き:プレイヤの向き(vec_x,vec_y)

LV:プレイヤのLV

MHP:プレイヤの最大HP

HP:プレイヤのHP

モード:ジャンプ中、攻撃中(攻撃パターン番号)、魔法中(魔法番号)

攻撃ターゲットのユニーク番号:攻撃対象の敵を識別する一意の番号

装備の番号:現在装備している武器の番号

マップ番号:現在いるマップの番号

回復を行ったHP量/MP量:他プレイヤへの回復の伝播用

名前:プレイヤの名前

ユニークID:プレイヤを識別する一意の番号(全ユーザで一意)

チャット発言:今の発言内容

 

モードが魔法中だった場合は攻撃ターゲットに対して1秒間魔法を発射します。

チャット発言が変更された場合、画面に発言を表示します。

 

4.6エネミーアーキテクチャ

敵は全てサーバで管理します。

サーバで管理する情報を次に示します。

 

敵の存在:この敵が存在するか

敵の位置:この敵の位置

敵のHP:この敵のHP

敵の種類:スライムか、バットか、アクリスか等

敵のマップ位置:この敵が出現した位置

敵が倒された後のカウント:一定時間後に同じ敵が出現できるようにする

 

サーバでは1秒に一回、現在のプレイヤの周辺にいる敵の数を計算し、

最も少ないプレイヤの周囲のマップを探索し、

敵が存在する場合は出現させるという操作を繰り返します。

ただし、街の人やボスの場合は、最も少ないプレイヤで無くても出現させます。

その後、存在する全ての敵の位置を、敵の種類に応じて適切に移動させます。

 

サーバからクライアントへは、1秒に一回、全ての敵の情報を送信します。

ただしクライアントは、位置がプレイヤから一定以上遠い敵については、処理をしません。

 

クライアントが敵に攻撃をした場合、サーバに、

どの敵にどれだけのダメージを与えたかを送信します。

ただし、毎回送信すると負荷が大きくなるので、1秒間に与えたダメージの合計を送信します。

サーバは、受け取ったダメージ分を減算し、0以下の場合は一定時間後に消滅させます。

一定時間というのは、クライアントに、倒したのか、消えたのかを判断させるために必要です。

 

敵からの攻撃は、各クライアントが個別に行います。

つまり、敵からの攻撃はネットワークで同期をしません。

これはサーバの負荷を抑えるためで、ドリームキャストのPSOもこの方式になっています。

 

4.7サーバの実装

サーバは、プレイヤから受け取った情報をまとめる役割をします。

具体的に、クライアントからCGIに送信されたプレイヤ情報をサーバプロセスが受け取り、

全プレイヤ分の情報を一つのテキストファイルに書き出します。

クライアントは定期的に取得CGIにアクセスし、このファイルから全プレイヤの情報を取得します。

メトセライズデストラクタではサーバプロセスはPerlで記述しており、

1つの常駐プログラムとなっています。CGIからサーバプロセスへは、UDPで通信しています。

 

CGIからサーバプロセスへUDPでデータを送信するプログラムを次に示します。

この例では、ポート50000$sendを送信します。

#UDPで伝送

$udpSock = IO::Socket::INET->new(

Proto    => "udp",

PeerAddr => "localhost",

PeerPort => 50000,

);

 

#UDPが開けない

if(!$udpSock){

              exit;

}

 

#送信

print $udpSock "$send\n";

$udpSock->flush();

$udpSock->close();

 

常駐プロセスでのソケットの初期化は起動時に一度行います。

$udpSock2 = IO::Socket::INET->new(

     Proto     => "udp",

     LocalPort => 50000,

     Reuse     => 1,

);

$udpSel2 = IO::Select->new;

$udpSel2->add($udpSock2);

 

メインループでのデータ受信を次に示します。

              $received=1;

              while($received==1){

                            $received=0;

                            if(IO::Select->select($udpSel2, undef, undef, 0)) {

                                          $received=1;

                                          #576Byteまでは保障

                                          $line=<$udpSock2>;

                                          chomp $line;

                                          #受信データを配列に格納

                                          @pairs1 = split(/## ##/, $line);

                                          $i=int $pairs1[0];

                                          $player_data[$i]=$pairs1[1];

                                          @pairs2 = split(/# #/, $pairs1[1]);

                                          $player_x[$i]=int $pairs2[1];

                                          $player_y[$i]=int $pairs2[2];

                                          $player_name[$i]=$pairs2[16];

                                          $player_time[$i]=time;

                            }

              }

 

こうして取得したデータを、一つのファイルに書き出します。

敵への攻撃も同様に、cgiで攻撃したという情報を受け取り、

UDPで常駐プロセスへ送信、敵のHPの配列から減算します。

また、敵をプレイヤに向けて移動させ、

現在の全ての敵の位置をファイルに書き出し、クライアントがCGIから取得します。

 

4.8アイテムアーキテクチャ

ネットワーク共有アイテムは非同期で実装しています。

サーバには次のcgiが存在しています。

 

List:アイテムのリストを取得する。

Set:アイテムを配置する。

Get:アイテムを取得する。

Time:アイテムの更新時間を取得する。

 

アイテムのリストは次のようになっています。

(アイテム1X位置、Y位置、アイテムの種類、強化値、配置した時間

(アイテム2)繰り返し

 

プレイヤは5秒ごとに更新時間を取得し、更新されていた場合はアイテムのリストを取得します。

アイテムを取得する場合は、欲しいアイテムを取得するリクエストを出します。

既に誰かが取得していた場合は、取得できなかったメッセージを返信します。

アイテムを配置する場合は、配置するリクエストを出します。

リクエストを出した後、プレイヤのアイテムを一時的に消去しますが、配置に失敗した場合は、復元します。

 

4.9マップエディタ

ゲームのマップデータは独自開発のエディタで作成します。

このエディタでは、壁やトラップの配置、各マップチップのスクリプトを設定できます。

スクリプトでは、このマップチップの上にキャラクターが来た場合、どのような処理を実行するかを設定できます。

スクリプトについては後述します。

マップエディタはVisualC++MFCで開発しましたが、

今ならVisualC# ExpressEdittion.NET Frameworkがオススメです。

無料で手軽に開発できます。

 

マップエディタで保存をすると、

(X座標,Y座標,マップチップ番号)および(X座標,Y座標,スクリプト)

のフォーマットでテキストに書き出します。

マップのほとんどは何も無いので、存在する場所のみを記述して容量を節約します。

 

ちなみに、マップは500*5001枚の平面で扱っています。

背景や壁のグラフィックはマップ番号に応じて変えています。

 

4.10イベントエディタ

イベントはテキストファイルに記述します。このファイルは次のような構成になっています。

 

--------0--------

イベント0のスクリプト

--------1--------

イベント1のスクリプト

--------2--------

イベント2のスクリプト

 

ゲーム中では、”adv;イベント番号;”というスクリプト命令を実行することで、

これらのイベントを起動しています。スクリプトはマップ移動等のスクリプトと共通です。

詳細はマップ/イベントスクリプトで解説します。

 

このように、イベントをプログラムから分離することで、

コンパイル無しでイベントの編集が可能になります。

また、プログラマでない人にもイベントの編集が可能になります。

 

4.11エネミーエディタ

敵データはExcelで管理します。Excelcsvファイルを書き出すと、

カンマと改行で区切られたテキストを取得できます。

これをperl等のスクリプトでパース(切り出し)することで、ゲームで使用できるデータに変換します。

 

具体的に、敵1体に対応するパラメータを次に示します。

メトセライズデストラクタでは街の人も敵として管理しています。

 

名前:敵の名前

エネミースクリプト:敵の攻撃パターン

お金:敵を倒した時に取得できる金額

画像:敵の画像ファイル名

属性:敵の属性

移動タイプ:歩き、浮遊、等。サーバ位置に補正する。

サイズ:敵の描画サイズ

HP:敵のHP

MP:敵のMP

攻撃:敵の物理攻撃力

防御:敵の物理防御力

魔法攻撃:敵の魔法攻撃力

魔法防御:敵の魔法防御力

移動スピード:敵の移動スピード

描画x:敵を描画する時のx方向シフト、画像によって足の位置が違うため

描画y:敵を描画する時のy方向シフト

重さ:敵の吹っ飛びやすさ

半径:敵に攻撃の当たる範囲

攻撃セリフ:攻撃時のセリフ

ダメージセリフ:ダメージ時のセリフ

倒れセリフ:倒した時のセリフ

倒しSE:倒した時の効果音ファイル名

倒しSeボリューム:倒した時の効果音のボリューム

会話スクリプト:街の人に話した時に実行するスクリプト

 

敵のゲームバランスについては、修正しては遊び、

修正しては遊びを繰り返す以外に方法はありません。

気合です。

敵の攻撃パターンはエネミースクリプトで記述します。

エネミースクリプトについては後述します。

 

敵の移動は基本的にサーバで行いますが、そのままですと、

プレイヤの動きと時間差がありますので、

プレイヤを追随したり、離れるなどの細かな動きができません。

 

そこで、移動タイプに応じて、サーバ上の位置からある程度の半径内で、自由に動かしています。

他プレイヤと同期は取れませんが、おおまかな位置は合っていますので、

そこまでの違和感は出ないと考えています。

 

PSOでも、マップ中の小さな部屋内での敵の位置は各プレイヤで異なっており、

違和感を無くすために各部屋は小さく設定されています。

 

4.12アイテムエディタ

アイテムも敵と同様に、エクセルで管理します。

 

 

編集可能な項目を次に示します。

名前:アイテムの名前

価格:アイテムの価格

確率:アイテムの出現確率。任意の整数値

種類:アイテムの種類。HP回復アイテム、MP回復アイテム、武器、頭防具、体防具等

属性:アイテムの属性

効用:回復アイテムの回復値

必要スキル:そのアイテムを装備するのに必要なスキル

HP、MP、剣攻撃、銃攻撃、格闘、防御、魔攻、魔防:装備することで上昇する値

色:装備品の色

ダンジョン16:各ダンジョンでこのアイテムが出現するかどうか

紹介文:アイテムを選択した際に表示するテキスト

 

アイテムの出現確率は任意の整数となっています。

出現アイテムを決定する場合は、0〜全(アイテムの出現確率の合計-1)の乱数を生成し、

0から順アイテムの出現確率を加算していき、乱数値を超えない点のアイテムを出現させます。

 

アイテムの価格は、出現確率に応じて設定します。売却時の価格は1/5になります。

 

アイテムの強さは、確率が低いほど大きく設定しています。

ただし、全てが最強の装備はできるだけ作らず、

剣攻撃が最強であれば、魔攻はマイナス値を持つなど、

選択の余地を残すようにしています。

 

4.13魔法エディタ

魔法もアイテムと同様に、エクセルで管理します。

細かな動きはハードコーディングしています。

 

 

編集可能な項目を次に示します。

名前:魔法の名前。

消費MP:魔法を使った際に消費するMP。

属性:魔法の属性。

魔力反映度:ダメージ決定に使用する倍数。

絶対補正:ダメージ決定に使用する加算値。

敵魔力反映度:敵の魔力反映度。

敵絶対補正:敵の絶対補正値。

弾数:一度に射出する弾数。

スピード:弾の速度。

色:弾の色。

持続時間:弾が消えるまでのフレーム数。

当たったら消えるか:弾が敵に当たった場合に画面から消えるかどうかのフラグ。

判定範囲:弾の当り判定範囲。

初期判定の存在:弾に当り判定があるか。回復魔法はなし。

壁に当たったときに消えるか:弾が壁に衝突した場合に画面から消えるかどうかのフラグ。

合成に必要な魔石の数:合成に各魔石がいくつ必要か。

効果音:発射時に再生する効果音のファイル名。

紹介文:合成時に表示するテキスト。

 

魔法の攻撃力は、魔法攻撃力*魔力反映度+絶対補正値、で計算しています。

魔法のバランスは、基本的に、(魔法の攻撃力*弾数)/消費MP、が一定になるように調整しています。

ただし、一度に与えるダメージが大きな魔法は敵を早く倒せます。

従って、ダメージの大きな魔法や、弾数の多い魔法ほど、スキルを上げる効率がよいことになります。

そこで、これらを加味し、ダメージおよび弾数に応じて、消費MPを補正しています。

 

4.14マップ/イベントスクリプト

メトセライズデストラクタでは、マップ/イベントスクリプトと、

エネミースクリプトの二種類があります。

 

マップ/イベントスクリプトでは、プレイヤーの発言、プレイヤーの位置、他のキャラクターの設定、

他のキャラクターの移動、壁を調べた時の動作、等の記述ができます。

 

エネミースクリプトでは、HPに応じた敵の攻撃パターンの設定ができます。

 

マップ/イベントスクリプトは、各行を実行していくインタプリタ言語となっています。

具体的に、スクリプトの文字列をセミコロンで分割し、

現在実行している命令の位置を示すプログラムカウンタを動かしながら、

随時実行していきます。

 

改行は無視されます。

また、アスタリスクでラベルを定義でき、簡単な条件分岐を行えます。

スクリプトのサンプルを次に示します。

 

兵長「ルシ…ア…様…;結界…が…;仇…を…;ぐふっ」;delete;127;52;

この場合、文字を表示した後、delete命令によってキャラクターを消去しています。

 

また、プログラム中から直接スクリプトを実行することもでき、

例えばゲームオーバ時は、ゲーム中から”town;”というスクリプトを実行します。

 

マップ/イベントスクリプトの命令リファレンスを次に示します。

種類

命令

記述例

動作

イベント命令

SAY

say;こんにちは;

画面に発言を表示します。よく使うので、sayは省略可能にしています。

SHOP

shop;1;2;0;0;0;買いなされ;

アイテムショップに入ります。番号は商品とするアイテムの番号となります。

INN

inn;旅館へようこそ;

旅館に入ります。

MAGIC

magic;魔法を作りますか?;

魔法屋に入ります。

BUILDUP

magic;鍛えますか?;

アイテム鍛え屋に入ります。

CARE

care;

回復します。

制御命令

IF

if;1;*a;2;*b;endif;

進行度カウンタに応じて条件分岐をします。進行度カウンタは、現在のゲームの進行度です。この場合、進行度カウンタが1の場合は*aへ、進行度カウンタが2の場合は*bへ、その他の場合はendifの後へジャンプします。

IFGE

ifge;10;*a;endif;

進行度カウンタに応じて条件分岐をします。この場合、進行度カウンタが10より大きい場合は*aへ、それ以外の場合はendifの後へジャンプします。

SET

set;1;

進行度カウンタに値をセットします。

WAIT

wait;10;

一定時間待ちます。この場合10フレーム待ちます。演出に役立ちます。

REF

ref;1;1;

参照位置のスクリプトを実行します。例えばある場所に行くとイベントが発生する場合、同じスクリプトを書くのは無駄なので、この命令によって一つのスクリプトを流用します。引数はマップ位置です。

REM

ref;コメント;

コメントを記述します。コメントは実行されません。イベント記述時のメモ書きに使います。

マップ制御

DELETE

delete;47;64;

マップを消去します。スクリプトも消去されます。引数はマップの座標です。壁や決壊を壊したりする時に使います。

WRITE

write;10;10;1;

マップに値を代入します。引数はマップの座標とマップチップの番号です。

GOTO

goto;29;47;2;B1;

プレイヤーを移動させます。かなり使用頻度の高い命令です。フィールドからマップへの移動、ワープをクリックした時の移動、全てこの命令です。引数はマップ座標、マップ番号、階です。

GOTOIN

goto;n;29;47;

同じマップ内でプレイヤーを移動させます。マップ番号と階を指定しなくていいので手軽です。階はnを指定すると同じ階、dを指定すると一つ下、uを指定すると一つ上になります。残りの2引数はマップ座標です。

TOWN

town;

街に移動します。

FIELD

field;

フィールドに移動します。

ADV

adv;1;

イベントを実行します。この場合、adv.txtのイベント1が起動します。

TREASURE

treasure;

アイテムを発生させます。宝箱にこのスクリプトを埋め込みます。

ENEMYKILLCNTRESET

enemykillcntreset;

敵の倒し数カウントを0クリアします。一定数倒さないと先に進めないマップで使います。

FORCESCROLL

forcescroll;0.5;

強制スクロール速度を設定します。教団の強制スクロールマップ用です。

JUMP

 

jump;10;5;

主人公の位置をエフェクト無しで設定します。教団の飛竜マップのジャンプ用です。

エフェクト

SHAKE

shake;

画面を揺らします。イベントの演出に欠かせません。

FILL

fill;#000000;

画面の背景色を決定します。nofillと組み合わせて画面フラッシュのエフェクトに使います。

NOFILL 

 

nofill;

画面の背景色を透明にします。

PICTURE

 

picture;a.jpg;

picture;none;

背景絵を変更します。Noneに設定すると瞬時に背景絵をキャンセルします。black.jpgに設定するとフェードアウトエフェクトとしても使用可能です。

TELOP

telop;1;

文字の表示をメッセージボックスでは無くテロップ表示にします。0にするとテロップ表示を終了します。天の声や語りに便利です。

THUNDER

thunder;1;

天候を雷雨に設定します。オープニングの雷雲の森で使っています。

アクター制御

MOVE

move;0;0;

プレイヤーを指定したマップ座標に移動させます。

MOVEWAIT 

 

movewait;

プレイヤーおよびアクターの移動完了まで待機します。

ACTORSET

actorset;no;xpos;ypos;imgname;name;

アクターを登録します。登録したアクターは以降の命令で使用できます。登録すると同時に画面に表示されます。

ACTORMOVE

actorset;no;xmove;ymove;movev;

アクターを移動します。移動量は今の位置からの差分です。最後の引数は移動速度になります。

ACTOROUT

actorout;no;

アクターを削除します。即座に画面から消えます。

ACTORFLASH

Actorflash;no;

アクターを点滅させます。アクターがダメージを受けて倒れる演出に使います。

ACTORATTACKEFFECT

actorattackeffect;no;addx;addy;

 

アクターに攻撃エフェクトを加えます。addxaddyは描画位置に加算するオフセットです。

ACTORZOOM

actorzoom;no;zoomsizemult;

アクターをズームインします。zoomsizemultから1に収束していきます。森でのワイバーンの登場シーンに使用しています。

ACTORYADD

actoryadd;no;addy;

アクターの描画位置をY方向にシフトします。三賢者が吹き飛ぶ場合や、浮いたキャラを表現する時に使用しています。

音声制御

BGM

Bgm;mp3name;

 

BGMを再生します。ファイル名を空白にすることで再生を停止します。

BGMHTL 

bgmhtl;headmp3name;loopmp3name;

ヘッダ音楽を再生後、ループ音楽をループ再生します。曲の開始時にのみ特別な音楽が入る場合に使用します。危機系のイベント曲で使用しています。

SE

se;mp3name;

効果音を鳴らします。

ENV

env;mp3name;

環境音をループします。雨で使用しています。

BGMVOL

bgmvol;0.5;

BGMのボリュームを変更します。イベント中は音量を抑えて、バトルに入る直前に音量を上げるともりあがります。

トラップ

DAMAGE 

damage;percent;

プレイヤーにダメージを与えます。蜃気楼の塔のトラップ用です。

 


オープニングのスクリプト例です。

TELOP命令でノベルのような表示を実現しています。

rem;オープニング;

debugpos;0;0;0;

fill;#000000;

wait;10;

telop;1;

bgm;img48.mp3;

遥かな過去か、遥かな未来。\n

赤い月と星が瞬くこの地には二つの大国があった。;

picture;monsyou_majyutu.jpg;

一つは魔術を力とする魔術院。;

picture;monsyou_souma.jpg;

一つは操魔を力とする操魔教団。;

picture;fadeout.jpg;

力在る所に争いが生じるのは必然。\n

ただ終わりなき戦乱のみが、そこに在った。;

picture;none;

 


イベント中のキャラクターはアクターで制御します。

オープニングのセクレのシーンでは、

セクレというアクターをセットし、このアクターにカメラを合わせています。

 

アクターはactormove命令で自在に動かす事ができ、

movewait命令で指定位置に動き終わるまで待機することができます。

アクターは最大32体まで設定できます。

rem;夜の雨森;

fill;#000000;

fill;#ffff00;

se;thunder.mp3;

fill;#000000;

goto;30;5;2;0;

actorset;1;30;5;3;secre.gif;セクレ;

actormove;1;16;0;0.4;

actorwalking;1;

actorcameraon;1;

thunder;1;

nofill;

env;rain.mp3;

movewait;

actorwalking;0;

セクレ「はぁ…はぁ…\n

 そんな…;

 アベル…;

 こんなネックレス…何よ!\n

 神なんて…神なんて!」;

 

4.15エネミースクリプト

エネミースクリプトでは、敵の動きを制御できます。

スライムの例を次に示します。

 

if;near;begin;attack;wait;10;end;

 

この場合、プレイヤが近くにいると、攻撃をして10フレーム待機します。

 

次に、スクリプトの命令リファレンスを示します。

 

種類

命令

記述例

動作

基本命令

ATTACK

attack;

基本攻撃を行います。

NOTICE

notice;

攻撃予告を行います。セクレの魔法前の振動等に使用しています。

WAIT

wait;10;

一定フレーム数待機します。魔法間隔の調整等に使用します。

GONEAR

gonear;

プレイヤに近づきます。

MAGIC

magic;1;

魔法を使います。数字は魔法番号です。40で銃になります。

JUMP

jump;

後方にジャンプします。ノアが使用します。

FRONTJUMP

frontjump

前方にジャンプします。カイルが使用します。

FLY

fly;

飛行モードへ移行します。ノアが使用します。

NOFLY  

 

nofly;

飛行モードを終了します。ノアが使用します。

MOVETYPE 

movetype;0;

この種類の敵のローカルでの移動方法を変更します。ガレスが積極的に近づいてきたり、離れたりするのはこれを使用しています。

MREVERSE

mreverse;30;

一定時間魔法を反射します。ガレスが使用します。魔法優位のバランスを調整するために使用しています。

制御命令

IF

if;hplow;begin;処理;end;

 

条件を満足する場合に指定した文を実行します。条件に使える項目を次に示します。

 

near:プレイヤーとの距離が1.5以下

hphighHP70%以上

hpmidHP40%〜70

hplowHP40%以下

hpnotlowHP40%以上

rand1001/100の確率で条件を満たす

rand301/30の確率で条件を満たす

rand101/10の確率で条件を満たす

IFNOT

ifnot;hplow;begin;処理;end;

条件を満足しない場合に指定した文を実行します。

構造命令

LOOPBEGIN

loopbegin;loopn;

ループを開始します。ネストはできません。

LOOPEND

loopend;

ループを終了し、回数が残っている場合はLOOPBEGINに戻ります。

 

 

カドモニコアの攻撃パターンは、このようにやや複雑になります。

if;hpnotlow;begin;attack;loopbegin;20;magic;1;wait;1;loopend;wait;50;loopbegin;20;

magic;6;wait;1;loopend;wait;50;end;if;hplow;begin;loopbegin;20;magic;5;wait;1;loopend;end;

 

4.16この章のオススメ書籍

ゲームアーキテクチャ系の書籍はあまりありません。あえて挙げるならばgemsでしょうか。

データ分離設計も紹介されています。

ActionScriptについてはこちらがオススメです。

 

次の章へ

面白さのプログラミング