feat: render ball (#1)

Reviewed-on: #1
This commit is contained in:
Dawid Wysokiński 2023-11-28 05:52:00 +00:00
parent 692cac6920
commit 4d0d0bb8a6
4 changed files with 173 additions and 32 deletions

View File

@ -107,7 +107,7 @@ linters-settings:
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#add-constant
- name: add-constant
severity: warning
disabled: false
disabled: true
arguments:
- maxLitCount: "3"
allowStrs: "\"\""

65
internal/ball.go Normal file
View File

@ -0,0 +1,65 @@
package internal
import (
"image"
"image/color"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/vector"
)
type ball struct {
x float32
speedX float32
y float32
speedY float32
r float32
}
const (
ballBaselRadius = 5
ballBaseSpeedX = 1
ballBaseSpeedY = 1
)
func newBall(screenWidth, screenHeight int) *ball {
fScreenWidth := float32(screenWidth)
fScreenHeight := float32(screenHeight)
r := ballBaselRadius * fScreenHeight / BaseHeight
return &ball{
x: fScreenWidth/2.0 - r,
speedX: ballBaseSpeedX * fScreenWidth / BaseWidth,
y: fScreenHeight/2.0 - r,
speedY: ballBaseSpeedY * fScreenHeight / BaseHeight,
r: r,
}
}
var ballColor = color.White
func (b *ball) draw(img *ebiten.Image) {
vector.DrawFilledCircle(img, b.x, b.y, b.r, ballColor, false)
}
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
return nil
}
func (b *ball) resize(x, y float32) {
b.x *= x
b.speedX *= x
b.y *= y
b.speedY *= y
b.r *= y
}

89
internal/game.go Normal file
View File

@ -0,0 +1,89 @@
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
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,
}
}
func (g *Game) Update() error {
return g.ball.update(image.Rect(0, 0, g.width, g.height))
}
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)
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",
ebiten.ActualFPS(),
g.ball.x,
g.ball.y,
g.ball.speedX,
g.ball.speedY,
g.ball.r,
),
)
}
//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))
if g.img != nil {
g.img.Dispose()
g.img = nil
}
g.width = outsideWidth
g.height = outsideHeight
}
return outsideWidth, outsideHeight
}

49
main.go
View File

@ -1,43 +1,30 @@
package main
import (
"flag"
"log"
"gitea.dwysokinski.me/classic-games/tennis-game/internal"
"github.com/hajimehoshi/ebiten/v2"
"github.com/hajimehoshi/ebiten/v2/ebitenutil"
)
type Game struct{}
var _ ebiten.Game = (*Game)(nil)
func (g *Game) Update() error {
return nil
}
func (g *Game) Draw(screen *ebiten.Image) {
ebitenutil.DebugPrint(screen, "Hello, World!")
}
const (
screenWidth = 320
screenHeight = 240
)
//nolint:nonamedreturns
func (g *Game) Layout(_, _ int) (_screenWidth, _screenHeight int) {
return screenWidth, screenHeight
}
const (
windowWidth = 640
windowHeight = 480
)
func main() {
ebiten.SetWindowSize(windowWidth, windowHeight)
ebiten.SetWindowTitle("Hello, World!")
if err := ebiten.RunGame(&Game{}); err != nil {
fullscreen := flag.Bool("fullscreen", true, "")
debug := flag.Bool("debug", false, "")
flag.Parse()
ebiten.SetWindowTitle("Tennis game")
ebiten.SetWindowResizingMode(ebiten.WindowResizingModeEnabled)
ebiten.SetWindowSizeLimits(internal.BaseWidth, internal.BaseHeight, -1, -1)
w, h := ebiten.ScreenSizeInFullscreen()
if *fullscreen {
ebiten.SetFullscreen(true)
} else {
ebiten.SetWindowSize(w, h)
}
if err := ebiten.RunGame(internal.NewGame(w, h, *debug)); err != nil {
log.Fatal(err)
}
}