diff --git a/dev-assets/doodads/azulian/azulian-red.js b/dev-assets/doodads/azulian/azulian-red.js index e3a4ea0..45f5881 100644 --- a/dev-assets/doodads/azulian/azulian-red.js +++ b/dev-assets/doodads/azulian/azulian-red.js @@ -5,6 +5,7 @@ function main() { var direction = "right"; + Self.SetHitbox(0, 0, 32, 32) Self.SetMobile(true); Self.SetGravity(true); Self.AddAnimation("walk-left", 100, ["red-wl1", "red-wl2", "red-wl3", "red-wl4"]); diff --git a/dev-assets/doodads/boy/boy.js b/dev-assets/doodads/boy/boy.js index 6d48705..362a6c0 100644 --- a/dev-assets/doodads/boy/boy.js +++ b/dev-assets/doodads/boy/boy.js @@ -9,7 +9,7 @@ function main() { Self.SetMobile(true); Self.SetGravity(true); - Self.SetHitbox(0, 0, 16, 52); + Self.SetHitbox(0, 0, 32, 52); Self.AddAnimation("walk-left", 200, ["stand-left", "walk-left-1", "walk-left-2", "walk-left-3", "walk-left-2", "walk-left-1"]); Self.AddAnimation("walk-right", 200, ["stand-right", "walk-right-1", "walk-right-2", "walk-right-3", "walk-right-2", "walk-right-1"]); diff --git a/go.mod b/go.mod index 119c22c..aec88d5 100644 --- a/go.mod +++ b/go.mod @@ -43,6 +43,3 @@ require ( -replace git.kirsle.net/go/render => /home/kirsle/SketchyMaze/deps/render -replace git.kirsle.net/go/ui => /home/kirsle/SketchyMaze/deps/ui -replace git.kirsle.net/go/audio => /home/kirsle/SketchyMaze/deps/audio diff --git a/pkg/collision/bounding_rect.go b/pkg/collision/bounding_rect.go index cecc93d..ac04655 100644 --- a/pkg/collision/bounding_rect.go +++ b/pkg/collision/bounding_rect.go @@ -40,3 +40,13 @@ func GetBoundingRectHitbox(a Actor, hitbox render.Rect) render.Rect { } return rect } + +// SizePlusHitbox adjusts an actor's canvas Size() to better fit the +// declared Hitbox by the actor's script. +func SizePlusHitbox(size render.Rect, hitbox render.Rect) render.Rect { + size.X += hitbox.X + size.Y += hitbox.Y + size.W -= size.W - hitbox.W + size.H -= size.H - hitbox.H + return size +} diff --git a/pkg/collision/collide_actors.go b/pkg/collision/collide_actors.go index b38d412..4f94569 100644 --- a/pkg/collision/collide_actors.go +++ b/pkg/collision/collide_actors.go @@ -14,6 +14,7 @@ type Actor interface { Size() render.Rect Grounded() bool SetGrounded(bool) + Hitbox() render.Rect } // BoxCollision holds the result of a collision BetweenBoxes. diff --git a/pkg/collision/collide_level.go b/pkg/collision/collide_level.go index 0e50cee..f455fae 100644 --- a/pkg/collision/collide_level.go +++ b/pkg/collision/collide_level.go @@ -57,6 +57,7 @@ func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point) (*Colli var ( P = d.Position() S = d.Size() + hitbox = d.Hitbox() result = &Collide{ MoveTo: P, @@ -71,8 +72,11 @@ func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point) (*Colli hitFloor bool ) + // Adjust the actor's bounding rect by its stated Hitbox from its script. + S = SizePlusHitbox(S, hitbox) + // Test all of the bounding boxes for a collision with level geometry. - if ok := result.ScanBoundingBox(GetBoundingRect(d), grid); ok { + if ok := result.ScanBoundingBox(GetBoundingRectHitbox(d, hitbox), grid); ok { // We've already collided! Try to wiggle free. if result.Bottom { if !d.Grounded() { diff --git a/pkg/fps.go b/pkg/fps.go index b1c820b..69afd37 100644 --- a/pkg/fps.go +++ b/pkg/fps.go @@ -6,7 +6,8 @@ import ( "git.kirsle.net/apps/doodle/pkg/balance" "git.kirsle.net/apps/doodle/pkg/collision" - "git.kirsle.net/apps/doodle/pkg/doodads" + "git.kirsle.net/apps/doodle/pkg/drawtool" + "git.kirsle.net/apps/doodle/pkg/uix" "git.kirsle.net/go/render" "git.kirsle.net/go/ui" ) @@ -133,10 +134,9 @@ func (d *Doodle) DrawDebugOverlay() { // 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) { +// The canvas will be the level Canvas, and the collision box is drawn in world +// space using the canvas.DrawStrokes function. +func (d *Doodle) DrawCollisionBox(canvas *uix.Canvas, actor *uix.Actor) { if !DebugCollision { return } @@ -144,12 +144,32 @@ func (d *Doodle) DrawCollisionBox(actor doodads.Actor) { var ( rect = collision.GetBoundingRect(actor) box = collision.GetCollisionBox(rect) + hitbox = actor.Hitbox() ) - 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]) + // Adjust the actor's bounding rect by its stated Hitbox from its script. + rect = collision.SizePlusHitbox(rect, hitbox) + + box = collision.GetCollisionBox(rect) + + // The stroke data for drawing the collision box "inside" the level Canvas, + // so it scrolls and works in world units not screen units. + var strokes = []struct{ + Color render.Color + PointA render.Point + PointB render.Point + }{ + {render.DarkGreen, box.Top[0], box.Top[1]}, + {render.DarkBlue, box.Bottom[0], box.Bottom[1]}, + {render.DarkYellow, box.Left[0], box.Left[1]}, + {render.Red, box.Right[0], box.Right[1]}, + } + for _, cfg := range strokes { + stroke := drawtool.NewStroke(drawtool.Line, cfg.Color) + stroke.PointA = cfg.PointA + stroke.PointB = cfg.PointB + canvas.DrawStrokes(d.Engine, []*drawtool.Stroke{stroke}) + } } // TrackFPS shows the current FPS once per second. diff --git a/pkg/play_scene.go b/pkg/play_scene.go index 5db1890..c42d724 100644 --- a/pkg/play_scene.go +++ b/pkg/play_scene.go @@ -427,7 +427,11 @@ func (s *PlayScene) Draw(d *Doodle) error { s.drawing.Present(d.Engine, s.drawing.Point()) // Draw out bounding boxes. - d.DrawCollisionBox(s.Player.Drawing) + if DebugCollision { + for _, actor := range s.drawing.Actors() { + d.DrawCollisionBox(s.drawing, actor) + } + } // Draw the UI screen and any widgets that attached to it. s.screen.Compute(d.Engine) diff --git a/pkg/uix/actor_collision.go b/pkg/uix/actor_collision.go index 3a296ea..53e3cc7 100644 --- a/pkg/uix/actor_collision.go +++ b/pkg/uix/actor_collision.go @@ -112,7 +112,7 @@ func (w *Canvas) loopActorCollision() error { w.loopContainActorsInsideLevel(a) // Store this actor's bounding box after they've moved. - boxes[i] = collision.GetBoundingRect(a) + boxes[i] = collision.SizePlusHitbox(collision.GetBoundingRect(a), a.Hitbox()) }(i, a) wg.Wait() } @@ -133,7 +133,7 @@ func (w *Canvas) loopActorCollision() error { // Call the OnCollide handler for A informing them of B's intersection. if w.scripting != nil { var ( - rect = collision.GetBoundingRect(b) + rect = collision.SizePlusHitbox(collision.GetBoundingRect(b), b.Hitbox()) lastGoodBox = render.Rect{ X: originalPositions[b.ID()].X, Y: originalPositions[b.ID()].Y, @@ -205,7 +205,7 @@ func (w *Canvas) loopActorCollision() error { // Did A protest? if err == scripting.ErrReturnFalse { // Are they on top? - aHitbox := collision.GetBoundingRectHitbox(a, a.Hitbox()) + aHitbox := collision.SizePlusHitbox(collision.GetBoundingRect(a), a.Hitbox()) if render.AbsInt(test.Y+test.H-aHitbox.Y) == 0 { onTop = true onTopY = test.Y diff --git a/pkg/uix/canvas_actors.go b/pkg/uix/canvas_actors.go index d50b956..05892e7 100644 --- a/pkg/uix/canvas_actors.go +++ b/pkg/uix/canvas_actors.go @@ -31,6 +31,11 @@ func (w *Canvas) InstallActors(actors level.ActorMap) error { return nil } +// Actors returns the list of actors currently in the Canvas. +func (w *Canvas) Actors() []*Actor { + return w.actors +} + // ClearActors removes all the actors from the Canvas. func (w *Canvas) ClearActors() { w.actors = []*Actor{} diff --git a/pkg/uix/canvas_strokes.go b/pkg/uix/canvas_strokes.go index aedc6c5..b902610 100644 --- a/pkg/uix/canvas_strokes.go +++ b/pkg/uix/canvas_strokes.go @@ -126,7 +126,7 @@ func (w *Canvas) presentStrokes(e render.Engine) { for _, stroke := range w.strokes { strokes = append(strokes, stroke) } - w.drawStrokes(e, strokes) + w.DrawStrokes(e, strokes) // Dynamic actor links visible in the ActorTool and LinkTool. if w.Tool == drawtool.ActorTool || w.Tool == drawtool.LinkTool { @@ -201,12 +201,12 @@ func (w *Canvas) presentActorLinks(e render.Engine) { } } - w.drawStrokes(e, strokes) + w.DrawStrokes(e, strokes) } -// drawStrokes is the common base function behind presentStrokes and +// DrawStrokes is the common base function behind presentStrokes and // presentActorLinks to actually draw the lines to the canvas. -func (w *Canvas) drawStrokes(e render.Engine, strokes []*drawtool.Stroke) { +func (w *Canvas) DrawStrokes(e render.Engine, strokes []*drawtool.Stroke) { var ( P = ui.AbsolutePosition(w) // Canvas point in UI VP = w.ViewportRelative() // Canvas scroll viewport