diff --git a/assets/wallpapers/test-128x128.png b/assets/wallpapers/test-128x128.png new file mode 100644 index 0000000..736302d Binary files /dev/null and b/assets/wallpapers/test-128x128.png differ diff --git a/balance/debug.go b/balance/debug.go index 1d630ab..9e55043 100644 --- a/balance/debug.go +++ b/balance/debug.go @@ -16,11 +16,11 @@ var ( ***************/ // Debug overlay (FPS etc.) settings. - DebugFontFilename = "./fonts/DejaVuSans-Bold.ttf" - DebugFontSize = 15 - DebugLabelColor = render.MustHexColor("#FF9900") - DebugValueColor = render.MustHexColor("#00CCFF") - DebugStrokeDarken int32 = 80 + DebugFontFilename = "./fonts/DejaVuSans.ttf" + DebugFontSize = 16 + DebugLabelColor = render.MustHexColor("#FF9900") + DebugValueColor = render.MustHexColor("#00CCFF") + DebugStrokeDarken = 80 // Background color to use when exporting a drawing Chunk as a bitmap image // on disk. Default is white. Setting this to translucent yellow is a great diff --git a/balance/numbers.go b/balance/numbers.go index 7305b8f..14ee9f6 100644 --- a/balance/numbers.go +++ b/balance/numbers.go @@ -15,8 +15,9 @@ var ( ScrollMaxVelocity = 24 // Player speeds - PlayerMaxVelocity = 12 - Gravity = 2 + PlayerMaxVelocity = 12 + PlayerAcceleration = 2 // pixels / second / second + Gravity = 2 // Default chunk size for canvases. ChunkSize = 128 diff --git a/commands.go b/commands.go index d3d314a..095bd5e 100644 --- a/commands.go +++ b/commands.go @@ -22,6 +22,17 @@ func (c Command) Run(d *Doodle) error { return nil } + // Cheats :P + if c.Raw == "unleash the beast" { + if fpsDoNotCap { + d.Flash("Reset frame rate throttle to factory default %d FPS", TargetFPS) + } 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/doodads/actor.go b/doodads/actor.go index 15f2191..2a77289 100644 --- a/doodads/actor.go +++ b/doodads/actor.go @@ -14,6 +14,8 @@ type Actor interface { Position() render.Point Velocity() render.Point SetVelocity(render.Point) + Acceleration() int + SetAcceleration(int) Size() render.Rect Grounded() bool SetGrounded(bool) diff --git a/doodads/collision.go b/doodads/collision.go index 739a7ad..fe8b264 100644 --- a/doodads/collision.go +++ b/doodads/collision.go @@ -96,8 +96,15 @@ const ( Right ) -// CollidesWithGrid checks if a Doodad collides with level geometry. -func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point) (*Collide, bool) { +/* +CollidesWithGrid checks if a Doodad collides with level geometry. + +The `target` is the point the actor wants to move to this tick. + +The `scroll` is the scroll offset of the canvas that is viewing the grid, so +that collision geometry can be offset properly on screen. +*/ +func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point, scroll render.Point) (*Collide, bool) { var ( P = d.Position() S = d.Size() @@ -109,14 +116,14 @@ func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point) (*Colli capHeight int32 // Stop vertical movement thru a ceiling capLeft int32 // Stop movement thru a wall capRight int32 - hitLeft bool // Has hit an obstacle on the left - hitRight bool // or right - hitFloor bool - capFloor int32 + capFloor int32 // Stop movement thru the floor + hitLeft bool // Has hit an obstacle on the left + hitRight bool // or right + hitFloor bool // or floor ) // Test all of the bounding boxes for a collision with level geometry. - if ok := result.ScanBoundingBox(GetBoundingRect(d), grid); ok { + if ok := result.ScanBoundingBox(GetBoundingRect(d).SubtractPoint(scroll), grid); ok { // We've already collided! Try to wiggle free. if result.Bottom { if !d.Grounded() { @@ -190,7 +197,7 @@ func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point) (*Colli Y: point.Y, W: S.W, H: S.H, - }, grid); has { + }.SubtractPoint(scroll), grid); has { if result.Bottom { if !hitFloor { hitFloor = true diff --git a/doodads/drawing.go b/doodads/drawing.go index 35c5c63..99837c0 100644 --- a/doodads/drawing.go +++ b/doodads/drawing.go @@ -12,6 +12,7 @@ type Drawing struct { id string point render.Point velocity render.Point + accel int size render.Rect grounded bool } @@ -49,6 +50,16 @@ func (d *Drawing) SetVelocity(v render.Point) { d.velocity = v } +// Acceleration returns the Drawing's acceleration. +func (d *Drawing) Acceleration() int { + return d.accel +} + +// SetAcceleration to set the acceleration. +func (d *Drawing) SetAcceleration(v int) { + d.accel = v +} + // Size returns the Drawing's size. func (d *Drawing) Size() render.Rect { return d.size diff --git a/doodle.go b/doodle.go index a437fd8..268c5a6 100644 --- a/doodle.go +++ b/doodle.go @@ -15,7 +15,7 @@ import ( const ( // Version number. - Version = "0.0.1-alpha" + Version = "0.0.7-alpha" // TargetFPS is the frame rate to cap the game to. TargetFPS = 1000 / 60 // 60 FPS @@ -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/fps.go b/fps.go index 57f2193..4de911a 100644 --- a/fps.go +++ b/fps.go @@ -33,6 +33,7 @@ var ( fpsFrames int fpsSkipped uint32 fpsInterval uint32 = 1000 + fpsDoNotCap bool // remove the FPS delay cap in Main Loop // Custom labels for scenes to add to the debug overlay view. customDebugLabels []debugLabel @@ -49,17 +50,22 @@ func (d *Doodle) DrawDebugOverlay() { 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:", "Scene:", "Mouse:", } values = []string{ - fmt.Sprintf("%d (skip: %dms)", fpsCurrent, fpsSkipped), + fmt.Sprintf("%d %s", fpsCurrent, framesSkipped), d.Scene.Name(), fmt.Sprintf("%d,%d", d.event.CursorX.Now, d.event.CursorY.Now), } diff --git a/pkg/wallpaper/wallpaper_test.go b/pkg/wallpaper/wallpaper_test.go index 72d3c1e..4efcecf 100644 --- a/pkg/wallpaper/wallpaper_test.go +++ b/pkg/wallpaper/wallpaper_test.go @@ -28,7 +28,7 @@ func TestWallpaper(t *testing.T) { img := image.NewRGBA(image.Rect(0, 0, width, height)) draw.Draw( // Corner: red - img, // dst Image + img, // dst Image image.Rect(0, 0, qWidth, qHeight), // r Rectangle image.NewUniform(red), // src Image image.Point{0, 0}, // sp Point diff --git a/play_scene.go b/play_scene.go index bf6546c..c1cf8bb 100644 --- a/play_scene.go +++ b/play_scene.go @@ -173,7 +173,7 @@ func (s *PlayScene) movePlayer(ev *events.State) { // Apply gravity. // var onFloor bool - info, ok := doodads.CollidesWithGrid(s.Player, s.Level.Chunker, delta) + info, ok := doodads.CollidesWithGrid(s.Player, s.Level.Chunker, delta, s.drawing.Scroll) if ok { // Collision happened with world. } diff --git a/render/color.go b/render/color.go index c16cda2..f953e49 100644 --- a/render/color.go +++ b/render/color.go @@ -156,15 +156,15 @@ func (c *Color) UnmarshalJSON(b []byte) error { } // Add a relative color value to the color. -func (c Color) Add(r, g, b, a int32) Color { +func (c Color) Add(r, g, b, a int) Color { var ( - R = int32(c.Red) + r - G = int32(c.Green) + g - B = int32(c.Blue) + b - A = int32(c.Alpha) + a + R = int(c.Red) + r + G = int(c.Green) + g + B = int(c.Blue) + b + A = int(c.Alpha) + a ) - cap8 := func(v int32) uint8 { + cap8 := func(v int) uint8 { if v > 255 { v = 255 } else if v < 0 { @@ -182,11 +182,22 @@ func (c Color) Add(r, g, b, a int32) Color { } // Lighten a color value. -func (c Color) Lighten(v int32) Color { +func (c Color) Lighten(v int) Color { return c.Add(v, v, v, 0) } // Darken a color value. -func (c Color) Darken(v int32) Color { +func (c Color) Darken(v int) Color { return c.Add(-v, -v, -v, 0) } + +// Transparentize adjusts the alpha level of a color. +func (c Color) Transparentize(v int) Color { + return c.Add(0, 0, 0, int(v)) +} + +// SetAlpha sets the alpha value to a specific setting. +func (c Color) SetAlpha(v uint8) Color { + c.Alpha = v + return c +} diff --git a/render/interface.go b/render/interface.go index 1a30ad9..a64d498 100644 --- a/render/interface.go +++ b/render/interface.go @@ -125,7 +125,8 @@ func (r Rect) Add(other Rect) Rect { } } -// Add a point to move the rect. +// Add (or subtract) a point to move the rect. This is usually the method you +// want to use: negative Point values will subtract the rect's position. func (r Rect) AddPoint(other Point) Rect { return Rect{ X: r.X + other.X, @@ -135,6 +136,17 @@ func (r Rect) AddPoint(other Point) Rect { } } +// SubtractPoint is the inverse of AddPoint. Use this only if you need to +// invert the Point being added. +func (r Rect) SubtractPoint(other Point) Rect { + return Rect{ + X: r.X - other.X, + Y: r.Y - other.Y, + W: r.W, + H: r.H, + } +} + // Text holds information for drawing text. type Text struct { Text string diff --git a/render/point.go b/render/point.go index 272238c..49f8576 100644 --- a/render/point.go +++ b/render/point.go @@ -69,12 +69,21 @@ func (p Point) Inside(r Rect) bool { (p.Y >= y1 && p.Y <= y2)) } -// Add (or subtract) the other point to your current point. +// Add (or subtract) the other point to your current point. This is usually +// the one you want: if the other Point has negative values it will subtract +// them from this Point, or if they are positive it will add them. func (p *Point) Add(other Point) { p.X += other.X p.Y += other.Y } +// Subtract is the inverse of Add. Use this if you want to force a subtraction +// operation (i.e. to invert a Point before adding it). +func (p *Point) Subtract(other Point) { + p.X -= other.X + p.Y -= other.Y +} + // MarshalText to convert the point into text so that a render.Point may be used // as a map key and serialized to JSON. func (p *Point) MarshalText() ([]byte, error) { diff --git a/render/sdl/fps.go b/render/sdl/fps.go deleted file mode 100644 index 4c625c9..0000000 --- a/render/sdl/fps.go +++ /dev/null @@ -1,22 +0,0 @@ -package sdl - -import ( - "git.kirsle.net/apps/doodle/level" -) - -// Frames to cache for FPS calculation. -const ( - maxSamples = 100 - TargetFPS = 1000 / 60 -) - -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 -) - -var pixelHistory []level.Pixel diff --git a/ui/theme/theme.go b/ui/theme/theme.go index 23c3186..1994128 100644 --- a/ui/theme/theme.go +++ b/ui/theme/theme.go @@ -8,5 +8,5 @@ var ( ButtonHoverColor = render.RGBA(200, 255, 255, 255) ButtonOutlineColor = render.Black - BorderColorOffset int32 = 40 + BorderColorOffset = 40 ) diff --git a/uix/canvas_scrolling.go b/uix/canvas_scrolling.go index 3c5f506..7c13aff 100644 --- a/uix/canvas_scrolling.go +++ b/uix/canvas_scrolling.go @@ -127,7 +127,7 @@ func (w *Canvas) loopFollowActor(ev *events.State) error { var ( APosition = actor.Position() // relative to screen APoint = actor.Drawing.Position() - ASize = actor.Canvas.Size() + ASize = actor.Drawing.Size() scrollBy render.Point )