Skip to content

Enemy Physical Collision

In our game we have made enemies move around and we’ve connected collision to player, enemies and bullets.
However one thing we still needed was to damage the player upon physical contact with an enemy.

As I hadn’t done collision in Unity/C# yet, I looked into what I’d need in order to make the collision work.

Monobehavior

Both Player and Enemy classes have the Monobehavior class which we use for basic Unity/C# functions.
It also has the perfect function for detecting collisions, namely OnTriggerEnter2D(Collider2D).

Using this function we can detect when a 2D object triggers another object’s collider trigger, which in turn is connected to the object’s Collider2D script or RigidBody2D script.
In the Enemy script we put OnTriggerEnter2D() and give it a Collider2D parameter called “collision”. This parameter gets used to check the information from this collision in the function itself.

Another problem occurred though, the collision did not discern between the player and other enemies. So we needed a check to see if the object hit was indeed the player. For that we decided to use the LayerMasks.

LayerMask

LayerMasks are a way for us to be able to manipulate different GameObjects on different layers in the exact manner we want.
While there are several options, like searching for specifically named GameObjects like “player”, LayerMasks are faster and more dynamic.

When an enemy is created, we assign it to the enemy layer with the LayerMask “Enemy” like so:

public void Initialize()
    {
        gameObject.layer = LayerMask.NameToLayer("Enemy");
        ...
    }

The player also gets assigned to a layer in a similar manner in the Player.cs->Create function:

    player.gameObject.SetLayerByName("Player");

So now we know that we can use LayerMasks, but we still need to get the information as to what layer is which from the Enemy class.
We could define the player in each enemy created, but we opted to use one of our interfaces instead.

Our IWeaponUser interface has the variables PlayerMask and EnemyMask which hold the LayerMask data like so:

public static LayerMask EnemyMask => 1 << LayerMask.NameToLayer("Enemy");
public static LayerMask PlayerMask => 1 << LayerMask.NameToLayer("Player");

The neat part about interfaces is that it allows you to call the data in other scripts. So we call on the IWeaponUser. PlayerMask in order to get the player’s LayerMask since it’s the one with the RigidBody2D.

Then we use the ContainMask function in order to check if the PlayerMask and EnemyMask have overlap.

Lastly we use the TryGetComponent from the Collision2D “collision” element in order to get the get the object in the collision (in this case the Player).

And with all that we finally use another interface called IDamageable to trigger a damage function and reduce the health of the player.

Final result

The final result of all that is listed above is as follows:

protected virtual void OnTriggerEnter2D(Collider2D collision)
    {
        //Debug.Log("Test");
        if (IWeaponUser.PlayerMask.ContainsLayer(collision.gameObject.layer))
        {
            if (collision.TryGetComponent(out IDamageable d))
            {

                d.Damage(damage);
            }
        }
    }

And in the slidingEnemy class we call on the base (Enemy.cs)’s OnTriggerEnter2D like this:

protected override void OnTriggerEnter2D(Collider2D collision)
    {
        base.OnTriggerEnter2D(collision);
        ...
    }

Possible improvements

Possible improvements could be:

  • Knockback on getting physically hit
  • Invulnerability frames after being hit

These might be addressed at a later time.

Sources:

  • OnTriggerEnter2D Unity Documentation - Bron
  • MonoBehavior Unity Documentation - Bron
  • Marwan

Last update: May 25, 2023