- Home /
Is there way to curve Raycast?
Hi! Is tere any way to make a curved raycasts? I need it for shooting ballistics. Rigidbody bullets are not suitable, when speed is very fast - rigidobies could come through object without detecting.
So is there any ways to make it? Thank you!
We did some tests a while back https://answers.unity.com/questions/1174027/object-moving-too-fast-so-that-the-collider-does-n.html
I dont know how much of it is still relevant in the latest Editions. The summary is that $$anonymous$$esh Colliders offer the best collision detection at high speeds.
Answer by BlueFire9020 · Jun 08, 2018 at 11:57 PM
I know this is kind of reviving a dead thread, but I was playing around with this and got something somewhat similar. It's by no means perfect, and could definitely use some improvement, but it does work and isn't that performance intensive. The iterations represents the scale of the curvature, as well as the scale of the ray. The Ray should have the same position as the startPos parameter and the Ray's direction is used to move the raycasts. You can tag things with a "Permeable" tag to get the raycast to pass through them (it only works once as I only included one secondary for loop, you can include more if you want to add more penetration). Like I said, it's not perfect but it could definitely be a start. Hope this helps! :D
void curvedRaycast(int iterations, Vector3 startPos, Ray ray, int velocity)
{
RaycastHit hit;
Vector3 pos = startPos;
var slicedGravity = Physics.gravity.y / iterations / velocity;
Ray ray2 = new Ray(ray.origin, ray.direction);
print(slicedGravity);
for (int i = 0; i < iterations; i++)
{
if (Physics.Raycast(pos, ray2.direction * velocity, out hit, velocity))
{
Debug.DrawRay(pos, ray2.direction * hit.distance, Color.green);
if (hit.transform.tag == "Permeable")
{
Debug.DrawRay(pos, ray2.direction * velocity, Color.green);
pos += ray2.direction * velocity;
ray2 = new Ray(ray2.origin, ray2.direction + new Vector3(0, slicedGravity, 0));
for (int x = 0; x < iterations; x++)
{
if (Physics.Raycast(pos, ray2.direction * velocity, out hit, velocity))
{
Debug.DrawRay(pos, ray2.direction * hit.distance, Color.yellow);
return;
}
Debug.DrawRay(pos, ray2.direction * velocity, Color.magenta);
pos += ray2.direction * velocity;
ray2 = new Ray(ray2.origin, ray2.direction + new Vector3(0, slicedGravity, 0));
}
}
else
{
return;
}
}
Debug.DrawRay(pos, ray2.direction * velocity, Color.cyan);
pos += ray2.direction * velocity;
ray2 = new Ray(ray2.origin, ray2.direction + new Vector3(0, slicedGravity, 0));
}
Debug.DrawRay(startPos, pos, Color.red);
/*for (int i = 0; i < iterations; i++)
{
Debug.DrawRay(pos, ray2.direction * velocity, Color.red);
pos += ray2.direction * velocity;
ray2 = new Ray(ray2.origin, ray2.direction + new Vector3(0, slicedGravity, 0));
}*/
}
This is the experimental version I was working on to try and reduce the number of parameters. Only issue with this one is that the rays don't connect, despite the math and logging suggesting they should. If anyone figures out why and can fix it feel free to let me know!
EDIT: I updated and redid this script, it works 100% percent now!
Vector3[] GravCast(Vector3 startPos, Vector3 direction, int killAfter, int velocity, bool reflect)
{
RaycastHit hit;
Vector3[] vectors = new Vector3[killAfter];
Ray ray = new Ray(startPos, direction);
for (int i = 0; i < killAfter; i++)
{
if(Physics.Raycast(ray,out hit,1f))
{
if (reflect)
{
print(hit.normal);
/*for (int e = 0; e < killAfter; e++)
{
if (Physics.Raycast(ray, out hit, 1f))
{
return vectors;
}
ray = new Ray(ray.origin + ray.direction, ray.direction + (Physics.gravity / killAfter / velocity));
}*/
}
return vectors;
}
Debug.DrawRay(ray.origin, ray.direction, Color.blue);
ray = new Ray(ray.origin + ray.direction, ray.direction + (Physics.gravity / killAfter / velocity));
vectors[i] = ray.origin;
}
return vectors;
}
}
Answer by Xornogard · Feb 06, 2018 at 09:41 AM
Have you considered combining raycast with rigidbody? Each fixed update check raycast toward next position, if it hits, then you'll detect your object even when rigidbody has high velocity.
Not towards next position, but against previous. You don't know next position and if you wanted to know it you'd have to perform extra calculation that are not needed while checking behind.
This is the method i would choose in this situation. have your bullet shoot a ray from its last position to its current position and check for collision that way. store the last position as the current position after this calculation fails.
f1 and f2 being the frames. solid red B being the current bullets position. dotted red B being the bullets last position.
Answer by fafase · Feb 06, 2018 at 08:51 AM
You can make your bullet report whether something is between its current position and previous position.
public class BulletCollision : MonoBehaviour
{
private Vector3 previous;
public event Action<GameObject> RaiseCollision;
void Start()
{
this.previous = this.transform.position;
}
void Update()
{
RaycastHit hit
if(Physics.Linecast(this.previous, this.transform.position, out hit)){
if(RaiseCollision != null) { RaiseCollision(hit.collider.gameObject); }
}
this.previous = this.transform.position;
}
}
At this point, your projectile does not need collider anymore.
Since Physics is synced with FixedUpdate this code should be executed there ins$$anonymous$$d of Update. Update is synced with rendering.
Would not make much difference here since it uses the position. Physics.Linecast is not related to actual Physics like Rigidbody.
Your answer
Follow this Question
Related Questions
raycast draw diagonal line problem? 1 Answer
Linecast, rotate end point relative to objects rotation 1 Answer
move a object hit by raycast 2 Answers
How to build a spaceship with interior? 1 Answer
Unity 2D Car Side Scroller question. 1 Answer