2022/5/13(金)

Siv3Dの勉強をした。標準ライブラリの存在ガン無視なことさえ除けばいいライブラリなんだよなほんと。

久しぶりに触ってみたが、設計周りの知識を多少付けたこととRustに触れてたせいか、良い書き方が格段に「見える」ようになっていた。

スマートポインタを使う際のヒープメモリの使用やvtableによるオーバーヘッドは過剰に恐れるもんではないんだとか、途中要素のeraseはゲームでやるような数百個レベルのオブジェクト数ではほぼほぼ問題にならないしなんならremove_if使えば良いんだとか、各オブジェクトの処理と各オブジェクト同士の当たり判定の処理は分ければ見通しいいじゃんとか。なんか気づいてみれば当たり前なのだけど、前の自分は分かっていなかった。

なんか前の自分は「仮想クラス=vtableで重い」「ヒープメモリを使う=メモリの確保開放で重い」みたいな雑な考えがあって、それで抽象クラスのスマートポインタを持つみたいなのは本当に最低限のところでしかやっていなかったのだが、普通に考えてJavaやC#のような参照型とGCを基本に置く言語が普通に使われている時点でそこまで速度が問題になる訳がない。もちろんスタックメモリに普通のクラスを置く方が軽いのは間違いないが、それは所詮雀の涙ほどの差でしかなく、プログラムの可読性などを犠牲にしてまで捨て去るものではない。スマートポインタをガシガシ使っても、だいたいC++な時点で他の大抵の言語よりは速いはずだ。

Siv3DのArrayは基本的に中身がvectorらしい。ということは、削除を繰り返したら最悪$O(N^2)$の計算量が発生する計算になるが、数百の二乗になったところでせいぜい数万だ。近年のコンピュータなら1フレームで十分に処理できる。だいたい、オブジェクトの衝突判定というものがだいたい$O(N^2)$なのだ。eraseに気を付けている暇があったらそっちに気を使った方が意味がある。そして、eraseがキモイと感じるようなら適宜削除フラグを設定してremove_ifを使えば良い。これで$O(N)$になる。こちらの方がit=erase(it)みたいな七面倒なことをしなくてよい。

オブジェクトの当たり判定というのは、衝突する二種のオブジェクトをなるべく同列に扱いたいものである。だから例えば、弾の処理中に敵との当たり判定を計算して敵HPの変数を書き換えたり、敵の処理中に弾との当たり判定を計算したりということはだいたい面倒なことになるのでやらない方が良い。弾だけで完結する処理、敵だけで完結する処理をそれぞれ行い、その外で弾と敵の衝突処理などを行えばよろしい。


今日解いた競プロの問題。

競プロ典型90問

036 Max Manhattan Distance: マンハッタン距離は45度回したチェビシェフ距離定期。x+yとx-yの最大最小を求めておけば良い。


昨日夕飯に作ったカレーが残っていたので、久しぶりに焼きカレーをいただいた。とてもおいしかった。

ちょっとチーズが溶け広がり過ぎたので、もうちょっと焼く時間を抑えればよかったか。

Categories: