Please Help with Enemy trigger

Hi all,

Looking for advice or a solution regarding the enemy trigger to flip the sprite when it reaches an intersection of the platform tilemap.

I can currently see two relevant scenarios:

  1. When the tilemap joins a wall and the enemy hits the vertical wall
  2. When the tilemap ends and the enemy reaches a “cliff”

With my current configuration scenario 1 is failing but scenario 2 is working.

For both scenarios, It appears that the OnTriggerEnter2D is executed when the game starts and the BoxCollider2D is already in contact with the Ground layer and Platforms tilemap collider.

However, it seems that the tilemap collider is being seen as one continuous object and the OnTriggerExit2D is not executed when passing a border, only when exiting the entire object (the part I refer to as “cliff”).

I have attached screenshots of the failing scenario to highlight.

a. Game start, enemy trigger executed (see console)

b. Enemy has passed vertical wall, no trigger (see console)

c. Enemy passes “cliff” trigger exit executed (see console). At this point enemy flips

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

public class EnemyMovement : MonoBehaviour
{
    Rigidbody2D enemyRigidBody2d;

    [SerializeField] float enemyMoveSpeed = 2.5f;

    void Start()
    {
        enemyRigidBody2d = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        enemyRigidBody2d.velocity = new Vector2(enemyMoveSpeed, 0f);
    }

    private void OnTriggerEnter2D(Collider2D other) {
        Debug.Log("Entering trigger");
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        Debug.Log("Exiting trigger");
        // flip sprite and turn around
        enemyMoveSpeed = -enemyMoveSpeed;
        transform.localScale = new Vector2(-(Mathf.Sign(enemyRigidBody2d.velocity.x)), 1);
    }
}

Please can you advise?

Thanks!

Unity version:

Screenshot 2023-05-15 at 11.22.07

You may need a second trigger. I can see your first trigger is positioned to detect when the enemy reaches the end of the platform. You need one that is a little higher and not touching the ground. This should be on its own game object. When this trigger enters the platform, it will fire. Something like
image

The ‘ground detector’ will react when the trigger exits the platform (over a cliff) and the ‘wall detector’ reacts when the trigger enters the platform (at a wall).

If you tag your game objects you can use the same script. Here I have tagged them ‘Ground Detector’ and ‘Wall Detector’

private void OnTriggerEnter2D(Collider2D other) {
    Debug.Log("Entering trigger");
    if (gameObject.CompareTag("Wall Detector"))
        FlipSprite();
}

private void OnTriggerExit2D(Collider2D other)
{
    Debug.Log("Exiting trigger");
    if (gameObject.CompareTag("Ground Detector"))
        FlipSprite();
}

private void FlipSprite()
{
    // flip sprite and turn around
    enemyMoveSpeed = -enemyMoveSpeed;
    transform.localScale = new Vector2(-(Mathf.Sign(enemyRigidBody2d.velocity.x)), 1);
}

Edit
Oh, you’d need those on their own script (instead of the EnemyMovement script). Move it to a nother script - maybe called EnemyCollision. You’ll then need to reference the EnemyMovement to flip the sprite and movement

// EnemyMovement.cs
using UnityEngine;
public class EnemyMovement : MonoBehaviour
{
    Rigidbody2D enemyRigidBody2d;

    [SerializeField] float enemyMoveSpeed = 2.5f;

    void Start()
    {
        enemyRigidBody2d = GetComponent<Rigidbody2D>();
    }

    void Update()
    {
        enemyRigidBody2d.velocity = new Vector2(enemyMoveSpeed, 0f) * transform.localScale;
    }

    public void SetScale(Vector3 localScale)
    {
        transform.localScale = localScale;
    }
}

// EnemyCollision.cs - one for each detector
using UnityEngine;
public class EnemyCollision : MonoBehaviour
{
    [SerializeField] EnemyMovement enemy;
    Rigidbody2D enemyRigidBody2d;

    private void Awake()
    {
        enemyRigidBody2d = enemy.GetComponent<Rigidbody2D>();
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        Debug.Log("Entering trigger");
        if (gameObject.CompareTag("Wall Detector"))
            FlipSprite();
    }

    private void OnTriggerExit2D(Collider2D other)
    {
        Debug.Log("Exiting trigger");
        if (gameObject.CompareTag("Ground Detector"))
            FlipSprite();
    }

    private void FlipSprite()
    {
        // flip sprite and turn around
        enemy.SetScale(new Vector2(-(Mathf.Sign(enemyRigidBody2d.velocity.x)), 1));
    }
}

image


Hi @bixarrio, thank you for your help.

I did something similar and your advice helped me get there. This is now working.

In case this is a problem seen by others I will attempt to explain my new setup.

The new enemy and it’s colliders look like this:

Screenshot 2023-05-15 at 21.16.47

The ground and wall colliders and separate objects beneath the main Enemy prefab that have their own scripts

The colliders are slightly separated with a small space between.

The entry point for the “wall collider” aims to be in line with the enemy’s right side so it can flip the sprite on contact with the wall, the “wall scenario”. This code uses OnTriggerEnter2D

GroundCollide.cs

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

public class GroundCollide : MonoBehaviour
{
    [SerializeField] GameObject enemy;

    private void OnTriggerExit2D(Collider2D other) {
        enemy.GetComponent<EnemyMovement>().FlipSprite();
    }
}

The exit point for the “ground collider” aims to be in line with the enemy’s right side so it can flip the sprite on leaving contact with the ground, the “cliff” scenario. This code uses OnTriggerExit2D

wallcolide.cs

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

public class WallCollide : MonoBehaviour
{
    [SerializeField] GameObject enemy;

    private void OnTriggerEnter2D(Collider2D other) {
        enemy.GetComponent<EnemyMovement>().FlipSprite();
    }
}

Blockquote Note: This I made a public method on the EnemyMovement class to call to Flip the Sprite.

1 Like

This is great. A simple note;
Since you only need access to the EnemyMovement you can reference that instead of GameObjcet. This will save you the need to GetComponent

public class GroundCollide : MonoBehaviour
{
    [SerializeField] EnemyMovement enemy;

    private void OnTriggerExit2D(Collider2D other) {
        enemy.FlipSprite();
    }
}

You still drag the same object into the field in the inspector

This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.

Privacy & Terms