[SOLVED] Raycasy2D not updating properly

So I am making a 2D platformer and recently started with creating the enemy AI, I created a few states for the enemy but only 2 are involved in the problem: Patrolling, it moves infinitely and using a raycast, positioned at the front of the enemy, I check if there is a wall, if there is then it flips. The problem is that when the enemy chases the player (which just takes the position of the player and flips the enemy accordingly) reaches a wall and then exits the chasing state the raycast doesn’t detect the wall? Hopefully this makes sense, all new to this btw. Screenshot (the white line is the ray, here the enemy is in patroll state)

Sounds like you wrote a bug… Time to start debugging!

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() 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.

NOTE: when raycasting for two different things (walls and the player, for instance), Layers and LayerMasks are usually used to differentiate them.

The difference between Layers vs LayerMasks:

“There are 10 types of people in this world: those who understand binary, and those who don’t.”

I think we would need to see your code to provide any specific answers. But as Kurt mentioned, adding Debug.Log throughout your code can help you detect if your code is reaching a certain point or if a variable has an unexpected value.

Yes I failed to mention, I have Debug.Log stuff in there and the function gets called but the part where I check for collision doesn’t get activated (btw Patrol() works just fine normally, only when it exits Chase() WHILE on a wall. Also when I slighly move the enemy when it is in it’s ‘buggy’ state he goes back to patrolling, this leads me to think that the ray doesn’t update properly, another thing to note to Kurt Dekker I don’t think the problem is the layer masks) here is the code:

public class EnemyStateMachine : MonoBehaviour
{
    [SerializeField] private Transform rayPoint;

    [SerializeField] private LayerMask playerLayer;

    [SerializeField] private float normalSpeed = 2f;

    [SerializeField] private float damage = 20f;

    [SerializeField] private float sightRange = 3f;
    [SerializeField] private float attackRange = 0.3f;

    private Rigidbody2D rb;
    private GameObject player;

    private float currentSpeed;

    bool isFacingRight;

    bool moveRight = true;

    private void Start()
    {
        rb = GetComponent<Rigidbody2D>();
        player = GameObject.FindGameObjectWithTag("Player");

        currentSpeed = normalSpeed;
    }

    private void Update()
    {
        bool playerInChaseSight = Physics2D.OverlapCircle(transform.position, sightRange, playerLayer);
        bool playerInAttackSight = Physics2D.OverlapCircle(transform.position, attackRange, playerLayer);

        if (!playerInChaseSight && !playerInAttackSight)
        {
            Patrol();
            //Debug.Log("Switched to state: Patrol!");
        } else if (playerInChaseSight && !playerInAttackSight)
        {
            ChasePlayer();
            //Debug.Log("Switched to state: Chase!");
        } else if (playerInAttackSight && playerInChaseSight)
        {
            Attack();
            //Debug.Log("Switched to state: Attack!");
        }
    }

    private void ChasePlayer()
    {
        rb.velocity = new Vector2(transform.right.x * currentSpeed, rb.velocity.y);

        Flip();
    }

    private void Patrol()
    {
        Debug.Log("Patroll");

        RaycastHit2D rayInfo = Physics2D.Raycast(rayPoint.position, transform.right, 0.01f);

        rb.velocity = new Vector2(transform.right.x * currentSpeed, rb.velocity.y);

        Debug.DrawRay(rayPoint.position, transform.right);

        if (rayInfo.collider != false && rayInfo.collider.transform.tag == "Ground")
        {
            Debug.Log("TestText");
            if (moveRight == true)
            {
                Debug.Log("Right");
                moveRight = false;
                transform.eulerAngles = new Vector3(0f, -180f, 0f);
            }
            else
            {
                Debug.Log("Left");
                moveRight = true;
                transform.eulerAngles = new Vector3(0f, 0f, 0f);
            }
            Debug.Log(rayInfo.collider);
        }
    }
  
    private void Attack()
    {
        // not written yet
    }

    private void Flip()
    {
        if (isFacingRight && transform.position.x < player.transform.position.x || !isFacingRight && transform.position.x > player.transform.position.x)
        {
            isFacingRight = !isFacingRight;
            transform.Rotate(0f, -180f, 0f);
        }
    }
}

Rays don’t “update”. It’s just a physics query where you ask what intersects the line so I’m not sure what you mean by this.

OverlapCircle does not return a bool as per the docs: https://docs.unity3d.com/ScriptReference/Physics2D.OverlapCircle.html

  • You can use “rayInfo == false” or “!rayInfo” here.

  • As per the docs, the “tag” property is on every component (it’s stored on the GameObject) so you don’t need to get the collider, get the transform then get the tag. You can get the tag from the collider.

  • If you specifically need the Transform of the hit then as per the docs again, it’s provided to you.

  • You should assign the ground to a layer and specify that in the raycast to remove this hardcoded string stuff.

  • Your raycast call returns a single hit only so if it hits your enemy, player, ground (etc) first, that’s all you’d get. You’d know this if you were to debug it with something useful like “Debug.Log(rayInfo.collider.name)”

If you want to flip the whole GameObject vertically then just use LocalScale with (0f, -1f, 0f).

So, what’s going wrong? All I can see is a lot of oddities so it might be worth looking at those first. You might consider debugging what you’re hitting with your raycast because right now you’re not beyond asking if it hits or not which isn’t useful.

So basically patrol works fine he goes back and forth and no bugs occur, but when the player chases the player and the player jumps on a ‘wall’ the enemy can’t get to the player so it just stands there which is fine by me, only when I get out of range he doesn’t go back and forth anymore but the second when I move him even a little bit he instantly ‘activates’ again as if he was ‘asleep’ and updating the transform ‘waked’ him, hopefully this makes sense here is a video (and I also cleaned some stuff up as you suggested)

https://www.youtube.com/watch?v=WVg3dm_dkYA

Yes, C# will implicitly convert the reference type to a bool i.e. if it’s NULL or not but my point was that you should know that it’s not returning bool, it’s returning a Collider2D or NULL as per the docs.

Well I cannot debug it from here despite you posting a code snippet and in the end it’s your logic that is determining when and how it moves so that’s what you need to debug. Note my points about how you’re using raycast i.e. not specifying a layer, only using the version that has a single hit. The enemy can detect itself here.

I think I found the problem, when the enemy exits chase mode while on a wall, it creates the ray inside the collision (I am using a CompositeCollider2D for the whole map) so it ignores it? Is this a realistic problem / considerable problem? If so are there solutions?

UPDATE: I fixed the problem. The problem was that the ray got created inside of the collider so it ignores it as mentioned above, I put the ray a little bit inside of the enemy an it worked, thank you all for your help!

It’s not ignoring it, it’s detecting itself. This is why I said you should use layers for the Raycast for the same reason you do it in the CircleCast.

Saying you’re using a CompositeCollider2D doesn’t really provide any information; you can set it to Outline mode which produces edges or Polygon mode which produces polygons. You only detect edges when you intersect edges and you only intersect polygons when you intersect them. If you surround an area with edges, there is no “inside”, it’s just edges so you only detect the intersection. This is no different than the EdgeCollider2D which also produces edges.

I actually did use layers and a Debug.Log to check what it is hitting it didn’t get me results. As you mentioned above the CompositeCollider2D doesn’t have an inside, I actually didn’t know this and now I truly know what the problem was: So the ray got created in the ‘inside’ ← with this I mean not inside in terms of inside a collider, but there in terms of there is no collision there and the ray is really small so the ray doesn’t hit it, here is it visually

1 Like