- Home /
Projectile Hit Detection with Bullet Drop
Hello, I am making a paintball game and am struggling with the shooting mechanics. I need my projectiles to be influenced by the worlds gravity, as well as travel a distance over time (i.e. not reach their target instantaneously). Also, I would like them to look realistic while in flight. With a simple Raycast, the hit detection functions very well, but the ray reaches the object it hits instantly, and does not account for gravity. Furthermore, I tried to apply a line renderer over the raycast to mimic the look of a paintball, but that attempt was unsuccessful.
My next, and current, approach is to fire a ray from the center of the player's screen/camera, get the point hit, and instantiate a paintball prefab (rigidbody) at the barrel of the players gun, with its rotation facing the point returned from the ray. I then add a force to the paintball in that direction. From there, in a separate script for the paintball, I cast a ray in the Update method (I have also tried FixedUpdate) at a short length in front of the paintball object, and detect hits based on these rays. The problem is, this solution does not detect hits consistently/accurately.
My best guess is that the issue has to do with the fact that the projectile is moving at a significant velocity. I know that colliders have a issues when objects are moving at high velocities so I thought that using a raycast would fix the issue, but that is not the case. I am wondering if anyone has ever implemented a similar mechanic, and if I am on the right track, or if I need to completely rework my approach? Any guidance in the right direction would help immensely. Thanks in advance for your time and help!
Gun Script:
RaycastHit hit;
// Create a vector at the center of the camera's viewport
Vector3 rayOrigin = fpsCam.ViewportToWorldPoint(new Vector3(0.5f, 0.5f, 0.0f));
gunAudio.Play();
if (Physics.Raycast(rayOrigin, fpsCam.transform.forward, out hit, range)) {
GameObject bullet = Instantiate(paintball, paintballSpawn.position,
Quaternion.LookRotation(hit.point - paintballSpawn.position)) as GameObject;
bullet.GetComponent<Rigidbody>().AddForce(bullet.transform.forward * paintVelocity);
}
Paintball Script:
void Update() {
RaycastHit hit;
Vector3 rayOrigin = gameObject.transform.position;
Debug.DrawRay(rayOrigin, transform.forward, Color.blue);
if (Physics.Raycast(rayOrigin, transform.forward, out hit, range)) {
Debug.Log(hit.transform.tag);
// Logic based on type of object hit
Destroy(gameObject);
}
}
In your Gun Script, you only spawn a bullet when the raycast hits something. Why would yo do that?
Also, for the raycast, I would recommend you store the position of the paintball of the previous frame and then do a linecast between that position and the current position.
private Vector3 previousPosition;
public void Awake()
{
previousPosition = transform.position;
}
public void Update()
{
Vector3 currentPosition = transform.position;
RaycastHit hitInfo;
if(Physics.Linecast(previousPosition, currentPosition, out hitInfo))
{
// Do your logic here
}
previousPosition = currentPosition;
}
Answer by Yoshinator2 · May 15, 2017 at 03:23 PM
Instead of using a raycast for bullet detection, I would recommend using an actual paintball prefab. Then, whenever the paintball gun is fired, have it spawn it at the tip and give it a velocity in the direction it is facing. Make sure to add a rigidbody and a trigger box collider to the paintball prefab, and give it a specific tag that you can then deal damage with a simple OnTriggerEnter. This allows for the gravity affect you want as well as the realistic bullet traveling.
If you have any more questions let me know! If this helped or solved your problem, please accept my answer. :)
Thanks Yoshinator. This approach is certainly working better than the one I had implemented. I am wondering if you can explain why the trigger is able to detect a hit better than the raycast? I know things get a bit more complicated when higher velocities are involved, but I still thought the raycast would provide more accurate results. Also, there is now an issue where the paintball is bouncing off a bunker if the player is pressed right against it and not detecting a hit. Any thoughts on how to remedy this? I will certainly accept this answer if you can just provide a bit more clarity as to why the trigger approach works and the raycast does not. Thanks again for your prompt reply and insightful solution.
After more testing today, this method is very inconsistent as well. If the velocity is increased slightly and the player increases the distance to their target, the game stops registering hits correctly. Ins$$anonymous$$d, the object behind the first one hit is being registered (and I have coded it so the paintball is destroyed when it comes in contact with the first object).
Have you tried setting the Collision Detection on the paintball rigidbody to continuous dynamic?
Set the rigidbody of the paintball to Continuous dynamic. This is used for fast objects and will collide with everything in its path. A trigger is better to detect a raycast as the raycast can not add any of the realistic features such as the bullet drop or delay. I personally never find myself using a raycast for any shooting because of this. $$anonymous$$ake sure that the collider of the paintball take ups the entire paintball as well! :)
Thanks guys. I changed the paintball's collision detection to continuous dynamic. Unfortunately, this did not completely solve the issue. After some googling around this new problem I came across this link: Collision Detection at High Speed. To summarize this thread, a hit or the OnTriggerEnter method will not be called on an object that is moving a distance greater than its size every FixedUpdate. To solve this problem, I decreased the time FixedUpdate is called so it occurs more frequently. This along with both your advice has seemed to solve my problem. Thanks for both your time and help!
Hi there, I would not reccommend messing with the fixed update too much as the lower you put it the more physics calucations are done when you have your bullets firing, and in turn this could lead to a substantial performence loss with many projectiles. I have made a solution that I use with raycasts ins$$anonymous$$d rigibodies that still simulate velocity and gravity.
if (active)
{
RaycastHit hit;
Vector3 newPos = transform.position + transform.forward * speed * Time.deltaTime;
Vector3 dir = (newPos- transform.position).normalized;
if (Physics.Raycast(transform.transform.position, dir, out hit, Vector3.Distance(newPos, transform.position)))
{
active = false;
transform.position = hit.point;
Destroy(this.gameObject, 0.2f);
return;
}
transform.position = newPos;
}`
I don't have the actual gravity in here but you could easily add your own but adjusting the projectiles y by a gravity factor and simulate gravity that way. but this collision detection will always guarentee that your proectile will never go through an object no matter the speed, as it checks each frame where it is going to end up and does a raycast to that point from its current position.
Your answer
Follow this Question
Related Questions
Air Strike shoot aiming at cross hairs in middle of the screen 2 Answers
My projectile shots wrong with Raycast 0 Answers
My Projectile System has Another Bug 1 Answer
Best way to shoot physical bullets? 2 Answers
Raycast from an objects co-ordinates 1 Answer