Skip to main content
Caching & restoring layer
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373
public class Squashable : MonoBehaviour {

    bool squashed = false;

    void OnTriggerEnter2D(Collider2D other) {
        // Don't double-squash if you get two trigger enter messages at once.
        if(squashed)
           return;

        // Only squash if we got hit by a squasher collider.
        // (Can check that it came from above too)
        var squasher = other.GetComponent<Squasher>();
        if(squasher == null)
            return;

        StartCoroutine(SquashMe());
    }

    IEnumerator SquashMe() {
        squashed = true;

        var animator = GetComponent<Animator>();
        if(animator != null)
            animator.SetBool("Squash", true);

        var body = GetComponent<RigidBody2D>();
        if(body != null)
            body = new Vector2(Mathf.Epsilon * Mathf.Sign(transform.localScale.x), 0f);

        // Make your Zombie controller or other monster AI implement this interface,
        // so we can switch off their behaviour / award score or pickups as needed,
        // without the Squash logic knowing anything about "zombies."
        var killable = GetComponent<IKillable>();
        if(killable != null)
            killable.Kill();

        int oldLayer = gameObject.layer;
        gameObject.layer = 11;

        yield return new WaitForSeconds(2f);

        // Hide this object and put all its components back the way we found them.
        gameObject.SetActive(false);
        gameObject.layer = oldLayer;
        if(animator != null)
            animator.SetBool("Squash", false);
        if(killable != null)
            killable.Resurrect();
        squashed = false;
    }
}
public class Squashable : MonoBehaviour {

    bool squashed = false;

    void OnTriggerEnter2D(Collider2D other) {
        // Don't double-squash if you get two trigger enter messages at once.
        if(squashed)
           return;

        // Only squash if we got hit by a squasher collider.
        // (Can check that it came from above too)
        var squasher = other.GetComponent<Squasher>();
        if(squasher == null)
            return;

        StartCoroutine(SquashMe());
    }

    IEnumerator SquashMe() {
        squashed = true;

        var animator = GetComponent<Animator>();
        if(animator != null)
            animator.SetBool("Squash", true);

        var body = GetComponent<RigidBody2D>();
        if(body != null)
            body = new Vector2(Mathf.Epsilon * Mathf.Sign(transform.localScale.x), 0f);

        // Make your Zombie controller or other monster AI implement this interface,
        // so we can switch off their behaviour / award score or pickups as needed,
        // without the Squash logic knowing anything about "zombies."
        var killable = GetComponent<IKillable>();
        if(killable != null)
            killable.Kill();

        gameObject.layer = 11;

        yield return new WaitForSeconds(2f);

        // Hide this object and put all its components back the way we found them.
        gameObject.SetActive(false);
        if(animator != null)
            animator.SetBool("Squash", false);
        if(killable != null)
            killable.Resurrect();
        squashed = false;
    }
}
public class Squashable : MonoBehaviour {

    bool squashed = false;

    void OnTriggerEnter2D(Collider2D other) {
        // Don't double-squash if you get two trigger enter messages at once.
        if(squashed)
           return;

        // Only squash if we got hit by a squasher collider.
        // (Can check that it came from above too)
        var squasher = other.GetComponent<Squasher>();
        if(squasher == null)
            return;

        StartCoroutine(SquashMe());
    }

    IEnumerator SquashMe() {
        squashed = true;

        var animator = GetComponent<Animator>();
        if(animator != null)
            animator.SetBool("Squash", true);

        var body = GetComponent<RigidBody2D>();
        if(body != null)
            body = new Vector2(Mathf.Epsilon * Mathf.Sign(transform.localScale.x), 0f);

        // Make your Zombie controller or other monster AI implement this interface,
        // so we can switch off their behaviour / award score or pickups as needed,
        // without the Squash logic knowing anything about "zombies."
        var killable = GetComponent<IKillable>();
        if(killable != null)
            killable.Kill();

        int oldLayer = gameObject.layer;
        gameObject.layer = 11;

        yield return new WaitForSeconds(2f);

        // Hide this object and put all its components back the way we found them.
        gameObject.SetActive(false);
        gameObject.layer = oldLayer;
        if(animator != null)
            animator.SetBool("Squash", false);
        if(killable != null)
            killable.Resurrect();
        squashed = false;
    }
}
Source Link
DMGregory
  • 136.3k
  • 22
  • 247
  • 373

Your problem is these two lines:

zombieController = FindObjectOfType<ZombieController>();

This says "give me the first ZombieController you find in the scene"

zombieController.Stomped();

This says "squash that specific zombie you found for me earlier" - ie. it doesn't care whether that's the zombie you actually landed on, or whether this zombie is still alive. You've set up your script so that one and only one zombie is predestined to receive every stomp.

To avoid this, I'd recommend centralizing the work of handling being squashed on the object that can be squashed. That way, any squashing always applies to "me," making it trivial to ensure it's hitting the right target.

Presumably you'll want other things you can squash beyond zombies (eg. other monster types, powerups, maybe even the player themselves (from falling blocks/etc), so let's separate the concept of Squashable from the concept of Zombie while we're at it.

First, we'll use a very simple script to mark our collider that does the squashing. You can also do this with tags, but doing it with a script lets you attach parameters to it (eg. a damage value dealt by this squasher, or flags for selective squash immunity, so you can ensure players don't squash other players)

public class Squasher : MonoBehaviour { }

Next we'll define our script for being squashed. I've set this up generically so it can work on anything that has a squash animation, so you minimize code duplication if you add other squashable types later.

public class Squashable : MonoBehaviour {

    bool squashed = false;

    void OnTriggerEnter2D(Collider2D other) {
        // Don't double-squash if you get two trigger enter messages at once.
        if(squashed)
           return;

        // Only squash if we got hit by a squasher collider.
        // (Can check that it came from above too)
        var squasher = other.GetComponent<Squasher>();
        if(squasher == null)
            return;

        StartCoroutine(SquashMe());
    }

    IEnumerator SquashMe() {
        squashed = true;

        var animator = GetComponent<Animator>();
        if(animator != null)
            animator.SetBool("Squash", true);

        var body = GetComponent<RigidBody2D>();
        if(body != null)
            body = new Vector2(Mathf.Epsilon * Mathf.Sign(transform.localScale.x), 0f);

        // Make your Zombie controller or other monster AI implement this interface,
        // so we can switch off their behaviour / award score or pickups as needed,
        // without the Squash logic knowing anything about "zombies."
        var killable = GetComponent<IKillable>();
        if(killable != null)
            killable.Kill();

        gameObject.layer = 11;

        yield return new WaitForSeconds(2f);

        // Hide this object and put all its components back the way we found them.
        gameObject.SetActive(false);
        if(animator != null)
            animator.SetBool("Squash", false);
        if(killable != null)
            killable.Resurrect();
        squashed = false;
    }
}