- Home /
Stopping a Rigidbody movement so it can reset?
Hey, so I'm building a physics-y game where you can shoot lots of tiny cubes from a player cube. When you fire it creates a tiny cube, adds force to it in one direction and adds force to the player cube in the other direction to move.
Now I've recently switched to a sort of almost pool, and every time it tries to 'reset' one of the cubes they just fly off in whatever direction they were going in before they were reset. I've tried to set the velocity to zero and it only appears to work on half of them, so I took it out.
So, any ideas on how to stop them properly so I can fire them again like I do when I originally initialise them?
if (Input.GetKey("w")) {
if (wayPointList[curPos]){.
wayPointList[curPos].constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY;
wayPointList[curPos].position = transform.position;
wayPointList[curPos].rotation = transform.rotation;
Physics.IgnoreCollision(wayPointList[curPos].collider, collider);
wayPointList[curPos].AddForce(wayPointList[curPos].transform.forward * 1000);
rigidbody.AddForce (rigidbody.transform.forward * -10);
} else {
wayPointList[curPos] = Instantiate(prefabToSpawn, transform.position, transform.rotation);
Physics.IgnoreCollision(wayPointList[curPos].collider, collider);
wayPointList[curPos].renderer.material.color = Color.red;
wayPointList[curPos].AddForce(wayPointList[curPos].transform.forward * 1000);
rigidbody.AddForce (rigidbody.transform.forward * -10);
}
curPos = (curPos + 1) % wayPointLimit;
}
Like this? Doesn't work.
Edit: There was a comment above this that I now can't see/has been deleted.
if (wayPointList[curPos]){
wayPointList[curPos].is$$anonymous$$inematic = true;
wayPointList[curPos].constraints = RigidbodyConstraints.FreezeRotationX | RigidbodyConstraints.FreezeRotationY;
wayPointList[curPos].position = transform.position;
wayPointList[curPos].rotation = transform.rotation;
Physics.IgnoreCollision(wayPointList[curPos].collider, collider);
wayPointList[curPos].is$$anonymous$$inematic = false;
wayPointList[curPos].AddForce(wayPointList[curPos].transform.forward * 1000);
rigidbody.AddForce (rigidbody.transform.forward * -10);
}
Answer by aldonaletto · Jul 30, 2013 at 12:18 AM
All the momentum of a rigidbody is stored in rigidbody.velocity and rigidbody.angularVelocity - if you assign Vector3.zero to both, the rigidbody gets completely reset. A better alternative is to set rigidbody.isKinematic to true, which also zeroes the momentum, then clear it before applying the forces, like apparently was suggested by a too shy somebody.
But it seems that you've tried both alternatives without success. If this is the case, something else is wrong - and I suspect that it's the shooting speed: you're not allowing any interval between shots, thus while W is pressed the cubes are recycled every frame, colliding with the previous ones and moving in weird directions.
I rewrote your code with some optimization and including a shot interval, and everything worked fine - the momentum is killed by zeroing the velocities, and I had to increase the back force to -50 in order to have a noticeable effect:
var prefabToSpawn: Rigidbody;
var wayPointLimit = 10;
var shotInterval: float = 0.1;
private var shotTime: float = 0;
private var wayPointList: Rigidbody[];
private var curPos = 0;
function Start () {
wayPointList = new Rigidbody[wayPointLimit];
}
function Update () {
if (Input.GetKey("w") && Time.time > shotTime) {
var rb = wayPointList[curPos]; // get next projectile
if (rb){ // if it's recycled...
rb.velocity = Vector3.zero; // kill previous momentum
rb.angularVelocity = Vector3.zero;
rb.position = transform.position;
rb.rotation = transform.rotation;
} else { // if not, create new projectile:
rb = Instantiate(prefabToSpawn, transform.position, transform.rotation);
wayPointList[curPos] = rb; // add to list
rb.renderer.material.color = Color.red; // set its color
Physics.IgnoreCollision(rb.collider, collider); // and ignore collisions with creator
}
rb.AddForce(transform.forward * 1000);
rigidbody.AddForce (transform.forward * -50);
shotTime = Time.time + shotInterval;
curPos = (curPos + 1) % wayPointLimit;
}
}
NOTE: My first answer used the isKinematic on/off approach to clear the momentum, but it actually didn't work - maybe we should wait for the next physics cycle for it to has effect. But the old and good velocity zeroing alternative worked fine, and the answer was updated.
I'm sure I've copied everything you've done here, and it still behaves erratically. I have no idea why is isn't shooting straight.
Also, even if it did work I fear slowing down the shooting too much would adversely affect my gameplay.
(Oh, and I guess you noticed I used your code from another question - I forgot to change all the mentions of wayPoints to Projectiles haha)
Aha! That's why curPos and the way it's incremented looked familiar to me... But that's weird that the whole thing isn't doing what you expect - it worked fine in my tests: the small red cubes were spit in the same direction, changing direction only after colliding with the others that slowed down or stopped. The small cubes in my tests are scaled to (0.25,0.25,0.25), what works fine with the 0.1 interval. If you want a shorter interval, place the projectiles in a special layer and clear collisions (menu Edit/Project Settings/Physics) between this layer and itself, so that projectiles won't collide with their brothers
I'll test the layer thing eventually, but currently I get decent enough performance if I just delete the projectiles rather than recycling them.
I'll try work out why setting the velocity isn't working as well...
Your answer
Follow this Question
Related Questions
AddForce to sphere 1 Answer
Can someone help me fix my Javascript for Flickering Light? 6 Answers
rigidbody.AddForce to another object 2 Answers