feat: render paddles
This commit is contained in:
parent
4d0d0bb8a6
commit
b58f6439cb
|
@ -258,7 +258,7 @@ linters-settings:
|
|||
- name: function-result-limit
|
||||
severity: warning
|
||||
disabled: false
|
||||
arguments: [3]
|
||||
arguments: [4]
|
||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#function-length
|
||||
- name: function-length
|
||||
severity: warning
|
||||
|
|
|
@ -17,15 +17,15 @@ type ball struct {
|
|||
}
|
||||
|
||||
const (
|
||||
ballBaselRadius = 5
|
||||
ballBaseSpeedX = 1
|
||||
ballBaseSpeedY = 1
|
||||
ballBaseRadius = 5
|
||||
ballBaseSpeedX = 1
|
||||
ballBaseSpeedY = 1
|
||||
)
|
||||
|
||||
func newBall(screenWidth, screenHeight int) *ball {
|
||||
fScreenWidth := float32(screenWidth)
|
||||
fScreenHeight := float32(screenHeight)
|
||||
r := ballBaselRadius * fScreenHeight / BaseHeight
|
||||
r := ballBaseRadius * fScreenHeight / BaseHeight
|
||||
return &ball{
|
||||
x: fScreenWidth/2.0 - r,
|
||||
speedX: ballBaseSpeedX * fScreenWidth / BaseWidth,
|
||||
|
@ -42,20 +42,37 @@ func (b *ball) draw(img *ebiten.Image) {
|
|||
}
|
||||
|
||||
func (b *ball) update(bounds image.Rectangle) error {
|
||||
if b.x+b.r >= float32(bounds.Max.X) || b.x-b.r <= float32(bounds.Min.X) {
|
||||
b.speedX *= -1
|
||||
}
|
||||
|
||||
if b.y+b.r >= float32(bounds.Max.Y) || b.y-b.r <= float32(bounds.Min.Y) {
|
||||
b.speedY *= -1
|
||||
}
|
||||
|
||||
b.x += b.speedX
|
||||
b.y += b.speedY
|
||||
|
||||
b.x, b.y, b.speedX, b.speedY = b.nextPosAndSpeed(bounds)
|
||||
return nil
|
||||
}
|
||||
|
||||
//nolint:nonamedreturns
|
||||
func (b *ball) nextPos(bounds image.Rectangle) (x, y float32) {
|
||||
x, y, _, _ = b.nextPosAndSpeed(bounds)
|
||||
return x, y
|
||||
}
|
||||
|
||||
//nolint:nonamedreturns
|
||||
func (b *ball) nextPosAndSpeed(bounds image.Rectangle) (x, y, speedX, speedY float32) {
|
||||
speedX, speedY = b.nextSpeed(bounds)
|
||||
return b.x + speedX, b.y + speedY, speedX, speedY
|
||||
}
|
||||
|
||||
//nolint:nonamedreturns
|
||||
func (b *ball) nextSpeed(bounds image.Rectangle) (speedX, speedY float32) {
|
||||
speedX = b.speedX
|
||||
if b.x+b.r >= float32(bounds.Max.X) || b.x-b.r <= float32(bounds.Min.X) {
|
||||
speedX *= -1
|
||||
}
|
||||
|
||||
speedY = b.speedY
|
||||
if b.y+b.r >= float32(bounds.Max.Y) || b.y-b.r <= float32(bounds.Min.Y) {
|
||||
speedY *= -1
|
||||
}
|
||||
|
||||
return speedX, speedY
|
||||
}
|
||||
|
||||
func (b *ball) resize(x, y float32) {
|
||||
b.x *= x
|
||||
b.speedX *= x
|
||||
|
|
|
@ -15,26 +15,44 @@ const (
|
|||
)
|
||||
|
||||
type Game struct {
|
||||
width int
|
||||
height int
|
||||
ball *ball
|
||||
debug bool
|
||||
img *ebiten.Image
|
||||
width int
|
||||
height int
|
||||
ball *ball
|
||||
leftPaddle *paddle
|
||||
rightPaddle *paddle
|
||||
debug bool
|
||||
img *ebiten.Image
|
||||
}
|
||||
|
||||
var _ ebiten.Game = (*Game)(nil)
|
||||
|
||||
func NewGame(width, height int, debug bool) *Game {
|
||||
return &Game{
|
||||
width: width,
|
||||
height: height,
|
||||
ball: newBall(width, height),
|
||||
debug: debug,
|
||||
width: width,
|
||||
height: height,
|
||||
ball: newBall(width, height),
|
||||
leftPaddle: newLeftPaddle(width, height, true),
|
||||
rightPaddle: newRightPaddle(width, height, false),
|
||||
debug: debug,
|
||||
}
|
||||
}
|
||||
|
||||
func (g *Game) Update() error {
|
||||
return g.ball.update(image.Rect(0, 0, g.width, g.height))
|
||||
bounds := image.Rect(0, 0, g.width, g.height)
|
||||
|
||||
if err := g.ball.update(bounds); err != nil {
|
||||
return fmt.Errorf("couldn't update ball: %w", err)
|
||||
}
|
||||
|
||||
if err := g.leftPaddle.update(bounds, g.ball); err != nil {
|
||||
return fmt.Errorf("couldn't update left paddle: %w", err)
|
||||
}
|
||||
|
||||
if err := g.rightPaddle.update(bounds, g.ball); err != nil {
|
||||
return fmt.Errorf("couldn't update right paddle: %w", err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
var backgroundColor = color.Black
|
||||
|
@ -47,6 +65,8 @@ func (g *Game) Draw(screen *ebiten.Image) {
|
|||
g.img.Fill(backgroundColor)
|
||||
|
||||
g.ball.draw(g.img)
|
||||
g.leftPaddle.draw(g.img)
|
||||
g.rightPaddle.draw(g.img)
|
||||
|
||||
if g.debug {
|
||||
g.drawDebug()
|
||||
|
@ -74,7 +94,12 @@ func (g *Game) drawDebug() {
|
|||
//nolint:nonamedreturns
|
||||
func (g *Game) Layout(outsideWidth, outsideHeight int) (_screenWidth, _screenHeight int) {
|
||||
if g.width != outsideWidth || g.height != outsideHeight {
|
||||
g.ball.resize(float32(outsideWidth)/float32(g.width), float32(outsideHeight)/float32(g.height))
|
||||
ratioWidth := float32(outsideWidth) / float32(g.width)
|
||||
ratioHeight := float32(outsideHeight) / float32(g.height)
|
||||
|
||||
g.ball.resize(ratioWidth, ratioHeight)
|
||||
g.leftPaddle.resize(ratioWidth, ratioHeight)
|
||||
g.rightPaddle.resize(ratioWidth, ratioHeight)
|
||||
|
||||
if g.img != nil {
|
||||
g.img.Dispose()
|
||||
|
|
125
internal/paddle.go
Normal file
125
internal/paddle.go
Normal file
|
@ -0,0 +1,125 @@
|
|||
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 = 10
|
||||
paddleBaseHeight = 100
|
||||
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:Revive,cyclomatic
|
||||
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) 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
|
||||
}
|
Loading…
Reference in New Issue
Block a user