もんしょの巣穴blog

スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。
  1. --/--/--(--) --:--:--|
  2. スポンサー広告

デバッガの仕業です

先週の水曜日に会社を休んで車検を取りに行きました。ユーザー車検ってやつ。
緊張してたのか、夜中にGが大量に発生する夢を見て飛び起きたり。Gとバイクは関係ないけど。
ちょっと身構えてたけど、やってみるとあっけない。
書類書いたりするのも含めて1時間とかかってない。
っていうか、こんな簡単でいいのかね?


土曜日、今月2度目のG登場。今回は茶色いやつで、生きがいい。
一瞬固まりかけたけど、すぐ側に置いてあったGJPで速攻虫の息に。
あとは食器用洗剤を上からかけて、完全に動きが止まるのを待ってからトイレにドボン。
慣れたわけではないのですが、以前より処理は速くなりましたね。


で、日曜日に早速ゴキアースレッド3個パックを購入。2週に1回は使用する予定。
購入して戻ってきてから、発射して再び外へ。
立ち読み等で時間を潰して2時間程度で戻ってきました。
でも、まだいる気配が…。気のせいならいいんですがね。


その後はお茶を飲みながらプログラム。弾幕ツールの移植。
川西さんのManagedDirectXの記事からタイマーやスレッドを使わなくてもいい方法を学んだので早速やってみる。
問題なく上手くいってほくほくしてたのも束の間、処理速度の問題が出てくる。
っていうか、はっきり言っておかしすぎる。
弾を100発程度撃っただけで10FPS近くまで落ちる。10発でも時折30FPSに落ちる。
やはり描画かと思ったのですが、描画だけでなく弾幕のアップデートだけでも遅い。
原因は色々考えてみた。
例えば、ポインタを弄っている最中にガベージコレクタが動いているとか、static_castでダウンキャストしてるのがまずいとか、メッセージ処理と描画がおかしな具合にかち合ってるとか…。
しかし、いろいろ試しても処理速度はほとんど変わらず。
若干早くなった気がする、という程度が限度。
そんなんで夜遅くになって、とりあえずリリースでビルドしてみることに。
これで実行したら、十分速いとはいえないまでもかなり高速化されてる。
まさか最適化か?と思ったけど、デバッグビルドで最適化してみてもあんまり変わらず。
しかし…まさかと思ってデバッグなしで実行してみたら、これがビンゴ。全く問題ない速度。
全てはデバッグモードの所為でした。半日のほとんどが無駄だったよ。

スポンサーサイト
  1. 2006/07/31(月) 23:10:27|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:0

マルチメディアタイマー制御は危険なのか?

ついに今年初めての黒い悪魔登場。
しかし、何故か浴槽の中で瀕死状態。一体何があった?
とはいえ、そんな状態でもキモイものはキモイ。
排水口から流して終了ですがね。そのあと、パイプユニッシュを流しておいたけどね。
やはりやつらを完全にシャットアウトするのは難しいようだ。
っていうか、一体どこから入ったんだ?


昨日は一日中自宅でプログラミング。
弾幕ツールを.NET Frameworkに移植中なのですが、これが色々面倒。
C#でカスタムコントロールを作るのは簡単ですが、マネージとアンマネージを混合させると色々制約が多くなってわかりづらい。
とはいえ、ゲーム製作にC#はちょっと…なので、描画エンジンを共有させようと思ったらC++を使うことになるわけで。
そうなると当然混合させる必要があるわけで。これが結構重いっぽいんですがねぇ…。


そんな状態でまず躓いたのがタイマー処理。
ツール上で60フレーム描画をする場合、私は今までタイマーを使用してきました。
タイマーで1/60秒(約17ms)ごとに描画イベントをキックするって感じ。
しかし、Forms.Timer は精度が非常に悪い。確か 55ms が限界のはず。
そこで調べてみたところ、.NET Framework にはタイマーが3つあることが判明。
1つは前述したフォームコントロールのForms.Timer、1つはスレッドのタイマー、1つはサーバ用のタイマー。
この中で最も精度が高いのはサーバ用のタイマーだということで、どの程度の精度があるか調べてみると、これがまた酷い。
17ms に設定してみたら、30ms 前後で動いてた。10ms だと 11?13ms が基本で、3?4回に1回は 23ms 前後の数値が出てくる。
これでは使い物にならないので、やっぱりいつも通りにマルチメディアタイマーを使うことに。


ここでまた躓いた。マネージコードではコールバックが使えないから。
まあ、これも仕方のないこと。
マネージコードではガベージコレクタによってメモリの再配置が行われる可能性がある。
コールバック関数のように関数ポインタを用いるもの場合、そのポインタがガベージコレクタによって無効にされる恐れがある。
もちろん、やりかた次第で出来ないことはないし、マネージコードでも関数ポインタを使用する仕組みがある。
ただ、出来ればカスタムコンポーネントとして作成したいので、Google先生に聞きまくった結果、マルチメディアタイマーをコンポーネントにしてるプログラムを発見。
ここまででかなり時間はかかってるのですが、先人が作っているなら使わせてもらおう。
実際、これは全く問題なく動いてバンバンザイだったのですが、ここで再び問題発生。


マルチメディアタイマーで描画命令をしてたら、ちょっと負荷がかかっただけでアプリが応答しなくなった。
タイマーとメインフォームを同期させていたため、描画命令が遅れてキューが溜まりまくったからっぽい。
ちょっと負荷って言っても、そんなに重いはずもないような描画なんですが。
スプライトの描画をスプライトエディタと共通させたのが間違いだったかなぁ?
それでも、負荷がかかると応答がなくなるのは困りもの。
タイマーとメインフォームを非同期にしてみたのですが、若干改善されたくらいでやっぱり応答がなくなることがしばしば。
結局、いろいろ考えて、別の非同期スレッドを作成してそこで描画を行うように変更。
VSync待ちはDirectXに任せることにした。多分大丈夫でしょう。うちでは大丈夫だし。


マルチメディアタイマーは結構危険という話は聞いたことがあるのですが、こういうことになるとはねぇ。
今まではなったことないんですがね、こんなこと。
まあ、1つ勉強になったから良しとしますか。

  1. 2006/07/24(月) 22:02:24|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:1

SIG-GT8

車検が切れそうなので取りに行かないといけない。
ユーザー車検にチャレンジする予定ですが、ちょっと不安もありまして。
2年にもなろうというのに走行距離が5000km程度なので大丈夫だとは思いますが。
っていうか、もっと乗れよな>自分


土曜日に開催されたIGDAのSIG-GT8に行ってきました。
とはいえ、会社の金で行ったので仕事です。ゆえにここでは書けません。
今日はレポートを書いてました。これも仕事です。
まあ、雨でツーリングも行けないからいいんですけどね。


懇親会も2次会まで出てきましたが、結構オフレコな話が多くてあんまり書けない。
ただ、あんがいXbox360が売れて欲しいと思ってる人はいるんですね。
まあ、作ってる人にとっては売れないと困るからね。
私は今月には買う予定。


話を聞いていて思ったのは、今後のゲーム業界は本格的に悩みを解決する方向に進むべきだということ。
このような講演会や研究会に積極的に出てくる人はみんな同じ悩みを抱えているということはわかっている人々ばかり。
どんなゲームをユーザが望んでいるか、とかはクリエイティブの悩みですが、開発環境を良くするとかはクリエイティブとはちょっと違う方向の悩みなわけで。
が、この手の悩みが実に多い。データやスケジュールの管理とかね。
これらは簡単に解決できるものではないとは思いますが、業界全体で色々やっていけば解決できるのではないかと思うものもあります。
しかし、飲み会の席で話をしたりとかでは解決するわけもなく、現状では実際に効力のある行動が求められているのではないでしょうか。
そのためには会社の偉い人とかもこういう場に出てきて話をしたり聞いたりすべきなのかもしれません。
結局、みんな悩みは同じだねぇ、から先に進んでないわけですよ。いや、少しずつは進んでいるのかもしれませんが、歩みは遅いように思います。
このままだと優秀な人材が業界から流れていくだけになりそうで困る。
MSとか任天堂とか、余裕がある企業が何とかしてくれないものかなぁ…(MSはそれなりに頑張っているとは思うが)。

  1. 2006/07/18(火) 01:06:04|
  2. ゲーム
  3. | トラックバック:0
  4. | コメント:0

Squirrel その9

前回予告した通り、ちょっと高度なSquirrelの使い方。
高度といってもちょっとです。難しいことはないと思います。


いわゆるスクリプト言語をゲームで使用する場合、主に外に出しておくと便利なものに使用します。
例えば敵キャラクタのAIとか、ゲーム中に発生するイベントシーンとかですね。
ゲーム中に発生する、ちょっとしたカメラの移動を例にとって処理を考えてみましょう。
まず、ゲームプレイ中にはカメラはプレイヤーキャラクタを注視しています。
ある位置に来るとプレイヤーキャラクタは動けなくなり、カメラがそれまで画面外にあったアイテムなどにフォーカスし、その後またプレイヤーに戻るとします。
カメラを移動させ、移動終了したらスクリプトも終了するというようなスクリプト関数を用意したとしましょう。
この関数をただ実行しただけだと上手くいきません。なぜなら、関数が終了して戻ってきた時には既にカメラの移動は終わっているわけですから、画面にそれが反映される事はありません。
どうすればいいか?
まず、スクリプト関数内で描画命令を発行することができますが、描画以外にもやらなければいけないことは多いのでそうはいきません。
毎フレームスクリプト関数を実行し、スクリプト関数内では1フレーム分の処理だけを行う。
この方法は十分機能しますが、初期化やデータの保持が面倒だったりします。
通常使われる方法は、やはりコルーチンだと思います。
言語仕様のほうでも紹介しましたが、コルーチンはメインルーチンから呼ばれ、任意にメインルーチンに戻り、戻った位置からコルーチンの再開が可能という代物です。
スクリプト関数の最初で初期化をし、その後移動終了までループ。
1フレーム分移動したところでメインルーチンに戻り、描画等を終えてコルーチンの再開。
コルーチンが終了するまでこれを繰り返せば初期化から実行までスクリプト関数内で全てまかなえるようになります。


では、実際のプログラムを見ていきましょう。と言っても、カメラを動かすのではなく適当な文字列を出すだけですが。
まず、test.nut などの適当なSquirrelファイルに以下の関数を書いてください。


function foo_thread(num)
{
    for(local i=0; i<num; i++){
        print("Round " + (i + 1) + " : Fight!\n");
        local ret = suspend("You ");
        print(ret + "\n");
    }
}


"Round n : Fight!"と表示し、その後にsuspend() でメインルーチンに戻り、"You win!"か"You lose!"と表示します。
特殊なところとして、"You "という文字列だけC++プログラム内で出力していることと、"win!"か"lose!"はC++プログラム内でランダムを用いて決定している点です。
Squirrelファイルを実行するところまでは同じです。実行に成功したら、スレッドを新規作成する必要があります。


HSQUIRRELVM  new_v = sq_newthread(v, 1024);


第1引数が元のVM、第2引数が新しいVMのスタックサイズです。
これで new_v に新しいスレッドが作成されました。今後、この new_v に対して処理を行います。
Squirrel関数の実行は new_v に対して通常の関数発行方法を用います。引数はルートテーブルとループ数を指定してください。
sq_call() 関数でSquirrel関数が実行されると suspend() でメインルーチンに戻ってきます。
suspend されたかどうかは以下の方法でチェックできます。


while(sq_getvmstate(new_v) == SQ_VMSTATE_SUSPENDED){
}


この式が false になると Squirrel関数は終了しています。
このループ内で以下の処理を行います。


char* str;
sq_getstring(new_v, -1, (const char**)&str);
sq_pop(new_v, 1);
printf("%s", str);
if(rand() & 0x01){
    sq_pushstring(new_v, "win!", -1);
}
else{
    sq_pushstring(new_v, "lose!", -1);
}
sq_wakeupvm(new_v, SQTrue, SQTrue, SQFalse);


sq_getstring() 関数でトップスタックの文字列を取得します。ここに"You "の文字列が入っています。
文字列を取得した後にはポップすることをお忘れなく。
次にランダムで"win!"か"lose!"の文字列をプッシュします。この文字列が Squirrel関数の ret に入ってきます。
それから sq_wakeupvm() 関数でコルーチンを再開します。
第2引数を true にすると先にプッシュした値を suspend() の戻り値として使用します。
第3引数はsuspend() もしくは関数終了時に戻り値を受け付けます。
第4引数はエラーが出た時にハンドラに送るかどうかです。
これで、次に suspend() されるか関数が終了するまでメインルーチンには戻ってきません。
今回はループ回数をC++側から指定していますが、もちろんSquirrel関数内で指定しても構いません。
new_v がサスペンド中である限り、sq_wakeupvm() で再開しつづければいいわけです。


今回はこれで終了。次はクラスでもやってみましょう。

  1. 2006/07/10(月) 22:35:52|
  2. プログラミング
  3. | トラックバック:0
  4. | コメント:0

ウルトラヴァイオレット

トイザらスでXbox360本体とゲーム1本を買うと1万円引きらしい。
買おうかとちょっと思ってる。
『クロムハウンズ』が面白そうなので。っていうか、会社でちょっと遊んでいい感じだったので。
しかし車検があるだよねぇ…。


先週の土曜日は映画が1000円だったので『ウルトラヴァイオレット』を見てきました。
『リベリオン』のカート・ウィマー監督が、ガンカタっぽいアクションの映画をまた作ったわけです。
が、これが駄作。『リベリオン』は好きだけど、残念ながらこの作品は擁護できない。
まずシナリオが酷い。
設定については最初に主人公の独白という感じで流れてそれまで。
作品中にその設定を強く感じさせる描写がほとんどないため、設定が生かされているように見えない。
子供についても非常にわかりにくく、主人公が子供に感情移入する理由とか子供が開発された理由とかわかりにくい。
とにかく全体的に投げっぱなしで、見てるこっちは( ゚д゚)ポカーン状態。
アクションについてはいいシーンもあるのですが、できの悪いミュージカルみたいなシーンとかもあったりでかなり微妙。
『リベリオン』でも言われていましたが、とにかく主人公が強すぎて全くピンチにならないのも問題。
特にダメなのはラスボス手前。
一人で突き進む。敵がわらわら出てくる。カメラが敵も主人公もいない場所を映す。剣戟、銃撃の音が聞こえる。扉開いて主人公登場。
こんなシーンが2回も出てくる。さすがにこれは酷い。
全体的に予算が足りなかったというのはわかります。CGの出来とかみればわかるし。
やりたいことと予算があってないんだろうな、とも思う。
しかし、それでももうちょっとやり方もあるだろうと思う。予算が少ないならそれに見合った造りをすべきだ。
さすがにこのDVDは買えないな。『リベリオン』は買ったけど。

  1. 2006/07/07(金) 20:54:19|
  2. 映画
  3. | トラックバック:0
  4. | コメント:0

プロフィール

Author:monsho
ゲームプログラマ?

最近の記事

最近のコメント

最近のトラックバック

月別アーカイブ

カテゴリー

ブロとも申請フォーム

この人とブロともになる

ブログ内検索

RSSフィード

リンク

このブログをリンクに追加する

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