- 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.
Your answer
 
 
              koobas.hobune.stream
koobas.hobune.stream 
                       
                
                       
			     
			 
                