diff options
| -rw-r--r-- | ecs/event.go | 6 | ||||
| -rw-r--r-- | ecs/gameobject.go | 16 | ||||
| -rw-r--r-- | go.mod | 3 | ||||
| -rw-r--r-- | go.sum | 10 | ||||
| -rw-r--r-- | input/input.go | 30 | ||||
| -rw-r--r-- | input/sdl.go | 34 | ||||
| -rw-r--r-- | loop/loop.go | 27 | ||||
| -rw-r--r-- | main.go | 24 | ||||
| -rw-r--r-- | objs/cursor.go | 31 | ||||
| -rw-r--r-- | objs/paddle.go | 26 | ||||
| -rw-r--r-- | objs/root.go | 25 | ||||
| -rw-r--r-- | render/init.go | 32 | ||||
| -rw-r--r-- | render/render.go | 24 |
13 files changed, 288 insertions, 0 deletions
diff --git a/ecs/event.go b/ecs/event.go new file mode 100644 index 0000000..00904d9 --- /dev/null +++ b/ecs/event.go @@ -0,0 +1,6 @@ +package ecs + +type Event struct { + // Delta is time between events in ms + Delta uint64 +} diff --git a/ecs/gameobject.go b/ecs/gameobject.go new file mode 100644 index 0000000..a2718c3 --- /dev/null +++ b/ecs/gameobject.go @@ -0,0 +1,16 @@ +package ecs + +import "github.com/Zyko0/go-sdl3/sdl" + +type GameObject struct { + Position sdl.FPoint + Children []IsGameObject +} + +func (g *GameObject) GO() *GameObject { + return g +} + +type IsGameObject interface { + GO() *GameObject +} @@ -4,5 +4,8 @@ go 1.26.5 require ( github.com/Zyko0/go-sdl3 v0.1.1 // indirect + github.com/Zyko0/purego-gen v0.0.0-20250727121216-3bcd331a1e0c // indirect + github.com/ebitengine/purego v0.10.0 // indirect github.com/spf13/pflag v1.0.10 // indirect + golang.org/x/sys v0.7.0 // indirect ) @@ -0,0 +1,10 @@ +github.com/Zyko0/go-sdl3 v0.1.1 h1:tXlnEcEJa9eqyzaBpCktOGteJGbUfnvG6ocURdsspHw= +github.com/Zyko0/go-sdl3 v0.1.1/go.mod h1:LOqUd6DUUkCO/8quWPfovV1Ep/nr/aw0uBT5vdlAIQY= +github.com/Zyko0/purego-gen v0.0.0-20250727121216-3bcd331a1e0c h1:3z1BdpfvUbaP7oXjPabl7STN7zz88S432hZJ8M095kI= +github.com/Zyko0/purego-gen v0.0.0-20250727121216-3bcd331a1e0c/go.mod h1:xpUxPkAb7v0Ffn/NGp1XpD+tZly4dpSPI7DTAFT37es= +github.com/ebitengine/purego v0.10.0 h1:QIw4xfpWT6GWTzaW5XEKy3HXoqrJGx1ijYHzTF0/ISU= +github.com/ebitengine/purego v0.10.0/go.mod h1:iIjxzd6CiRiOG0UyXP+V1+jWqUXVjPKLAI0mRfJZTmQ= +github.com/spf13/pflag v1.0.10 h1:4EBh2KAYBwaONj6b2Ye1GiHfwjqyROoF4RwYO+vPwFk= +github.com/spf13/pflag v1.0.10/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU= +golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= diff --git a/input/input.go b/input/input.go new file mode 100644 index 0000000..94f4e56 --- /dev/null +++ b/input/input.go @@ -0,0 +1,30 @@ +package input + +import "ponger/ecs" + +type DeviceID int + +type Event struct { + ecs.Event + Which DeviceID + Dx, Dy float32 + JustPressed, JustReleased, IsPressed bool +} + +type Handler interface { + Process(ev Event) +} + +func ProcessTree(root any, ev Event) { + if inp, ok := root.(Handler); ok { + inp.Process(ev) + } + if g, ok := root.(*ecs.GameObject); ok { + for _, c := range g.Children { + if c == nil { + continue + } + ProcessTree(c, ev) + } + } +} diff --git a/input/sdl.go b/input/sdl.go new file mode 100644 index 0000000..6b88f35 --- /dev/null +++ b/input/sdl.go @@ -0,0 +1,34 @@ +package input + +import ( + "github.com/Zyko0/go-sdl3/sdl" + "ponger/ecs" +) + +func Poll(root ecs.IsGameObject, delta uint64) error { + e := Event{ + Event: ecs.Event{ + Delta: delta, + }, + } + var event sdl.Event + for sdl.PollEvent(&event) { + switch event.Type { + case sdl.EVENT_QUIT: + return sdl.EndLoop + case sdl.EVENT_MOUSE_MOTION: + ev := event.MouseMotionEvent() + e.Which = DeviceID(ev.Which) + e.Dx = ev.Xrel + e.Dy = ev.Yrel + case sdl.EVENT_MOUSE_BUTTON_DOWN, sdl.EVENT_MOUSE_BUTTON_UP: + ev := event.MouseButtonEvent() + e.Which = DeviceID(ev.Which) + e.JustPressed = ev.Down + e.JustReleased = !ev.Down + e.IsPressed = ev.Down + } + } + ProcessTree(root, e) + return nil +} diff --git a/loop/loop.go b/loop/loop.go new file mode 100644 index 0000000..8d64e1e --- /dev/null +++ b/loop/loop.go @@ -0,0 +1,27 @@ +package loop + +import ( + "github.com/Zyko0/go-sdl3/sdl" + "ponger/ecs" + "ponger/input" + "ponger/render" +) + +func New(game ecs.IsGameObject, window *sdl.Window, renderer *sdl.Renderer) func() error { + now := sdl.Ticks() + return func() error { + next := sdl.Ticks() + delta := next - now + err := input.Poll(game, delta) + if err != nil { + return err + } + render.Render(game, renderer) + err = renderer.Present() + if err != nil { + return err + } + now = next + return nil + } +} @@ -1,5 +1,29 @@ package main +import ( + "github.com/Zyko0/go-sdl3/bin/binsdl" + "github.com/Zyko0/go-sdl3/sdl" + "github.com/spf13/pflag" + "ponger/loop" + "ponger/objs" + "ponger/render" +) + func main() { + pflag.Parse() + + defer binsdl.Load().Unload() + defer sdl.Quit() + + window, renderer, exit, err := render.Init() + defer exit() + if err != nil { + panic(err) + } + game := objs.NewRoot(objs.NewCursor()) + err = sdl.RunLoop(loop.New(game, window, renderer)) + if err != nil { + panic(err) + } } diff --git a/objs/cursor.go b/objs/cursor.go new file mode 100644 index 0000000..b1fdca3 --- /dev/null +++ b/objs/cursor.go @@ -0,0 +1,31 @@ +package objs + +import ( + "github.com/Zyko0/go-sdl3/sdl" + "ponger/ecs" + "ponger/input" +) + +type Cursor struct { + *ecs.GameObject +} + +func (c *Cursor) Render(renderer *sdl.Renderer) { + renderer.SetDrawColor(255, 0, 0, 255) + renderer.RenderPoint(c.Position.X, c.Position.Y) +} + +func (c *Cursor) Process(ev input.Event) { + c.Position.X += ev.Dx + c.Position.Y += ev.Dy +} + +func (c *Cursor) GO() *ecs.GameObject { + return c.GameObject +} + +func NewCursor() ecs.IsGameObject { + return &Cursor{ + GameObject: &ecs.GameObject{}, + } +} diff --git a/objs/paddle.go b/objs/paddle.go new file mode 100644 index 0000000..e997ff9 --- /dev/null +++ b/objs/paddle.go @@ -0,0 +1,26 @@ +package objs + +import ( + "github.com/Zyko0/go-sdl3/sdl" + "ponger/ecs" + "ponger/input" +) + +type Paddle struct { + *ecs.GameObject +} + +func (p *Paddle) Process(ev input.Event) { + //TODO implement me + panic("implement me") +} + +func NewPaddle() *ecs.GameObject { + p := &Paddle{ + GameObject: &ecs.GameObject{ + Position: sdl.FPoint{}, + Children: nil, + }, + } + return p.GameObject +} diff --git a/objs/root.go b/objs/root.go new file mode 100644 index 0000000..59e0c6a --- /dev/null +++ b/objs/root.go @@ -0,0 +1,25 @@ +package objs + +import ( + "github.com/Zyko0/go-sdl3/sdl" + "ponger/ecs" +) + +type Root struct { + *ecs.GameObject +} + +func (root *Root) Render(r *sdl.Renderer) { + r.SetDrawColor(255, 255, 255, 255) + r.Clear() +} + +func NewRoot(children ...ecs.IsGameObject) ecs.IsGameObject { + r := &Root{ + GameObject: &ecs.GameObject{ + Position: sdl.FPoint{}, + Children: children, + }, + } + return r.GameObject +} diff --git a/render/init.go b/render/init.go new file mode 100644 index 0000000..9858cd4 --- /dev/null +++ b/render/init.go @@ -0,0 +1,32 @@ +package render + +import ( + "context" + "github.com/Zyko0/go-sdl3/sdl" + "github.com/spf13/pflag" +) + +var ( + vsync = pflag.Int("vsync", 0, "vsync value (0 disabled, 1 every, 2 double, -1 adaptive)") +) + +func Init() (*sdl.Window, *sdl.Renderer, context.CancelFunc, error) { + if err := sdl.Init(sdl.INIT_VIDEO); err != nil { + return nil, nil, nil, err + } + + window, renderer, err := sdl.CreateWindowAndRenderer("ponger", 500, 500, 0) + if err != nil { + return nil, nil, nil, err + } + err = window.SetRelativeMouseMode(true) + if err != nil { + return nil, nil, nil, err + } + renderer.SetVSync(int32(*vsync)) + + return window, renderer, func() { + window.Destroy() + renderer.Destroy() + }, nil +} diff --git a/render/render.go b/render/render.go new file mode 100644 index 0000000..83fc2d0 --- /dev/null +++ b/render/render.go @@ -0,0 +1,24 @@ +package render + +import ( + "github.com/Zyko0/go-sdl3/sdl" + "ponger/ecs" +) + +type Renders interface { + Render(renderer *sdl.Renderer) +} + +func Render(root any, renderer *sdl.Renderer) { + if r, ok := root.(Renders); ok { + r.Render(renderer) + } + if g, ok := root.(*ecs.GameObject); ok { + for _, c := range g.Children { + if c == nil { + continue + } + Render(c, renderer) + } + } +} |
