Home > OS >  Check for "Are all enemies dead ?" in Dungeaon Generation for each room
Check for "Are all enemies dead ?" in Dungeaon Generation for each room

Time:09-01

Im in my 1st year in game design / dev , and my project is to make a simpler "binding of isaac" type of game 3D I managed to make Dungeon Generation (with a lot of help from YouTube lol)

And now I'm working on a system that will detect in each room if all the enemies have died so that the doors in that room will be in "open" mode [bool] .

my idea was to create a C# script in the prefab of each room. and it goes something like this > Timer [after 5sec to check if all enemies in rooms is dead] and loop until they are.

1- now the problem is if they are all dead in room X how to keep room Y closed ? [ because its the same prefab for the Dungeon generation]

2 - and what is the best way to check if they are all dead? [the easiest way for me is just by using: game tag "enemies" ] but using colliders / tags is very costly...

using Unity/c# btw Any kind of help would be greatly appreciated :)

CodePudding user response:

Instead of using a timer to check periodically (if the player kills the last monster 0.01s after the previous check, they have to wait 4.99s before the doors open), have the room manage a collection of monsters in it, and when a monster dies have the monster notify the room. Psuedo code for the room:

private bool DoorsOpen = true;
private List<GameObject> MonstersInMe { get; set; }

private void GenerateMonster(GameObject monsterPrefab)
{
    var monster = Instantiate(monsterPrefab);
    monster.transform.SetParent(this.transform);
    MonstersInMe.Add(monster);
}

public void RemoveMonster(GameObject monster)
{
    MonstersInMe.Remove(monster);

    if (MonstersInMe.Count == 0)
    {
        OnClear();
    }
}

private void OnClear()
{
    DoorsOpen = false;
    // do whatever else
}

The room shouldn't be dependent on the Prefab after its been instantiated, so you shouldn't have to worry about room X confusing room Y due to being the same prefab.

CodePudding user response:

In general instead of poll checking values or existence of things to be more efficient you want to make your code as event driven as possible.

I would have a dedicated component on the monsters so you can make all your code event based and track when one is destroyed:

public class Monster : MonoBehaviour
{
    // event to be invoked when this monster is destroyed
    public UnityEvent<Monster> whenDestroyed;

    private void OnDestroy()
    {
        whenDestroyed.Invoke(this);
    }
}

Then in your rooms you could do something like e.g.

public class BasicRoom : MonoBehaviour
{
    // the default prefab to spawn, can be different for each room instance
    [SerializeField] protected Monster defaultMonsterPrefab;

    private readonly HashSet<Monster> monsters = new ();

    // event to be invoked when this room is cleared
    // per default needs at least one monster to have existed
    public UnityEvent whenCleared;

    // making this virtual - maybe different rooms do different things
    // also adding an optional prefab parameter to allow to overrule the default fallback prefab
    public virtual void SpawnMonster(Monster monsterPrefab = null)
    {
        // if monsterPrefab is not passed in use the defaultMonsterPrefab as fallback instead
        if(monsterPrefab == null)
        {
            monsterPrefab = defaultMonsterPrefab;
        }

        // create the monster instance from the given prefab
        // optionally as a child of he room
        var instance = Instantiate(monsterPrefab, transform);

        // keep track of the created monsters 
        monsters.Add(monster);

        // and react when it gets destroyed
        instance.whenDestroyed.AddListener(OnMonsterDestroyed);
    }

    // make this virtual - maybe different rooms do different / additional things
    protected virtual void OnMonsterDestroyed(Monster monster)
    {
        monsters.Remove(monster);
        CheckAllDestroyed();
    }

    // again making this virtual - maybe there is a special room that has different condition
    // also make this public so you could still check it from somewhere else if needed
    public virtual bool CheckIsCleared()
    {
        if(monsters.Count == 0)
        {
            whenCleared?.Invoke();
            return true;
        }

        return false;
    }
}

Now in the whenAllDestroyed field you can either assign callbacks via the Unity Inspector (like e.g. for Button.onClick) or via code like

someRoom.whenCleared.AddListener(OpenDoor);

By having some methods virtual you could have different room implementations with different behavior. One could e.g. not have monsters at all but simply play some sequence or whatever and automatically call whenCleared after X seconds

  • Related