スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。

外部ファイルで、実行ファイルの動作を自在に変更するシステムを作ってみた!

苦節 2週間。 (短いな)

とりあえず、外部ファイルで
実行ファイルの動作を完全に書き換えるシステム
を作ってみました。
(DXライブラリ、C++で実装。)


今年は、開発に必要なシステムや技術を、
どんどん実装したい、とか思ってます。頑張ります。
(「こうしたいなー」とかではなく、実現させて形にする。


【要約】
・SampleGame.exe
・MyArchive.arc


必要なのは上記2つ。

実行ファイルは、MyArchive.arcの中身を解析して実行するようになっており、
MyArchive.arcを書き換えれば、
SampleGame.exeを実行した際の動作がガラリと変える事が出来る
という仕様になっております。

極端な話、
SampleGame.exeを実行したら"ぷよぷよ"みたいなパズルゲームだったのに、
MyArchive.arcを別のものに差し替えたら、アクションゲームに変貌
した、
という事も出来るのです。


まだ簡易版なので、様々なゲームには対応出来ないと思いますが、
ひとまず、実装方法のご紹介。


~やり方~
----------------------------------------------------
【1】命令と引数がセットの構造体を作る
【2】構造体の配列を作る
【3】命令をswitchで場合分けし、引数を各関数に渡して処理

----------------------------------------------------
これだけ。意外と単純です。


//色んな型に対応できる共用体
union ParamInfo {
int m_Int;
float m_Float;
double m_Double;
DWORD m_Dword;
};

//命令を示す列挙体
enum CommandID {
CMD_GET_POSX,//描画オブジェクトのX座標取得
CMD_GET_POSY,//描画オブジェクトのY座標取得
CMD_GET_POSZ,//描画オブジェクトのZ座標取得
CMD_IF_I, //int型同士のif判定をさせる
CMD_CHANGE_INIT, //命令配列の、何番目の命令から実行するかを変更
CMD_FINISH, //1フレーム毎の処理終了を示す
CMD_END //命令を終了する。
};

//命令と、引数(共用体)の構造体
struct CommandInfo {
CommandID m_Command;
std::vector< ParamInfo > m_ParamVec;
};


class CMover {
public:
CMover();
~CMover();
MoveStateID Move();
private:
std::vector< CommandInfo > m_CommandVec; //命令の配列。
int m_InitVecNum; //何番目の命令から実行するか?(初期値は0。)
int m_NowVecNum; //現在の命令配列の添え字
MoveStateID m_MoveState;
};

MoveStateID CMover::Move()
{
//命令配列の何番目から実行するかをセット
m_NowVecNum = m_InitVecNum;

//1フレームの終了命令 と CMoverクラス自体の破棄命令ではなく、
//かつCMoverクラスが有効である場合は ループ。
while( m_CommandVec[ m_NowVecNum ].m_CommandID != CMD_FINISH &&
m_CommandVec[ m_NowVecNum ].m_CommandID != CMD_END && m_MoverState == MOVE_NOW ){
switch( m_CommandVec[ m_NowVecNum ].m_CommandID ){
case CMD_GET_POSX: GetPosX(); break;
case CMD_IF_I: CompInt(); break;
case CMD_CHANGE_INIT: m_InitVecNum = m_CommandVec[ m_NowVecNum ].m_ParamVec[ 0 ].m_Int;
case CMD_FINISH: break;
case CMD_END: m_MoverState = MOVE_FINISH; break;
default: m_MoverState = MOVE_ERROR; break;
}
}
return( m_MoveState );
}



色々と省略してますが、
上記の様な感じです。


命令番号は上記の例と一致してませんが、
読み込ませるアーカイブファイルは下記のフォーマットのようになります。

■描画オブジェクト0番のX座標を、
 5秒(5000ミリ秒)かけて50から180へ動かすサンプル

0 0:CMD_SET_NOW_TIME, 0 //変数[0]に現時刻をセット
1 1:CMD_SET_VALUE_DWORD, 1, 5000 //変数[1]に5000をセット
2 1:CMD_SET_VALUE_DWORD, 2, 50 //変数[2]に50をセット
3 1:CMD_SET_VALUE_DWORD, 3, 180 //変数[3]に180をセット
4 2:CMD_CHANGE_INIT, 5, //命令の初期位置を[5]にする
5 0:CMD_SET_NOW_TIME, 4, //変数[4]に現時刻をセット
6 3:CMD_DIF_DWORD, 5, 4, 0 //引き算。 [4] - [0] = [5] (現時刻 - 開始時刻)
7 8:CMD_IF_DWORD, 5, 2:LARGE, 1, 14, 8 //変数[5]が変数[1]より大きければ命令配列[14]、そうでなけば[8]へ移動 ( if( 経過時間 > 5000 ) )
8 4:CMD_DIV_DWORD, 6, 5, 1 //変数[5]を変数[1]で割る ( 経過時間 / 5000 = 変数[6] )
9 3:CMD_DIF_DWORD, 7, 3, 2 //変数[3] - 変数[2] = 変数[7] ( 180 - 50 = 130 )
10 5:CMD_MULTI_DOUBLE, 8, 7, 6 //変数[7] * 変数[6] = 変数[8] ( 130 * 割合 = 変数[8] )
11 6:CMD_ADD_DWORD, 9, 2, 8 //変数[2] + 変数[8] ( 50 + 変数[8] = 変数[9] )
12 7:CMD_SET_POSX, 0, 9 //変数[9]を、描画オブジェクト0番のX座標にセット
13 9:CMD_FINISH, //1フレームあたりの処理終了
14 7:CMD_SET_POSX, 0, 3 //変数[3]を、描画オブジェクト0番のX座標にセット (Object[0].PosX = 180)
15 10:CMD_END


※ポイント
命令番号[0]~[4]は、初回のループ時のみ実行されます。
(命令番号[4]にて、命令開始初期位置を[5]に変更しているため。)

つまり、コンストラクタのような初期化処理を実装できるのです。


で、見ても分かりますが・・・可読性0です。
これはちょっと、エディタが必要かもしれない。


とりあえず、会社でもポチポチとcsvファイルをいじって開発できるようになったので、
(勝手に会社のPCに visual stdioなどの開発環境をインストールしたりするのはマズいが、
    メモ帳なんかで文字を打つぐらいなら何も言われん。)

多少は開発速度が上がるかもしれない。
どーよ!(`・ω・´)

【課題】
・vectorとか、mapとか、listとかも操作できるようにしたい。
・エディタ作りたい。
スポンサーサイト

テーマ : ゲーム製作 関連 - ジャンル : ゲーム

コメント

No title

スクリプトを作ってる感じですかね・・・?
Luaとかはどうなんでしょうか?

No title

はい、簡易スクリプトを作っています・・・!

Luaはまだ扱ったことが無いので、何とも言えないのですが、
やっぱり導入した方が良いのでしょうかね。。

実際の企業でも導入している所があるようですし、
Luaについて、もう少し調べてみようと思いますv-290
情報ありがとうございますe-76

No title

自分も昔、同じことを考えて実際に俺俺インタプリタを実現しましたが、開発効率が悪すぎる上に、JITがないので速度も思ったように出ず、コンパイラによる静的チェックまで失われるため、実行するまでエラーがわからないなど、まるで使用するメリットがありませんでした。
ただ、ゲームの一部(例えばシナリオ進行等)には、プログラマ以外でも作業ができ、デプロイも容易であるなど、かなりメリットがありました。
*この程度の事であれば、XMLで事足りる事に後々気づきますが(笑)

ので、私としては無理に全体を外部DSL化するよりかはキャラクタ制御やUI制御、シナリオ制御など、
部分的に使用する方が良いと思う次第です。
あと、注意点として俺俺インタプリタを作り出すと、
ゲームを作る目的が、いつの間にかゲームを作るための開発が目的になったりするので、
どっぷりハマらないように注意してください。

No title

アドバイスありがとうございますv-411

本当にそうですね・・・。
最初は全部外部ファイルにしてしまえば、
動作を自在に変えられる、凄い!
と思っていたのですが、

・変数の代入といった処理まで命令化してしまうと、
 外部ファイル作成に時間がかかる
・実行しないと、結果が分からない。
(正しい結果が出たと思えても、実は一部おかしな値が入る様になっていて、後で不具合に気づく場合もあったり)

上記のデメリットが非常にネックになり過ぎて、
「普通にコード打ち込んでった方が速い」という結論に至りました。
("RPGツクール"のようなエディタ(エラーチェック、外部ファイル自動生成)を作れれば、
そこそこの速度が出せるとは思うのですが)

今現在は、
・どの画像を読み込むのか?
・どの音声データを読み込むのか?
・ちょっとしたキーフレームアニメーションの定義
・各ゲームに応じた、データ

(RPGなら、2次元配列のフィールドマップなど)

上記の様な一部のデータのみ、外部ファイル化して
適宜、修正してプログラムの動作に調整を加えている
感じにしています。

ハマり始めると怖いですね。
開発ツール作りに時間をかけて、肝心のゲームはいつまで経っても制作段階にすら入れない
というのは本末転倒ですねv-404

ゲームを継続的に作成しながら、
「こうした方がもっと便利になるんじゃ?」と思える所に
改修を加えていく感じが良いのかなと思いましたv-411
コメントの投稿
管理者にだけ表示を許可する



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。