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;
|
var startedAnimation = false;
|
||||||
|
|
||||||
Events.OnCollide(function(e) {
|
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 the floor is falling, the player passes right thru.
|
||||||
if (state === stateFalling || state === stateFallen) {
|
if (state === stateFalling || state === stateFallen) {
|
||||||
|
@ -36,6 +32,11 @@ function main() {
|
||||||
return false;
|
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.
|
// Begin the animation sequence if we're in the solid state.
|
||||||
if (state === stateSolid) {
|
if (state === stateSolid) {
|
||||||
state = stateShaking;
|
state = stateShaking;
|
||||||
|
|
|
@ -9,6 +9,8 @@
|
||||||
* `import antigravity` - during Play Mode, disables gravity for the player
|
* `import antigravity` - during Play Mode, disables gravity for the player
|
||||||
character and allows free movement in all directions with the arrow keys.
|
character and allows free movement in all directions with the arrow keys.
|
||||||
Enter the cheat again to restore gravity to normal.
|
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.
|
* `ghost mode` - during Play Mode, toggles noclip for the player character.
|
||||||
|
|
||||||
## Bool Props
|
## Bool Props
|
||||||
|
|
|
@ -427,6 +427,12 @@ func (s *PlayScene) Draw(d *Doodle) error {
|
||||||
func (s *PlayScene) movePlayer(ev *event.State) {
|
func (s *PlayScene) movePlayer(ev *event.State) {
|
||||||
var playerSpeed = balance.PlayerMaxVelocity
|
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
|
var velocity render.Point
|
||||||
|
|
||||||
if ev.Left {
|
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
|
// 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
|
// solid hitbox if A protests the movement. Trace a vector from
|
||||||
// B's original position to their current one and ping A's
|
// 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.
|
// Touching the solid actor from the side is already fine.
|
||||||
var onTop = false
|
var onTop = false
|
||||||
|
|
||||||
|
var (
|
||||||
|
lockX int
|
||||||
|
lockY int
|
||||||
|
)
|
||||||
|
|
||||||
for point := range render.IterLine(
|
for point := range render.IterLine(
|
||||||
origPoint,
|
origPoint,
|
||||||
b.Position(),
|
b.Position(),
|
||||||
) {
|
) {
|
||||||
|
point := point
|
||||||
test := render.Rect{
|
test := render.Rect{
|
||||||
X: point.X,
|
X: point.X,
|
||||||
Y: point.Y,
|
Y: point.Y,
|
||||||
|
@ -158,11 +177,6 @@ func (w *Canvas) loopActorCollision() error {
|
||||||
H: rect.H,
|
H: rect.H,
|
||||||
}
|
}
|
||||||
|
|
||||||
var (
|
|
||||||
lockX bool
|
|
||||||
lockY bool
|
|
||||||
)
|
|
||||||
|
|
||||||
if info, err := collision.CompareBoxes(boxes[tuple.A], test); err == nil {
|
if info, err := collision.CompareBoxes(boxes[tuple.A], test); err == nil {
|
||||||
// B is overlapping A's box, call its OnCollide handler
|
// B is overlapping A's box, call its OnCollide handler
|
||||||
// with Settled=false and see if it protests the overlap.
|
// with Settled=false and see if it protests the overlap.
|
||||||
|
@ -176,39 +190,50 @@ func (w *Canvas) loopActorCollision() error {
|
||||||
// Did A protest?
|
// Did A protest?
|
||||||
if err == scripting.ErrReturnFalse {
|
if err == scripting.ErrReturnFalse {
|
||||||
// Are they on top?
|
// 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
|
onTop = true
|
||||||
|
onTopY = test.Y
|
||||||
}
|
}
|
||||||
|
|
||||||
// What direction were we moving?
|
// What direction were we moving?
|
||||||
if test.Y != lastGoodBox.Y {
|
if test.Y != lastGoodBox.Y {
|
||||||
lockY = true
|
if lockY == 0 {
|
||||||
b.SetGrounded(true)
|
lockY = lastGoodBox.Y
|
||||||
|
}
|
||||||
|
if onTop {
|
||||||
|
b.SetGrounded(true)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if test.X != lastGoodBox.X {
|
if test.X != lastGoodBox.X {
|
||||||
if !onTop {
|
if !onTop {
|
||||||
lockX = true
|
lockX = lastGoodBox.X
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Move them back to the last good box, locking the
|
// Move them back to the last good box.
|
||||||
// axis they were moving from being able to enter
|
|
||||||
// this box.
|
|
||||||
tmp := lastGoodBox
|
|
||||||
lastGoodBox = test
|
lastGoodBox = test
|
||||||
if lockY {
|
if lockX != 0 {
|
||||||
lastGoodBox.Y = tmp.Y
|
lastGoodBox.X = lockX
|
||||||
}
|
|
||||||
if lockX {
|
|
||||||
lastGoodBox.X = tmp.X
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
// Move them back to the last good box.
|
||||||
lastGoodBox = test
|
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 {
|
if !b.noclip {
|
||||||
b.MoveTo(lastGoodBox.Point())
|
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
|
// Movement has been settled. Check if B's point is still invading
|
||||||
// A's box and call its OnCollide handler one last time in
|
// A's box and call its OnCollide handler one last time in
|
||||||
// Settled=true mode so it can run its actions.
|
// Settled=true mode so it can run its actions.
|
||||||
|
|
Loading…
Reference in New Issue
Block a user