Need Help With Raycast Tags (Solved)

I’m trying to make an “eye” for an enemy that it constantly facing the player and sends out a ray with Raycast, and if it hits the player it will tell the enemy to attack. I’ve gotten it to face the player and send out a ray, but I can’t get it to only react when looking at objects tagged “Player”.
I’ve tried different methods to fix this (such as, in the version of the script below, use hitInfo which causes the error “Unknown Identifier: hitInfo”) but can’t get it to work. Can anyone help me out?

var Target : Transform;
var Damping = 100.0;
var fwd = transform.TransformDirection (Vector3.forward);

function Update ()
{
    lookAt();
   
    var fwd = transform.TransformDirection (Vector3.forward);
    if (Physics.Raycast (transform.position,fwd))
    {
        //Debug.Log("I see something.");
       
        if (hitInfo.transform.tag == "Player")
        {
            Debug.Log("I see the player.");
        }
    }
}

function lookAt ()
{
    var rotation = Quaternion.LookRotation(Target.position - transform.position);
    transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * Damping);
}

You never declared a hitInfo variable, nor are you using the correct Physics.Raycast overload.

Check out the second example in the docs.

I don’t understand (I have very little experience with Unity). Do you think you could provide an example? With the info offered in your reply I only got as far as putting in a “var hitInfo : RaycastHit;” at the top of the script and change “(Physics.Raycast(transform.position,fwd))” to “(Physics.Raycast (transform.position, -Vector3.up, hit))”, and that didn’t do much.

Well, when you say “it didn’t do much”, I assume you mean you got a new error message, because it should have. In the future, when asking for help, explaining the exact way something failed is a crucial part of getting help. There’s a huge difference between getting the same error message, getting a different error message, getting a warning, and simply getting no results when you hit play - these are all very different scenarios.

Use ‘hitInfo’ in your function call, not ‘hit’. In C#, you’ll have to use ‘out hitInfo’.

What’s actually happening here: Physics.Raycast returns a bool - whether or not anything was hit. But, sometimes you need it to return more than that. You need the coordinates that were hit, the object that was hit, etc. So what’s a function to do? It gives you another option: an output parameter.

var hitInfo : RaycastHit = new RaycastHit();

When you do this, you’re basically creating a container - a box that Physics.Raycast can use to dumb all this extra data it’s going to give you.

So when you feed this container into Physics.Raycast, you have to use the one you created. When you used ‘hit’, the compiler had no idea what that was; it’s expecting “some RaycastHit-shaped box to put stuff in”; you gave it “something I’ve never mentioned before”.

(The ‘out’ keyword basically tells the C# compiler: “Yes, I know that this function is going to modify this variable I passed into it, and I’m okay with that.” IIRC, the Javascript compiler just sort of assumes you already know that.)

Okay, so now the script looks like this:

var Target : Transform;
var Damping = 100.0;
var fwd = transform.TransformDirection (Vector3.forward);
var hitInfo : RaycastHit = new RaycastHit();

function Update ()
{
    lookAt();
   
    var fwd = transform.TransformDirection (Vector3.forward);
   
    if (Physics.Raycast (transform.position, -Vector3.up, hitInfo))
    {
        Debug.Log("I see something.");
       
        if (hitInfo.collider.gameObject == "Player")
        {
            Debug.Log("I see the player.");
        }
    }
   
}

function lookAt ()
{
    var rotation = Quaternion.LookRotation(Target.position - transform.position);
    transform.rotation = Quaternion.Slerp(transform.rotation, rotation, Time.deltaTime * Damping);
}

However it still doesn’t work. I don’t get any errors and the Debug Log for “I see something” still works just fine. Forgive me if the error is obvious, as I said I’m a real newbie.

Hey, don’t worry about not understanding! We were all there once. The important part is that you’ve learned to give us all the information we need to help you (and, as your understanding of the engine grows, how to gather all the information you need to help yourself!)

So, you see “I see something” but not “I see the player”, correct? That means that that if statement is not coming back as true, so we’ve got the problem pinpointed. It looks like you’re comparing hitInfo.collider.gameObject - which is of the type GameObject - to the string “Player”, which is just text. Those things are never going to be equal. You probably want to compare hitInfo.collider.gameObject.name instead.

If this still doesn’t work, it’s pretty common for raycasts to unexpectedly hit other things - try outputting the name of the object you hit in a Debug.Log.

I tried putting in “hitInfo.collider.gameObject.name” as well as also trying “hitInfo.collider.gameObject.tag”, so I’m guessing it either doesn’t know what the player is, fails to store it in the variable, or as you say hits something else. In order to test the latter, can you explain how you output the name of what is hit? I tried to look it up, but found nothing.

Change your first debug statement to:

Debug.Log("I see something! Its name is "+hitInfo.collider.gameObject.name);

I believe I have found the problem. It said it was seeing the floor, so I tried disabling it. The result was that it didn’t hit anything at all, but when I moved my player so close that it collided with the “eye” it finally noticed the player. So the problem is not that it has troubles identifying the player after all, it has troubles seeing it.
Is there a way to make the Raycast ignore some objects? Like in a way similar to how you can make a camera ignore layers? If I can make the eye only see the player and the objects that are supposed to block the eye’s view it might work.

Yes - in fact, exactly like that! Look through the Raycast documentation, and there are variations of it that take a “layer mask” parameter. Use one of those variations, and feed it a layer mask you create like this:

int myLayerToRaycastFor = 9;
int myLayerMask = 1 << myLayerToRaycastFor;
//now, use myLayerMask in that spot in the parameters

A Layer Mask is basically an int that takes advantage of the fact that it’s really a collection of bits. An int is a 32-bit integer, meaning it is composed of 32 ones/zeroes. It looks something like this:

00000000 00000000 00000010 00000000

That represents the number 512 (2 to the 9th power). In a layermask, we don’t care about that - we care about the bits.

Have you noticed that, in Unity, there are 32 layers? Not a coincidence. Each layer corresponds to one of those 1’s or 0’s. If you set your layermask to 1, it will have all 0’s and a single 1 in the last place (on the right). That would mean the first layer is the one that gets hit, and no other layers will. (Note that “layer 0” is all the way to the right, in this representation)

So this is what that code does: You start with a 1 in the first index, and then bitshift it 9 spots over. That’s what << is - it takes your integer and shifts all the bits in it to the left.

Fun fact: If you want your raycast to hit multiple layers, that’s easy! You just need a way to stick a 1 in multiple of those slots, right? That’s where bitwise or comes in - it takes two ints, goes bit-by-bit, and if either one or the other is a 1, makes the new value a 1. The bitwise or operator in C# is ^

int layersOneAndNine = (1 << 1) ^ (1 << 9);

I’ve done some testing, and now I’m pretty sure I know what’s wrong. The Raycast is simply not shooting out the way it should. It just points straight down, explaining why it kept seeing the floor and no other objects. Apparently only the model is following the player and the Raycast stays in place pointing down, and now that I think about it I shouldn’t have assumed that the Raycast would move like the model.

So the only issue left is to make the Raycast always point at the player… I’ll look around for a solution to that.

EDIT: Solved that as well. Now the whole finally works the way it should!
Thanks for the help, It would probably have taken me ages to figure this out otherwise!