How do I do headshots

Hi! I’m working on an FPS and I’m having trouble with headshots. currently guns operate on raycasts and when the raycast fires it checks for script components to apply damage etc. the enemy taking damage normally is fine, but the headshot doesn’t work. I have a cube parented to a capsule(the enemy) acting as my head collider, and for some reason when I check for the head script component on the head and call a function that sets a bool to true on the head, triggering an event that sets the enemy’s (capsule’s)health to zero, it doesn’t work. watching the variables during runtime, the bool on the head doesn’t even set to true.

this function handles the raycast

 void Shoot()
    {
        //muzzle flash
        particleSystem.Play();
        //subtracts ammo
        currentAmmo--;
        //raycast
        RaycastHit hit;
       

        if (Physics.Raycast(fpsCam.transform.position, fpsCam.transform.forward, out hit, range))
        {
            Debug.Log(hit.transform.name);
            //finds if the object has the enemy script that handles health
            Enemy target = hit.transform.GetComponent<Enemy>();
            //finds if the object has the Head script that handles headshots
            Head head = hit.transform.GetComponent<Head>();

            //bodyshots, take normal damage
            if (target != null)
            {
                target.TakeDamage(damage);
            }
            //headshot, in theory sets a bool headPop to true in the targeted head script
            if (head != null)
            {
                head.Pop();
            }
            //applies a force if it can
            if (hit.rigidbody != null)
            {
                hit.rigidbody.AddForce(-hit.normal * impactForce);
            }

        }
      
    }

this function handles enemy health(on the enemy capsule)

  public void TakeDamage(float amount)
    {
        //subtracts health
        health -= amount;

      
        //destroys the enemy (theres a function in update that handles a seperate die function, which is why the number is not zero)
        if (health <= -25f)
        {
            Destroy(enemy);
        }

    }

and lastly, this is the headshot handler(on the head cube), should be super easy, not sure why it isn’t working

public class Head : MonoBehaviour
{
    public bool headPop = false;

    private void Update()
    {
        if(headPop == true)
        {
            Enemy  enemy = gameObject.GetComponentInParent(typeof(Enemy )) as Enemy;

            enemy.HeadPop();

        }
    }

    public void Pop()
    {
        headPop = true;
    }
}

and fyi I just tested, setting the headPop bool to true on the head does do what it should to the capsule, so there’s an issue between the raycast script and the head.

What does it print out when you shoot the head?

nothing, but it won’t print for anything else either, which I hadn’t noticed. I wonder why it’s doing that. like I said earlier, regular damage to the enemy works fine so clearly some raycast us happening, but it’s not printing anything to the console…

I’m also getting this error but since the game was still running I figured it was nothing. what does it mean, because I don’t know
NullReferenceException: Object reference not set to an instance of an object
UnityEditor.Graphs.Edge.WakeUp () (at /Users/bokken/buildslave/unity/build/Editor/Graphs/UnityEditor.Graphs/Edge.cs:114)

ps I’m not the most experienced with unity so if any of these are obvious fixes I apologize

Oh my… GO FIX THAT FIRST!

ANY error invalidates ALL program running, especially the above error.

And the answer is ALWAYS the same… ALWAYS!!!

How to fix a NullReferenceException error

https://forum.unity.com/threads/how-to-fix-a-nullreferenceexception-error.1230297/

Three steps to success:

  • Identify what is null
  • Identify why it is null
  • Fix that
1 Like

I don’t know where the error is, where do I find /Users/bokken/buildslave/unity/build/Editor/Graphs/UnityEditor.Graphs/Edge.cs:114
I don’t see a users folder anywhere in unity or on my computer in general(other than the apple users folder, which doesn’t have a bokken folder in it), where do I even begin looking for this

Double click on the error log and it will take you straight to the part where your game screwed up in vs.

it may not be the line of code you need to edit though. Null errors mean that it hit that line and a value was null (which is different from zero).

Once at that line look around for why it doesn’t have a value.

And a lot of times you can just give it a value when you declare it to fix the problem.

Apologies… crashes in Graphs is Unity’s crash… if everything is working, then it is NOT contributing to your code not working. It’s just such a common thing with colliders because this construct:

… is commonly the source of the problem: get something (enemy) and then blindly use it without checking if it is null. Yes, it can work, but it’s always the first suspect. As long as the enemy.HeadPop() is NOT throwing the nullref, then you can move onto further debugging.

You must find a way to get the information you need in order to reason about what the problem is.

What is often happening in these cases is one of the following:

  • the code you think is executing is not actually executing at all
  • the code is executing far EARLIER or LATER than you think
  • the code is executing far LESS OFTEN than you think
  • the code is executing far MORE OFTEN than you think
  • the code is executing on another GameObject than you think it is
  • you’re getting an error or warning and you haven’t noticed it in the console window

To help gain more insight into your problem, I recommend liberally sprinkling Debug.Log() statements through your code to display information in realtime.

Doing this should help you answer these types of questions:

  • is this code even running? which parts are running? how often does it run? what order does it run in?
  • what are the values of the variables involved? Are they initialized? Are the values reasonable?
  • are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

Knowing this information will help you reason about the behavior you are seeing.

You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as Debug.Log("Problem!",this);

If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

You could also just display various important quantities in UI Text elements to watch them change as you play the game.

If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://discussions.unity.com/t/700551 or this answer for Android: https://discussions.unity.com/t/699654

Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

Here’s an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

https://discussions.unity.com/t/839300/3

I figured out the general area of the issue but I don’t know how to fix it. Just to see what would happen I added an unpainted head prefab to the scene, shot it, the bool switched to true, and as could be expected, the scene paused and returned an error because it wasn’t parented to an enemy and thus couldn’t find a reference to the enemy script. so, the issue has something to do with the head being parented to the capsule, but I don’t know how to get around that.
As a quick refresh I discovered the raycast not registering the head when it hit it was the issue. is there a thing where an object parented to another object won’t be registered in a raycast?

Nope, raycasts hit colliders. Parenting isn’t part of the deal. Layers and layermasks can make a difference however.

You might want to clarify your raycast calls by naming your arguments, just to ensure you’re using the arguments properly:

Always use named arguments with Physics.Raycast() because it contains many poorly-designed overloads:

https://discussions.unity.com/t/758115/8

that’s really good to know, thanks.
I just typed

 if (head = null)
            {
                Debug.Log("something aint right");
            }

just to see what would happen, it didn’t log it.

If hitting the head doesn’t get the enemy component and hitting anything else doesn’t return the lack thereof, what’s the issue? by the way, I shot the head and it logged the enemy, which means the ray is just going through the head…?
they’re on the same layer, I can’t understand what the cause of this is.

This line just made head become null.

One equals is assignment.

Two equals is comparison.

Do you mean perhaps if (head == null)

Oh yeah, I always forget that

my bad

Ok, now that I’ve fixed that…uh…oversight, it logs the right message when I hit anything. unfortunately the ray still goes through the head, how do I make that… not happen? like what might be causing that.

You have to be super-close to getting this working. What you have above looks really really simple and straightforward. There has to be just one thing missing somewhere.

Your original code was correct here:

Head head = hit.transform.GetComponent<Head>();

if (head != null)
{
   head.Pop();
}

because you’re saying “does the GameObject that I just hit have a head? If so tell the head to pop”

When you write this:

Are you saying that EVERYTHING appears to have a head and get popped?

Or are you saying that NOTHING appears to have a head and get popped?

Like I said, you have got to be really close here. Go down the hierarchy of parts: body, head, etc. Make sure the Head is on the collider you think it is, etc.

Keep in mind that Raycast will only return the FIRST thing you hit, so if the guy has goggles with a collider, or the body collider is too large, that may be shielding the head collider. Use Debug.Log() liberally immediately after the raycast to prove what you’re hitting.

ALSO: you could be hitting your own person, such as your own body collider, or your own gun collider… this is remedied by using layers and layermasks.

TL;DR for this whole post, the head cube is parented to the body capsule and so the game registers the cube as part of the enemy collider and not it’s own separate entity. how do I work around this?

ok, so the head == null message that I added to test runs when I hit everything, but unfortunately the ray cast just refuses to collide with the head if its parented to the capsule. as for colliding with something else first, the enemy is currently a cube on a capsule, no aesthetic pieces or extra colliders, no goggles, nothing. why might something not collide? is it because the cube is a child of the capsule and counts as part of its collider, so its registering as the enemy instead of the head?

Edit: It’s definitely registering the cube as part of the enemy’s collider, I just shot it at an angle where it couldn’t possibly have hit the capsule(the cube sticks out from it a fair bit) and it dealt damage to the main enemy instead of running the head.pop() function.

Edit 2: just to double check that I wasn’t crazy, I messed around with the arangement of the two so that the cube was above the capsule, and the ray had very little chance of intersecting the capsule. It definitely is registering the cube as part of the parent capsule. is there a workaround for this

OK FOR SOME REASON IT WON’T LET ME ADD A NEW POST SO THIS IS THE FIX

hit.collider.transform.GetComponent<>();
~Rather Than~
hit.transform.GetComponent<>();

such a simple change took 3 days and multiple forums to fix

I love code

no but seriously, thanks for all the help Kurt, you’ve replied to all of the threads I’ve posted and you’ve solved it pretty much every time.

I too love code Bananaking, but all of this would instantly have been obvious with:

Debug.Log( hit.collider.transform.name);```

When in doubt, print it out. I think I'm going to get a teeshirt made with that logo.

that’s not a bad idea, Kurt. I was unaware you could find the specific collider until with raycast until today, and I will absolutely be using that in future projects.

I had a similar problem. If your enemy is animated, and you are using a box or sphere collider on the head, I found out that the collider doesn’t follow the animation. In my case a Zombie FPS the zombie walk, run and attack animations move the head forward quite a bit so the collider is way back from the head. In short, I wasn’t hitting the collider. Now I’m searching for a different way to register a headshot.

9645815--1371923--zombie sphere collider.png