Collision: Fix clipping thru left walls, w/ caveats

There was a clipping bug where the player could sometimes clip thru a
left-side wall, if the left wall and floor made a 90 degree bend and the
player was holding the Left key while jumping slightly into the wall.

A band-aid that seems to work involved two steps:
1. When capping their leftward movement, add a "+ 1" to the cap.
2. At the start of the point loop, enforce the left cap like we do the
   ceiling cap.

This seems to patch the problem, BUT it breaks the ability to walk up
slopes while moving left. Right-facing slopes can be climbed fine still.

Note: the original bug never was a problem against right walls, only
left ones, but the true root cause was not identified. See TODO comments
in collide_level.go.
This commit is contained in:
Noah 2020-04-11 19:21:12 -07:00
parent d615619aba
commit 695ff4da42
2 changed files with 21 additions and 5 deletions

View File

@ -17,6 +17,7 @@ var (
PlayerMaxVelocity float64 = 6
PlayerAcceleration float64 = 0.2
Gravity float64 = 6
SlopeMaxHeight = 8 // max pixel height for player to walk up a slope
// Default chunk size for canvases.
ChunkSize = 128

View File

@ -3,6 +3,7 @@ package collision
import (
"sync"
"git.kirsle.net/apps/doodle/pkg/balance"
"git.kirsle.net/apps/doodle/pkg/level"
"git.kirsle.net/go/render"
)
@ -117,7 +118,7 @@ func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point) (*Colli
} else {
height -= result.RightPoint.Y
}
if height <= 8 {
if height <= balance.SlopeMaxHeight {
target.Y -= height
if target.X < P.X {
target.X-- // push along to the left
@ -147,6 +148,11 @@ func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point) (*Colli
if capHeight != 0 && point.Y < capHeight {
point.Y = capHeight
}
if capLeft != 0 && point.X < capLeft {
// TODO: this along with a "+ 1" hack prevents clipping thru the
// left wall sometimes, but breaks walking up leftward slopes.
point.X = capLeft
}
if has := result.ScanBoundingBox(render.Rect{
X: point.X,
@ -165,12 +171,21 @@ func CollidesWithGrid(d Actor, grid *level.Chunker, target render.Point) (*Colli
if result.Top && !ceiling {
// This is a newly discovered ceiling.
ceiling = true
capHeight = result.TopPoint.Y
capHeight = result.TopPoint.Y + 1
// TODO: the "+ 1" helps prevent clip thru ceiling, probably.
// Similar to the "+ 1" on the left side, below.
}
if result.Left && !hitLeft {
hitLeft = true
capLeft = result.LeftPoint.X
capLeft = result.LeftPoint.X + 1
// TODO: there was a clipping bug where the player could clip
// thru a left wall if they jumped slightly while pressing into
// it. (90 degree angle between floor and left wall). The bug
// does NOT repro on right walls, only left. The "+ 1" added to
// capLeft works around it, BUT breaks walking up leftward slopes
// (walking up rightward slopes still works).
}
if result.Right && !hitRight {
hitRight = true
@ -251,8 +266,8 @@ func (c *Collide) ScanGridLine(p1, p2 render.Point, grid *level.Chunker, side Si
// pixel with each side, so the Left and Right edges will check the
// left- and right-most point.
if side == Top || side == Bottom {
p1.X += 1
p2.X -= 1
p1.X++
p2.X--
}
for point := range render.IterLine(p1, p2) {