examples/drag: use image.Alpha to detect user interaction

This commit is contained in:
Hajime Hoshi 2023-10-27 10:04:11 +09:00
parent 55702a7c28
commit a7b87fddb4

View File

@ -40,9 +40,10 @@ const (
// Sprite represents an image. // Sprite represents an image.
type Sprite struct { type Sprite struct {
image *ebiten.Image image *ebiten.Image
x int alphaImage *image.Alpha
y int x int
y int
} }
// In returns true if (x, y) is in the sprite, and false otherwise. // In returns true if (x, y) is in the sprite, and false otherwise.
@ -50,10 +51,10 @@ func (s *Sprite) In(x, y int) bool {
// Check the actual color (alpha) value at the specified position // Check the actual color (alpha) value at the specified position
// so that the result of In becomes natural to users. // so that the result of In becomes natural to users.
// //
// Note that this is not a good manner to use At for logic // Use alphaImage (*image.Alpha) instead of image (*ebiten.Image) here.
// since color from At might include some errors on some machines. // It is because (*ebiten.Image).At is very slow as this reads pixels from GPU,
// As this is not so important logic, it's ok to use it so far. // and should be avoided whenever possible.
return s.image.At(x-s.x, y-s.y).(color.RGBA).A > 0 return s.alphaImage.At(x-s.x, y-s.y).(color.Alpha).A > 0
} }
// MoveBy moves the sprite by (x, y). // MoveBy moves the sprite by (x, y).
@ -186,7 +187,10 @@ type Game struct {
sprites []*Sprite sprites []*Sprite
} }
var ebitenImage *ebiten.Image var (
ebitenImage *ebiten.Image
ebitenAlphaImage *image.Alpha
)
func init() { func init() {
// Decode an image from the image file's byte slice. // Decode an image from the image file's byte slice.
@ -195,6 +199,16 @@ func init() {
log.Fatal(err) log.Fatal(err)
} }
ebitenImage = ebiten.NewImageFromImage(img) ebitenImage = ebiten.NewImageFromImage(img)
// Clone an image but only with alpha values.
// This is used to detect a user cursor touches the image.
b := img.Bounds()
ebitenAlphaImage = image.NewAlpha(b)
for j := b.Min.Y; j < b.Max.Y; j++ {
for i := b.Min.X; i < b.Max.X; i++ {
ebitenAlphaImage.Set(i, j, img.At(i, j))
}
}
} }
func NewGame() *Game { func NewGame() *Game {
@ -203,9 +217,10 @@ func NewGame() *Game {
w, h := ebitenImage.Bounds().Dx(), ebitenImage.Bounds().Dy() w, h := ebitenImage.Bounds().Dx(), ebitenImage.Bounds().Dy()
for i := 0; i < 50; i++ { for i := 0; i < 50; i++ {
s := &Sprite{ s := &Sprite{
image: ebitenImage, image: ebitenImage,
x: rand.Intn(screenWidth - w), alphaImage: ebitenAlphaImage,
y: rand.Intn(screenHeight - h), x: rand.Intn(screenWidth - w),
y: rand.Intn(screenHeight - h),
} }
sprites = append(sprites, s) sprites = append(sprites, s)
} }