canvasに画像を拡大縮小回転しようとすると苦労するよねって話
六花です。
最近なにも作れてないなぁと思ったので前回の記事にミニゲームを掲載したのですが、開発の大半の時間がcanvasにおける画像の変形だったので、参考にしたい人がもしかしたらいるかもしれないと思ったので備忘録を残します。
早速javascriptのソースコードを掲載します。
function f_drawImage(p_ctx, p_image, p_x, p_y, is_flip = false, p_rate = 1.0, rotate = 0.0, rot_x = 0, rot_y = 0)
{
if(is_flip == false)
{
p_ctx.save();
p_ctx.translate(p_x, p_y);
p_ctx.scale(p_rate, p_rate);
p_ctx.rotate(rotate);
p_ctx.drawImage(p_image, -(p_image.width / 2 + rot_x), -(p_image.height / 2 + rot_y));
p_ctx.restore();
}
else
{
p_ctx.save();
p_ctx.translate(p_x, p_y);
p_ctx.scale(-p_rate, p_rate);
p_ctx.rotate(rotate);
p_ctx.drawImage(p_image, -(p_image.width / 2 + rot_x), -(p_image.height / 2 + rot_y));
p_ctx.restore();
}
}
ここで、「rot_x」「rot_y」は回転するときの軸を画像の中心からずらしたいときに使います。(画像の中心がキャラクタの中心とは限らないので)
指定した座標に、画像の中央が来るように描画されます。
まず前提として、描画を回転させる機能として用意されているrotate()は、canvasの左上を中心に回転させます。
ですので、適当にやると地球の周囲を回る月の用に、ぐるぐると回る画像が確認できます。
ですから、まずtranslate()を使って画像が(0,0)に描画されるように位置を補正してあげる必要があります。
scale()は画像の描画開始座標(左上)も伸縮しますので、translate()で移動してからscale()することで座標の移動の影響をなくします。
save()とrestore()で包んであげないと設定変更のゴミが残るので、やっておいた方が無難だと思います。
ここまでなんとなくで理解するのは楽なんでですが、実際に実装しようとすると非常に苦戦したので同じことで悩む人が減ることを祈ってソースコードを公開しておきます。
ライブラリも色々あるようですが、あまり私はライブラリが好きではないので、こういうのはついつい自前で用意できないか考えてしまいます。