- Home /
Reflect a Rigidbody in Javascript
I first started out with a regular OnCollisionEnter reflection, and this worked well, but after reading about coroutines, I got to wondering if it would be faster by doing my own Raycast and reflecting manually.
First I wanted to show my original reflection code, which uses OnCollisionEnter, keep in mind, the collision function is based on FixedUpdate. The collision data isn't updated until the next update.
function Start() {
for (var i = 0;i < 360; i++) {
//Create Object.
var newObj = GameObject.CreatePrimitive(PrimitiveType.Sphere);
//Enable a Objects' Collider.
newObj.GetComponent.<Rigidbody>().GetComponent.<Collider>().enabled = true;
//Rotate 90 degrees on Y axis.
newObj.GetComponent.<Rigidbody>().transform.rotation = Quaternion.Euler(0,90,0);
//Add a degree for each X axis.
newObj.GetComponent.<Rigidbody>().transform.rotation.eulerAngles += Vector3(i,0,0);
//Add velocity.
newObj.GetComponent.<Rigidbody>().AddRelativeForce(Vector3(0,objSpeed,0));
}
}
function OnCollisionEnter(collision: Collision) {
//Change velocity based on reflection.
gameObject.GetComponent.<Rigidbody>().velocity = Vector3.Reflect(gameObject.GetComponent.<Rigidbody>().velocity, collision.contacts[0].normal);
//Visualize Helper variable.
var reflection = Vector3.Reflect (gameObject.GetComponent.<Rigidbody>().transform.position, collision.contacts[0].normal);
//Visualize.
Debug.DrawRay(gameObject.GetComponent.<Rigidbody>().transform.position, collision.contacts[0].normal, Color.green, 1);
Debug.DrawRay(collision.contacts[0].point, gameObject.GetComponent.<Rigidbody>().velocity, Color.red, 1);
Debug.DrawRay(collision.contacts[0].point, reflection,Color.blue,1);
}
We start out creating 360 objects, then we add a force to each, relative to their own rotation. In my setup, I rotated the Y axis 90 degrees, and then in the for-loop, rotated the X-axis 1 - 360 degrees. (This was done for my own camera layout, rotate accordingly.)
Giving each object a velocity of 10, based on its relative direction.
Create an object for it to collide with, and it should reflect it. Also, you will want to add this to its own layer, and disable collisions for that layer in Project Settings -> layers.
That reflection code works....
However, i wanted to create a "coroutine" for reflecting, which uses Raycast to do the collision detection, so heres how I did it:
(Note: You may want to add this to a new script and attach it, to the one you have above.)
function Start() {
//This is a bitwise operation, used to listen to colliders on layer 9.
var layermask = 1 << 9;
//coroutine loop.
while (true) {
//Initialize Raycasting object.
var hit: RaycastHit;
//Get this scripts rigidbody position.
var ray = gameObject.GetComponent.<Rigidbody>().transform.position;
//Plot a line using rigidbody(ray) and multiply by the Up position, since we used rotated by the
// Y-axis in our previous script, the floating point math is to make the lines smaller.
Debug.DrawLine(ray + (transform.up *.03), ray + (transform.up * .2), Color.red);
if (Physics.Raycast(ray + (transform.up *.03), ray + (transform.up *.2), hit, 20, layermask)) {
//Get Objects current rotation.
var myRotation = gameObject.GetComponent.<Rigidbody>().rotation;
//Get Objects current velocity.
var myVelocity = gameObject.GetComponent.<Rigidbody>().velocity;
//Get Objects new Reflection vector, based on Objects velocity, where hit.normal is the Raycast line colliding with a rigidbody.
var myReflect = Vector3.Reflect(myVelocity, hit.normal);
//Get Objects new Rotation using Velocity and Reflection vector.
var newRotation = Quaternion.FromToRotation(myVelocity, myReflect);
//Visualize.
Debug.DrawLine(ray, hit.point, Color.red);
Debug.DrawRay(hit.point, myReflect, Color.green);
//Change Objects velocity to the new Reflection vector.
gameObject.GetComponent.<Rigidbody>().velocity = myReflect;
//Change Objects rotation angle to the new rotation.
gameObject.GetComponent.<Rigidbody>().transform.rotation = newRotation * myRotation;
}
//Coroutine statement.
yield;
}
}
This code also works, and its inside a coroutine.
However, I ended up not using the coroutine at all, because if you ever change the time scale, (which i am), the coroutine code will fail to work (as expected). This is because the collider updates the Collider data each frame, and everything is synchronized to work together.
While the coroutine is independantly based on the Time settings, so the velocity of the objects would keep the objects in motion, while our Raycast script would not be processed in time to detect the collision.
There were some ways around this, by modifying the script Update refresh rate in Settings -> Time or by increasing the Raycast length.
In the end I decided there wasn't any speed or accuracy advantages I was getting with coroutines that I wasn't getting with a plain and simple OnCollisionEnter.
I realize this isn't a Question, but perhaps it will help someone out there banging their head against the wall with Reflection scripts.
If you are using Rigidbody anyway, the only reason to detect collision with raycasts rather than OnCollisionEnter / OnTriggerEnter is if you need to detect things far away from the object or at a specific point.
In that case, using Coroutine will be a really bad idea, as coroutines will be called inumerous times per second, while the OnCollisionEnter /OnTriggerEnter will only be called when needed.
yeah, in hindsight i wished I'd never used the coroutine to begin with, as I wasted a lot of time doing the same thing with a lot less code, with no obvious benefit.
That's why I really wanted to post this, to show that it can be done, but that you're not going to be gaining anything from it. I could have even made this coroutine to work like the other with enough tinkering, but its just not practical.
I was curious why I never seen any questions about raycasting in a coroutine... now i know why.