もはや買い物メモ変わりになってしまっている当ブログですが、たまには技術っぽいエントリも書きたくなるのです。
未だに完成の目処は全く立っていませんが、じわりじわりとDXライブラリでゲーム作りを進めたりしています。
相変わらずライブラリづくりメインですが。
で、
使ってて気づいたり調べたりしたTIPSをメモしておこうと思います。
なんとなく後で見返す気がするので。
DXライブラリ使いまくってる人には不要な内容ですかね。
マルチスレッド化
DXライブラリ使ってて、一度は考えるマルチスレッド化ですが、ググってみてもマトモに成功してる人はあまり見当たらないです。単に成功してても情報公開してないだけかもしれないけど。
DXライブラリはスレッドセーフではないので、なにも考えずにマルチスレッド化するのはよろしくないです。
実際私も時間の掛かる処理だけ別スレッドで動かそうとしてみたのですが、DXライブラリの関数がエラーを返したり返さなかったり不安定な動作をしてくれるのでやめました。
DXライブラリの関数はメインスレッドのみで使用し、別スレッドでは一切DXライブラリの関数を使用しないような使い方しかないかな。
でもその使い方だと用途が限られる・・・というか、戦略シミュレーションゲームの敵ターンのAI処理みたいな、処理にソコソコ時間が掛かっても許されるケースくらいしか思いつかない。
ファイルの非同期読込
マルチスレッドは無理だけど、ファイルの読込は非同期で行えるので、「Now Loading…」なアニメーションをさせながら画像や音声ファイルやらの読込待機をすることは可能です。
//ファイルサイズ取得
int size = FileRead_size("読み込むファイルのパス");
//第二引数にTRUEを指定することでFileRead_readが非同期に動作する
int hFileHandle = FileRead_open("読み込むファイルのパス", TRUE);
//ファイルの内容を格納するメモリ確保
void* pBuff = malloc(size);
//非同期読込
FileRead_read(pBuffer, size, hFileHandle );
FileRead_openの第二引数を指定しない(FALSE)場合、FileRead_readでファイルの読込が終るまで処理が止まりますが、TRUEを指定すると読込処理をDXライブラリ内で別スレッドで行なってくれるので、処理が止まらずに先に進みます。
読込が完了したかどうかはFileRead_idle_chkで確認できます。
引数にFileRead_openの戻り値を渡すと、読込完了していれば1を返してくれます。
読込が完了したら、画像ならばCreateGraphFromMemを使用してメモリからグラフィックハンドルを作ればOK。
音声の場合はLoadSoundMemByMemImageを使用する。
残念ながら3Dモデルや動画ファイルをメモリからハンドル作る関数は今のところ無い。
つか動画は単に再生するだけならPlayMovie使ったほうがいいし、LoadGraphで動画読み込んでも非同期処理されるのでメモリからハンドル作る必要はない。
と、こういう仕組みなので、実際のゲーム制作だと読み込みたい大量のファイルを一度にガーっと非同期読込させちゃって、メインループの中で毎フレームごとにFileRead_idle_chkでチェックして、読込完了してるファイルからCreateGraphFromMemとかでハンドルつくったりするってやり方になると思う。
一応この非同期読込処理を纏めたクラスを作ってみた。
LoadingCtrl.zip
CallBackの部分は実際にはデリゲートで実装してあるのを、ちょちょいと関数ポインタで書きなおしただけなので、もしかしたらコンパイルエラーとか出るかもしれない。適当に直して。まだ作りかけだしね。
そのままだとあんまり使えないとおもうので、ヒントになればいい程度。
非同期読込しても大きなファイルは処理が止まる
5Mとかの大きなmp3を、上記の方法で非同期読込しても、LoadSoundMemByMemImageでハンドル作る時に1~2秒どうしても処理が止まる。
これはもうどうしようも無いので、諦めてPlaySoundFile使ったほうがいい。
PlaySoundFileはストリーミング再生できるので、処理が止まることはない。BGM程度なら問題ない。
音ゲーみたいに再生タイミングがシビアだったり、曲をフェードアウトさせつつ別の曲をフェードイン(つまり同時に複数再生)とかしたい場合は・・・ホントどうしたらいいんだろうね。
この関数だけ別スレッドでやっても大丈夫かなぁ・・・。
DrawGraph不要論
DXライブラリは画像の表示関数がやたらと多いのですが、
単純に画像を表示させるだけならDrawGraphが使い方がシンプルで楽ではある。
でも実際にゲームを作成する場合、拡大縮小回転なんかは当たり前に使う訳で、拡大縮小回転がある場合とない場合でDrawGraphと他の関数を使い分けるのも面倒。
正直DrawRotaGraph2さえあれば機能的に事足りる訳で。
そこで気になるのが表示速度。
DrawGraphとDrawRotaGraph2だったら、シンプルな分DrawGraphのほうが早いだろうと思ってたのですが・・・
実際は大差ないようです。
ただ、DrawRotaGraph2で角度つけたり倍率指定したりすると3倍程度遅くなったりしますが。
単にそのまま表示するだけなら速度的に大差ないので、だったらDrawRotaGraph2一本で組んだほうがフレームワークが組みやすいです。
その他小ネタ
2Dのゲームでは、画面に画像を表示する位置(座標)はピクセルなので整数ですが、内部的には浮動小数で持っておいたほうがよかったりします。斜め移動の場合とか、速度の微調整とか。
で、DrawGraph等はx,yの引数がintですが、実はDrawGraphFっていうx,yがfloatの関数もあります。
これで「型が違うよー」って五月蝿い警告出さずに済むね!
DxLib.hは一度は目を通すべき。