Add new doodads:
* Start Flag: place this in a level to set the spawn point of the player
character. If no flag is found, the player spawns at 0,0 in the top
corner of the map. Only use one Start Flag per level, otherwise the
player will randomly spawn at one of them.
* Crumbly Floor: a solid floor that begins to shake and then fall apart
after a moment when a mobile character steps on it. The floor respawns
after 5 seconds.
* State Blocks: blue and orange blocks that toggle between solid and
pass-thru whenever a State Button is activated.
* State Button: a solid "ON/OFF" block that toggles State Blocks back
and forth when touched. Only activates if touched on the side or bottom;
acts as a solid floor when walked on from the top.
New features for doodad scripts:
* Actor scripts: call SetMobile(true) to mark an actor as a mobile mob
(i.e. player character or enemy). Other doodads can check if the actor
colliding with them IsMobile so they don't activate if placed too close
to other (non-mobile) doodads in a level. The Blue and Red Azulians
are the only mobile characters so far.
* Message.Broadcast allows sending a pub/sub message out to ALL doodads
in the level, instead of only to linked doodads as Message.Publish does.
This is used for the State Blocks to globally communicate on/off status
without needing to link them all together manually.
* Improve the collision detection algorithm so that Actor OnCollide
scripts get called more often WHILE an actor is moving, to prevent a
fast-moving actor from zipping right through the "solid" hitbox and
not giving the subject actor time to protest the movement.
* It's implemented by adding a `Settled` boolean to the OnCollide event
object. When the game is testing out movement, Settled=false to give
the actor a chance to say "I'm solid!" and have the moving party be
stopped early.
* After all this is done, for any pair of actors still with overlapping
hitboxes, OnCollide is called one last time with Settled=true. This is
when the actor should run its actions (like publishing messages to
other actors, changing state as in a trapdoor, etc.)
* The new collision detection algorithm works as follows:
* Stage 1 is the same as before, all mobile actors are moved and
tested against level geometry. They record their Original and New
position during this phase.
* Stage 2 is where we re-run that movement but ping actors being
intersected each step of the way. We trace the steps between
Original and New position, test OnCollide handler, and if it returns
false we move the mobile actor to the Last Good Position along the
trace.
* Stage 3 we run the final OnCollide(Settled=true) to let actors run
actions they wanted to for their collide handler, WITHOUT spamming
those actions during Stage 2.
* This should now allow for tweaking of gravity speed and player speed
without breaking all actor collision checking.
* Events.OnCollide now receives a CollideEvent object, which makes
available the .Actor who collided and the .Overlap rect which is
zero-relative to the target actor. Doodad scripts can use the .Overlap
to see WHERE in their own box the other actor has intruded.
* Update the LockedDoor and ElectricDoor doodads to detect when the
player has entered their inner rect (since their doors are narrower
than their doodad size)
* Update the Button doodads to only press in when the player actually
touches them (because their sizes are shorter than their doodad
height)
* Update the Trapdoor to only trigger its animation when the board
along its top has been touched, not when the empty space below was
touched from the bottom.
* Events.OnLeave now implemented and fires when an actor who was
previously intersecting your doodad has left.
* The engine detects when an event JS callback returns false.
Eventually, the OnCollide can return false to signify the collision is
not accepted and the actor should be bumped away as if they hit solid
geometry.