diff --git a/docs/Shell.md b/docs/Shell.md new file mode 100644 index 0000000..9868442 --- /dev/null +++ b/docs/Shell.md @@ -0,0 +1,7 @@ +# Developer Console + +## Cheats + +| Cheat Code | Effect | +|-------------------|--------------------------------| +| unleash the beast | Disable frame rate throttling. | diff --git a/pkg/balance/numbers.go b/pkg/balance/numbers.go index 2149fca..0530578 100644 --- a/pkg/balance/numbers.go +++ b/pkg/balance/numbers.go @@ -9,6 +9,16 @@ var ( // Speed to scroll a canvas with arrow keys in Edit Mode. CanvasScrollSpeed int32 = 8 + // Window scrolling behavior in Play Mode. + ScrollboxHoz = 64 // horizontal px from window border to start scrol + ScrollboxVert = 128 + ScrollMaxVelocity = 24 + + // Player speeds + PlayerMaxVelocity = 12 + PlayerAcceleration = 2 + Gravity = 2 + // Default chunk size for canvases. ChunkSize = 128 diff --git a/pkg/commands.go b/pkg/commands.go index c4d6f49..11026bc 100644 --- a/pkg/commands.go +++ b/pkg/commands.go @@ -22,6 +22,17 @@ func (c Command) Run(d *Doodle) error { return nil } + // Cheat codes + if c.Raw == "unleash the beast" { + if fpsDoNotCap { + d.Flash("Reset frame rate throttle to factory default FPS") + } else { + d.Flash("Unleashing as many frames as we can render!") + } + fpsDoNotCap = !fpsDoNotCap + return nil + } + switch c.Command { case "echo": d.Flash(c.ArgsLiteral) diff --git a/pkg/doodle.go b/pkg/doodle.go index 811af92..e6316d9 100644 --- a/pkg/doodle.go +++ b/pkg/doodle.go @@ -148,13 +148,15 @@ func (d *Doodle) Run() error { } // Delay to maintain the target frames per second. - elapsed := time.Now().Sub(start) - tmp := elapsed / time.Millisecond var delay uint32 - if TargetFPS-int(tmp) > 0 { // make sure it won't roll under - delay = uint32(TargetFPS - int(tmp)) + if !fpsDoNotCap { + elapsed := time.Now().Sub(start) + tmp := elapsed / time.Millisecond + if TargetFPS-int(tmp) > 0 { // make sure it won't roll under + delay = uint32(TargetFPS - int(tmp)) + } + d.Engine.Delay(delay) } - d.Engine.Delay(delay) // Track how long this frame took to measure FPS over time. d.TrackFPS(delay) diff --git a/pkg/editor_scene.go b/pkg/editor_scene.go index c972af4..a4380a8 100644 --- a/pkg/editor_scene.go +++ b/pkg/editor_scene.go @@ -32,6 +32,11 @@ type EditorScene struct { Level *level.Level Doodad *doodads.Doodad + // Custom debug overlay values. + debTool *string + debSwatch *string + debWorldIndex *string + // Last saved filename by the user. filename string } @@ -43,6 +48,16 @@ func (s *EditorScene) Name() string { // Setup the editor scene. func (s *EditorScene) Setup(d *Doodle) error { + // Debug overlay values. + s.debTool = new(string) + s.debSwatch = new(string) + s.debWorldIndex = new(string) + customDebugLabels = []debugLabel{ + {"Pixel", s.debWorldIndex}, + {"Tool", s.debTool}, + {"Swatch", s.debSwatch}, + } + // Initialize the user interface. It references the palette and such so it // must be initialized after those things. s.d = d @@ -107,6 +122,11 @@ func (s *EditorScene) Setup(d *Doodle) error { // Loop the editor scene. func (s *EditorScene) Loop(d *Doodle, ev *events.State) error { + // Update debug overlay values. + *s.debTool = s.UI.Canvas.Tool.String() + *s.debSwatch = s.UI.Canvas.Palette.ActiveSwatch.Name + *s.debWorldIndex = s.UI.Canvas.WorldIndexAt(s.UI.cursor).String() + // Has the window been resized? if resized := ev.Resized.Read(); resized { w, h := d.Engine.WindowSize() @@ -262,6 +282,5 @@ func (s *EditorScene) SaveDoodad(filename string) error { // Destroy the scene. func (s *EditorScene) Destroy() error { - debugWorldIndex = render.Origin return nil } diff --git a/pkg/editor_ui.go b/pkg/editor_ui.go index 7bfa3e4..2108064 100644 --- a/pkg/editor_ui.go +++ b/pkg/editor_ui.go @@ -164,11 +164,10 @@ func (u *EditorUI) Loop(ev *events.State) error { // Update status bar labels. { - debugWorldIndex = u.Canvas.WorldIndexAt(u.cursor) u.StatusMouseText = fmt.Sprintf("Rel:(%d,%d) Abs:(%s)", ev.CursorX.Now, ev.CursorY.Now, - debugWorldIndex, + *u.Scene.debWorldIndex, ) u.StatusPaletteText = fmt.Sprintf("%s Tool", u.Canvas.Tool, diff --git a/pkg/fps.go b/pkg/fps.go index 8074f91..f9f2261 100644 --- a/pkg/fps.go +++ b/pkg/fps.go @@ -33,37 +33,72 @@ var ( fpsFrames int fpsSkipped uint32 fpsInterval uint32 = 1000 + fpsDoNotCap bool // remove the FPS delay cap in main loop - // XXX: some opt-in WorldIndex variables for the debug overlay. - // This is the world pixel that the mouse cursor is over, - // the Cursor + Scroll position of the canvas. - debugWorldIndex render.Point + // Custom labels for individual Scenes to add debug info. + customDebugLabels []debugLabel ) +type debugLabel struct { + key string + variable *string +} + // DrawDebugOverlay draws the debug FPS text on the SDL canvas. func (d *Doodle) DrawDebugOverlay() { - if !d.Debug || !DebugOverlay { + if !DebugOverlay { return } + var framesSkipped = fmt.Sprintf("(skip: %dms)", fpsSkipped) + if fpsDoNotCap { + framesSkipped = "uncapped" + } + var ( darken = balance.DebugStrokeDarken Yoffset int32 = 20 // leave room for the menu bar - Xoffset int32 = 5 + Xoffset int32 = 20 keys = []string{ - " FPS:", + "FPS:", "Scene:", - "Pixel:", "Mouse:", } values = []string{ - fmt.Sprintf("%d (skip: %dms)", fpsCurrent, fpsSkipped), + fmt.Sprintf("%d %s", fpsCurrent, framesSkipped), d.Scene.Name(), - debugWorldIndex.String(), fmt.Sprintf("%d,%d", d.event.CursorX.Now, d.event.CursorY.Now), } ) + // Insert custom keys. + for _, custom := range customDebugLabels { + keys = append(keys, custom.key) + if custom.variable == nil { + values = append(values, "") + } else if len(*custom.variable) == 0 { + values = append(values, `""`) + } else { + values = append(values, *custom.variable) + } + } + + // Find the longest key to align the labels up. + var longest int + for _, key := range keys { + if len(key) > longest { + longest = len(key) + } + } + + // Space pad the keys for alignment. + for i, key := range keys { + if len(key) < longest { + key = strings.Repeat(" ", longest-len(key)) + key + keys[i] = key + } + } + key := ui.NewLabel(ui.Label{ Text: strings.Join(keys, "\n"), Font: render.Text{ @@ -97,7 +132,7 @@ func (d *Doodle) DrawDebugOverlay() { // DrawCollisionBox draws the collision box around a Doodad. func (d *Doodle) DrawCollisionBox(actor doodads.Actor) { - if !d.Debug || !DebugCollision { + if !DebugCollision { return } diff --git a/pkg/play_scene.go b/pkg/play_scene.go index 73ed517..23b2c4f 100644 --- a/pkg/play_scene.go +++ b/pkg/play_scene.go @@ -22,6 +22,12 @@ type PlayScene struct { d *Doodle drawing *uix.Canvas + // Custom debug labels. + debPosition *string + debViewport *string + debScroll *string + debWorldIndex *string + // Player character Player doodads.Actor } @@ -34,6 +40,20 @@ func (s *PlayScene) Name() string { // Setup the play scene. func (s *PlayScene) Setup(d *Doodle) error { s.d = d + + // Initialize debug overlay values. + s.debPosition = new(string) + s.debViewport = new(string) + s.debScroll = new(string) + s.debWorldIndex = new(string) + customDebugLabels = []debugLabel{ + {"Pixel:", s.debWorldIndex}, + {"Player:", s.debPosition}, + {"Viewport:", s.debViewport}, + {"Scroll:", s.debScroll}, + } + + // Initialize the drawing canvas. s.drawing = uix.NewCanvas(balance.ChunkSize, false) s.drawing.MoveTo(render.Origin) s.drawing.Resize(render.NewRect(int32(d.width), int32(d.height))) @@ -63,6 +83,23 @@ func (s *PlayScene) Setup(d *Doodle) error { // Loop the editor scene. func (s *PlayScene) Loop(d *Doodle, ev *events.State) error { + // Update debug overlay values. + *s.debWorldIndex = s.drawing.WorldIndexAt(render.NewPoint(ev.CursorX.Now, ev.CursorY.Now)).String() + *s.debPosition = s.Player.Position().String() + *s.debViewport = s.drawing.Viewport().String() + *s.debScroll = s.drawing.Scroll.String() + + // Has the window been resized? + if resized := ev.Resized.Read(); resized { + w, h := d.Engine.WindowSize() + if w != d.width || h != d.height { + d.width = w + d.height = h + s.drawing.Resize(render.NewRect(int32(d.width), int32(d.height))) + return nil + } + } + // Switching to Edit Mode? if ev.KeyName.Read() == "e" { log.Info("Edit Mode, Go!")