Enemies don't die on collision with player, they 'freeze' and also stop respawning

Hey ya’ll,

I have the following problem:

All my layers and Tags are assigned correctly Player to Player & Enemy to Enemy.

My Enemies die upon collision with my bullet! Which is great!
But i also want them to die upon collision with my Player and he has then a invulnerability period.

All my Prefabs for Enemies, Player and Bullet got Polygon Collider 2D and Rigidbody 2D on them with
Kinematic and is Trigger.

But as of now once the Enemy and Player collide the Enemy just freeze up and stops respawning.

Here are my scripts:

PlayerController.cs

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

public class PlayerController : MonoBehaviour
{
    public GameObject bulletPrefab; // Reference to the bullet prefab
    public Transform bulletSpawnPoint; // Reference to the spawn point for bullets
    public float playerSpeed = 5f; // Speed of the player movement
    public int playerHealth = 100; // Player's health
    public float fireRate = 0.2f; // Firing rate (delay between shots)
    public float invulnerabilityDuration = 0.25f; // Duration of invulnerability after colliding with an enemy

    public delegate void OnPlayerHitDelegate();
    public static event OnPlayerHitDelegate OnPlayerHit; // Event declaration

    private float nextFireTime = 0f; // Time of the next allowed shot
    private bool isInvulnerable = false; // Flag to track if the player is currently invulnerable

    private void Update()
    {
        // Get the input for player movement
        float moveHorizontal = Input.GetAxis("Horizontal");
        float moveVertical = Input.GetAxis("Vertical");

        // Calculate the new position based on the input and player speed
        Vector3 newPos = transform.position + new Vector3(moveHorizontal, moveVertical, 0f) * playerSpeed * Time.deltaTime;

        // Clamp the new position within the screen boundary
        newPos.x = Mathf.Clamp(newPos.x, -Camera.main.orthographicSize * Camera.main.aspect + 0.25f, Camera.main.orthographicSize * Camera.main.aspect - 0.25f);
        newPos.y = Mathf.Clamp(newPos.y, -Camera.main.orthographicSize + 0.25f, Camera.main.orthographicSize - 0.25f);

        // Update the player position
        transform.position = newPos;

        // Check if the player is currently invulnerable
        if (isInvulnerable)
        {
            // Decrease the invulnerability timer
            invulnerabilityDuration -= Time.deltaTime;

            // If the invulnerability period is over, reset the invulnerable flag
            if (invulnerabilityDuration <= 0f)
            {
                isInvulnerable = false;
            }
        }

        // Check if the shoot input (e.g., left mouse button or space bar) is being held down
        if (Input.GetButton("Fire1") && Time.time >= nextFireTime)
        {
            // Call the Shoot method to spawn a bullet
            Shoot();

            // Update the next allowed shot time based on the fire rate
            nextFireTime = Time.time + fireRate;
        }
    }

    private void Shoot()
    {
        // Instantiate the bullet at the bulletSpawnPoint position and rotation
        GameObject newBullet = Instantiate(bulletPrefab, bulletSpawnPoint.position, bulletSpawnPoint.rotation);

        // Apply velocity to the bullet in the forward direction
        Rigidbody2D bulletRigidbody = newBullet.GetComponent<Rigidbody2D>();
        BulletController bulletController = newBullet.GetComponent<BulletController>();

        if (bulletController != null)
        {
            bulletRigidbody.velocity = bulletSpawnPoint.up * bulletController.bulletSpeed;
            bulletController.SetBulletDamage(10); // Set the damage here
        }
    }

    public void TakeDamage(int damageAmount)
    {
        if (!isInvulnerable)
        {
            // Reduce player health by the specified amount
            playerHealth -= damageAmount;

            // Check if the player's health is depleted
            if (playerHealth <= 0)
            {
                // Player is defeated, you can handle game over logic here
                Destroy(gameObject);
            }
            else
            {
                // Set the player invulnerable and reset the invulnerability timer
                isInvulnerable = true;
                invulnerabilityDuration = 0.25f;
            }
        }
    }

    private void OnTriggerEnter2D(Collider2D other)
    {
        // Check if the player collided with an enemy
        if (other.CompareTag("Enemy"))
        {
            // Invoke the event to notify the EnemyController that the player is hit
            OnPlayerHit?.Invoke();
        }
    }
}

EnemyController.cs

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

public class EnemyController : MonoBehaviour
{
    public GameObject[] enemyPrefabs; // Array of enemy prefabs (enemy0 to enemy7)
    public GameObject enemyBulletPrefab; // Enemy bullet prefab
    public float respawnTime = 2f; // Time between enemy spawns
    public float respawnDelay = 2f; // Delay before starting a new wave
    public float spawnXMin = -5f; // Minimum X position for enemy spawn
    public float spawnXMax = 5f; // Maximum X position for enemy spawn
    public float enemySpeed = 2f; // Speed of the falling enemies
    public int baseHealth = 1; // Base health of enemies
    public float healthScalingFactor = 0.05f; // Scaling factor for health increase per 20 enemies killed
    public int enemiesToIncreaseHealth = 20; // Number of enemies to kill before increasing enemy health

    private float screenWidth;
    private Transform playerTransform;
    private int enemiesKilled = 0; // Variable to keep track of the number of enemies killed
    private int waveNumber = 0; // Variable to keep track of the current wave number
    private bool canSpawnEnemies = true; // Variable to control enemy spawning

    private List<GameObject> activeEnemies = new List<GameObject>();

    private void Start()
    {
        playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
        screenWidth = Camera.main.orthographicSize * Camera.main.aspect * 2f;
        StartCoroutine(SpawnWave());
        PlayerController.OnPlayerHit += OnPlayerHitHandler; // Subscribe to the OnPlayerHit event
    }

    private void OnDestroy()
    {
        PlayerController.OnPlayerHit -= OnPlayerHitHandler; // Unsubscribe from the OnPlayerHit event
    }

    private void OnPlayerHitHandler()
    {
        // Destroy the enemy upon collision with the player
        DestroyEnemy();
    }

    private void DestroyEnemy()
    {
        // Code to handle enemy destruction
        Destroy(gameObject);
    }

    private IEnumerator SpawnWave()
    {
        // Increase the wave number
        waveNumber++;

        // Calculate the number of enemies to spawn in this wave based on the wave number
        int enemiesToSpawn = Mathf.RoundToInt(waveNumber * 1.5f);

        for (int i = 0; i < enemiesToSpawn; i++)
        {
            if (canSpawnEnemies) // Check if new enemies can be spawned
            {
                SpawnEnemyRandomly();
                yield return new WaitForSeconds(respawnDelay);
            }
        }

        // Increase respawnDelay after each wave
        respawnDelay *= 0.9f;

        // Start a new wave after a delay
        yield return new WaitForSeconds(respawnTime);
        StartCoroutine(SpawnWave());
    }

    private void SpawnEnemyRandomly()
    {
        // Randomly choose an X position within the spawnXMin and spawnXMax range
        float spawnX = Random.Range(spawnXMin, spawnXMax);

        // Set a fixed Y position to spawn from the top of the screen
        float spawnY = Camera.main.orthographicSize;

        Vector3 spawnPosition = new Vector3(spawnX, spawnY, 0f);

        // Check if there are any enemies nearby before spawning
        Collider2D[] colliders = Physics2D.OverlapCircleAll(spawnPosition, 1f);
        bool isOverlap = false;
        foreach (Collider2D collider in colliders)
        {
            if (collider.CompareTag("Enemy"))
            {
                isOverlap = true;
                break;
            }
        }

        if (!isOverlap)
        {
            int randomIndex = Random.Range(0, enemyPrefabs.Length);
            GameObject enemyPrefab = enemyPrefabs[randomIndex];
            GameObject newEnemy = Instantiate(enemyPrefab, spawnPosition, Quaternion.identity);

            // Set the enemy's initial position to spawn from the top of the screen
            newEnemy.transform.position = spawnPosition;

            // Start the movement behavior towards the bottom of the screen
            StartCoroutine(MoveTowardsBottom(newEnemy.transform));

            // Set the increased health to the new enemy
            int increasedHealth = Mathf.RoundToInt(baseHealth * (1f + enemiesKilled * healthScalingFactor));

            EnemyStats enemyStats = newEnemy.GetComponent<EnemyStats>();
            if (enemyStats != null)
            {
                enemyStats.SetHealth(increasedHealth);
            }

            // Add the new enemy to the list of active enemies
            activeEnemies.Add(newEnemy);
        }
        else
        {
            // If there is already an enemy nearby, do not spawn a new one at this position
            // Try again to find a valid spawn position
            SpawnEnemyRandomly();
        }
    }

    private IEnumerator MoveTowardsBottom(Transform enemyTransform)
    {
        while (enemyTransform != null && enemyTransform.position.y > -Camera.main.orthographicSize)
        {
            // Move the enemy towards the bottom of the screen on the Y-axis
            Vector3 targetPosition = new Vector3(enemyTransform.position.x, -Camera.main.orthographicSize, enemyTransform.position.z);
            enemyTransform.position = Vector3.MoveTowards(enemyTransform.position, targetPosition, enemySpeed * Time.deltaTime);

            // Check if any active enemies are overlapping, and move them apart if necessary
            foreach (GameObject activeEnemy in activeEnemies)
            {
                if (activeEnemy != enemyTransform.gameObject && activeEnemy != null)
                {
                    if (Vector3.Distance(enemyTransform.position, activeEnemy.transform.position) < 1f)
                    {
                        Vector3 newPosition = new Vector3(activeEnemy.transform.position.x + 1f, activeEnemy.transform.position.y, activeEnemy.transform.position.z);
                        activeEnemy.transform.position = newPosition;
                    }
                }
            }

            yield return null;
        }

        // If the enemy reaches the bottom, destroy it and increase the enemies killed count
        if (enemyTransform != null)
        {
            activeEnemies.Remove(enemyTransform.gameObject);
            Destroy(enemyTransform.gameObject);
            enemiesKilled++;

            // Check if enough enemies have been killed to increase enemy health
            if (enemiesKilled % enemiesToIncreaseHealth == 0)
            {
                baseHealth = Mathf.RoundToInt(baseHealth * (1f + healthScalingFactor));
            }
        }
    }
}

EnemyStats.cs

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

public class EnemyStats : MonoBehaviour
{
    private int health;

    public void SetHealth(int newHealth)
    {
        health = Mathf.Max(newHealth, 0);
    }

    public int GetHealth()
    {
        return health;
    }

    public void TakeDamage(int damageAmount)
    {
        // Reduce enemy health by the specified amount
        health -= damageAmount;

        // Check if the enemy's health is depleted
        if (health <= 0)
        {
            // Enemy is defeated, explode and destroy the enemy
            Explode();
        }
    }

    private void Explode()
    {
        // Code to handle enemy explosion and destruction
        Destroy(gameObject);
    }
}

BulletController.cs

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

public class BulletController : MonoBehaviour
{
    public float bulletSpeed = 10f; // Speed of the bullet
    public int bulletDamage = 1; // Damage the bullet deals to enemies

    // Update is called once per frame
    void Update()
    {
        // Destroy the bullet if it goes out of the screen
        if (Mathf.Abs(transform.position.x) > Camera.main.orthographicSize * Camera.main.aspect
            || Mathf.Abs(transform.position.y) > Camera.main.orthographicSize)
        {
            Destroy(gameObject);
        }
    }

    public void SetBulletDamage(int damage)
    {
        bulletDamage = Mathf.Max(damage, 0);
    }

    private void OnTriggerEnter2D(Collider2D collision)
    {
        if (collision.CompareTag("Enemy"))
        {
            // Get the EnemyStats component of the collided enemy
            EnemyStats enemyStats = collision.GetComponent<EnemyStats>();

            // Check if the enemy has the EnemyStats component
            if (enemyStats != null)
            {
                // Deal damage to the enemy
                enemyStats.TakeDamage(bulletDamage);

                // Destroy the bullet after hitting the enemy
                Destroy(gameObject);
            }
        }
    }
}

Thank you all in advance for your help. :grin:

Kinematic rigidbodies are not generating any collision events. If you want to do so, go to your project settings - physics section and enable kinematic pairs collision

I set the Contact Pairs Mode to Enable Kinematic Pairs, but still have the same issue. :woozy_face: