Search code examples
unity-game-engineunity-webgl

RaycastHit2D stops working when another Coroutine is active. Unity2D Platformer, WebGL


I'm working on an Unity project, it is a classic Mario style 2D Platformer. The occuring problems are with an enemy, the known Snail, which can be kicked away when it is stunned.

There are two functions, both work on their own, but doesn't work together. The project Build has been exportet as WebGL, to be playable in the browser.

1. ChangeDirection:

ChangeDirection() is a Coroutine and is called in the Start-Function. It flips the sprite and moving direction of the snail, when it reaches the end of a platform.

2. CheckCollision:

CheckCollision is called in the Update-Function and detects Collisions on 4 GameObjects, which are attached to the snail.

Problem Description:

When I outcomment "StartCoroutine(ChangeDirection());" inside the Start-Function, CheckCollision works fine. I can stun the snail and kick it away, after it has been stunned.

When I put the ChangeDirection()-Coroutine back, the snail changes its direction perfectly. Also the top_Collision can be detected. I can stun the snail and it changes the animation and stops moving, but the left and right Collision seems to stop working, so that I can not kick the snail away, after it has been stunned.

Assumption:

The ChangeDirection() Coroutine doesn't prevent CheckCollision() completely from working, because the detection of the top collision still works. topHit is a Collider2D, but leftHit and rightHit are RaycastHit2D. Somehow the RaycastHit2D doesn't work with ChangeDirection() Coroutine activated at the same time.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SnailScript : MonoBehaviour
{

    public float moveSpeed = 1f;
    private Rigidbody2D myBody;
    private Animator anim;

    public LayerMask playerLayer;

    private bool moveLeft;

    private bool canMove;
    private bool stunned;

    public Transform left_Collision, right_Collision, top_Collision, down_Collision;
    private Vector3 left_Collision_Pos, right_Collision_Pos;

    void Awake()
    {
        myBody = GetComponent<Rigidbody2D>();
        anim = GetComponent<Animator>();

        left_Collision_Pos = left_Collision.position;
        right_Collision_Pos = right_Collision.position;
    }

    void Start()
    {
        moveLeft = true;
        canMove = true;
        StartCoroutine(ChangeDirection());
    }

    void Update()
    {
        if (canMove)
        {
            if (moveLeft)
            {
                myBody.velocity = new Vector2(-moveSpeed, myBody.velocity.y);
            }
            else
            {
                myBody.velocity = new Vector2(moveSpeed, myBody.velocity.y);
            }
        }

        CheckCollision();

    }

    void CheckCollision()
    {
        //ATACHED GAMEOBJECTS FOR COLLISION DETECTION
        RaycastHit2D leftHit = Physics2D.Raycast(left_Collision.position, Vector2.left, 0.1f, playerLayer);
        RaycastHit2D rightHit = Physics2D.Raycast(right_Collision.position, Vector2.right, 0.1f, playerLayer);

        Collider2D topHit = Physics2D.OverlapCircle(top_Collision.position, 0.2f, playerLayer);

        if (topHit != null)
        {
            if (topHit.gameObject.CompareTag(MyTags.PLAYER_TAG))
            {
                if (!stunned)
                {
                    //Player does a little rebounce after jumping on the snail
                    topHit.gameObject.GetComponent<Rigidbody2D>().velocity =
                        new Vector2(topHit.gameObject.GetComponent<Rigidbody2D>().velocity.x, 7f);

                    canMove = false;
                    myBody.velocity = new Vector2(0, 0);

                    anim.Play("Stunned");
                    stunned = true;
                }
            }
        }

        if (leftHit)
        {
            if (leftHit.collider.gameObject.CompareTag(MyTags.PLAYER_TAG))
            {
                if (stunned)
                {
                    //SNAIL KICKED TO THE RIGHT
                    myBody.velocity = new Vector2(15f, myBody.velocity.y);
                }
            }
        }

        if (rightHit)
        {
            if (rightHit.collider.gameObject.CompareTag(MyTags.PLAYER_TAG))
            {
                if (stunned)
                {
                    //SNAIL KICKED TO THE LEFT
                    myBody.velocity = new Vector2(-15f, myBody.velocity.y);
                }
            }
        }
    }

    IEnumerator ChangeDirection()
    {
        if (!Physics2D.Raycast(down_Collision.position, Vector2.down, 0.1f))
        {
            moveLeft = !moveLeft;

            Vector3 tempScale = transform.localScale;

            if (moveLeft)
            {
                //SNAIL LOOKS TO THE LEFT
                tempScale.x = Mathf.Abs(tempScale.x);

                //Changing position of the attached GameObjects for collision detection
                left_Collision.position = left_Collision_Pos;
                right_Collision.position = right_Collision_Pos;

            }
            else
            {
                tempScale.x = -Mathf.Abs(tempScale.x);

                left_Collision.position = right_Collision_Pos;
                right_Collision.position = left_Collision_Pos;
            }

            //new sprite-orientation
            transform.localScale = tempScale;
        }

        yield return new WaitForSeconds(0.5f);

        StartCoroutine(ChangeDirection());
    }
}

Solution

  • As I finally found out, RaycastHit2D doesn't work very well, when you export your build as WebGL. I assume the older code should have worked without WebGL.

    I found a way to replace the RaycastHit2D with a simple OnCollisionEnter2D, where I additional checked the position of the player relatively to the snail, to determine if it is a left or right collision. Now it works fine.

        //SNAIL GETS KICKED AWAY
    private void OnCollisionEnter2D(Collision2D collision)
    {
        if ((collision.gameObject.tag == "Player") && (stunned))
        {
                                //                 Player    -    Snail
            if( ((collision.gameObject.transform.position.x) - (gameObject.transform.position.x)) <= 0f)
            {
                //Player stands left to snail, Snail must be kicked to the right!
                myBody.velocity = new Vector2(15f, myBody.velocity.y);
            }
            else
            {
                myBody.velocity = new Vector2(-15f, myBody.velocity.y);
            }
    
            if (((collision.gameObject.transform.position.y) - (gameObject.transform.position.y)) >= 0.2f)
            {
                //Player does a little Rebounce, when higher than the snail
                collision.gameObject.GetComponent<Rigidbody2D>().velocity =
                        new Vector2(collision.gameObject.GetComponent<Rigidbody2D>().velocity.x, 7f);
            }
    
            StartCoroutine(Dead(3f));
        }
    }