feat: render ball #1
|
@ -107,7 +107,7 @@ linters-settings:
|
||||||
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#add-constant
|
# https://github.com/mgechev/revive/blob/master/RULES_DESCRIPTIONS.md#add-constant
|
||||||
- name: add-constant
|
- name: add-constant
|
||||||
severity: warning
|
severity: warning
|
||||||
disabled: false
|
disabled: true
|
||||||
arguments:
|
arguments:
|
||||||
- maxLitCount: "3"
|
- maxLitCount: "3"
|
||||||
allowStrs: "\"\""
|
allowStrs: "\"\""
|
||||||
|
|
65
internal/ball.go
Normal file
65
internal/ball.go
Normal 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
89
internal/game.go
Normal 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
49
main.go
|
@ -1,43 +1,30 @@
|
||||||
package main
|
package main
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"flag"
|
||||||
"log"
|
"log"
|
||||||
|
|
||||||
|
"gitea.dwysokinski.me/classic-games/tennis-game/internal"
|
||||||
"github.com/hajimehoshi/ebiten/v2"
|
"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() {
|
func main() {
|
||||||
ebiten.SetWindowSize(windowWidth, windowHeight)
|
fullscreen := flag.Bool("fullscreen", true, "")
|
||||||
ebiten.SetWindowTitle("Hello, World!")
|
debug := flag.Bool("debug", false, "")
|
||||||
if err := ebiten.RunGame(&Game{}); err != nil {
|
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)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user