Only limit player input and not external forces (Rigidbody 3D)
Hey! I have been trying to properly limit movement on my 3D fps controller, and I have so far just been using basic clamping to limit the speed on the X and Z axis. The problem with this is that any external forces will never cause the player to exceed its predefined maximum speed, meaning that external forces like explosions do basically nothing to move the player like an explosion should. My idea for getting this to work was to only allow additional movement input if the player was below a certain maximum velocity, but so far I have been unable to get it to work in code. I am fairly new to working in 3D space with vectors, so I am pretty lost on what to do. My attempted implementation worked until the player turned their head while moving, at which point the movement would not be limited. Here is the code I have tried:
xInput = Input.GetAxisRaw("Horizontal");
yInput = Input.GetAxisRaw("Vertical");
if (xInput > 0 && transform.InverseTransformDirection(rb.velocity).x > inputMaximumSpeed) xInput = 0;
if (xInput < 0 && transform.InverseTransformDirection(rb.velocity).x > -inputMaximumSpeed) xInput = 0;
if (yInput > 0 && transform.InverseTransformDirection(rb.velocity).z > inputMaximumSpeed) yInput = 0;
if (yInput < 0 && transform.InverseTransformDirection(rb.velocity).z > -inputMaximumSpeed) yInput = 0;
//Apply Movement
moveDirection = (xInput * transform.right + yInput * transform.forward).normalized;
rb.AddForce(moveDirection * groundAccSpeed);
Not too sure what to do to fix this, as I have found little to none in terms of examples on how others have gotten this to work. Thanks for any help!
Answer by streeetwalker · Sep 22, 2020 at 08:36 AM
you can AddForce multiple times over the course of a FixedUpdate frame, and the physics engine will aggregate the forces together for you. To limit the force due to input, calculate the resultant velocity due to the input force manually before you add the force. If you are over the limit, you can set the input force vector to zero.
Another method is to accumulate your forces just by adding all the force vectors together - that is what Unity is doing if you use AddForce multiple times. Then you can use AddForce once. Again, you want to limit the force due to input and you use the same method.
You don't show us enough code to understand what you mean by your statement about velocity not being limited when you look to the side.
I managed to get it to kind of work by changing the code to this:
xInput = Input.GetAxisRaw("Horizontal");
yInput = Input.GetAxisRaw("Vertical");
//Apply $$anonymous$$ovement
moveDirection = (xInput * transform.right + yInput * transform.forward).normalized;
if (rb.velocity.magnitude < input$$anonymous$$aximumSpeed)
rb.AddForce(moveDirection * groundAccSpeed);
This does limit the movement by not allowing further inputs if they will cause the player to go over the maximum speed while still allowing external forces, as well as fixing the issue that caused the player to go faster while turning (as long as I have the counter-movement portion of the code running), but the new issue is that it also prevents any turning at all when rotating the player. I've been looking for ways to fix this for a couple of hours, but I can not find or come up with a way to fix it. Not sure if this is the method you intended on how to limit the speed though, I might have misunderstood what you meant.