2023-11-29 06:59:38 +00:00
|
|
|
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 (
|
2023-12-02 08:11:39 +00:00
|
|
|
paddleBaseWidth = 7
|
2023-12-02 08:08:52 +00:00
|
|
|
paddleBaseHeight = 75
|
2023-11-29 06:59:38 +00:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2023-12-01 05:42:57 +00:00
|
|
|
//nolint:gocyclo
|
2023-11-29 06:59:38 +00:00
|
|
|
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
|
|
|
|
}
|
|
|
|
|
2023-11-30 06:28:09 +00:00
|
|
|
func (p *paddle) reset() {
|
|
|
|
p.x = p.initX
|
|
|
|
p.y = p.initY
|
|
|
|
}
|
|
|
|
|
2023-11-29 06:59:38 +00:00
|
|
|
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
|
|
|
|
}
|
2023-11-30 06:28:09 +00:00
|
|
|
|
|
|
|
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))
|
|
|
|
}
|