public void RunSimulation()
{
Physics.autoSimulation = false;
simulatedBodies = FindObjectsOfType<Rigidbody>().Select(rb => new SimulatedBody(rb)).ToArray();
striker.GetComponent<Rigidbody> ().AddForce (new Vector3 (200.0f, 0.0f, 200.0f));
for (int i = 0; i < maxIterations; i++)
{
Physics.Simulate(0.02f);
//GET COLLISIONS HERE
if (simulatedBodies.All(body => body.rigidbody.IsSleeping()))
{
print(i);
break;
}
}
Physics.autoSimulation = true;
}
I am trying to use physics.simulate in unity. According to unity documentation "simulation includes all the stages of collision detection, rigidbody and joints integration, and filing of the physics callbacks (contact, trigger and joints" I need to get at which iteration does my striker gameobject collides with other gameobject. If I user auto simulation, OnCollisionEnter works. However it doesn't work when I use Physics.Simulate it doesn't register. What am I doing wrong or how do I get when my object collides with other objects.
Can we detect when a rigid body collides using Physics.Simulate in unity
Yes, it can.
I once did an experiment on this and it worked, I opened the-same sample scene used and made the test again and it worked again. Here is an statement from the doc which is also in your question:
Simulation includes all the stages of collision detection, rigidbody and joints integration, and filing of the physics callbacks (contact, trigger and joints).
So, it can detect collision.
If I user auto simulation, OnCollisionEnter works. However it doesn't work when I use Physics.Simulate it doesn't register.
You can't use IsSleeping()
to get collision. Assuming you have collider and Rigidbody properly setup then the problem is that the maxIterations
value is too small leading to the simulation not being finished and not reaching the destination where it is supposed to collide with another object. If this collision is not done, OnCollisionEnter
will not be called.
Increase your maxIterations
to give it more distance movement in the simulation and OnCollisionEnter
should be called. As for detecting which iteration your GameObject collides with other GameObject, use a boolean variable as flag and set it to true
in the OnCollisionEnter
function then break
out of the for
loop when this boolean variable is true
.
const int maxIterations = 60;
int collideIteration = 0;
bool collided = false;
public void RunSimulation()
{
//RESET OLD VALUES
collided = false;
collideIteration = 0;
Physics.autoSimulation = false;
Rigidbody rbdy = GetComponent<Rigidbody>();
rbdy.AddForce(new Vector3(200.0f, 0.0f, 200.0f));
for (int i = 0; i < maxIterations; i++)
{
Physics.Simulate(0.02f);
//Check if collided then break out of the loop
if (collided)
{
collideIteration = i;
print(i);
break;
}
}
Physics.autoSimulation = true;
}
public int GetCollideIteration()
{
return collideIteration;
}
void OnCollisionEnter(Collision collision)
{
collided = true;
Debug.Log("Collision: " + collision.collider.name);
}
If increasing maxIterations
did not solve your issue then look into time based simulations. It will do the simulation in x seconds. 5
seconds is used in the code below and the only thing changes is the RunSimulation()
function. The rest of the code above is still valid:
public void RunSimulation()
{
//RESET OLD VALUES
collided = false;
collideIteration = 0;
Physics.autoSimulation = false;
Rigidbody rbdy = GetComponent<Rigidbody>();
rbdy.AddForce(new Vector3(200.0f, 0.0f, 200.0f));
//Simulate where it will be in 5 seconds
float timeInSec = 5f;
int i = 0;
while (timeInSec >= Time.fixedDeltaTime)
{
timeInSec -= Time.fixedDeltaTime;
Physics.Simulate(Time.fixedDeltaTime);
//Check if collided then break out of the loop
if (collided)
{
collideIteration = i;
print(i);
break;
}
i++;
}
Physics.autoSimulation = true;
}