Noah Petherbridge
08e65c32b5
* Player character now experiences acceleration and friction when walking around the map! * Actor position and movement had to be converted from int's (render.Point) to float64's to support fine-grained acceleration steps. * Added "physics" package and physics.Vector to be a float64 counterpart for render.Point. Vector is used for uix.Actor.Position() for the sake of movement math. Vector is flattened back to a render.Point for collision purposes, since the levels and hitboxes are pixel-bound. * Refactor the uix.Actor to no longer extend the doodads.Drawing (so it can have a Position that's a Vector instead of a Point). This broke some code that expected `.Doodad` to directly reference the Drawing.Doodad: now you had to refer to it as `a.Drawing.Doodad` which was ugly. Added convenience method .Doodad() for a shortcut. * Moved functions like GetBoundingRect() from doodads package to collision, where it uses its own slimmer Actor interface for just the relevant methods it needs.
178 lines
4.3 KiB
Go
178 lines
4.3 KiB
Go
package doodle
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
|
|
"git.kirsle.net/apps/doodle/pkg/balance"
|
|
"git.kirsle.net/apps/doodle/pkg/collision"
|
|
"git.kirsle.net/apps/doodle/pkg/doodads"
|
|
"git.kirsle.net/go/render"
|
|
"git.kirsle.net/go/ui"
|
|
)
|
|
|
|
// 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 = false
|
|
DebugCollision = false
|
|
|
|
DebugTextPadding = 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 = 20 // leave room for the menu bar
|
|
Xoffset = 20
|
|
keys = []string{
|
|
"FPS:",
|
|
"Scene:",
|
|
"Mouse:",
|
|
}
|
|
values = []string{
|
|
fmt.Sprintf("%d %s", fpsCurrent, framesSkipped),
|
|
d.Scene.Name(),
|
|
fmt.Sprintf("%d,%d", d.event.CursorX, d.event.CursorY),
|
|
}
|
|
)
|
|
|
|
// 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 = collision.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.
|
|
//
|
|
// In debug mode, changes the window title to include the FPS counter.
|
|
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
|
|
}
|
|
|
|
if d.Debug {
|
|
d.Engine.SetTitle(fmt.Sprintf("%s (%d FPS)", d.Title(), fpsCurrent))
|
|
}
|
|
}
|