Remove pointers for concurrency
parent
e20133d5d0
commit
4882cdedf5
|
@ -0,0 +1,15 @@
|
|||
{
|
||||
// Use IntelliSense to learn about possible attributes.
|
||||
// Hover to view descriptions of existing attributes.
|
||||
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
|
||||
"version": "0.2.0",
|
||||
"configurations": [
|
||||
{
|
||||
"name": "Launch Package",
|
||||
"type": "go",
|
||||
"request": "launch",
|
||||
"mode": "auto",
|
||||
"program": "${workspaceFolder}"
|
||||
}
|
||||
]
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
game.title = "Project Ely"
|
||||
game.framerate = 60.0
|
||||
|
||||
log.utcTime = false
|
||||
log.file = "output.log"
|
||||
log.writeToFile = false
|
||||
|
|
|
@ -9,6 +9,7 @@ import (
|
|||
var defaultConfig gosimpleconf.ConfigMap = gosimpleconf.ConfigMap{
|
||||
"game.title": "Project Ely",
|
||||
"game.framerate": "60.0",
|
||||
"log.utcTime": "false",
|
||||
"log.writeToFile": "false",
|
||||
}
|
||||
|
||||
|
|
|
@ -9,19 +9,24 @@ import (
|
|||
|
||||
type logWriter struct {
|
||||
writeToFile bool
|
||||
utcTime bool
|
||||
logFile *os.File
|
||||
}
|
||||
|
||||
func (w *logWriter) Write(bytes []byte) (int, error) {
|
||||
t := time.Now().UTC().Format(time.RFC3339)
|
||||
return fmt.Fprintf(w.logFile, "%v %v", t, string(bytes))
|
||||
t := time.Now()
|
||||
if w.utcTime {
|
||||
t = t.UTC()
|
||||
}
|
||||
format := t.Format(time.RFC3339)
|
||||
return fmt.Fprintf(w.logFile, "%v %v", format, string(bytes))
|
||||
}
|
||||
|
||||
func (w *logWriter) Cleanup() {
|
||||
defer w.logFile.Close()
|
||||
}
|
||||
|
||||
func SetupLogging(writeToFile bool, logFilename string) (*logWriter, error) {
|
||||
func SetupLogging(writeToFile bool, utcTime bool, logFilename string) (*logWriter, error) {
|
||||
var err error
|
||||
log.SetFlags(0)
|
||||
|
||||
|
@ -35,6 +40,7 @@ func SetupLogging(writeToFile bool, logFilename string) (*logWriter, error) {
|
|||
|
||||
writer := &logWriter{
|
||||
writeToFile: writeToFile,
|
||||
utcTime: utcTime,
|
||||
logFile: logFile,
|
||||
}
|
||||
log.SetOutput(writer)
|
||||
|
|
|
@ -6,7 +6,7 @@ import "github.com/veandco/go-sdl2/sdl"
|
|||
// Since this is only a 2D game with SDL, the projection is relatively simple: window + camera = world.
|
||||
// https://gamedev.stackexchange.com/a/123844
|
||||
type camera struct {
|
||||
pos *sdl.Point
|
||||
pos sdl.Point
|
||||
}
|
||||
|
||||
func NewCamera() *camera {
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
)
|
||||
|
||||
type SpriteAnimation interface {
|
||||
Draw(frame int, worldPosition *sdl.Point, angle float64, center *sdl.Point, flip sdl.RendererFlip) error
|
||||
Draw(frame int, worldPosition sdl.Point, angle float64, center sdl.Point, flip sdl.RendererFlip) error
|
||||
}
|
||||
|
||||
// An entityAnimation will take a SpriteAnimation and may manipulate it somehow (e.g. flipped for walking the other direction)
|
||||
|
@ -15,7 +15,7 @@ type entityAnimation struct {
|
|||
speed int
|
||||
length int
|
||||
angle float64
|
||||
center *sdl.Point
|
||||
center sdl.Point
|
||||
flip sdl.RendererFlip
|
||||
}
|
||||
|
||||
|
@ -24,11 +24,11 @@ func NewEntityAnimation(
|
|||
speed int,
|
||||
length int,
|
||||
angle float64,
|
||||
center *sdl.Point,
|
||||
center sdl.Point,
|
||||
flip sdl.RendererFlip,
|
||||
) *entityAnimation {
|
||||
) entityAnimation {
|
||||
|
||||
e := entityAnimation{
|
||||
return entityAnimation{
|
||||
spriteAnimation: spriteAnimation,
|
||||
speed: speed,
|
||||
length: length,
|
||||
|
@ -36,18 +36,23 @@ func NewEntityAnimation(
|
|||
center: center,
|
||||
flip: flip,
|
||||
}
|
||||
|
||||
return &e
|
||||
}
|
||||
|
||||
func (e *entityAnimation) Draw(frame int, windowPosition *sdl.Point) error {
|
||||
func (e entityAnimation) Draw(frame int, windowPosition sdl.Point) error {
|
||||
return e.spriteAnimation.Draw(frame, windowPosition, e.angle, e.center, e.flip)
|
||||
}
|
||||
|
||||
func (e *entityAnimation) GetSpeed() int {
|
||||
func (e entityAnimation) GetSpeed() int {
|
||||
return e.speed
|
||||
}
|
||||
|
||||
func DefineAnimations() {
|
||||
DefinePenguinAnimations()
|
||||
}
|
||||
|
||||
func getCenter(dimensions sdl.Point) sdl.Point {
|
||||
x := dimensions.X / 2
|
||||
y := dimensions.Y / 2
|
||||
|
||||
return sdl.Point{X: x, Y: y}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ import (
|
|||
"github.com/veandco/go-sdl2/sdl"
|
||||
)
|
||||
|
||||
var PenguinAnimations map[int]*entityAnimation
|
||||
var PenguinAnimations map[int]entityAnimation
|
||||
|
||||
const (
|
||||
PENGUIN_WALK_RIGHT int = iota
|
||||
|
@ -29,21 +29,21 @@ func DefinePenguinAnimations() {
|
|||
var (
|
||||
dimensions sdl.Point
|
||||
offset sdl.Point
|
||||
center *sdl.Point
|
||||
center sdl.Point
|
||||
length int
|
||||
speed int
|
||||
border int
|
||||
)
|
||||
|
||||
dimensions = sdl.Point{X: 13, Y: 17}
|
||||
PenguinAnimations = make(map[int]*entityAnimation)
|
||||
PenguinAnimations = make(map[int]entityAnimation)
|
||||
|
||||
// Walking Right is in the spritesheet.
|
||||
speed = 5
|
||||
offset = sdl.Point{X: 0, Y: 1}
|
||||
length = 5
|
||||
border = 1 // optional border around each sprite
|
||||
center = nil // center is for rotation, nil will default to w/2 h/2
|
||||
border = 1 // optional border around each sprite
|
||||
center = getCenter(dimensions) // center is for rotation, nil will default to w/2 h/2
|
||||
walkRight := sprite.NewAnimation(filename, dimensions, offset, length, border)
|
||||
PenguinAnimations[PENGUIN_WALK_RIGHT] = NewEntityAnimation(walkRight, speed, length, 0, center, sdl.FLIP_NONE)
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ import (
|
|||
)
|
||||
|
||||
type EntityAnimation interface {
|
||||
Draw(step int, windowPosition *sdl.Point) error
|
||||
Draw(step int, windowPosition sdl.Point) error
|
||||
GetSpeed() int
|
||||
}
|
||||
|
||||
|
@ -21,12 +21,12 @@ const (
|
|||
// The following are axis direction vectors based on world coordinates.
|
||||
// UP/DOWN is intentionally UP = positive (which is different from window coordinates)
|
||||
var (
|
||||
VEC_LEFT = &vector.Vec2F{X: -1, Y: 0}
|
||||
VEC_RIGHT = &vector.Vec2F{X: 1, Y: 0}
|
||||
VEC_UP = &vector.Vec2F{X: 0, Y: 1}
|
||||
VEC_DOWN = &vector.Vec2F{X: 0, Y: -1}
|
||||
VEC_LEFT = vector.Vec2F{X: -1, Y: 0}
|
||||
VEC_RIGHT = vector.Vec2F{X: 1, Y: 0}
|
||||
VEC_UP = vector.Vec2F{X: 0, Y: 1}
|
||||
VEC_DOWN = vector.Vec2F{X: 0, Y: -1}
|
||||
|
||||
VEC_DIRECTIONS = []*vector.Vec2F{
|
||||
VEC_DIRECTIONS = []vector.Vec2F{
|
||||
// Prefer left/right animations by checking them first in the list
|
||||
VEC_LEFT,
|
||||
VEC_RIGHT,
|
||||
|
@ -35,7 +35,7 @@ var (
|
|||
}
|
||||
)
|
||||
|
||||
func determineClosestDirection(velocity *vector.Vec2F) int {
|
||||
func determineClosestDirection(velocity vector.Vec2F) int {
|
||||
closest := DIR_RIGHT
|
||||
max := 0.0
|
||||
buffer := 0.5 // This buffer lets us stick to the left/right animations for diagonal movement
|
||||
|
|
|
@ -20,27 +20,25 @@ type penguin struct {
|
|||
updateAnimation bool // if false, don't change the animation
|
||||
|
||||
// Physical parameters
|
||||
worldPosition *vector.Vec2F // where is the center of this object
|
||||
velocity *vector.Vec2F // movement direction to be applied each tick
|
||||
speed float64 // movement magnitude to multiply with the velocity
|
||||
worldPosition vector.Vec2F // where is the center of this object
|
||||
velocity vector.Vec2F // movement direction to be applied each tick
|
||||
speed float64 // movement magnitude to multiply with the velocity
|
||||
}
|
||||
|
||||
func NewPenguin(renderer *sdl.Renderer) *penguin {
|
||||
func NewPenguin(renderer *sdl.Renderer) penguin {
|
||||
position := vector.Vec2F{}
|
||||
velocity := vector.Vec2F{}
|
||||
speed := 1.0
|
||||
|
||||
p := penguin{
|
||||
return penguin{
|
||||
currentAnimation: animation.PenguinAnimations[animation.PENGUIN_DEFAULT],
|
||||
animationStep: 0,
|
||||
direction: DIR_RIGHT,
|
||||
|
||||
worldPosition: &position,
|
||||
worldPosition: position,
|
||||
speed: speed,
|
||||
velocity: &velocity,
|
||||
velocity: velocity,
|
||||
}
|
||||
|
||||
return &p
|
||||
}
|
||||
|
||||
func (p *penguin) Draw() error {
|
||||
|
@ -48,7 +46,7 @@ func (p *penguin) Draw() error {
|
|||
|
||||
// TODO
|
||||
//windowPosition := worldPosToWindowPos()
|
||||
windowPosition := &sdl.Point{
|
||||
windowPosition := sdl.Point{
|
||||
X: int32(math.Round(p.worldPosition.X)),
|
||||
Y: int32(math.Round(-1 * p.worldPosition.Y)),
|
||||
}
|
||||
|
@ -63,7 +61,7 @@ func (p *penguin) Draw() error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func (p *penguin) SetPosition(vec *vector.Vec2F) {
|
||||
func (p *penguin) SetPosition(vec vector.Vec2F) {
|
||||
p.worldPosition = vec
|
||||
}
|
||||
|
||||
|
@ -91,7 +89,7 @@ func (p *penguin) MoveX(x float64) {
|
|||
defer p.mx.Unlock()
|
||||
|
||||
p.velocity.X = x
|
||||
p.velocity.Normalize()
|
||||
p.velocity = p.velocity.Normalized()
|
||||
p.updateAnimation = true
|
||||
}
|
||||
|
||||
|
@ -101,7 +99,7 @@ func (p *penguin) MoveY(y float64) {
|
|||
|
||||
// (0,0) is the top left, so negative y moves up
|
||||
p.velocity.Y = y
|
||||
p.velocity.Normalize()
|
||||
p.velocity.Normalized()
|
||||
p.updateAnimation = true
|
||||
}
|
||||
|
||||
|
|
|
@ -78,7 +78,6 @@ func Run(ctx context.Context, configMap gosimpleconf.ConfigMap) error {
|
|||
err = fmt.Errorf("failed in InitSpriteCache: %w", err)
|
||||
return err
|
||||
}
|
||||
defer sprite.CleanupSpriteCache()
|
||||
|
||||
animation.DefineAnimations()
|
||||
|
||||
|
@ -93,7 +92,7 @@ func Run(ctx context.Context, configMap gosimpleconf.ConfigMap) error {
|
|||
// Let them control a penguin to start with
|
||||
player1 := player.NewPlayer(ctx, inputHandler)
|
||||
penguinEntity := types.NewPenguin(renderer)
|
||||
penguinCmdHandler := command.NewCommandHandler(ctx, penguinEntity)
|
||||
penguinCmdHandler := command.NewCommandHandler(ctx, &penguinEntity)
|
||||
penguinEntity.SetSpeed(2.0)
|
||||
entityList = append(entityList, penguinCmdHandler)
|
||||
player1.SetEntityChan(penguinCmdHandler.CommandRequest())
|
||||
|
@ -105,9 +104,9 @@ func Run(ctx context.Context, configMap gosimpleconf.ConfigMap) error {
|
|||
|
||||
for i := 0; i < 10; i++ {
|
||||
entity := types.NewPenguin(renderer)
|
||||
entityCmd := command.NewCommandHandler(ctx, entity)
|
||||
entityCmd := command.NewCommandHandler(ctx, &entity)
|
||||
randomPos := vector.Vec2F{X: rand.Float64() * 500, Y: rand.Float64() * -500}
|
||||
entity.SetPosition(&randomPos)
|
||||
entity.SetPosition(randomPos)
|
||||
entity.SetAnimation(rand.Intn(animation.PENGUIN_NUM_ANIMS))
|
||||
entityList = append(entityList, entityCmd)
|
||||
|
||||
|
@ -204,6 +203,8 @@ func Run(ctx context.Context, configMap gosimpleconf.ConfigMap) error {
|
|||
e.CloseRequests()
|
||||
}
|
||||
|
||||
sprite.CleanupSpriteCache()
|
||||
|
||||
wg.Wait()
|
||||
|
||||
return nil
|
||||
|
|
|
@ -22,26 +22,24 @@ func NewAnimation(
|
|||
offset sdl.Point,
|
||||
length int,
|
||||
border int,
|
||||
) *spriteAnimation {
|
||||
) spriteAnimation {
|
||||
|
||||
spritesheet := GetSpritesheet(filename)
|
||||
|
||||
a := spriteAnimation{
|
||||
return spriteAnimation{
|
||||
spritesheet: spritesheet,
|
||||
dimensions: dimensions,
|
||||
offset: offset,
|
||||
length: length,
|
||||
border: border,
|
||||
}
|
||||
|
||||
return &a
|
||||
}
|
||||
|
||||
func (a *spriteAnimation) Draw(
|
||||
func (a spriteAnimation) Draw(
|
||||
frame int,
|
||||
windowPosition *sdl.Point,
|
||||
windowPosition sdl.Point,
|
||||
angle float64,
|
||||
center *sdl.Point,
|
||||
center sdl.Point,
|
||||
flip sdl.RendererFlip,
|
||||
) error {
|
||||
|
||||
|
@ -64,7 +62,7 @@ func (a *spriteAnimation) Draw(
|
|||
H: height,
|
||||
}
|
||||
|
||||
err := a.checkBounds(§ion)
|
||||
err := a.checkBounds(section)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -76,7 +74,7 @@ func (a *spriteAnimation) Draw(
|
|||
H: height * 2,
|
||||
}
|
||||
|
||||
err = a.spritesheet.Draw(§ion, &placement, angle, center, flip)
|
||||
err = a.spritesheet.Draw(section, placement, angle, center, flip)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -84,7 +82,7 @@ func (a *spriteAnimation) Draw(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (a *spriteAnimation) checkBounds(section *sdl.Rect) error {
|
||||
func (a spriteAnimation) checkBounds(section sdl.Rect) error {
|
||||
width := a.spritesheet.surface.W
|
||||
height := a.spritesheet.surface.H
|
||||
|
||||
|
@ -103,7 +101,7 @@ func (a *spriteAnimation) checkBounds(section *sdl.Rect) error {
|
|||
}
|
||||
|
||||
if outOfBounds {
|
||||
return fmt.Errorf("draw section was out of bounds - section: %v, image: %v", *section, a.spritesheet.surface.Bounds())
|
||||
return fmt.Errorf("draw section was out of bounds - section: %v, image: %v", section, a.spritesheet.surface.Bounds())
|
||||
}
|
||||
|
||||
return nil
|
||||
|
|
|
@ -49,39 +49,33 @@ func NewSprite(renderer *sdl.Renderer, filename string) (*spritesheet, error) {
|
|||
}
|
||||
|
||||
func (s *spritesheet) Cleanup() {
|
||||
// Clean up image
|
||||
defer func() {
|
||||
if s.surface != nil {
|
||||
sdl.Do(func() {
|
||||
s.surface.Free()
|
||||
})
|
||||
}
|
||||
}()
|
||||
|
||||
// Clean up spritesheet
|
||||
defer func() {
|
||||
sdl.Do(func() {
|
||||
// Clean up spritesheet
|
||||
if s.texture != nil {
|
||||
sdl.Do(func() {
|
||||
err := s.texture.Destroy()
|
||||
if err != nil {
|
||||
log.Printf("error destroying spritesheet %v: %v\n", s.filename, err)
|
||||
}
|
||||
})
|
||||
err := s.texture.Destroy()
|
||||
if err != nil {
|
||||
log.Printf("error destroying spritesheet %v: %v\n", s.filename, err)
|
||||
}
|
||||
}
|
||||
}()
|
||||
|
||||
// Clean up image
|
||||
if s.surface != nil {
|
||||
s.surface.Free()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func (s *spritesheet) Draw(
|
||||
section *sdl.Rect,
|
||||
placement *sdl.Rect,
|
||||
section sdl.Rect,
|
||||
placement sdl.Rect,
|
||||
angle float64,
|
||||
center *sdl.Point,
|
||||
center sdl.Point,
|
||||
flip sdl.RendererFlip,
|
||||
) error {
|
||||
|
||||
var err error
|
||||
sdl.Do(func() {
|
||||
err = s.renderer.CopyEx(s.texture, section, placement, angle, center, flip)
|
||||
err = s.renderer.CopyEx(s.texture, §ion, &placement, angle, ¢er, flip)
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@ -90,10 +84,9 @@ func (s *spritesheet) Draw(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (s *spritesheet) Bounds() *sdl.Point {
|
||||
p := sdl.Point{
|
||||
func (s *spritesheet) Bounds() sdl.Point {
|
||||
return sdl.Point{
|
||||
X: s.surface.W,
|
||||
Y: s.surface.H,
|
||||
}
|
||||
return &p
|
||||
}
|
||||
|
|
|
@ -28,20 +28,19 @@ var (
|
|||
)
|
||||
|
||||
func InitSpriteCache(renderer *sdl.Renderer) error {
|
||||
var err error
|
||||
|
||||
defaultSprite, err = createDefaultSprite(renderer)
|
||||
if err != nil {
|
||||
log.Printf("failed to create DefaultSprite: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
spriteCache = make(map[string]*spritesheet)
|
||||
|
||||
for _, filename := range fileList {
|
||||
s, err := NewSprite(renderer, filename)
|
||||
if err != nil {
|
||||
log.Printf("error creating sprite %v, using DefaultSprite: %v", filename, err)
|
||||
|
||||
defaultSprite, err = createDefaultSprite(renderer)
|
||||
if err != nil {
|
||||
log.Printf("failed to create DefaultSprite: %v", err)
|
||||
return err
|
||||
}
|
||||
|
||||
spriteCache[filename] = defaultSprite
|
||||
} else {
|
||||
spriteCache[filename] = s
|
||||
|
@ -82,6 +81,7 @@ func createDefaultSprite(renderer *sdl.Renderer) (*spritesheet, error) {
|
|||
}
|
||||
|
||||
s := spritesheet{
|
||||
filename: "DEFAULT_SPRITE",
|
||||
renderer: renderer,
|
||||
texture: texture,
|
||||
surface: surface,
|
||||
|
|
|
@ -11,24 +11,28 @@ type Vec2F struct {
|
|||
Y float64
|
||||
}
|
||||
|
||||
func (v *Vec2F) Zero() bool {
|
||||
func (v Vec2F) Zero() bool {
|
||||
return v.X == 0.0 && v.Y == 0.0
|
||||
}
|
||||
|
||||
func (v *Vec2F) LengthSquared() float64 {
|
||||
func (v Vec2F) LengthSquared() float64 {
|
||||
return v.X*v.X + v.Y*v.Y
|
||||
}
|
||||
|
||||
func (v *Vec2F) Normalize() {
|
||||
func (v Vec2F) Normalized() Vec2F {
|
||||
output := Vec2F{X: v.X, Y: v.Y}
|
||||
|
||||
length := math.Hypot(v.X, v.Y)
|
||||
if length == 0 {
|
||||
return
|
||||
return output
|
||||
}
|
||||
|
||||
v.X = v.X / length
|
||||
v.Y = v.Y / length
|
||||
output.X = v.X / length
|
||||
output.Y = v.Y / length
|
||||
|
||||
return output
|
||||
}
|
||||
|
||||
func (v *Vec2F) Dot(other *Vec2F) float64 {
|
||||
func (v Vec2F) Dot(other Vec2F) float64 {
|
||||
return v.X*other.X + v.Y*other.Y
|
||||
}
|
||||
|
|
3
main.go
3
main.go
|
@ -58,8 +58,9 @@ func run(ctx context.Context) error {
|
|||
|
||||
// Setup logging
|
||||
writeToFile := gosimpleconf.Bool(configMap["log.writeToFile"])
|
||||
utcTime := gosimpleconf.Bool(configMap["log.utcTime"])
|
||||
logFilename := configMap["log.file"]
|
||||
logWriter, err := config.SetupLogging(writeToFile, logFilename)
|
||||
logWriter, err := config.SetupLogging(writeToFile, utcTime, logFilename)
|
||||
if err != nil {
|
||||
log.Fatalf("error setting up logging: %v\n", err)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue