Noah Petherbridge
258b2eb285
* CLI: fix the `doodad convert` command to share the same Palette when converting each frame (layer) of a doodad so subsequent layers find the correct color swatches for serialization. * Scripting: add timers and intervals to Doodad scripts to allow them to animate themselves or add delayed callbacks. The timers have the same API as a web browser: setTimeout(), setInterval(), clearTimeout(), clearInterval(). * Add support for uix.Actor to change its currently rendered layer in the level. For example a Button Doodad can set its image to Layer 1 (pressed) when touched by the player, and Trapdoors can cycle through their layers to animate opening and closing. * Usage from a Doodad script: Self.ShowLayer(1) * Default Doodads: added scripts for all Buttons, Doors, Keys and the Trapdoor to run their various animations when touched (in the case of Keys, destroy themselves when touched, because there is no player inventory yet)
172 lines
4.2 KiB
Go
172 lines
4.2 KiB
Go
package doodle
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.kirsle.net/apps/doodle/lib/render"
|
|
"git.kirsle.net/apps/doodle/lib/ui"
|
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
|
"git.kirsle.net/apps/doodle/pkg/collision"
|
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
|
)
|
|
|
|
// Frames to cache for FPS calculation.
|
|
const maxSamples = 100
|
|
|
|
// Debug mode options, these can be enabled in the dev console
|
|
// like: boolProp DebugOverlay true
|
|
var (
|
|
DebugOverlay = true
|
|
DebugCollision = false
|
|
|
|
DebugTextPadding int32 = 8
|
|
DebugTextSize = 24
|
|
DebugTextColor = render.SkyBlue
|
|
DebugTextStroke = render.Grey
|
|
DebugTextShadow = render.Black
|
|
)
|
|
|
|
var (
|
|
fpsCurrentTicks uint32 // current time we get sdl.GetTicks()
|
|
fpsLastTime uint32 // last time we printed the fpsCurrentTicks
|
|
fpsCurrent int
|
|
fpsFrames int
|
|
fpsSkipped uint32
|
|
fpsInterval uint32 = 1000
|
|
fpsDoNotCap bool // remove the FPS delay cap in main loop
|
|
|
|
// 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 !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 = 20
|
|
keys = []string{
|
|
"FPS:",
|
|
"Scene:",
|
|
"Mouse:",
|
|
}
|
|
values = []string{
|
|
fmt.Sprintf("%d %s", fpsCurrent, framesSkipped),
|
|
d.Scene.Name(),
|
|
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{
|
|
Text: strings.Join(keys, "\n"),
|
|
Font: render.Text{
|
|
Size: balance.DebugFontSize,
|
|
FontFilename: balance.ShellFontFilename,
|
|
Color: balance.DebugLabelColor,
|
|
Stroke: balance.DebugLabelColor.Darken(darken),
|
|
},
|
|
})
|
|
key.Compute(d.Engine)
|
|
key.Present(d.Engine, render.NewPoint(
|
|
DebugTextPadding+Xoffset,
|
|
DebugTextPadding+Yoffset,
|
|
))
|
|
|
|
value := ui.NewLabel(ui.Label{
|
|
Text: strings.Join(values, "\n"),
|
|
Font: render.Text{
|
|
Size: balance.DebugFontSize,
|
|
FontFilename: balance.DebugFontFilename,
|
|
Color: balance.DebugValueColor,
|
|
Stroke: balance.DebugValueColor.Darken(darken),
|
|
},
|
|
})
|
|
value.Compute(d.Engine)
|
|
value.Present(d.Engine, render.NewPoint(
|
|
DebugTextPadding+Xoffset+key.Size().W+DebugTextPadding,
|
|
DebugTextPadding+Yoffset, // padding to not overlay menu bar
|
|
))
|
|
}
|
|
|
|
// DrawCollisionBox draws the collision box around a Doodad.
|
|
//
|
|
// TODO: move inside the Canvas. Currently it takes an actor's World Position
|
|
// and draws the box as if it were a relative (to the window) position, so the
|
|
// hitbox drifts off when the level scrolls away from 0,0
|
|
func (d *Doodle) DrawCollisionBox(actor doodads.Actor) {
|
|
if !DebugCollision {
|
|
return
|
|
}
|
|
|
|
var (
|
|
rect = doodads.GetBoundingRect(actor)
|
|
box = collision.GetCollisionBox(rect)
|
|
)
|
|
|
|
d.Engine.DrawLine(render.DarkGreen, box.Top[0], box.Top[1])
|
|
d.Engine.DrawLine(render.DarkBlue, box.Bottom[0], box.Bottom[1])
|
|
d.Engine.DrawLine(render.DarkYellow, box.Left[0], box.Left[1])
|
|
d.Engine.DrawLine(render.Red, box.Right[0], box.Right[1])
|
|
}
|
|
|
|
// TrackFPS shows the current FPS once per second.
|
|
func (d *Doodle) TrackFPS(skipped uint32) {
|
|
fpsFrames++
|
|
fpsCurrentTicks = d.Engine.GetTicks()
|
|
|
|
// Skip the first second.
|
|
if fpsCurrentTicks < fpsInterval {
|
|
return
|
|
}
|
|
|
|
if fpsLastTime < fpsCurrentTicks-fpsInterval {
|
|
fpsLastTime = fpsCurrentTicks
|
|
fpsCurrent = fpsFrames
|
|
fpsFrames = 0
|
|
fpsSkipped = skipped
|
|
}
|
|
}
|