モバイル向けに、Canvasでつくったゲームを
Retinaディスプレイ対応をしたときにハマったこと。
CanvasのRetina対応は一筋縄にはいかないッ
基本的にCanvasのRetina対応は以下のように、
実際のサイズの2倍のサイズでつくったCanvas要素を、CSSで実際のサイズに縮める。
<canvas id="sample_canvas" width="640" height="800" style="width: 320px; height: 400px"></canvas>
これで、Retinaディスプレイできれいに表示できる。
しかし、このままでは以下のような問題が起きちゃう。
- 2倍のサイズのCanvasに描画を行うため、処理が重くなる
- そのため 一部のAndroid端末にて、ブラウザが落ちる、端末が発熱する
- 一部のAndroid端末にて、Canvas要素のstyle属性を動的に変更するとブラウザが落ちる
そこで、Retina以外の端末向けに、処理の切り分けが必要になる。
Canvas要素は実際のサイズ。Canvas上の座標系をあわせるために、
Canvasのscaleを0.5にする。
<canvas id="sample_canvas" width="320" height="400"></canvas>
var canvas = document.getElementById("sample_canvas");
var context = canvas.getContext("2d");
context.scale(0.5,0.5);
これで、Canvas内の座標は同じ数値を指定できるようになる。
window.devicePixelRatioの値に応じてCanvasサイズを決める方法もあるが、
上記のstyle属性をいじると落ちるバグがあるため、
iOSのRetinaディスプレイとそれ以外で切り分けるのがおすすめ。
その他 注意すること
widthとheightは変更しない
一部のAndroid端末では、Canvas要素のwidthとheightを変更すると、
Canvasの描画が2重になり、clearRect してもクリアされないというバグがある。
一度設定したwidthとheightは変更しないッ(再代入はOK
drawImage での縮小だと画像がボケる
Canvas APIのdrawImageでも、2倍の大きさの画像を実際のサイズに縮小して表示できる。
var image = new Image();
image.src = "sample.png"; // 実際のsample.pngのサイズ 200x200
image.addEventListener("load", function() {
context.drawImage(image,0,0,100,100); // 半分のサイズを指定
}, false);
しかし、これだとCanvas上のピクセルは2倍にならないため
Retinaディスプレイでは画像がボケる。
まとめ
今回は、Android端末にも広く対応を考えた場合に必要な話なので、
対応端末が限られる場合(iOSだけとか)の場合は気にする必要なしッ
とはいえ、結構シェアの高い端末でも発生する問題だったりします...!