package internal import ( "image" "image/color" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/vector" ) type paddle struct { x float32 // top left corner - X y float32 // top left corner - Y initX float32 initY float32 width float32 height float32 speed float32 isControlledByPlayer bool } func newRightPaddle(screenWidth, screenHeight int, isControlledByPlayer bool) *paddle { return newPaddle( screenWidth, screenHeight, isControlledByPlayer, func(paddleWidth, paddleHeight, screenWidth, screenHeight float32) (float32, float32) { return screenWidth - paddleWidth, screenHeight/2 - paddleHeight/2 }, ) } func newLeftPaddle(screenWidth, screenHeight int, isControlledByPlayer bool) *paddle { return newPaddle( screenWidth, screenHeight, isControlledByPlayer, func(paddleWidth, paddleHeight, screenWidth, screenHeight float32) (float32, float32) { return 0, screenHeight/2 - paddleHeight/2 }, ) } const ( paddleBaseWidth = 7 paddleBaseHeight = 75 paddleBaseSpeed = 1 ) func newPaddle( screenWidth, screenHeight int, isControlledByPlayer bool, getPos func(paddleWidth, paddleHeight, screenWidth, screenHeight float32) (x, y float32), ) *paddle { fScreenWidth := float32(screenWidth) fScreenHeight := float32(screenHeight) p := &paddle{ width: paddleBaseWidth * fScreenWidth / BaseWidth, height: paddleBaseHeight * fScreenHeight / BaseHeight, isControlledByPlayer: isControlledByPlayer, speed: paddleBaseSpeed * fScreenHeight / BaseHeight, } p.x, p.y = getPos(p.width, p.height, fScreenWidth, fScreenHeight) p.initX, p.initY = p.x, p.y return p } var paddleColor = color.White func (p *paddle) draw(img *ebiten.Image) { vector.DrawFilledRect(img, p.x, p.y, p.width, p.height, paddleColor, false) } //nolint:gocyclo func (p *paddle) update(bounds image.Rectangle, b *ball) error { newY := p.y if p.isControlledByPlayer && ebiten.IsFocused() { _, cursorY := ebiten.CursorPosition() newY = float32(cursorY) - p.height/2 } ballNextX, _ := b.nextPos(bounds) isBallGettingCloser := p.x-ballNextX < p.x-b.x // move the paddle according to the position of the ball if !p.isControlledByPlayer && isBallGettingCloser { if newY+p.height/2 > b.y { newY -= p.speed } else if newY-p.height/2 < b.y { newY += p.speed } } // move the paddle to the init position if !p.isControlledByPlayer && !isBallGettingCloser { if newY > p.initY { newY -= min(newY-p.initY, p.speed) } else if newY < p.initY { newY += min(p.initY-newY, p.speed) } } if minY := float32(bounds.Min.Y); newY <= minY { newY = minY } if maxY := float32(bounds.Max.Y); newY+p.height >= maxY { newY = maxY - p.height } p.y = newY return nil } func (p *paddle) reset() { p.x = p.initX p.y = p.initY } func (p *paddle) resize(x, y float32) { p.x *= x p.width *= x p.initX *= x p.y *= y p.height *= y p.speed *= y p.initY *= y } func (p *paddle) bounds() image.Rectangle { return image.Rect(int(p.x), int(p.y), int(p.x+p.width), int(p.y+p.height)) }