Proposition for tumbler physics

Started by geoo, September 12, 2017, 06:47:19 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

geoo

Issue: (1) on 45 degree slopes, and as far as I'm aware also 60 degree slopes, the behaviour when a tumbler/jumper encounters terrain is inconsistent.
(2) the tumbler code is a messy blob.

Simon is addressing (2) with a solution that cannot address (1). Thus I'd propose a slightly different solution, which is rather modular, and the modules are easy to comprehend in what they are doing. I think the proposed rewrite mixes moving and collision checks a lot more than my proposal, which should make the code clearer.


Subroutine (1):
Determine first point of impact via going along the trajectory 1 pixel vertically or horizontally at a time.

Subroutine (2) [takes coordinate as argument], or probably better even 3 separate subroutines.
Let's call the coordinate that we got as argument (0,0).
Is there space below at (0,-1) or (0,-2), if yes, we've hit a ceiling.
Is there space above at (0,+1) or (0,+2)? if yes, we've hit floor.
Is there space one pixel behind at (-1,0)? If yes, we've hit a wall.
Return those three booleans.
Remark: Notice that as (0,0) is the first point of impact by only going vertically and horizontally, at least one of the three will be true.

Subroutine (3):
Call (1)
Call (2)
If we've hit floor and ceiling, use y-speed to determine whether to call landing or bumping subroutine (this only happens if you have a 1-px layer of terrain).
Else If we've hit floor, call landing subroutine.
Else If we've hit a ceiling, call bumping subroutine.
Else we've hit a wall (and nothing else), call reflection subroutine.

Note: The reason I propose checking 2 pixels in the ceiling and floor check in (2) is to handle 60 degree slopes consistently. Inconsistent behaviour will now only happen at slopes going at least 3 pixels up/down per 1 pixel horizontally, which I don't believe exist as tiles.

Simon

Interesting approach! On paper, this looks plausible. I went over some corner cases in my mind, like single pixels of terrain in mid-air, and your algo produces meaningful results.

My rewrite is still buggy and I don't feel like working on it today. Maybe I'll implement your algo in a couple days and give better feedback.

Jumpers feel nice when they latch onto ledges with their upper body, not only with their foot. Maybe I can run several instances of your (1) for jumpers: One at the feet as normal, and a couple extra trajectories shifted upwards, to make the upper body collide with the terrain. For (2), we use the trajectory that hit earliest out of the many in (1).

-- Simon

geoo

#2
There is one issue I noticed, which is a real borderline case but should probably be considered anyway:

If you have a 45 degree slope, which is just 1 or 2 pixels thick (vertically). If a lix is flinging slightly up and with high horizontal velocity, it can land on such an upwards slope, but the algorithm would make it glitch through the slope. Similarly if you have such a thin ceiling slope and a lix bumps into it while moving slightly downwards.
I think both are extremely rare, but should be fixed anyway. I haven't found a simple way of fixing that yet.

EDIT: So the only instance the glitch happens if both the landing and bumping flag are set (i.e. at most 2px thin terrain), and the terrain was encountered while moving one pixel horizontally in (1). I'm not quite sure how this case is handled in the current code, but it works. So maybe whatever happens there can be implemented as a special subroutine for this case. Or implement the subroutine as follows:
Go one pixel back horizontally, and check above at (-1, +1) and (-1, +2). If these are non-solid, you cannot bump, thus you have to land. Otherwise bump.
So overall for this solution, you'd need that (1) additionally returns if terrain was encountered while moving horizontally or vertically.
Then in case both the landing and bumping flags are set, if (1) returned "horizontally", you have to call the special subroutine that decides whether to land or bump.

Simon

#3
Illustration of geoo's borderline case:

. . . . . . #
. . . . . # .
. . . . # . .
------L . . .
. . # ? . . .
. # . ? . . .
# . . . . . .


Key:
. air
- air with flight path (can't draw upwards flight)
# terrain
L terrain and impact of Lix
? air, checked by algo to conclude we hit ceiling

Lix thinks she hit a ceiling, and will bonk off this ceiling: Losing sidewards momentum and move downwards.

I agree that this is a problem. Super-thin terrain is problematic in general when we check small neighborhoods of impact. We have to use the direction of flight even more as a tiebreaker.

I don't like entering the terrain in the first place. Ideally, we stop short of the terrain. Can probably adapt geoo's proposal slightly to stop short of the impact, and still use 95 % of the ideas:

. . . . . . #
. . . . . # .
. . . . # . .
----L # . . .
. . # . . . .
. # . . . . .
# . . . . . .


I want to stop here.

-- Simon

Simon

#4
The new tumbler code, I've rejected it for 0.9 because it breaks about 50 replays with jumpers, but I'll keep it on the backburner, refine its accuracy w.r.t. 0.8 flinging, and maybe merge it into 0.10.

I've eyeball-profiled the new tumbler code as follows. On my 1-year-old i5 processor, I built from source with dmd, without debugging flags, with optimizations. Fling 1,000 lix horizontally back and forth between two opposing steams, with regular fast-forward = 60 physics updates per second.

The 0.8 tumbler code dropped from 60 fps to 44 fps. The new tumbler code drops from 60 fps to 58 fps for just a moment, then maintains 59 to 60 fps.

The 0.8 tumbler code has everything we're looking for in legacy code: Long functions that do too much. :lix-evil: It's the main reason that Organ Symphony grinds everybody's machine to a halt.

-- Simon