First run at basic structure
This commit is contained in:
117
internal/hero/hero.go
Normal file
117
internal/hero/hero.go
Normal file
@@ -0,0 +1,117 @@
|
||||
package hero
|
||||
|
||||
import (
|
||||
"image/color"
|
||||
"math"
|
||||
|
||||
"github.com/hajimehoshi/ebiten/v2"
|
||||
"github.com/hajimehoshi/ebiten/v2/vector"
|
||||
)
|
||||
|
||||
// Direction flags from the controls.
|
||||
type Input struct {
|
||||
Left bool
|
||||
Right bool
|
||||
Up bool
|
||||
Down bool
|
||||
}
|
||||
|
||||
// Playfield limits for movement.
|
||||
type Bounds struct {
|
||||
Width float64
|
||||
Height float64
|
||||
}
|
||||
|
||||
// Player avatar data.
|
||||
type Hero struct {
|
||||
X float64
|
||||
Y float64
|
||||
Radius float64
|
||||
Speed float64
|
||||
Color color.NRGBA
|
||||
}
|
||||
|
||||
// Spawn settings for the avatar.
|
||||
type Config struct {
|
||||
StartX float64
|
||||
StartY float64
|
||||
Radius float64
|
||||
Speed float64
|
||||
Color color.NRGBA
|
||||
}
|
||||
|
||||
// Builds an avatar from the config with fallbacks.
|
||||
func New(cfg Config) *Hero {
|
||||
if cfg.Radius <= 0 {
|
||||
cfg.Radius = 24
|
||||
}
|
||||
if cfg.Speed <= 0 {
|
||||
cfg.Speed = 180
|
||||
}
|
||||
if cfg.Color.A == 0 {
|
||||
cfg.Color = color.NRGBA{R: 210, G: 220, B: 255, A: 255}
|
||||
}
|
||||
|
||||
return &Hero{
|
||||
X: cfg.StartX,
|
||||
Y: cfg.StartY,
|
||||
Radius: cfg.Radius,
|
||||
Speed: cfg.Speed,
|
||||
Color: cfg.Color,
|
||||
}
|
||||
}
|
||||
|
||||
// Applies movement input and clamps to the playfield.
|
||||
func (h *Hero) Update(input Input, dt float64, bounds Bounds) {
|
||||
dx, dy := 0.0, 0.0
|
||||
|
||||
if input.Left {
|
||||
dx -= 1
|
||||
}
|
||||
if input.Right {
|
||||
dx += 1
|
||||
}
|
||||
if input.Up {
|
||||
dy -= 1
|
||||
}
|
||||
if input.Down {
|
||||
dy += 1
|
||||
}
|
||||
|
||||
if dx != 0 || dy != 0 {
|
||||
length := math.Hypot(dx, dy)
|
||||
dx /= length
|
||||
dy /= length
|
||||
}
|
||||
|
||||
h.X += dx * h.Speed * dt
|
||||
h.Y += dy * h.Speed * dt
|
||||
|
||||
maxX := math.Max(h.Radius, bounds.Width-h.Radius)
|
||||
maxY := math.Max(h.Radius, bounds.Height-h.Radius)
|
||||
|
||||
h.X = clamp(h.X, h.Radius, maxX)
|
||||
h.Y = clamp(h.Y, h.Radius, maxY)
|
||||
}
|
||||
|
||||
// Renders the avatar as a filled circle.
|
||||
func (h *Hero) Draw(screen *ebiten.Image) {
|
||||
vector.FillCircle(
|
||||
screen,
|
||||
float32(h.X),
|
||||
float32(h.Y),
|
||||
float32(h.Radius),
|
||||
h.Color,
|
||||
false,
|
||||
)
|
||||
}
|
||||
|
||||
func clamp(value, min, max float64) float64 {
|
||||
if value < min {
|
||||
return min
|
||||
}
|
||||
if value > max {
|
||||
return max
|
||||
}
|
||||
return value
|
||||
}
|
||||
Reference in New Issue
Block a user