スプライトはキャンバスから外に出て見えなくなっても、存在しつづけています。外に出て見えなくなったそのスプライトをまた表示しないのであれば、そのスプライトは削除すべきです。削除しないとメモリの無用な消費になります。
目次
スプライトの寿命
Sprite.lifeプロパティは名前通り、スプライトが存在しつづける寿命を決めます。スプライトを作成するときにlife値を設定すると、draw()が1回呼び出されるたびに1ずつ自動的に減っていき、0になったらSprite.remove()メソッドが呼び出されて、そのスプライトは削除されます。
次のサンプルでは、画面のマウスプレスで花火のアニメーションを描画するスプライトを作成します。スプライトにはlifeプロパティを使って寿命が設定してあるので、アニメーションが終わるとほどなく削除されます。画面の左上には、現在存在する全スプライトを管理するallSpritesが持っているスプライト数の情報を表示しています。
let fwAnim;
let backImage;
function preload() {
fwAnim = loadAnimation('assets/fireworks/01.png', 'assets/fireworks/14.png');
backImage = loadImage('assets/background.png');
}
function setup() {
createCanvas(800, 500);
textSize(20);
fill(255);
}
function draw() {
// 星空のイメージを背景として描画
image(backImage, 0, 0);
// 左上に現時点の花火スプライトの数を表示
text("スプライトの数: " + allSprites.length, 10, 30);
// 全スプライトを描画
drawSprites();
}
// ページのマウスプレスで、マウスプレス位置近くに花火スプライトを作成してアニメーションを追加
function mousePressed() {
const sp = createSprite(mouseX - 40, mouseY + 80);
sp.addAnimation('fw', fwAnim);
// スプライトの寿命 => 1回のdraw()の間に1減る。0になったらスプライトは削除される。
sp.life = 50;
}
リファレンスメモ
Sprite.life
life Number
スプライトが自分で自分を削除するまでの一巡(1サイクル)。カウントダウンを初期化するために設定すると、描画サイクル(draw()が1回呼び出される)ごとに、lifeプロパティの値は1単位減り、0になったらSprite.remove()が呼び出される。無効化するには-1に設定する。デフォルトは-1。
スプライトの削除
スプライトの削除は、Sprite.remove()メソッドをそのスプライト自身から呼び出すことで行えます。スプライトを削除するということは、そのスプライトが占めていたメモリを解放するということなので、たとえ画面に表示されていても、削除された瞬間に見えなくなります。
次の例では、画面のマウスプレスでグーかチョキかパーのイメージを描画するスプライトが表示され、回転しながらランダムな方向に動いて、左右どちらかの端に触れた瞬間に消えます。画面左上には、前の例と同様に、今存在しているスプライトの数を表示しています。
let anim;
function preload() {
anim = loadAnimation('assets/hands/gu.png', 'assets/hands/choki.png', 'assets/hands/pa.png');
}
function setup() {
createCanvas(400, 400);
textSize(20);
}
function draw() {
background(215);
// 左上に現時点のスプライトの数を表示
text("スプライトの数: " + allSprites.length, 10, 30);
// スプライト関係の論理
update();
// 全スプライトを描画
drawSprites();
}
function update() {
// 現在の全スプライトを保持するallSpritesプロパティを繰り返し処理
for (let i = 0; i < allSprites.length; i++) {
// 対象とするスプライトを特定
const sp = allSprites[i];
// 回転
sp.rotation += 3;
// 落下
sp.addSpeed(0.1, 90);
// 跳ね返りのy位置
const bounceY = height - (sp.height / 2);
// 下端では跳ね返り
if (sp.position.y >= bounceY) {
sp.velocity.y *= -1;
sp.position.y = bounceY;
}
// 左右の端から出そうになったら削除
if (sp.position.x > width || sp.position.x < 0) {
sp.remove();
}
}
}
// マウスプレスされたら
function mousePressed() {
// 新しいスプライトを作成
const sp = createSprite();
// スプライトにアニメーションを追加
sp.addAnimation('normal', anim);
// 再生しない。
sp.animation.stop();
// アニメーションからフレーム番号をランダムに選択して表示をそのフレームに固定する
// spのアニメーション(Animationオブジェクトのフレーム数(0から始まる)
const frameNum = sp.animation.getLastFrame();
// 行先フレーム番号をランダム選択
const toFrame = round(random(0, frameNum));
// 表示をそのフレームに固定
sp.animation.changeFrame(toFrame);
// スプライトの速度(X方向とY方向の1描画サイクル当たりの移動量)をランダムに決める
// => xが-3から3の間の値になるので、左右どちらかへの移動になる。
sp.velocity.y = random(3);
sp.velocity.x = random(-3, 3);
// 最初の位置はマウスプレスの位置
sp.position.x = mouseX;
sp.position.y = mouseY;
}
スプライトが画面の左端が右端に来たら削除するのは、draw()から呼び出されるupdate()関数内でallSpritesが保持するスプライトを繰り返し処理するforループ内の次のコードです。
// 左右の端から出そうになったら削除
if (sp.position.x > width || sp.position.x < 0) {
sp.remove();
}
このようにforループ内でスプライトを削除する場合には、forループの最後で削除するようにします。そうしないと、以降のコードでスプライトを参照したとき、そのスプライトはもう存在しないので、エラーになります。
その上では、各スプライトの回転と、前の例で見た落下、跳ね返りを行っています。
mousePressed()内で使っている新しいテクニックは、複数のフレームを持つスプライトを使って、アニメーションさせずに、あるフレームだけを固定して描画する方法です。ただイメージだけの描画する場合には必要ありませんが、Spriteオブジェクトのさまざまなプロパティやメソッドが活用できるので便利です。
次のコードは、SpriteプロパティのanimationプロパティからgetLastFrame()メソッドを呼び出しています。Sprite.animationはそのスプライトのAnimationオブジェクトを指しています。AnimationオブジェクトはgetLastFrame()メソッドを持っています。その下の sp.animation.changeFrame(toFrame) も同様です。
const frameNum = sp.animation.getLastFrame();
リファレンスメモ
Sprite.remove()
remove ()
スケッチからSpriteオブジェクトを削除する。削除されたSpriteオブジェクトはもう描画も更新もされない。
Sprite.animation
animation Animation
現在のAnimationオブジェクトへの参照。