Design patterns for idenifying type of colliding object

I hop im in the right forum.

I dont have a problem but im rather curious on how you solve identification of what has collided with a certain object. If there are number of enemies that could collide with your player you could have a switch or lots ofif statements to see what the name of the game object is.

This breaks if you change the names. This can be worked around by storing the name of each enemy in a static variable accesable by everyone.

Another way is to try and cast the gameObject to
var monsterType1 = collider.gameObject.GetComponent();
var monsterType2 = collider.gameObject.GetComponent();
var monsterType3 = collider.gameObject.GetComponent();

But this will create a lot of code that is probably unnescesary especially if you have lots of monster types.

So what other ideas are out there? :slight_smile:

Usually you should haven’t to find out what you hit… or in very specific cases, only find out a very basic amount of information of what you hit.

How I usually do this is:

#Entity

  1. create a script called something like ‘Entity’. This script is placed on the root of all entities, the top most GameObject of a hierarchy of GameObjects that represents an object… if you created a ‘prefab’ of this entity, the gameobject that is the prefab would be your root.

You should then be able to ‘GetComponentInParent’ to find the ‘root’ of the entity:

#EntityType
2) Entity might house an enum to give very limited information about said entity. I usually have an enum like this:

public enum EntityType
{
    Generic,
    Player,
    Mob //or Enemy
}

Where generic is just anything… a lamp post, a piece of furniture, etc.
Player is obvious.
And Mob is any enemy or mobile unit.

#Functional Abstraction
3) Now entities that can be interacted with in different ways will have abstracted scripts somewhere in their hierarchy.

Lets say it’s something that can be struck by a weapon… with this scenario we will have a ‘HitBox Collider’ and a ‘HealthMeter’ which contains a ‘Strike(Weapon wpn)’ method.

So our code might be that:

a) OnColliderEnter/OnTriggerEnter we receive Collider that was struck by weapon
b) Test that collider is valid (maybe it has a tag called ‘HitBox’, or if it was set to a special physics layer that only weapon and hitboxes are on), if fail… stop now
c) Get ‘Entity’ script (if not found, stop now)
d) Using ‘GetComponentInChildren’ find the ‘HealthMeter’ (if not found, stop now)
e) Call ‘Strike’ method, passing in the Weapon doing the striking.
f) HealthMeter adjusts its health by the appropriate amount, maybe triggers some UnityEvent that it was struck so animations could be wired up, and if dead calls some other UnityEvent.

You can see this here:

using UnityEngine;
using System.Collections.Generic;

using com.spacepuppy;
using com.spacepuppy.Scenario;
using com.spacepuppy.Utils;

namespace com.mansion.Entities.Weapons
{

    public class MeleeWeapon : SPComponent, IWeapon
    {


        #region Fields

        [SerializeField()]
        [EnumFlags()]
        private IEntity.EntityType _strikableEntity;

        [SerializeField()]
        private float _damage;

        [SerializeField()]
        [Tooltip("This gives a duration of invulnerability to specific entities.")]
        private float _attackCooldownPerEntity = 0f;

        [SerializeField]
        private float _delayActivate = 0f;
        [SerializeField]
        private float _delayDeactivate = 0.1f;

        [SerializeField()]
        private Trigger _onStrike;
        [SerializeField()]
        private Trigger _onKilled;

        [System.NonSerialized()]
        private IEntity _entity;

        [System.NonSerialized()]
        private com.spacepuppy.Collections.CooldownPool<IEntity> _attackCooldownPool = new spacepuppy.Collections.CooldownPool<IEntity>();

        #endregion

        #region CONSTRUCTOR

        protected override void Awake()
        {
            base.Awake();

            _entity = SPEntity.Pool.GetFromSource<IEntity>(this);
        }

        #endregion

        #region Properties

        public float AttackCooldownPerEntity
        {
            get { return _attackCooldownPerEntity; }
            set { _attackCooldownPerEntity = value; }
        }

        public float DelayActivate
        {
            get { return _delayActivate; }
            set { _delayActivate = value; }
        }

        public float DelayDeactivate
        {
            get { return _delayDeactivate; }
            set { _delayDeactivate = value; }
        }

        #endregion

        #region Messages

        protected void OnTriggerEnter(Collider c)
        {
            var e = SPEntity.Pool.GetFromSource<IEntity>(c);
            if (e == null) return;
            if (e == _entity) return; //can't strike self

            _attackCooldownPool.Update();
            if (_attackCooldownPool.Contains(e)) return;

            if (EnumUtil.HasFlag(_strikableEntity, e.Type))
            {
                if (e.HealthMeter != null)
                {
                    if (e.HealthMeter.Strike(this))
                    {
                        _onKilled.ActivateTrigger(this, null);
                    }
                    else
                    {
                        _onStrike.ActivateTrigger(this, null);
                    }
                }
                if (_attackCooldownPerEntity > 0f) _attackCooldownPool.Add(e, _attackCooldownPerEntity);
            }
        }

        #endregion

        #region IWeapon Interface

        public float Damage
        {
            get { return _damage; }
            set { _damage = value; }
        }

        #endregion


    }

}

A base class with an enum. Thats brilliant! Love it. :slight_smile: