今日の雑記

生きることでいっぱいいっぱい

まあ昨日の話の続きだが

浮動少数 が nan になってどうこうという話。
プログラミング的には「防御的プログラミング」というのを施さないといけないわけで、いくつか考えられるのだけど。
例えば昨日の例で言うと「座標をチェックする」ことにしよう。
1.座標を更新した時に座標をチェックしてタスクを殺す


TskBuf[id].px += TskBuf[id].vx;
TskBuf[id].py += TskBuf[id].vy;
if(isnan(TskBuf[id].px) || isnan(TskBuf[id].py)) TskBuf[id].step = -1; // nan なのでタスクを殺す
でも良いんだけど、これはこれであまり美しくないねえ。処理中にオブジェクトが突然消えたりして、チェック中に「オブジェクトが破壊されたのかどうか」が、テストプレイ中だと気がつない、という問題が。
2.毎ループごとに座標をチェックしてassert.

TskBuf[id].px += TskBuf[id].vx;
TskBuf[id].py += TskBuf[id].vy;
assert(!isnan(TskBuf[id].px) && !isnan(TskBuf[id].py));
コレが妥当な案かしら?ただボクのシステムの場合、タスクバッファってのはグローバルアクセス可能で、このチェックだけでは「何処から更新されたか」までは判別できない。まあ座標系は他から更新することがまずないので問題ないと言えばないんだけど、ゲームシステムによっては起こりうる問題なので安心はできない。
でもまあ一応対策はあって、メンバを更新したタスクが解るようなしくみを導入することはできる。無理矢理だけど。

// eid = 更新先のタスク ID
TskBuf[eid].px = TskBuf[id].trg_x;
TskBuf[eid].py = TskBuf[id].trg_y;
TskBuf[eid].update_id = id;
こうしておいて、

if(isnan(TskBuf[id].px) || isnan(TskBuf[id].py)){
// TskBuf[id].update_id のタスク内容を表示
assert(false);
}
とかしておけばまあ、デバッグの助けにはなるか。
さらにこれらの処理を、

debug{
// 先ほどのデバッグ用の処理
}
としておけば、-RELEASE オプションで弾かれるので、リリース時も安心、みたいな。