you have a player actor. great. heres one. it's lexy

she is standing on a slope. you are savvy at physics and understand that:
-
gravity will attempt to pull her downwards
-
she will immediately collide with the slope itself
-
her remaining motion will be projected onto the slope (roughly equivalent to subtracting the normal force)
-
she will then slide down the slope.
this is bad, because lexy is not trying to move. neither she nor the ground are made of ice, so surely she can hold herself in place.
but again, you are savvy at physics, so you know what holds her there: friction. so you say, ok, add a bunch of friction.
now you have a problem. the good news is that your physics engine is completely homegrown, so you can explain the problem in excruciating detail. the bad news is that it is your problem to solve for the same reasons. and the problem is that your movement code integrates everything upfront, then performs a motion.
that means you have your current velocity (presumably zero), gravity (pointing downwards), and friction (pointing up along the slope). you add them together in some fashion, and the result can never be zero, even with friction's natural capping behavior — this is just how vector addition works. so lexy will definitely try to accelerate in some direction, and the best you can hope for is that she will try to accelerate exactly towards the ground. but working out how to make that happen requires essentially working backwards from gravity (non-trivial because various effects can interact with gravity) and also just feels real dumb to be doing.
so where did you go wrong?
(an aside: the reason this doesn't happen in the demo is that i also have a cutoff on very small movement, so that little rounding-error levels of velocity don't make things shift a pixel at a time over the course of seconds. but that cutoff is too coarse, and in particular it makes some slow objects just not move on monitors with high refresh rates, so i've reduced it dramatically, and that has caused lexy to slide downhill. i thought i'd fixed this before but apparently i was just masking it by accident!)
i think the problem,
conceptually, is that friction happens at the wrong time. it's integrated with velocity and acceleration accumulated over the course of the last tic before movement is attempted, but friction isn't something that happens in a vacuum. i mean, literally, it won't happen if there's nothing else around. friction is an interaction with another object we're touching, and before we start moving, there aren't any of those!
so it seems like friction should only apply between steps 3 and 4 — after colliding with the ground, before actually moving along it. this is the point at which we know we are, in fact, sliding against the ground. and now we even have the ground available, so we don't need friction itself to be a vector at all, which is kinda convenient.
but that's in the guts of basic motion i... hesitate... to put something like friction in the middle of that. also, what happens if you collide and slide again? does friction apply again? probably not. so it only applies specifically the second time through a loop? that's rather weird. maybe it's okay that it's weird? it does add complexity for "out-of-turn" motion though, like being pushed or climbing a ladder, which probably won't have a big perf impact but does feel inappropriate.
other solutions
skip gravity
i could simply not apply gravity to a player on the ground. i've seen mention of that being done before. but that just feels goofy?? they are trying to move downwards, and on a slippery slope they even should move downwards.
also i have a bunch of objects that care about things landing on them, and this implies some weird special cases (in who knows how many places) for detecting that a player is walking on top of them without actually moving into them. and i have enough special cases as it is man. expressing a physics condition is so goddamn hard. i have the unsettling feeling that this would have other unforeseen consequences as well
a possible upside of this is that it could very well skip an entire movement iteration every tic — currently, a walking player tries to move sideways (for walking) + downwards (for gravity), immediately hits the ground, projects along the ground, and then tries to move a second time. without gravity in there, they'd skip the first collision and move exactly sideways from the beginning.
remember the ground
i do in fact remember the ground (tile or actor or whatever) for each actor, so i could use that to get the friction right upfront.
but what does that mean in practice? i guess it means that the motion vector would be projected along the ground before even attempting to move at all (and then that would be shortened by friction). so it's kind of like skipping gravity — if lexy is standing on flat ground, her attempted motion (straight down) will be projected along the ground (horizontal) and always come out zero.
i guess essentially this combines the other two options — it applies friction to the movement vector, but it skips ahead one attempt by making use of knowledge from the previous frame. it would get the friction stuff out of the movement core, which i like, but it would still make objects not push against the ground, which i don't like.
ah, all the options seem nebulously Not Great, which is always a sign of a fun problem. and don't worry, this gets even more complicated with physics problems part 3
maybe the last option works after all
what i'm trying to model now isn't that infinite friction keeps the player at zero velocity, but that zero friction has the player moving directly into the ground
i imagined simply projecting the frame motion along the ground and applying friction to that, which would end up with zero motion into the ground. but i could instead separate the frame motion into normal and tangent parts, apply friction to the tangent part, and then add the normal part back in. now infinite friction makes the tangent part zero, but the normal part is still there and shouldn't actually cause any movement
it does feel a bit weird to talk about applying friction to a motion. it's an acceleration (well, force, whatever) being simulated over a unit of time, so it really applies to velocity. i'm not yet sure how i want to square that.
there's still the question of whether i do this before movement or as part of sliding. i think that will come down to what makes the components easier to juggle — moving, walking, and falling are all separate and i like them to rely on each other (beyond telling move what to do) as little as possible. that, plus the conceptual issue where friction should really apply to velocity and not motion, are strongly inclining me to do it before movement
anyway this is what i was trying to do all along — it's just that the friction vector is (due to code arrangement) calculated before gravity's effect on velocity, so it's like it's acting on old information. if i make it a scalar and make movement code responsible for turning that into a vector at the latest possible moment, i think everything Just Works? maybe
this should work anyway. applying friction is capped, so, it shouldn't matter how strong gravity is; if i just set friction to a real damn big vector pointing uphill, it should work. and lexy's walk acceleration is pretty high so this should work correctly already. right? am i confusing the hell out of myself?
...
hmmmmmm
it looks like i tried to apply a ½ factor to friction in the name of integrating it "correctly", but friction has a hard cap so you can't really integrate it correctly. i knew this was Dubious when i tried it, but it seemed to work, so i left it in. turns out it only worked because of that small-movement cutoff kludge that i recently removed
and if i also remove that ½...
it's fine. lexy holds still and her attempted velocity points exactly into the hillside. lol. lmao
in my defense i conceived of the explanation for the problem a few days ago when i was so exhausted i couldn't do anything but stare into space and think about physics. once i was more awake i just thought about how to fix it, since that part seemed harder. very impressed that i managed to explain in detail how friction needs to exactly precisely cancel gravity without ever thinking "ah hm yes wait, no it fucking doesn't"