Heliodorさんをフォローして、最新情報をチェックしよう!

マイページへ

Ci-enはクリエイターに対して、金銭的な支援を送ることができるサービスです。

有料支援者特典のエロドットビュワー裏話

プログラム話です。

先日公開した支援者様向けのヴィータ大脱出エロドットビュワーですが、ただ敵をON/OFFするスイッチを付けただけのものなので、そんなに手間はかからないだろうと思ってました。
……しかしそんなことはありませんでした(泣)。

まず、素直に敵だけ非表示にできるように作ったのですが、そうすると白濁液とかヨダレとか白い息のエフェクトが何もない空間から出てくるんですよ。


文面では伝わりにくいかもしれませんが、実際に画面で見たときは衝撃的でした……。


ヴィータ大脱出ではキャラクターの表示・非表示を切り替えるといった動作が皆無だったので、エフェクトを生成するときに、生成元となるキャラクターが表示状態なのか、非表示状態なのかをチェックする機構というのはついていませんでした。

そんなわけで、「エフェクトを生成するときにその生成元のキャラクターの状態をチェックし、非表示状態であればエフェクトを生成しない」というコードを追加しました。

ただ、それを一律に適用してしまうと、パーティクルをまき散らすための隠しキャラクター(ジェネレーターとかエミッターとか呼ばれる)がパーティクルを一切生成しなくなってしまいますので、アルバムモードかつCi-en限定版でのみ、このような条件でエフェクト生成するようにしたわけです。

本当ならば敵をOFFにしたときに、敵から生成されたヨダレ、地面にヨダレが落ちた跡、跳ね返りの液体もすべて一括でOFFにできればスマートでよかったのですが、意外と大変なのでボツにしました。

それをやるためには、何が何を生成したのかという関係を追跡して管理する仕組みが必要ですが、そういった仕組みはヴィータ大脱出では不要だったので作っていなかったのです。そもそも、そういう仕組みを作ること自体が意外と大変です。

例えば、敵がヨダレをたらし、そのヨダレが地面に衝突して涎の跡(以下水たまり)を生成すると同時に、付近に飛び散る液体(以下水しぶき)を生成したとします。生成関係の追跡を素直に実装すると、各オブジェクトがそれぞれ自分が誰から生まれたのかという情報を持つようにして、ヨダレは敵から、水たまりはヨダレから、水しぶきは水たまりから、ということが後から調べられるように作ると思います。

これを逆に辿っていくと、水しぶきは元々敵から由来したものだから、敵の表示をOFFにしたら水しぶきも消えるべきだとわかるわけです。

これで問題なさそうですが、実際にはそうはいきません。水しぶきが上がったときにはヨダレはすでに消えているため、水しぶき→水たまり→ヨダレまでは辿ることができますが、この時点でヨダレはすでに存在しないため、ヨダレがどこから来たのかという情報が消えているからです。

となれば、こういった情報は各オブジェクトに持たせるのではなく、外部の管理者に任せるようにすればよいという事になります。しかし、それはこれまでに作成したオブジェクトの履歴をずっと持っているという意味になるので、実行時間が長くなるほど管理するべき履歴の量が増え、負担が大きくなってしまいます。

だったらどこか適当なところで古い履歴を削除して……などとやっていると、こういった仕組みをまじめに作るのは結構大変だという事に気づきます。そんな面倒なことしなくても、空中からヨダレが出ないようにするだけで十分ですしね。

それよりも大変だったのは、アルバムモードでの非同期ロードが原因と思われるエラーです。

今回のアルバムモードでは起動時にすべてのアルバムが強制的に解放されるので、アルバムのロードが40個ぐらい同時進行で進んでいます。これは初めから意図していた動作ですので、当然スレッドセーフになるように作っていたのですが、どうやら穴があったようで、起動直後にアルバムを高速スクロールしていると落ちる時があるんです。

さらにデバッグモードでは落ちずにリリースモードの場合だけ落ちるといういやらしさです。しかも検証用のコードを入れたとたんに落ちなくなるという……。プログラムあるある的な話ですね。

直接の不正落ちの原因は、配列の範囲外のインデックスを参照してNULLが返った事によるNULLポインタ参照エラー(ぬるぽ、懐かしいですね)なのですが、そこに配置してあるインデックス確認用の assert には一度もひっかったことがないんですよね。デバッグモードで assert が有効な時は不正なインデックスが入って来ず、リリースモードで assert が消えた瞬間に不正なインデックスが入ってくるという……。

メモリ関係のエラーはちょっとコードを書き換えただけで挙動が変化してしまうので、本当にやりにくいです。結局今回は NULL チェックを追加して参照を回避しただけで、そもそもなぜ範囲外のインデックスが来たのかという根本的解決にはならず、でした。

https://twitter.com/helio_dor/status/1064442433004482560
https://twitter.com/helio_dor/status/1064442686541721600

この辺のツイートは大体そんな感じです。ヤケクソ感漂いますね。

\いいねで応援!/