diff --git a/cmd/doodle/main.go b/cmd/doodle/main.go index 688cb39..eba0dea 100644 --- a/cmd/doodle/main.go +++ b/cmd/doodle/main.go @@ -13,10 +13,12 @@ var Build string // Command line args var ( debug bool + edit bool ) func init() { flag.BoolVar(&debug, "debug", false, "Debug mode") + flag.BoolVar(&edit, "edit", false, "Edit the map given on the command line. Default is to play the map.") } func main() { @@ -31,7 +33,11 @@ func main() { app := doodle.New(debug) if filename != "" { - app.LoadLevel(filename) + if edit { + app.EditLevel(filename) + } else { + app.PlayLevel(filename) + } } app.Run() } diff --git a/doodle.go b/doodle.go index 422187c..6f7beb2 100644 --- a/doodle.go +++ b/doodle.go @@ -139,8 +139,8 @@ func (d *Doodle) Run() error { return nil } -// LoadLevel loads a map from JSON into the EditorScene. -func (d *Doodle) LoadLevel(filename string) error { +// EditLevel loads a map from JSON into the EditorScene. +func (d *Doodle) EditLevel(filename string) error { log.Info("Loading level from file: %s", filename) scene := &EditorScene{} err := scene.LoadLevel(filename) @@ -151,6 +151,18 @@ func (d *Doodle) LoadLevel(filename string) error { return nil } +// PlayLevel loads a map from JSON into the PlayScene. +func (d *Doodle) PlayLevel(filename string) error { + log.Info("Loading level from file: %s", filename) + scene := &PlayScene{} + err := scene.LoadLevel(filename) + if err != nil { + return err + } + d.Goto(scene) + return nil +} + // TODO: not a global type Pixel struct { start bool diff --git a/editor_scene.go b/editor_scene.go index 1d26a24..d9cf6a9 100644 --- a/editor_scene.go +++ b/editor_scene.go @@ -23,6 +23,11 @@ type EditorScene struct { height int32 } +// Name of the scene. +func (s *EditorScene) Name() string { + return "Edit" +} + // Setup the editor scene. func (e *EditorScene) Setup(d *Doodle) error { if e.pixelHistory == nil { diff --git a/events/events.go b/events/events.go index 5d5b5ab..e98d20b 100644 --- a/events/events.go +++ b/events/events.go @@ -15,6 +15,10 @@ type State struct { // Screenshot key. ScreenshotKey *BoolTick + Up *BoolTick + Left *BoolTick + Right *BoolTick + Down *BoolTick // Cursor positions. CursorX *Int32Tick @@ -27,6 +31,10 @@ func New() *State { Button1: &BoolTick{}, Button2: &BoolTick{}, ScreenshotKey: &BoolTick{}, + Up: &BoolTick{}, + Left: &BoolTick{}, + Right: &BoolTick{}, + Down: &BoolTick{}, CursorX: &Int32Tick{}, CursorY: &Int32Tick{}, } @@ -107,6 +115,14 @@ func (s *State) Poll(ticks uint64) (*State, error) { switch t.Keysym.Scancode { case sdl.SCANCODE_F12: s.ScreenshotKey.Push(t.State == 1) + case sdl.SCANCODE_UP: + s.Up.Push(t.State == 1) + case sdl.SCANCODE_LEFT: + s.Left.Push(t.State == 1) + case sdl.SCANCODE_RIGHT: + s.Right.Push(t.State == 1) + case sdl.SCANCODE_DOWN: + s.Down.Push(t.State == 1) } } } diff --git a/fps.go b/fps.go index a624a22..56c04f0 100644 --- a/fps.go +++ b/fps.go @@ -27,11 +27,12 @@ func (d *Doodle) DrawDebugOverlay() { } text := fmt.Sprintf( - "FPS: %d (%dms) (%d,%d) F12=screenshot", + "FPS: %d (%dms) (%d,%d) S:%s F12=screenshot", fpsCurrent, fpsSkipped, d.events.CursorX.Now, d.events.CursorY.Now, + d.scene.Name(), ) render.StrokedText(render.TextConfig{ Text: text, diff --git a/play_scene.go b/play_scene.go new file mode 100644 index 0000000..7b4dd9e --- /dev/null +++ b/play_scene.go @@ -0,0 +1,112 @@ +package doodle + +import ( + "git.kirsle.net/apps/doodle/events" + "git.kirsle.net/apps/doodle/level" + "github.com/veandco/go-sdl2/sdl" +) + +// PlayScene manages the "Edit Level" game mode. +type PlayScene struct { + canvas Grid + + // Canvas size + width int32 + height int32 + + // Player position and velocity. + x int32 + y int32 + vx int32 + vy int32 +} + +// Name of the scene. +func (s *PlayScene) Name() string { + return "Play" +} + +// Setup the play scene. +func (s *PlayScene) Setup(d *Doodle) error { + s.x = 10 + s.y = 10 + + if s.canvas == nil { + s.canvas = Grid{} + } + s.width = d.width // TODO: canvas width = copy the window size + s.height = d.height + return nil +} + +// Loop the editor scene. +func (s *PlayScene) Loop(d *Doodle) error { + s.PollEvents(d.events) + + // Apply gravity. + + return s.Draw(d) +} + +// Draw the pixels on this frame. +func (s *PlayScene) Draw(d *Doodle) error { + // Clear the canvas and fill it with white. + d.renderer.SetDrawColor(255, 255, 255, 255) + d.renderer.Clear() + + d.renderer.SetDrawColor(0, 0, 0, 255) + for pixel := range s.canvas { + d.renderer.DrawPoint(pixel.x, pixel.y) + } + + // Draw our hero. + d.renderer.SetDrawColor(0, 0, 255, 255) + d.renderer.DrawRect(&sdl.Rect{ + X: s.x, + Y: s.y, + W: 16, + H: 16, + }) + + // Draw the FPS. + d.DrawDebugOverlay() + d.renderer.Present() + + return nil +} + +// PollEvents checks the event state and updates variables. +func (s *PlayScene) PollEvents(ev *events.State) { + if ev.Down.Now { + s.y += 4 + } + if ev.Left.Now { + s.x -= 4 + } + if ev.Right.Now { + s.x += 4 + } + if ev.Up.Now { + s.y -= 4 + } +} + +// LoadLevel loads a level from disk. +func (e *PlayScene) LoadLevel(filename string) error { + e.canvas = Grid{} + + m, err := level.LoadJSON(filename) + if err != nil { + return err + } + + for _, point := range m.Pixels { + pixel := Pixel{ + x: point.X, + y: point.Y, + } + e.canvas[pixel] = nil + } + + return nil +} diff --git a/scene.go b/scene.go index 8493a02..6b8d179 100644 --- a/scene.go +++ b/scene.go @@ -4,6 +4,7 @@ package doodle // scene at a time and that scene has control over the main loop, and its own // state information. type Scene interface { + Name() string Setup(*Doodle) error Loop(*Doodle) error }