Fix Actor Collision Checks Again
* Recent collision update caused a regression where the player would get "stuck" while standing on top of a solid doodad, unable to walk left or right. * When deciding if the actor is on top of a doodad, use the doodad's Hitbox (if available) instead of the bounding box. This fixes the upside-down trapdoor acting solid when landed on from the top, since its Hitbox Y coordinate is not the same as the top of its sprite. * Cheats: when using the noclip cheat in Play Mode, you can hold down the Shift key while moving to only move one pixel at a time.
This commit is contained in:
parent
a43e45fad0
commit
0e3a30e633
|
@ -19,10 +19,6 @@ function main() {
|
|||
var startedAnimation = false;
|
||||
|
||||
Events.OnCollide(function(e) {
|
||||
// Only trigger for mobile characters.
|
||||
if (!e.Actor.IsMobile()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the floor is falling, the player passes right thru.
|
||||
if (state === stateFalling || state === stateFallen) {
|
||||
|
@ -36,6 +32,11 @@ function main() {
|
|||
return false;
|
||||
}
|
||||
|
||||
// If movement is not settled, be solid.
|
||||
if (!e.Settled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Begin the animation sequence if we're in the solid state.
|
||||
if (state === stateSolid) {
|
||||
state = stateShaking;
|
||||
|
|
|
@ -9,6 +9,8 @@
|
|||
* `import antigravity` - during Play Mode, disables gravity for the player
|
||||
character and allows free movement in all directions with the arrow keys.
|
||||
Enter the cheat again to restore gravity to normal.
|
||||
* Note: under antigravity, hold down the Shift key to lower the player
|
||||
speed to only one pixel per tick.
|
||||
* `ghost mode` - during Play Mode, toggles noclip for the player character.
|
||||
|
||||
## Bool Props
|
||||
|
|
|
@ -427,6 +427,12 @@ func (s *PlayScene) Draw(d *Doodle) error {
|
|||
func (s *PlayScene) movePlayer(ev *event.State) {
|
||||
var playerSpeed = balance.PlayerMaxVelocity
|
||||
|
||||
// If antigravity enabled and the Shift key is pressed down, move the
|
||||
// player by only one pixel per tick.
|
||||
if s.antigravity && ev.Shift {
|
||||
playerSpeed = 1
|
||||
}
|
||||
|
||||
var velocity render.Point
|
||||
|
||||
if ev.Left {
|
||||
|
|
|
@ -127,6 +127,19 @@ func (w *Canvas) loopActorCollision() error {
|
|||
}
|
||||
)
|
||||
|
||||
// HACK: below, when we determine the moving actor is "onTop" of
|
||||
// the doodad's solid hitbox, we lockY their movement so they don't
|
||||
// fall down further; but sometimes there's an off-by-one error if
|
||||
// the actor fell a distance before landing, and so the final
|
||||
// Settled collision check doesn't fire (i.e. if they fell onto a
|
||||
// Crumbly Floor which should begin shaking when walked on).
|
||||
//
|
||||
// When we decide they're onTop, record the Y position, and then
|
||||
// use it for collision-check purposes but DON'T physically move
|
||||
// the character by it (moving the character may clip them thru
|
||||
// other solid hitboxes like the upside-down trapdoor)
|
||||
var onTopY int
|
||||
|
||||
// Firstly we want to make sure B isn't able to clip through A's
|
||||
// solid hitbox if A protests the movement. Trace a vector from
|
||||
// B's original position to their current one and ping A's
|
||||
|
@ -147,10 +160,16 @@ func (w *Canvas) loopActorCollision() error {
|
|||
// Touching the solid actor from the side is already fine.
|
||||
var onTop = false
|
||||
|
||||
var (
|
||||
lockX int
|
||||
lockY int
|
||||
)
|
||||
|
||||
for point := range render.IterLine(
|
||||
origPoint,
|
||||
b.Position(),
|
||||
) {
|
||||
point := point
|
||||
test := render.Rect{
|
||||
X: point.X,
|
||||
Y: point.Y,
|
||||
|
@ -158,11 +177,6 @@ func (w *Canvas) loopActorCollision() error {
|
|||
H: rect.H,
|
||||
}
|
||||
|
||||
var (
|
||||
lockX bool
|
||||
lockY bool
|
||||
)
|
||||
|
||||
if info, err := collision.CompareBoxes(boxes[tuple.A], test); err == nil {
|
||||
// B is overlapping A's box, call its OnCollide handler
|
||||
// with Settled=false and see if it protests the overlap.
|
||||
|
@ -176,39 +190,50 @@ func (w *Canvas) loopActorCollision() error {
|
|||
// Did A protest?
|
||||
if err == scripting.ErrReturnFalse {
|
||||
// Are they on top?
|
||||
if render.AbsInt(lastGoodBox.Y+lastGoodBox.H-boxes[tuple.A].Y) <= 2 {
|
||||
aHitbox := doodads.GetBoundingRectHitbox(a, a.Hitbox())
|
||||
if render.AbsInt(test.Y+test.H-aHitbox.Y) == 0 {
|
||||
onTop = true
|
||||
onTopY = test.Y
|
||||
}
|
||||
|
||||
// What direction were we moving?
|
||||
if test.Y != lastGoodBox.Y {
|
||||
lockY = true
|
||||
b.SetGrounded(true)
|
||||
if lockY == 0 {
|
||||
lockY = lastGoodBox.Y
|
||||
}
|
||||
if onTop {
|
||||
b.SetGrounded(true)
|
||||
}
|
||||
}
|
||||
if test.X != lastGoodBox.X {
|
||||
if !onTop {
|
||||
lockX = true
|
||||
lockX = lastGoodBox.X
|
||||
}
|
||||
}
|
||||
|
||||
// Move them back to the last good box, locking the
|
||||
// axis they were moving from being able to enter
|
||||
// this box.
|
||||
tmp := lastGoodBox
|
||||
// Move them back to the last good box.
|
||||
lastGoodBox = test
|
||||
if lockY {
|
||||
lastGoodBox.Y = tmp.Y
|
||||
}
|
||||
if lockX {
|
||||
lastGoodBox.X = tmp.X
|
||||
break
|
||||
if lockX != 0 {
|
||||
lastGoodBox.X = lockX
|
||||
}
|
||||
} else {
|
||||
// Move them back to the last good box.
|
||||
lastGoodBox = test
|
||||
}
|
||||
} else {
|
||||
// No collision between boxes, increment the lastGoodBox
|
||||
lastGoodBox = test
|
||||
}
|
||||
}
|
||||
|
||||
// Did we lock their X or Y coordinate from moving further?
|
||||
if lockY != 0 {
|
||||
lastGoodBox.Y = lockY
|
||||
}
|
||||
if lockX != 0 {
|
||||
lastGoodBox.X = lockX
|
||||
}
|
||||
|
||||
if !b.noclip {
|
||||
b.MoveTo(lastGoodBox.Point())
|
||||
}
|
||||
|
@ -220,6 +245,10 @@ func (w *Canvas) loopActorCollision() error {
|
|||
)
|
||||
}
|
||||
|
||||
if onTopY != 0 && lastGoodBox.Y-onTopY <= 1 {
|
||||
lastGoodBox.Y = onTopY
|
||||
}
|
||||
|
||||
// Movement has been settled. Check if B's point is still invading
|
||||
// A's box and call its OnCollide handler one last time in
|
||||
// Settled=true mode so it can run its actions.
|
||||
|
|
Loading…
Reference in New Issue
Block a user