- Home /
Multiple raycasts in same fixedupdate
So I have a bullet script that goes very fast using a rigidbody and then calculates collisions using raycasts inside fixedupdate. It works great except for this one detail. If you manage to shoot the same object twice in the same fixedupdate, it will only perform the check on the first hit. I know I am bad at explaining...
Inside FixedUpdate() I have a linecast from the bullet position to its previous position (or opposite rather). If the linecast returns true I have a 'RaycastHit[] hits RaycastAll(...)' and a 'foreach(RaycastHit hit in hits)' This is where my problem occurs. The RaycastAll only returns a raycasthit the first time it hits an object, so only one raycasthit per object. I need to redo the checks every time an object is hit.
I tried making a for/foreach/while loop that raycasted from the last hit point towards the bullets current position until there was no more objects between it, but this didn't work any different for some reason.
Answer by Lahzar · Aug 09, 2015 at 11:30 AM
I think I found the error, I feel so stupid now. I changed for(int c = 0; c < 1; c++) to c < 2 and it worked flawlessly.
I also added an offset, since it was shorten than having an if statement and storing an extra position. However this didn't change the behaviour of the script!
Anyway for anyone who is interrested, here is a pretty nice bullet script: void FixedUpdate() { Ray diray = new Ray(prev, transform.position-prev);
// if(Physics.Linecast(prev, transform.position, mask)) { //Uncomment to add .000000001 FPS and use slightly less RAM
Vector3 start = prev;
for(int c = 0; c < 2; c++) {
Debug.Log(c);
RaycastHit hit = new RaycastHit();
if(Physics.Linecast(start, transform.position, out hit, mask)) {
Debug.DrawLine(start, hit.point, new Color(Random.value, Random.value, Random.value));
Instantiate(debugObj, hit.point, Quaternion.LookRotation(hit.normal));
//If hit.gameobject has a script that implements IDamagable, TakeDMG(damage)
//If(wallbang.Contains(hit.tag)) Do stuff
//Else if ricochet.contains(hit.tag) Do other stuff
c = 0;
start = hit.point + diray.direction*.01f;
Instantiate(debugObj, start, Quaternion.LookRotation(diray.direction));
// continue;
//If loop hasn't continued yet, DestroyImmidiate(gameObject);
} else {
c = 2;
Debug.DrawLine(start, transform.position, Color.green);
break;
}
}
// }
Debug.Break();
prev = transform.position;
}
Answer by Bunny83 · Aug 09, 2015 at 10:43 AM
A raycast will always hit a single object only once, no matter how many intersections you'll have. If you want to know all hit points on a concave object you have to use multiple raycasts. Just start a new raycast at the last hit point. You should move the new startpoint a bit forward to prevent hitting the same spot again. You can do this in a while loop until you don't get a "new" hit. It's probably better to use a for loop to setup a max hit count to prevent a possible infinite loop.
Vector3 pos;
Vector3 dir;
for(int i = 0; i < MaxHitCount; i++)
{
RaycastHit hit;
if (Physics.Raycast(pos, dir, out hit))
{
// calculate new starting point for the next raycast
pos = hit.point + dir*0.1f;
// handle your hit
}
else
{
// No more hits so stop the loop
break;
}
}
To actually be able to hit a concave object you need of course a non convex mesh collider. Convex meshcolliders always can only have one hit point since it's surface is a convex hull.
This is exactly what I did, I also had a if(Vector3.Distance(lastHit, hit.point) < .1f) it would return an error, but it never did. I could try to offset the raycast, I didn't try that. But I don't think that is the problem, see.
Answer by sparkzbarca · Aug 09, 2015 at 02:44 AM
um, how fast are you shooting wowsers.
fixedupdate runs once per frame. most games need to be run at minimum 30fps to run ok.
that means your shooting something twice in less than 1/30th of a second which is fast lol.
an actual 6,000 rpm 6 barreled minigun is 100 rounds a second and your firing at least 60? like you might want to tone that shit down a bit hoss. :P
But to address your issue
so firstly, i'm only vaguely understanding what your saying but it sounds possible your leading bullet is actually destroying instances of bullets behind it if your doing any kind of destruction calls. I think your first bullets raycastall trigger might be actually pinging off a follow up round.
i'm trying to understand you are you saying your bullet is flying through the air and you ray cast behind it to see if it "passed through" something to hit it? Like its some kind of explosive round?
why are you using raycasts to do collision detection with a rigidbody anyways?
rigidbodies should use OnCollsionEnter() to react to the object they hit.
raycasts should be for laserbeam style weapons. These are normally referred to in FPS game parlance as "hitscan" weapons because the moment you fire they scan to see what was in front of the gun and hit it. they suffer zero bullet drop/travel time etc. They are laser beams, instantly traveling exactly straight.
If your going to use rigidbodies for a bullet thats fine but make sure you slow the bullets to a quasi reasonable value. if the bullets are travelling too fast it's possible for them completely pass through an object between frame movement and not be "caught" colliding. Turning on continous dynamic collision detection for the rigidbody can technically fix this but it also means a huge performance hit.
Right so I will try to explain a bit better. When I shoot, my weapon script instantiates a new bullet and shoots it forward at a set value. The test bullet goes 250m/s but thats not the issue, it handles fine :P
FixedUpdate() is called every .22 sec by default. I use FixedUpdate for raycasting from the bullet, not shooting the bullet :P
Each bullet has its own script and a rigidbody, but no colliders. The bullets to go fast to detect collisions! Just like you said. Thats why I use raycasts.
The bullet doesn't collide with any other bullet. I only shoot 1 at a time when testing and they use a collisionmask so they only collider with certain objects.
The bulletscript saves the bullets previous position at the end of every fixedUpdate. But before it does that, it does a linecast from the current position to the previous position.
If this linecast returns true, meaning there is something between the bullets current position and its previous position, I need to get a hit.point every time it hits an object.
It doesn't do that no matter what I try. For the time being I use RaycastAll() which returns all the hit colliders, but it only returns 1 hit.point per collider. This means if the bullet hits the same object twice, and the object isn't set to destroy the bullet ofc, it will only do the physics test for the first hit.
The physics test is just: - if the object can be shot through, loose some velocity and instantiate bulletmarks and such. - if the object is marked as ricochet, the bullet will bounce off the wall and loose velocity based on the angle. - if the bullet hit something that isn't marked as ricochet or wallbang, it will destroy the bullet!
I tried to make an infinte for loop inside a linecast.
It raycasted/linecasted from hit.point (the first RaycastHit.point from the linecast) to the bullets position. If that raycast hit something, it would reset the whole hit value and then artifically set its .point value to the hit.point of this raycast. And then repeat until there was nothing to be hit between the bullets current position and the raycast.
In theory this would mean that it would raycast, and if it hit something it would raycast again from that hit point, and then repeat that whole process until there was nothing left between the bullet and the latest hit.point.
But when I tested it I got the same result. It works fine if you hit multiple objects, it does every test properly in order for each hit. But if you hit the same object twice, it will only do the checks once. Thats not good!
TLDR: Rigidbody is for physics. Raycast is for collision. Bullets fire reasonably, around 11 bullets/s for the A$$anonymous$$-12 testing machinegun. Bullets ignore other bullets.
$$anonymous$$y problem is that I need a raycasthit every time it hits an object, even if it has already hit said object!