JavaScriptで残像を描画するにはどうすればよいでしょうか?

準備

以下のコードでcanvasとボタンを表示させるところまで作ります。

index.js

更新時に薄い背景色で全体を塗りつぶす方法

問題はここからです。残像を描画する方法として更新時に薄い背景色で全体を塗りつぶす方法があります。この方法だと更新処理が繰り返されるたびに、前に描画されたものは背景色によってだんだん見えなくなります。

ただ、問題点もあります。ctx.fillStyle = ‘rgba(0, 0, 0, 0.05)’;としていますが、0.05の部分の値が大きすぎると残像がすぐに消えてしまうし、小さすぎるとなかなか消えてくれません。いつまでたっても残像が消えないというのはこれはこれで困ります。

また残像を残したいものと残したくないものが混在する場合も困ります。その場合はcanvasをふたつ生成するなどの工夫が必要です。

移動するときに前の座標を記録する

ふたつめの方法は移動するときに前の座標を記録しておき、これを薄く描画するという方法です。

Playerクラスを定義して、移動したら前の座標をMaxHistory件分配列のなかに保存しておきます。

あとはPlayerクラスのインスタンスを生成してMove関数とDraw関数を呼び出します。

この方法もあまりうまくいきません。古いものから順に、つまり不透明度(opacity)が低い順に描画していったとしても何度も描画が繰り返されることで濃くなってしまい残像のように見えなくなってしまうのです。

改善策

そこでopacityが設定された色と背景色が合成された色を求めてから残像を古いものから順に描画していくことにします。それが以下のコードです。PlayerクラスのDraw関数を修正します。

ところで背景色にrgbaで透明度を含めて表現される色をrgbに変換するためにはどうすればよいでしょうか?

まず前景色と背景色のRGB成分をそれぞれ [0, 1] の範囲に正規化します。RGB成分は[0, 255]なので255で割ればよいです。次に(1 – アルファ値) * 背景色のRGB成分 + アルファ値 * RGBA色のRGB成分を計算します。最後に結果をもとの [0, 255] の範囲に戻すために255倍して四捨五入します。