package internal import ( "fmt" "image" "image/color" "github.com/hajimehoshi/ebiten/v2" "github.com/hajimehoshi/ebiten/v2/ebitenutil" ) const ( BaseWidth = 640 BaseHeight = 360 ) type Game struct { 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), leftPaddle: newLeftPaddle(width, height, true), rightPaddle: newRightPaddle(width, height, false), debug: debug, } } func (g *Game) Update() error { 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 func (g *Game) Draw(screen *ebiten.Image) { if g.img == nil { g.img = ebiten.NewImage(g.width, g.height) } g.img.Fill(backgroundColor) g.ball.draw(g.img) g.leftPaddle.draw(g.img) g.rightPaddle.draw(g.img) if g.debug { g.drawDebug() } screen.DrawImage(g.img, nil) } func (g *Game) drawDebug() { ebitenutil.DebugPrint( g.img, fmt.Sprintf( "FPS: %0.2f"+ "\nBall: x=%v, y=%v, speedX=%v, speedY=%v, radius=%v"+ "\nLeft paddle: x=%v, y=%v, speed=%v, width=%v, height=%v, isControlledByPlayer=%v"+ "\nRight paddle: x=%v, y=%v, speed=%v, width=%v, height=%v, isControlledByPlayer=%v", ebiten.ActualFPS(), g.ball.x, g.ball.y, g.ball.speedX, g.ball.speedY, g.ball.r, g.leftPaddle.x, g.leftPaddle.y, g.leftPaddle.speed, g.leftPaddle.width, g.leftPaddle.height, g.leftPaddle.isControlledByPlayer, g.rightPaddle.x, g.rightPaddle.y, g.rightPaddle.speed, g.rightPaddle.width, g.rightPaddle.height, g.rightPaddle.isControlledByPlayer, ), ) } //nolint:nonamedreturns func (g *Game) Layout(outsideWidth, outsideHeight int) (_screenWidth, _screenHeight int) { if g.width != outsideWidth || g.height != outsideHeight { 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() g.img = nil } g.width = outsideWidth g.height = outsideHeight } return outsideWidth, outsideHeight }