前回の続きです。
これまでは画面上に表示されるリソースがソースコードにハードコードされた状態だったので、入力に合わせて動的に Sprite を生成することを考えてみます。
題材はキャラクターからの飛び道具、マリオで言うファイアーボールです。
Spriteの生成
Spriteの生成自体は、ボタン入力などに合わせて NewSprite
な関数を呼び出し、動的に struct を生成すればよさそうです。
ただし、Spriteを生成した後はなんらかの方法で破棄することを考えなければメモリ上の用の済んだSpriteが保持され続け、あまりよろしくありません。
GoはGCが載っている言語なので、用の済んだSpriteは参照を外してGCに改修されるようにすれば良さそうです(多分。ちょっと理解が曖昧)。
ソースコード
-
全体の差分は以下
-
sprite/ball.go
package sprite
import (
"image"
"github.com/hajimehoshi/ebiten"
"github.com/zenwerk/go-pixelman3/utils"
)
const (
ball_img = `--+++--
-+++++-
-+++++-
--+++--`
ballSpeed = 4
screenWidth = 320
screenHeight = 240
)
type Balls []*Ball
var (
ballImg *ebiten.Image
)
func init() {
tmpImage := image.NewRGBA(image.Rect(0, 0, 7, 4))
utils.CreateImageFromString(ball_img, tmpImage)
ballImg, _ = ebiten.NewImage(7, 4, ebiten.FilterNearest)
ballImg.ReplacePixels(tmpImage.Pix)
}
type Ball struct {
BaseSprite
}
func NewBall(pos position) *Ball {
ball := new(Ball)
ball.Images = []*ebiten.Image{
ballImg,
}
ball.ImageNum = len(ball.Images)
ball.Position = pos
return ball
}
func (bs *Balls) Move(viewport position) {
balls := *bs
for i := 0; i < len(balls); i++ {
b := balls[i]
b.Position.X += ballSpeed
// 表示領域外に出たら配列から削除する
if b.Position.X > (screenWidth-viewport.X) || b.Position.Y > (screenHeight-viewport.Y) || b.Position.X < 0 || b.Position.Y < 0 {
balls = append(balls[:i], balls[i+1:]...)
i--
}
}
*bs = balls
}
Move
関数で表示領域外に出たら、スライスから削除するようにしています。これで無駄なメモリを使用せずに済むと思います。
表示領域外の他にも、他のSpriteとの衝突などで同様の処理をしても良いでしょう。
実行結果
参考
- GoのGCについて
- スライスが構造体のレシーバの時に、要素を削除する方法について
- スライスの操作一覧