- Home /
Rigidbody physics behaving differently from editor to build
In editor my non-kinematic RB controller is snappy, in build it's slippery as heck. Here is a video I recorded that hopefully shows the difference well enough:
Any suggestions/ideas/theories would be very appreciated.
***added the motor script
vague explanation of this mess: accelMult increases from 0-1 with input and instantly becomes 0 under certain conditions.
In FixedUpdate I take the velocity, increment/decrement it, and add it back along with a projected movement delta (for nice slope movement).
In air movement is just acceleration force with some dampening.
LASTLY: in the physics settings the default physics material is a (0. 0. 0, Average, Average) material I made.
Initial theory was its somehow airborne in build, but you can perform grounded actions so thats that theory gone.
public class Motor : MonoBehaviour
{
private Rigidbody _rigidbody;
private InputReader _inputReader;
private Grounded _grounded;
private CapsuleCollider _collider;
private void OnEnable()
{
_rigidbody = GetComponent<Rigidbody>();
_inputReader = GetComponent<InputReader>();
_grounded = GetComponent<Grounded>();
_collider = GetComponent<CapsuleCollider>();
}
[HideInInspector] public float speed; // max speed
[HideInInspector] public float accelRate; // how fast acceleration goes from 0-1 (0%-100%)
[HideInInspector] public float sprintHorizontalInputReductionMult; // less acceleration when sprinting
[HideInInspector] public bool disabledWorkAround;
private Vector3 localMoveDirection;
private Vector3 localVelocity;
private Vector3 addVelocityFromStandingOnRigidbody;
private Vector3 wantedSpeed;
[HideInInspector] public Vector3 accelMult; // 0-1 multiplier
private bool hitGround;
private bool removeYVelocity;
private float stepsSinceLastGrounded;
private float slopeStickSpeed {get{return speed * 1.5f;}}
private void Update()
{
if (!disabledWorkAround)
{
localMoveDirection.x = _inputReader.moveHorizontal;
localMoveDirection.z = _inputReader.moveVertical;
localMoveDirection = Vector3.ClampMagnitude(localMoveDirection, 1f);
if (_grounded.isGrounded)
{
// only triggers once on landing from air
if (hitGround)
{
// yes/no instant moving at full speed on landing
Vector3 localVelocityWithoutY = new Vector3(localVelocity.x, 0, localVelocity.z);
accelMult = Vector3.Angle(localMoveDirection, localVelocityWithoutY) < 90f ? accelMult : Vector3.zero;
hitGround = false;
}
accelMult.x = localMoveDirection.x != 0 ? accelMult.x += accelRate * Time.deltaTime : 0;
accelMult.x *= sprintHorizontalInputReductionMult;
accelMult.x = Mathf.Clamp(accelMult.x, 0, 1);
accelMult.z = localMoveDirection.z != 0 ? accelMult.z += accelRate * Time.deltaTime : 0;
accelMult.z = Mathf.Clamp(accelMult.z, 0, 1);
wantedSpeed = accelMult * speed;
}
else
hitGround = true; // reset this for next time it becomes grounded
}
}
private void FixedUpdate()
{
localVelocity = transform.InverseTransformDirection(_rigidbody.velocity);
if (_grounded.isGrounded)
{
Vector3 newLocalVelocity = localVelocity;
// to make the multiplier positive or negative depending on input
newLocalVelocity.x += localMoveDirection.x >= 0 ?
(wantedSpeed.x * accelMult.x) - newLocalVelocity.x:
(wantedSpeed.x * -accelMult.x) - newLocalVelocity.x;
newLocalVelocity.z += localMoveDirection.z >= 0 ?
(wantedSpeed.z * accelMult.z) - newLocalVelocity.z:
(wantedSpeed.z * -accelMult.z) - newLocalVelocity.z;
newLocalVelocity = Vector3.ClampMagnitude(newLocalVelocity, speed);
Vector3 deltaLocalVelocity = newLocalVelocity - localVelocity;
deltaLocalVelocity = transform.TransformDirection(deltaLocalVelocity);
deltaLocalVelocity = Vector3.ProjectOnPlane(deltaLocalVelocity, _grounded.contactNormal);
localVelocity = transform.TransformDirection(localVelocity);
_rigidbody.velocity = localVelocity + deltaLocalVelocity;
Debug.DrawRay(transform.position + Vector3.up * 2f, _rigidbody.velocity, Color.red);
}
else // in air control
{
if (_rigidbody.velocity.magnitude <= speed)
_rigidbody.AddForce(transform.TransformDirection(localMoveDirection * speed), ForceMode.Acceleration);
float slowdown = 0.2f * Time.deltaTime;
_rigidbody.velocity -= new Vector3(_rigidbody.velocity.x * slowdown, 0, _rigidbody.velocity.z * slowdown);
}
// TODO: movement only works as wanted with input settings "Gravity" set to 99 or whatever
}
}
Tell us how you set it up. What's affecting the movement? (Physic $$anonymous$$aterials, how do you move the character, which Unity method did you put the code into, etc).
If you're using a complex character controller, do a simple test:
Just a Cube with a Rigidbody and a script that simply adds force when you press a key. $$anonymous$$eep the same world (the ground you were standing on). Do you still see a difference?
Well I rebuilt the controller on a fresh empty gameobject and it behaves incorrectly, just like the build. Until I disable and re-enable it during runtime, then it behaves as expected. ...huh? So I drag in an already built "player" prefab, moves properly, disable/enable during runtime, now its super slidey. $$anonymous$$ore toggling wont fix it, only works the once lol. *more testing: toggling in Awake()/Start() make it slidey, OnEnable() does not.
The values on my components are saved on an external source so they are identical on every controller. Is the difference the rigidbody+collider components? Those too have had identical settings
Well I can bandaid the issue by having a script toggle the controller gameobject disabled/enabled as it spawns in. This changes movement from slippery -> sticky for some reason.
Or I can rebuild everything in a new project from scratch and it all works great
...
Except the mouse look script does not work in a fresh project
??? I dont even know anymore
$$anonymous$$ade another fresh project and put mouse look on a cube, works fine.
Is there some kind of precedence for scripts that just stop working in a project?
Script Execution Order comes to $$anonymous$$d. Do you by any chance have scripts that need to be executed in a certain order?
Yeah we'll need to see some code to deter$$anonymous$$e what's actually going on.