JavaScriptでゲーム作ろう

pixi.jsでタイルマップのようにスプライトを並べて表示するとノイズが発生することがあります。上の画像の黒い線がノイズです。。

これはenchant.jsでも同様の症状が起こるので知っていたんですが、原因は小数点以下の数字にあります。

整数だけで移動処理をしていればこのノイズは全くでないんですが、小数点以下を含む数字を扱うとこのノイズが出てしまいます。小数点以下の数字が悪さをしているようです。

「じゃぁゲーム作れないじゃないか!!!」

なんて怒らないでください。対処法があります(‘ω’)ノ

小数点以下を切り分けたり戻したりする

原因は小数点以下の数字が含まれていることにあるので、だったら小数点以下の数字をとっちゃえばいいじゃないのってことになります。

じゃぁMath.floorで小数点以下を切り捨てちゃえばいいのかっていうとそうでもありません。ただ切り捨ててしまうと座標計算が狂って表示がおかしくなってしまいます。

切り捨てるんじゃなくて小数点以下は別に一旦分けてからスプライトを表示させて、次回計算時にこの小数点以下を戻して計算すれば誤差が出ずに奇麗に移動してくれるようになります。

まずはクラスに小数点以下を保存する変数を用意します。「余り」の英語がremainderだったのでそういう変数名にしました(^^;)

this.remainderX = 0; 
this.remainderY = 0;

で移動計算時にこの変数を座標に加えるようにします。

this.x += this.remainderX;
 this.y += this.remainderY;

で、新しい座標を計算し終わったら座標から小数点以下をremainderに保存して座標を整数だけにします。

const x = this.x | 0;
 const y = this.y | 0;
 this.remainderX = this.x - x;
 this.remainderY = this.y - y;
 this.x = x; this.y = y;

これで表示時は座標が整数だけになって、計算時は少数点以下を戻して計算するのでズレが発生しません。

 

一応これで単純な上下左右移動ではノイズはでなくなりましたが回転や拡大縮小を使うとではやっぱりノイズは出ます。

完璧な対応策

絶対にノイズが出なくなる究極の対応策が「マップを画像にしてしまう」です。

タイルマップはスプライトを並べているのでどうしても隙間が生じてしまうわけで一枚の画像にしてしまえばその後回転させようが拡大縮小させようが1枚の画像なのでなんの問題もないわけです。

マップを画像にするというのはマップが作られているContainerクラスからテクスチャーを生成することです。それは以下のようにするとできます。

const newTexture = new PIXI.RenderTexture(
  new PIXI.BaseRenderTexture({width: container.width, height: container.height})
);
core.app.renderer.render(container, newTexture);

これでマップ(上の例ではcontainer)からnewTextureというテクスチャーが生成されて一つのマップ画像になっています。あとはこれをSpriteのテクスチャーに設定すればOKです。

こんな感じに回転させてももうノイズはでません。

ちなみにContainerをテクスチャーにするクラスを作ってQiitaに投稿してみました。

興味ある方はどうぞ(‘ω’)ノ