# Anyone have tips for a physics problem?

Discussion in '2D' started by depress, Apr 21, 2014.

1. ### depress

Joined:
Jul 11, 2012
Posts:
14
Hi all,

I'm having a small problem with my game's 2D physics that I'm hoping to fish for some tips on. The problem I'm having is that when my character runs up a ramp instead of sticking to the ramp as he descends down it, he kind of takes off and gets airborn. This can be seen via the crude red line I've drawn in the screenshot below. What I'd like to happen is for the character to move on the ramp (as demonstrated by the purple line) at the same speeds up and down.

Below is a small snippet of my code. I'm sure that this is happening because as my character reaches the apex of my ramp he is maintaining the vertical velocity he accumulated while running up it.

Code (csharp):
1. void FixedUpdate()
2. {
3.     float move = Input.GetAxis("Horizontal");
4.     rigidbody2D.velocity = new Vector2(move * maxSpeed, rigidbody2D.velocity.y );
5. }
I'd love for some tips on how to tackle this. The more I try to rig it to work the less confident I feel in the code to be as stable as it needs to be (some real ghetto code like I tried adding (grounded?0:rigidbody2D.velocity.y) to the line that updates my velocity lol.) I kind of feel like I should avoid using rigidbody2D to control my character, but if it's possible to avoid that I'd like to. I don't want to lose the benefits of it!

Thanks for taking the time to read this!

2. ### imaginaryhuman

Joined:
Mar 21, 2010
Posts:
5,670
I guess you'll have to fiddle with it by doing a raycast from the player down to the floor, then reposition him at the floor level. . otherwise intertia and gravity will make him fly off like you described. This is easier done with fake physics than real physics.

### Unity Technologies

Joined:
Aug 16, 2013
Posts:
170
You could also zero-out the y component of the characters velocity every frame. It's a brutish solution, but easy.

4. ### Invertex

Joined:
Nov 7, 2013
Posts:
952
I did something similar to this, but instead of repositioning, I simply took the groundHit.normal of the corner hitting the ground, and applied a force negative to that normal direction, and also modified the move direction of my movement code based on this surface normal, so that my move speed stayed consistent.
This is a little more complex of a setup, but it makes for smooth results.

5. ### depress

Joined:
Jul 11, 2012
Posts:
14
Echhh this solution seems kind of written in stone to me. Maybe the values worked out for the best but if you wanted to make the character faster / slower or apply an undetermined number of unknown forces would it still work just fine? I also imagine the calculations are a little expensive, especially if more than one character were to use this system..

Is there any way to salvage some Unity components such as Colliders for fake physics? I would really hate to lose all this awesome functionality surely there must be a way to make this also work without it being too rigged.

6. ### Kurius

Joined:
Sep 29, 2013
Posts:
412
Trying adding more mass and more friction.

7. ### depress

Joined:
Jul 11, 2012
Posts:
14
Eh this just messes up the jumping and if there is too much friction it messes with running, then I have to compensate by increasing the jump force and max move speed which brings me back to square one.

Another problem here is that if my character tries to stand still on a slope they will start sliding down it thanks to gravity. I can correct this with friction but then on flat ground my character doesn't move at all any longer.

8. ### Kurius

Joined:
Sep 29, 2013
Posts:
412
Can I ask why you need the player to hug the ground like that? It's not realistic to hug the ground like that ;-)

9. ### Invertex

Joined:
Nov 7, 2013
Posts:
952
What do you mean "colliders for fake physics"?

But no, it's not set in stone, nor are the calculations expensive. You disable your rigidbody gravity while grounded, and make up for it with a surface normal based gravity using AddForce. And your movement AddForce being applied as usual. The only real extra computation happening is a few raycasts which are nothing at all computation wise, and some addition/substraction to get the direction Vector perpendicular to the surface normal to use in your movement code.

This gives you the most freedom, as the player can still be affected by other forces, can do speed boosts, can angle your character to the surface if you want even to do Sonic like looping if you construct a circle out of an edge collider for example. You're still using the colliders.

10. ### depress

Joined:
Jul 11, 2012
Posts:
14
Man I just... I'm sorry Kurius but that question really wears on me. I can't stand when people are like "Why would you want to do this?" I mean, because I want to lol. I don't think a platformer would be fun at all if you were trying to fight in some stage going uphill and you kept sliding down the hill. You also accelerate down the hill as things stand instead of going at the same speed up and down. Who makes a realistic 2D game... did you see my screenshot?

Ach anyways I digress, I don't mean to rag on you Kurius you're only trying to help me. It's kind of my fault for trying to make a rigidbody be fake physics, but there is just so much that makes it desirable and it's such a shame that I'd have to write my own 'fake' physics .

11. ### depress

Joined:
Jul 11, 2012
Posts:
14

So are you saying that if you get the ground's normal, you basically add force in the opposite direction so that it would sort of 'magnetize' your character to that surface effectively pinning them in place? Am I making any sense trying to understand this?

12. ### Invertex

Joined:
Nov 7, 2013
Posts:
952
Yes that's the gist of it, you're creating your own gravity that's direction is determined by the angle of the surface you're on, thus the gravity pushing you down won't cause you to slide around, nor fight your movement forces.

Then on top of that, you're also changing your player's horizontal movement direction by that ground normal, further making sure you stay with the ground, and also maintaining the movespeed you want regardless of the angle of the surface.
(of course, you could add in a small calculation to reduce speed based on the angle of the slope as well, if you don't want your movespeed to be consistent)

Last edited: Apr 26, 2014
13. ### depress

Joined:
Jul 11, 2012
Posts:
14
Well cool man now that you detail it a little more I think I'll give it a shot.

So would I need to move him based on the slope he's on? I think you mentioned that but let me see if I've got it here. Basically I should add a force the direction of the slope which I should be able to find by crossing the normal of the slope with the z axis, not just in the x axis?

14. ### depress

Joined:
Jul 11, 2012
Posts:
14
Well if I want to give this a shot I'm going to have to rework a lot of my game's terrain actually... to include normals. As of now I just use nice little 64x64 pixel blocks and ramps, but because they're just images they have no normals technically. I'm pretty sure they're all just 'up' but if I were to rotate the squares by 45 degrees instead of using ramp things then they might have the right normals. This is still sort of a problem because I've also used the same terrain for walls and ceilings, and there is potential for me to accidentally be considered grounded against them but that has more to do with how my colliders and ground check are setup at the moment.

Point is it'd be a bit of dedication to get these in place but so far it feels like the best solution. Thanks for the advice Invertex!

15. ### Invertex

Joined:
Nov 7, 2013
Posts:
952
The raycast hitting any type of 2D collider, will report back what the world-space surface normal of that point is, even if it's just a box collider that's rotated, the normal it reports back will be the angle you visually see it as. So there's no problem there.

I would still advise moving to EdgeColliders though, this way your walls can be separate layers for detection, as well as your ceilings. EdgeColliders also avoid the ghost-vertices issue that can cause you to get stuck on the points between 2 box colliders touching eachother, even though they are flush.
With the EdgeCollider, you can also create convex and concave shapes, just hold Shift to add more points on the edge and move it around. You can quickly create a set of prefab tiles with their EdgeColliders already constructed, or empty game object prefabs with all the types of EdgeColliders you use commonly. This way you can also have different friction values for different surfaces.

The simplest way I figured to get the perpendicular angle, was to simply just calculate it like this (groundGravity is just my RaycastHit.normal):
Code (csharp):
1. moveAng = new Vector2(groundGravity.y, -groundGravity.x);
Using the surface normal's Y value as the X value and using the reverse value of the X as the Y, effectively gives you the perpendicular angle of the surface. Super simple, no calculations needed.

And then I'd just use my moveAng in my movement code, and multiply it by whatever speed and left/right direction is currently in effect.

Here's an example of one of my old tests:
http://i.gyazo.com/ee7f1aaf8eaf4a018c6ce2f6fa3b7640.mp4

Last edited: Apr 26, 2014
16. ### tuanpham

Joined:
Nov 18, 2016
Posts:
1
Thanks Invertex,

I do exact same way, very good result.

17. ### JohnPet

Joined:
Aug 19, 2012
Posts:
78
So you in fact do this?
Code (CSharp):
1. rb.velocity = new Vector2(move * moveSpeed, rb.velocity.y) + new Vector2(groundHit.normal.y, -groundHit.normal.x);
In my case it doesnt work...