I have been having a bug where raycasts work fine for my gun in the editor for a game I am making, only for when I put it in a build, it sometimes does not detect the enemies. I have found that for a gun firing every 0.1 seconds, only 1 in 10-20 shots actually work. Anyone know anything that can fix this? I will post the two guns scripts and the enemy health script.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Entity : MonoBehaviour
{
[SerializeField] private float StartingHealth;
private float health;
public float Health
{
get
{
return health;
}
set
{
health = value;
Debug.Log(health);
if(health <= 0f)
{
Destroy(gameObject);
}
}
}
void Start()
{
Health = StartingHealth;
}
void Update()
{
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DamageGun : MonoBehaviour
{
public float Damage;
public float bulletRange;
private Transform PlayerCamera;
public Camera cam;
public bool useShotgun = false;
public int pellets = 10;
public float spreadAngle = 20f;
void Start()
{
PlayerCamera = Camera.main.transform;
}
public void Shoot()
{
if (useShotgun)
{
ShootShotgun();
}
else
{
ShootSingleBullet();
}
}
private void ShootSingleBullet()
{
Ray ray = cam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
RaycastHit hit;
Vector3 targetPoint;
if (Physics.Raycast(ray, out hit))
targetPoint = hit.point;
else
targetPoint = ray.GetPoint(75);
Ray gunRay = new Ray(PlayerCamera.position, PlayerCamera.forward);
if (Physics.Raycast(gunRay, out RaycastHit hitInfo, bulletRange))
{
if (hitInfo.collider.gameObject.TryGetComponent(out Entity enemy))
{
enemy.Health -= Damage;
}
}
}
private void ShootShotgun()
{
for (int i = 0; i < pellets; i++)
{
float spreadX = Random.Range(-spreadAngle / 2, spreadAngle / 2);
float spreadY = Random.Range(-spreadAngle / 2, spreadAngle / 2);
Vector3 direction = Quaternion.Euler(spreadY, spreadX, 0) * PlayerCamera.forward;
if (Physics.Raycast(PlayerCamera.position, direction, out RaycastHit hit, bulletRange))
{
if (hit.collider.gameObject.TryGetComponent(out Entity enemy))
{
enemy.Health -= Damage;
}
}
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, bulletRange);
}
}
using System.Collections;
using System.Collections.Generic;
using UnityEngine.Events;
using UnityEngine;
public class Gun : MonoBehaviour
{
public UnityEvent OnGunShoot;
public float fireCoolDown;
public bool Automatic;
private float currentCooldown;
void Start()
{
currentCooldown = fireCoolDown;
}
void Update()
{
if(Automatic)
{
if(Input.GetMouseButton(0))
{
if(currentCooldown <= 0f)
{
OnGunShoot?.Invoke();
currentCooldown = fireCoolDown;
}
}
}
else if (Input.GetMouseButtonDown(0))
{
if (currentCooldown <= 0f)
{
OnGunShoot?.Invoke();
currentCooldown = fireCoolDown;
}
}
if (Automatic)
{
if (Input.GetKey(KeyCode.JoystickButton5))
{
if (currentCooldown <= 0f)
{
OnGunShoot?.Invoke();
currentCooldown = fireCoolDown;
}
}
}
else if (Input.GetKeyDown(KeyCode.JoystickButton5))
{
if (currentCooldown <= 0f)
{
OnGunShoot?.Invoke();
currentCooldown = fireCoolDown;
}
}
currentCooldown -= Time.deltaTime;
}
}
You check your inputs and work out why they don’t give you the expect outputs. Same as any debugging, really.
There’s only so many ways a raycast can fail. Wrong position/direction, wrong physics layers, wrong parameters into the method, etc etc. Test all those to work it out.
But there’s not really much that can change between the editor and the build that would cause this.
How have you actually determined the raycasts are the issue? What debugging have you done specifically?
I have been looking through the debug in the build, it says that it has fired the gun, yet only a third if not less of the shots even hit, I have done a decent lot of testing to make sure this is the bug/issue. It is not wrong direction or anything as the raycasts do sometime work with moving anything.
Well like I said, there’s only so many ways a raycast can fail. They simply don’t “not work” for no reason. Test the possible ways.
Otherwise, the raycasts are potentially not the issue.
1 Like
Well, it is the raycast or the raycast detection, both of which shouldn’t break like this but it legit cannot be anything else because I have logs that are saying it is being fired meaning the raycast is triggered, but the raycast is either not working or detecting the collision.
Unity wouldn’t be an effective engine if 15+ year old features simply didn’t work in a build for unexplainable reasons.
We know raycasts work. Thousands upon thousands of us use them without issue on a daily basis.
You need to post the code you’re using to debug this, because debugging that the gun is firing is simply not enough to come to this conclusion.
1220
UnityEngine.StackTraceUtility:ExtractStackTrace () (at C:/build/output/unity/unity/Runtime/Export/Scripting/StackTrace.cs:37)
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
UnityEngine.Logger:Log (UnityEngine.LogType,object)
UnityEngine.Debug:Log (object)
Entity:set_Health (single) (at C:/Users/User/Game Project/Assets/Scripts/Entity.cs:19)
DamageGun:ShootSingleBullet () (at C:/Users/User/Game Project/Assets/Scripts/DamageGun.cs:50)
DamageGun:Shoot () (at C:/Users/User/Game Project/Assets/Scripts/DamageGun.cs:29)
UnityEngine.Events.InvokableCall:Invoke () (at C:/build/output/unity/unity/Runtime/Export/UnityEvent/UnityEvent.cs:178)
UnityEngine.Events.UnityEvent:Invoke () (at C:/build/output/unity/unity/artifacts/generated/UnityEvent/UnityEvent_0.cs:57)
Gun:Update () (at C:/Users/User/Game Project/Assets/Scripts/Gun.cs:33)
(Filename: C:/Users/User/Game Project/Assets/Scripts/Entity.cs Line: 19)
Hit enemy.
UnityEngine.StackTraceUtility:ExtractStackTrace () (at C:/build/output/unity/unity/Runtime/Export/Scripting/StackTrace.cs:37)
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
UnityEngine.Logger:Log (UnityEngine.LogType,object)
UnityEngine.Debug:Log (object)
DamageGun:ShootSingleBullet () (at C:/Users/User/Game Project/Assets/Scripts/DamageGun.cs:51)
DamageGun:Shoot () (at C:/Users/User/Game Project/Assets/Scripts/DamageGun.cs:29)
UnityEngine.Events.InvokableCall:Invoke () (at C:/build/output/unity/unity/Runtime/Export/UnityEvent/UnityEvent.cs:178)
UnityEngine.Events.UnityEvent:Invoke () (at C:/build/output/unity/unity/artifacts/generated/UnityEvent/UnityEvent_0.cs:57)
Gun:Update () (at C:/Users/User/Game Project/Assets/Scripts/Gun.cs:33)
(Filename: C:/Users/User/Game Project/Assets/Scripts/DamageGun.cs Line: 51)
Fired bullet.
UnityEngine.StackTraceUtility:ExtractStackTrace () (at C:/build/output/unity/unity/Runtime/Export/Scripting/StackTrace.cs:37)
UnityEngine.DebugLogHandler:LogFormat (UnityEngine.LogType,UnityEngine.Object,string,object[])
UnityEngine.Logger:Log (UnityEngine.LogType,object)
UnityEngine.Debug:Log (object)
DamageGun:Shoot () (at C:/Users/User/Game Project/Assets/Scripts/DamageGun.cs:30)
UnityEngine.Events.InvokableCall:Invoke () (at C:/build/output/unity/unity/Runtime/Export/UnityEvent/UnityEvent.cs:178)
UnityEngine.Events.UnityEvent:Invoke () (at C:/build/output/unity/unity/artifacts/generated/UnityEvent/UnityEvent_0.cs:57)
Gun:Update () (at C:/Users/User/Game Project/Assets/Scripts/Gun.cs:33)
This is what the logs look like, thing is, it does the “Fired Bullet” about 10 times before you get a hhit,
I did ask for the code, not the logs.
Have you also considered testing if the raycast is hitting a different game object than you expect?
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class DamageGun : MonoBehaviour
{
public float Damage;
public float bulletRange;
private Transform PlayerCamera;
public Camera cam;
public bool useShotgun = false;
public int pellets = 10;
public float spreadAngle = 20f;
void Start()
{
PlayerCamera = Camera.main.transform;
}
public void Shoot()
{
if (useShotgun)
{
ShootShotgun();
}
else
{
ShootSingleBullet();
Debug.Log("Fired bullet.");
}
}
private void ShootSingleBullet()
{
Ray ray = cam.ViewportPointToRay(new Vector3(0.5f, 0.5f, 0));
RaycastHit hit;
Vector3 targetPoint;
if (Physics.Raycast(ray, out hit))
targetPoint = hit.point;
else
targetPoint = ray.GetPoint(75);
Ray gunRay = new Ray(PlayerCamera.position, PlayerCamera.forward);
if (Physics.Raycast(gunRay, out RaycastHit hitInfo, bulletRange))
{
if (hitInfo.collider.gameObject.TryGetComponent(out Entity enemy))
{
enemy.Health -= Damage;
Debug.Log("Hit enemy.");
}
}
}
private void ShootShotgun()
{
for (int i = 0; i < pellets; i++)
{
float spreadX = Random.Range(-spreadAngle / 2, spreadAngle / 2);
float spreadY = Random.Range(-spreadAngle / 2, spreadAngle / 2);
Vector3 direction = Quaternion.Euler(spreadY, spreadX, 0) * PlayerCamera.forward;
if (Physics.Raycast(PlayerCamera.position, direction, out RaycastHit hit, bulletRange))
{
if (hit.collider.gameObject.TryGetComponent(out Entity enemy))
{
enemy.Health -= Damage;
}
}
}
}
private void OnDrawGizmosSelected()
{
Gizmos.color = Color.red;
Gizmos.DrawWireSphere(transform.position, bulletRange);
}
}
The fired bullet and hit enemy, there is one other I am using for this in the Entity script.
So you are only checking that the gun fires, and whether the TryGetComponent passes, but you are not assessing anything about the raycast itself, so you cannot come to the conclusion that the raycast is not working.
Simply printing out text to show certain code is executing is not enough to debug. You need to print out pertinent values to understand what your data is doing and where it may not meet your expectations. For example, you should printing out what game object you’re hitting before you attempt the TryGetComponent.
You need to keep following the clues until you find the source of the problem. You have not yet found the source of the problem.
3 Likes
I have already checked that.
As I mentioned in your other thread, you haven’t finished debugging until you find the source of the problem.
NOTE: Raycasts cannot fail.
Your software can fail to use them correctly however.
Mis-using a raycast is commonly called “a bug.”
You are responsible for identifying and fixing bugs in your software.
Here are the most-common bugs encountered with raycasting:
Code flow:
- you aren’t even calling the raycast code
- you supplied arguments in the wrong order (always use named arguments)
- you’re using the wrong raycast:
- 2D vs 3D
- many versus one
- alloc vs non-alloc
- you are misinterpreting the results from the raycast:
- branch logic wrong
- filter logic wrong (tag for instance; no tag, wrong tag)
Math / Logic:
- your raycast starts from the wrong position
- your raycast goes in the wrong direction (such as Vector3.zero)
- your raycast isn’t long enough (if you give a max distance)
- your raycast doesn’t have the right LayerMask (if you’re using one)
About the thing you’re sensing:
- the object(s) you’re trying to sense don’t exist at the time you raycast
- the object isn’t enabled / active
- the object doesn’t have a collider
- the collider isn’t enabled
- the object doesn’t have the correct collider (2D vs 3D)
- the object is not where you think it is when you raycast
About the rest of the scene and your raycast’s relationship to it:
- you’re raycasting from within the collider volume
- you’re attempting to sense the back of a planar collider
- you are hitting something else first:
- your player?
- your shot?
- the environment?
So… back to you… time to debug!
By debugging you can find out exactly what your program is doing so you can fix it.
Use the above techniques to get the information you need in order to reason about what the problem is.
You can also use Debug.Log(...); statements to find out if any of your code is even running. Don’t assume it is.
Once you understand what the problem is, you may begin to reason about a solution to the problem.
1 Like
I have tried debugging, it is saying the raycast is hitting the gun but the gun shouldn’t be colliding with it and the issue is still there after disabling all of the collisions.
Maybe you should be using physics layers?
Raycast accepts a mask parameter, and you can use the LayerMask struct to assign these via the inspector.
You don’t seem to be in the code you posted.
From what I know about it, it is only for other layers, the raycast isn’t a layer, but I have done a layermask thing for it.
Ray gunRay = new Ray(PlayerCamera.position, PlayerCamera.forward);
if (Physics.Raycast(gunRay, out RaycastHit hitInfo, bulletRange))
{
Debug.Log("Collided" + gameObject.name);
if (Physics.Raycast(ray, out hit, Mathf.Infinity, LayerMask.value))
{
Debug.Log("Collided 2" + gameObject.name);
if (hitInfo.collider.gameObject.TryGetComponent(out Entity enemy))
{
enemy.Health -= Damage;
Debug.Log("Hit enemy.");
}
}
}
(If something is wrong, I just new and quite stupid.)
Why are you doing two raycasts?
You only need to the one raycast with the correct layermask.
I forgot to remove it when changing the code.