Improvements to the Debug Overlay Feature
* Scenes can insert custom key/value labels to the debug overlay and track string variables in real time * Added ability to unthrottle FPS in main loop
This commit is contained in:
parent
bd3dd41cea
commit
8fc4f39da0
7
docs/Shell.md
Normal file
7
docs/Shell.md
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# Developer Console
|
||||||
|
|
||||||
|
## Cheats
|
||||||
|
|
||||||
|
| Cheat Code | Effect |
|
||||||
|
|-------------------|--------------------------------|
|
||||||
|
| unleash the beast | Disable frame rate throttling. |
|
|
@ -9,6 +9,16 @@ var (
|
||||||
// Speed to scroll a canvas with arrow keys in Edit Mode.
|
// Speed to scroll a canvas with arrow keys in Edit Mode.
|
||||||
CanvasScrollSpeed int32 = 8
|
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.
|
// Default chunk size for canvases.
|
||||||
ChunkSize = 128
|
ChunkSize = 128
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,17 @@ func (c Command) Run(d *Doodle) error {
|
||||||
return nil
|
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 {
|
switch c.Command {
|
||||||
case "echo":
|
case "echo":
|
||||||
d.Flash(c.ArgsLiteral)
|
d.Flash(c.ArgsLiteral)
|
||||||
|
|
|
@ -148,13 +148,15 @@ func (d *Doodle) Run() error {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delay to maintain the target frames per second.
|
// Delay to maintain the target frames per second.
|
||||||
|
var delay uint32
|
||||||
|
if !fpsDoNotCap {
|
||||||
elapsed := time.Now().Sub(start)
|
elapsed := time.Now().Sub(start)
|
||||||
tmp := elapsed / time.Millisecond
|
tmp := elapsed / time.Millisecond
|
||||||
var delay uint32
|
|
||||||
if TargetFPS-int(tmp) > 0 { // make sure it won't roll under
|
if TargetFPS-int(tmp) > 0 { // make sure it won't roll under
|
||||||
delay = uint32(TargetFPS - int(tmp))
|
delay = uint32(TargetFPS - int(tmp))
|
||||||
}
|
}
|
||||||
d.Engine.Delay(delay)
|
d.Engine.Delay(delay)
|
||||||
|
}
|
||||||
|
|
||||||
// Track how long this frame took to measure FPS over time.
|
// Track how long this frame took to measure FPS over time.
|
||||||
d.TrackFPS(delay)
|
d.TrackFPS(delay)
|
||||||
|
|
|
@ -32,6 +32,11 @@ type EditorScene struct {
|
||||||
Level *level.Level
|
Level *level.Level
|
||||||
Doodad *doodads.Doodad
|
Doodad *doodads.Doodad
|
||||||
|
|
||||||
|
// Custom debug overlay values.
|
||||||
|
debTool *string
|
||||||
|
debSwatch *string
|
||||||
|
debWorldIndex *string
|
||||||
|
|
||||||
// Last saved filename by the user.
|
// Last saved filename by the user.
|
||||||
filename string
|
filename string
|
||||||
}
|
}
|
||||||
|
@ -43,6 +48,16 @@ func (s *EditorScene) Name() string {
|
||||||
|
|
||||||
// Setup the editor scene.
|
// Setup the editor scene.
|
||||||
func (s *EditorScene) Setup(d *Doodle) error {
|
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
|
// Initialize the user interface. It references the palette and such so it
|
||||||
// must be initialized after those things.
|
// must be initialized after those things.
|
||||||
s.d = d
|
s.d = d
|
||||||
|
@ -107,6 +122,11 @@ func (s *EditorScene) Setup(d *Doodle) error {
|
||||||
|
|
||||||
// Loop the editor scene.
|
// Loop the editor scene.
|
||||||
func (s *EditorScene) Loop(d *Doodle, ev *events.State) error {
|
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?
|
// Has the window been resized?
|
||||||
if resized := ev.Resized.Read(); resized {
|
if resized := ev.Resized.Read(); resized {
|
||||||
w, h := d.Engine.WindowSize()
|
w, h := d.Engine.WindowSize()
|
||||||
|
@ -262,6 +282,5 @@ func (s *EditorScene) SaveDoodad(filename string) error {
|
||||||
|
|
||||||
// Destroy the scene.
|
// Destroy the scene.
|
||||||
func (s *EditorScene) Destroy() error {
|
func (s *EditorScene) Destroy() error {
|
||||||
debugWorldIndex = render.Origin
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -164,11 +164,10 @@ func (u *EditorUI) Loop(ev *events.State) error {
|
||||||
|
|
||||||
// Update status bar labels.
|
// Update status bar labels.
|
||||||
{
|
{
|
||||||
debugWorldIndex = u.Canvas.WorldIndexAt(u.cursor)
|
|
||||||
u.StatusMouseText = fmt.Sprintf("Rel:(%d,%d) Abs:(%s)",
|
u.StatusMouseText = fmt.Sprintf("Rel:(%d,%d) Abs:(%s)",
|
||||||
ev.CursorX.Now,
|
ev.CursorX.Now,
|
||||||
ev.CursorY.Now,
|
ev.CursorY.Now,
|
||||||
debugWorldIndex,
|
*u.Scene.debWorldIndex,
|
||||||
)
|
)
|
||||||
u.StatusPaletteText = fmt.Sprintf("%s Tool",
|
u.StatusPaletteText = fmt.Sprintf("%s Tool",
|
||||||
u.Canvas.Tool,
|
u.Canvas.Tool,
|
||||||
|
|
55
pkg/fps.go
55
pkg/fps.go
|
@ -33,37 +33,72 @@ var (
|
||||||
fpsFrames int
|
fpsFrames int
|
||||||
fpsSkipped uint32
|
fpsSkipped uint32
|
||||||
fpsInterval uint32 = 1000
|
fpsInterval uint32 = 1000
|
||||||
|
fpsDoNotCap bool // remove the FPS delay cap in main loop
|
||||||
|
|
||||||
// XXX: some opt-in WorldIndex variables for the debug overlay.
|
// Custom labels for individual Scenes to add debug info.
|
||||||
// This is the world pixel that the mouse cursor is over,
|
customDebugLabels []debugLabel
|
||||||
// the Cursor + Scroll position of the canvas.
|
|
||||||
debugWorldIndex render.Point
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type debugLabel struct {
|
||||||
|
key string
|
||||||
|
variable *string
|
||||||
|
}
|
||||||
|
|
||||||
// DrawDebugOverlay draws the debug FPS text on the SDL canvas.
|
// DrawDebugOverlay draws the debug FPS text on the SDL canvas.
|
||||||
func (d *Doodle) DrawDebugOverlay() {
|
func (d *Doodle) DrawDebugOverlay() {
|
||||||
if !d.Debug || !DebugOverlay {
|
if !DebugOverlay {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var framesSkipped = fmt.Sprintf("(skip: %dms)", fpsSkipped)
|
||||||
|
if fpsDoNotCap {
|
||||||
|
framesSkipped = "uncapped"
|
||||||
|
}
|
||||||
|
|
||||||
var (
|
var (
|
||||||
darken = balance.DebugStrokeDarken
|
darken = balance.DebugStrokeDarken
|
||||||
Yoffset int32 = 20 // leave room for the menu bar
|
Yoffset int32 = 20 // leave room for the menu bar
|
||||||
Xoffset int32 = 5
|
Xoffset int32 = 20
|
||||||
keys = []string{
|
keys = []string{
|
||||||
"FPS:",
|
"FPS:",
|
||||||
"Scene:",
|
"Scene:",
|
||||||
"Pixel:",
|
|
||||||
"Mouse:",
|
"Mouse:",
|
||||||
}
|
}
|
||||||
values = []string{
|
values = []string{
|
||||||
fmt.Sprintf("%d (skip: %dms)", fpsCurrent, fpsSkipped),
|
fmt.Sprintf("%d %s", fpsCurrent, framesSkipped),
|
||||||
d.Scene.Name(),
|
d.Scene.Name(),
|
||||||
debugWorldIndex.String(),
|
|
||||||
fmt.Sprintf("%d,%d", d.event.CursorX.Now, d.event.CursorY.Now),
|
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, "<nil>")
|
||||||
|
} 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{
|
key := ui.NewLabel(ui.Label{
|
||||||
Text: strings.Join(keys, "\n"),
|
Text: strings.Join(keys, "\n"),
|
||||||
Font: render.Text{
|
Font: render.Text{
|
||||||
|
@ -97,7 +132,7 @@ func (d *Doodle) DrawDebugOverlay() {
|
||||||
|
|
||||||
// DrawCollisionBox draws the collision box around a Doodad.
|
// DrawCollisionBox draws the collision box around a Doodad.
|
||||||
func (d *Doodle) DrawCollisionBox(actor doodads.Actor) {
|
func (d *Doodle) DrawCollisionBox(actor doodads.Actor) {
|
||||||
if !d.Debug || !DebugCollision {
|
if !DebugCollision {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,6 +22,12 @@ type PlayScene struct {
|
||||||
d *Doodle
|
d *Doodle
|
||||||
drawing *uix.Canvas
|
drawing *uix.Canvas
|
||||||
|
|
||||||
|
// Custom debug labels.
|
||||||
|
debPosition *string
|
||||||
|
debViewport *string
|
||||||
|
debScroll *string
|
||||||
|
debWorldIndex *string
|
||||||
|
|
||||||
// Player character
|
// Player character
|
||||||
Player doodads.Actor
|
Player doodads.Actor
|
||||||
}
|
}
|
||||||
|
@ -34,6 +40,20 @@ func (s *PlayScene) Name() string {
|
||||||
// Setup the play scene.
|
// Setup the play scene.
|
||||||
func (s *PlayScene) Setup(d *Doodle) error {
|
func (s *PlayScene) Setup(d *Doodle) error {
|
||||||
s.d = d
|
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 = uix.NewCanvas(balance.ChunkSize, false)
|
||||||
s.drawing.MoveTo(render.Origin)
|
s.drawing.MoveTo(render.Origin)
|
||||||
s.drawing.Resize(render.NewRect(int32(d.width), int32(d.height)))
|
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.
|
// Loop the editor scene.
|
||||||
func (s *PlayScene) Loop(d *Doodle, ev *events.State) error {
|
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?
|
// Switching to Edit Mode?
|
||||||
if ev.KeyName.Read() == "e" {
|
if ev.KeyName.Read() == "e" {
|
||||||
log.Info("Edit Mode, Go!")
|
log.Info("Edit Mode, Go!")
|
||||||
|
|
Loading…
Reference in New Issue
Block a user