I have a very weird issue in my 2D Unity game, which I was able to reduce to the following core problem/minimal reproducing test case. Follow these steps to reproduce (Unity 5.1.1f1):
- Create a player object (Cube) at location
(0,0,0). - Remove the
BoxColliderComponent. - Attach the following
C#script, Unity will automatically add the required Components and thereby make it a Rigidbody Collider. - Set the
isKinematicflag. - Add another Cube to the scene at location
(2,0,0). - Remove the
BoxColliderComponent and add aBoxCollider2D. This makes this cube a static Collider. - Set the
isTriggerflag. - Run the scene.
Expected behavior:
The player cube accelerates towards the other cube and stops moving once it touches it.
Observed behavior:
The player cube accelerates towards the other cube, then continues moving at constant speed.
Additional implementation details:
I originally moved all objects by translating their transform and didn't use Rigidbodies at all because I didn't need collision detection. Now I do, so I want Rigidbodies. I dived into online resources and found out I'm supposed to use rigidbody.MovePosition() rather than transform.Translate() or transform.position. I changed my script, and the above error appeared.
Going back to transform.position fixes the issue, but that's not a good solution, as it involves bad practice which, according to what I read, produces significant CPU loads.
Failed attempts to solve:
- Switching to
Update()andTime.deltaTimedidn't make any difference. - I tried not returning in the
Update()and instead simply resetting thetimestepto0whilestopis set. No change. - Fiddling with the Inspector and doing stuff like freezing position on the rigidbody or setting the player objects to also be a trigger had no effect at all. Changing anything on the Rigidbody component while the game is running (after the collision) makes the cube stop immediately. Literally anything, even setting its mass to 0.
- I also tried setting
velocityto 0, resulting in no change. Which does make sense sinceUpdate()is skipped entirely (I also checked that with aDebug.Log()by the way).
So at this point, I'm down to barely 30 lines of code and I still have no idea what's causing this. Since the involved objects are a static Trigger collider and a kinematic rigidbody collider, both with no physics materials, there should be nothing that makes this thing move once the flag is set. But it does move.
SimpleController2D.cs
using UnityEngine;
using System.Collections;
[RequireComponent (typeof (BoxCollider2D), typeof (Rigidbody2D))]
public class SimpleController2D : MonoBehaviour {
public Vector3 velocity = Vector3.zero;
private Transform thisTransform;
private Rigidbody2D thisRigidbody;
public bool stop = false;
void Awake () {
thisTransform = GetComponent<Transform> ();
thisRigidbody = GetComponent<Rigidbody2D> ();
}
void FixedUpdate() {
float timestep = Time.fixedDeltaTime; // temporarily stored for ease of access
if (stop) {
return; // freeze on hit
}
velocity.x += timestep; // accelerate
/* add a second slash (/) to toggle between transform and rigidbody
thisTransform.position += velocity * timestep; /*/
thisRigidbody.MovePosition ((Vector3)thisRigidbody.position + velocity*timestep); //*/
}
void OnTriggerEnter2D(Collider2D col) {
stop = true;
}
}