Search code examples
c#artificial-intelligenceunity-game-engineragdoll

Cannot assign "Death" because its a method group


I have recently started to learn c# but I have encountered an error which I hope some of you will be able to help me with. We are developing a game in Unity5 and when the players health hits 0 the rag-doll function will kick in but unfortunately I cannot call death as it is a method group... Any ideas? Cheers. Here is the code(I commented it out so I could enter play mode in Unity because the error wasn't letting me in line 47 and 53):

using UnityEngine;
using System.Collections;

public class EnemyAI_Basic : MonoBehaviour
{
    private EnemyAI_Basic enemyAI_Basic;
    Animator controller;
    float health;
    Animator anim;
    bool Alive = true;
    public bool Dead = false;
    int pointValue = 5;
    private Collider myCollider;
    private Rigidbody myRigidbody;

    CapsuleCollider capsuleCollider;


    void Start()
    {
        controller = GetComponentInParent<Animator>();
        health = 40;
        capsuleCollider = GetComponent<CapsuleCollider>();
        anim = GetComponent<Animator>();
    }

    void Update()
    {
        if (!Dead)
        {
            anim.SetTrigger("Alive");
        }
    }

    void Death()
    {
        Dead = true;
        Alive = false;
        capsuleCollider.isTrigger = true;
        anim.SetTrigger("Dead");
        Destroy(gameObject, 4f);
    }

    void OnEnable()
    {
        SetInitialReferences();
        enemyAI_Basic.Death += ActivateRagdoll;
    }


    void OnDisable()
    {
        enemyAI_Basic.Death -= ActivateRagdoll;
    }

    void SetInitialReferences()
    {
        enemyAI_Basic = transform.root.GetComponent<EnemyAI_Basic>();

        if (GetComponent<Collider>() != null)
        {
            myCollider = GetComponent<Collider>();
        }

        if (GetComponent<Rigidbody>() != null)
        {
            myRigidbody = GetComponent<Rigidbody>();
        }

    }

    void ActivateRagdoll()
    {
        if (myRigidbody != null)
        {
            myRigidbody.isKinematic = false;
            myRigidbody.useGravity = true;
        }

        if (myCollider != null)
        {
            myCollider.isTrigger = false;
            myCollider.enabled = true;
        }
    }
}

Solution

  • I see your problem. You're treating the death method like a delegate, which it isn't, in this case. You can only register methods to either delegates or events, you can't register methods to method groups. For your situation, there are a few ways to resolve this.

    First solution, and by far the easiest, put in a call to ActivateRagdoll inside the Death function, like so:

    void Death()
    {
        Dead = true;
        Alive = false;
        capsuleCollider.isTrigger = true;
        anim.SetTrigger("Dead");
        ActivateRagdoll();
        Destroy(gameObject, 4f);
    }
    

    Then remove the:

    enemyAI_Basic.Death += ActivateRagdoll;
    

    and

    enemyAI_Basic.Death -= ActivateRagdoll;
    

    from the OnEnable and OnDisable methods, that should remove any compiler errors. Now, in order to use this method, all you have to do is call it from somewhere in code. Depending on how you kill the Ai, you may consider making that method public, or have some death logic inside your update loop,

    if(health <= 0)
    {
       Death();
       enabled = false;  //disable the component so the update loop doesn't repeat the death procedure multiple times, Unity might not be pleased.
    }
    

    The other way, and the way that you're trying to do it, is to create an event that classes can subscribe methods to. This event will call all of the subscribed methods, providing them with a means of being notified, whenever something interesting happens, like the Ai dying in this case. This can be useful for external classes that shouldn't have to constantly check the death status of the Ai, after all, they may not be concerned with the Ai if its on full health. They only need to know, when the Ai does die. Events are ideal for this situation.

    To make an event you'll be doing something like this:

    public class EnemyAI_Basic : MonoBehaviour
    {
        //your other variables
    
        public delegate void EnemyDies();  //declare the method types that can be registered to the event
    
        public event EnemyDies onEnemyDeath; //declare event, using the delegate for the method type
    
        //other methods here
    
        private void OnEnable()
        {
            //must be the same method type as the event, the compiler will let you know if it isn't
            onEnemyDeath += Death;
            onEnemyDeath += ActivateRagdoll;            
        }
    
        private void OnDisable()
        {
            onEnemyDeath -= Death;
            onEnemyDeath -= ActivateRagdoll;
        }
    
        //other things here
    
        //doesn't have to be public, just in case you want a bullet to kill the enemy
        public void KillAi()
        {
            //checking for null basically says: is anybody registered? If not, nothing to invoke. 
            //It will get upset if you try and invoke an event without any registered methods, hence the check.
            if(onEnemyDeath != null)
            {
                onEnemyDeath();
            }
        }
    
        void Death()
        {
           Dead = true;
           Alive = false;
           capsuleCollider.isTrigger = true;
           anim.SetTrigger("Dead");
           //ActivateRagdoll();   You don't have to manually call this now, invoking the event will call it for you.
           //Registration order is important, me thinks. Experiment :)
           Destroy(gameObject, 4f);
        }
    }
    

    There are several other ways to rig up a system like this, but, in your case this may be what you're after.

    Some reading:

    Events: https://www.codeproject.com/Articles/11541/The-Simplest-C-Events-Example-Imaginable https://www.tutorialspoint.com/csharp/csharp_events.htm

    Delegates: https://msdn.microsoft.com/en-us/library/ms173171.aspx

    Method groups: What is a method group in C#?

    Hopefully this helps.