副作用のあるコード

ぷらづまれいヤはバグがありつつも何とかリプレイを実装してリリースできてたのですが(バグがあるのは何とかとは云わない)、通常再生だけだと物足りないので、早送りだの遅送りだのを実装したわけです*1。そしたら、早送りしてズレるズレる。理論上ズレるはずのない設計なのになんでズレるんだーって見てたら、あー副作用のせいでした。。。

とりあえずワタシは、アクションゲーで一般的な、Update(Obj* )とView(Obj* )をセットにして動かす作りにしてます。Update(Obj* )でキャラクタを動かし、View(Obj* )でキャラクタを表示するのですね。で、通常はUpdate(Obj* )とView(Obj* )を1対1で動かすのですが、リプレイ時に2回Updateして1回View(2倍速)とかすると、再生速度を可変にできるわけです。

当然、Viewの中でObj(キャラクタデータ)を更新するような処理を書いてはいけません。速度を弄った時に更新処理の回数が変わってしまいますからね。なんですが、なんですが、あーくそなんでリプレイがズレるんぢゃーあああああってソースを眺めてたら、見事にViewの中に更新処理がありましたとも。

もちろん、View(Obj* )は、View(Obj const* )と書いていれば防げたバグです。View(Obj* )とView(Obj const* )の違いは、Objの中身を更新できるかできないかの違いがあるのでした。View(Obj const* )の中で更新処理をすると、コンパイルエラーがでますね。

じゃあなんでView(Obj const* )にしなかったかと云うと設計上の都合で…アレコレで…要は「めんどくさかった」からです。いやーやっぱ、プログラマの「気をつけて書くから大丈夫」ほど充てにならんものはないですね。「気をつければちゃんと動く」コードじゃなくて、「気をつけないと動かない」コードを書くようにしましょうね〜。

*1:リプレイ機能はプレイヤが面白いのもありますが、開発者にとって非常に強力な機能なのです。バグがでたらリプレイを貰って再現とか効能は数しれず。