I give up.....call to SendMessage on object can't find the specified message handler.

I have a button with an attached script that calls SendMessage(…) on an attached object when clicked with the mouse.

See m_gameobjPatternManager.SendMessage(“DoChangePattern”, (int)m_enPattern); in function OnMouseDown() in the first code snippet below.

The gameobject attached to my member gameobjPatternManager in the first code snippet has the script, specified in the second code snippet below, attached to it.

That code snippet clearly has a function called DoChangePattern(enPattern enPatternID).

So why am I getting this infernal error when I try to run my program?

SendMessage DoChangePattern has no receiver!
UnityEngine.GameObject:SendMessage(String, Object)
SaveButtonManager:OnMouseDown() (at Assets/Buttons/SaveButtonManager.cs:40)
UnityEngine.SendMouseEvents:smile:oSendMouseEvents(Int32)

Why can’t SaveButtonManager see function DoChangePattern(enPattern enPatternID) in PatternManager?

using UnityEngine;
using System.Collections;

publicclassSaveButtonManager:MonoBehaviour
{
     publicSpritem_spritePressed,m_spriteUnpressed;
     publicGameObjectm_gameobjPatternManager,m_gameobjOptions,m_gameobjBingo;

     privateenumenPattern{NONE, CORNERS, X, ROW, COL, ROW2, COL2, FULL};
     privateenPatternm_enPattern=enPattern.NONE;

     privateSpriteRendererm_spriterender;

     //Usethisfor initialization
     voidStart()
    {
         m_spriterender=(SpriteRenderer)GetComponent("SpriteRenderer");
    }

    //Updateiscalledonceper frame
     voidUpdate()
     {
     }

     voidDoChangePattern(enPatternenPatternID)
     {
        m_enPattern=enPatternID;
        Debug.Log(m_enPattern);
     }

     voidRestoreButton()
     {
         m_spriterender.sprite=m_spriteUnpressed;
     }

     voidOnMouseDown()
     {
         m_spriterender.sprite=m_spritePressed;
         Invoke("RestoreButton",0.5f);
         m_gameobjPatternManager.SendMessage("DoChangePattern",(int)m_enPattern);
         //Debug.Log(m_enPattern);
         m_gameobjOptions.SetActive(false);
         m_gameobjBingo.SetActive(true);
     }
}

*****************************************************************************************************************

using UnityEngine;
using System.Collections;

public class PatternManager : MonoBehaviour
{
    private int m_nMax = 5;
    private int m_nColRowStart = 0;
    private bool m_bChangePattern = true;
    private float m_fDeltaTime = 0.0f;

    private enum enPattern {NONE, CORNERS, X, ROW, COL, ROW2, COL2, FULL};
    private enPattern m_enPattern = enPattern.NONE;

    public GameObject m_gameobjCounter1;
    public GameObject m_gameobjCounter2;
    public GameObject m_gameobjCounter3;
    public GameObject m_gameobjCounter4;
    public GameObject m_gameobjCounter5;
    public GameObject m_gameobjCounter6;
    public GameObject m_gameobjCounter7;
    public GameObject m_gameobjCounter8;
    public GameObject m_gameobjCounter9;
    public GameObject m_gameobjCounter10;
    public GameObject m_gameobjCounter11;
    public GameObject m_gameobjCounter12;
    public GameObject m_gameobjCounter13;
    public GameObject m_gameobjCounter14;
    public GameObject m_gameobjCounter15;
    public GameObject m_gameobjCounter16;
    public GameObject m_gameobjCounter17;
    public GameObject m_gameobjCounter18;
    public GameObject m_gameobjCounter19;
    public GameObject m_gameobjCounter20;
    public GameObject m_gameobjCounter21;
    public GameObject m_gameobjCounter22;
    public GameObject m_gameobjCounter23;
    public GameObject m_gameobjCounter24;
    public GameObject m_gameobjCounter25;
    public float m_fChangePatternTimer = 1000.0f;

    int GetCounterNumber(int nRow, int nCol)
    {
        return (nRow * 5) + nCol + 1;
    }

    GameObject GetCounterGameObject(int nRow, int nCol)
    {
        int nCounterNumber = GetCounterNumber(nRow, nCol);
        GameObject gameobj = m_gameobjCounter1;

        switch(nCounterNumber)
        {
            case 1:
                gameobj = m_gameobjCounter1;
                break;
            case 2:
                gameobj = m_gameobjCounter2;
                break;
            case 3:
                gameobj = m_gameobjCounter3;
                break;
            case 4:
                gameobj = m_gameobjCounter4;
                break;
            case 5:
                gameobj = m_gameobjCounter5;
                break;
            case 6:
                gameobj = m_gameobjCounter6;
                break;
            case 7:
                gameobj = m_gameobjCounter7;
                break;
            case 8:
                gameobj = m_gameobjCounter8;
                break;
            case 9:
                gameobj = m_gameobjCounter9;
                break;
            case 10:
                gameobj = m_gameobjCounter10;
                break;
            case 11:
                gameobj = m_gameobjCounter11;
                break;
            case 12:
                gameobj = m_gameobjCounter12;
                break;
            case 13:
                gameobj = m_gameobjCounter13;
                break;
            case 14:
                gameobj = m_gameobjCounter14;
                break;
            case 15:
                gameobj = m_gameobjCounter15;
                break;
            case 16:
                gameobj = m_gameobjCounter16;
                break;
            case 17:
                gameobj = m_gameobjCounter17;
                break;
            case 18:
                gameobj = m_gameobjCounter18;
                break;
            case 19:
                gameobj = m_gameobjCounter19;
                break;
            case 20:
                gameobj = m_gameobjCounter20;
                break;
            case 21:
                gameobj = m_gameobjCounter21;
                break;
            case 22:
                gameobj = m_gameobjCounter22;
                break;
            case 23:
                gameobj = m_gameobjCounter23;
                break;
            case 24:
                gameobj = m_gameobjCounter24;
                break;
            case 25:
                gameobj = m_gameobjCounter25;
                break;
        }
        return gameobj;
    }

    void ShowCell(int nRowNum, int nColNum, bool bShow = true)
    {
        if ((nRowNum >= 0) && (nRowNum < m_nMax) && (nColNum >= 0) && (nColNum < m_nMax))
        {
            GameObject gameobj = GetCounterGameObject(nRowNum, nColNum);
            gameobj.SetActive(bShow);
        }
    }

    void ShowRow(int nRowNum, bool bShow = true)
    {
        for (int nColNum = 0; nColNum < m_nMax; nColNum++)
        {
            ShowCell(nRowNum, nColNum, bShow);
        }
    }

    void ShowCol(int nColNum, bool bShow = true)
    {
        for (int nRowNum = 0; nRowNum < m_nMax; nRowNum++)
        {
            ShowCell(nRowNum, nColNum, bShow);
        }
    }

    void ShowDiag(int nRowStart, int nColStart, bool bShow = true)
    {
        if (nRowStart > 0)
        {
            for (int nRow = nRowStart, nCol = nColStart; (nRow >= 0) && (nCol < m_nMax); nRow--, nCol++)
            {
                ShowCell(nRow, nCol, bShow);
            }
        }
        else
        {
            for (int nRow = nRowStart, nCol = nColStart; (nRow < m_nMax) && (nCol < m_nMax); nRow++, nCol++)
            {
                ShowCell(nRow, nCol, bShow);
            }
        }
    }

    void ClearPattern()
    {
        for (int nRowNum = 0; nRowNum < m_nMax; nRowNum++)
        {
            ShowRow(nRowNum, false);
        }
    }

    void DoX()
    {
        if (m_bChangePattern)
        {
            m_bChangePattern = false;
            ClearPattern();
            ShowDiag (0, 0, true);
            ShowDiag (4, 0, true);
        }
    }

    void DoCol()
    {
        ClearPattern();
        ShowCol(m_nColRowStart, true);
        m_nColRowStart++;
        if (m_nColRowStart == m_nMax)
            m_nColRowStart = 0;
    }

    void Do2Cols()
    {
        ClearPattern();
        if ((m_nColRowStart + 1) < m_nMax)
        {
            ShowCol(m_nColRowStart, true);
            ShowCol(m_nColRowStart + 1, true);
        }
        else
        {
            ShowCol(m_nColRowStart, true);
            ShowCol(0, true);
        }
        m_nColRowStart++;
        if (m_nColRowStart == m_nMax)
            m_nColRowStart = 0;
    }

    void DoRow()
    {
        ClearPattern();
        ShowRow(m_nColRowStart, true);
        m_nColRowStart++;
        if (m_nColRowStart == m_nMax)
            m_nColRowStart = 0;
    }

    void Do2Rows()
    {
        ClearPattern();
        if ((m_nColRowStart + 1) < m_nMax)
        {
            ShowRow(m_nColRowStart, true);
            ShowRow(m_nColRowStart + 1, true);
        }
        else
        {
            ShowRow(m_nColRowStart, true);
            ShowRow(0, true);
        }
        m_nColRowStart++;
        if (m_nColRowStart == m_nMax)
            m_nColRowStart = 0;
    }

    void DoFull()
    {
        if (m_bChangePattern)
        {
            m_bChangePattern = false;
            for (int nRow = 0; nRow < m_nMax; nRow++)
                ShowRow (nRow, true);
        }
    }

    void DoCorners()
    {
        if (m_bChangePattern)
        {
            m_bChangePattern = false;
            ClearPattern ();
            ShowCell (0, 0, true);
            ShowCell (0, 4, true);
            ShowCell (4, 0, true);
            ShowCell (4, 4, true);
        }
    }

    // Use this for initialization
    void Start()
    {
    }
   
    void DoUpdatePattern()
    {
        switch (m_enPattern)
        {
            case enPattern.CORNERS: DoCorners(); break;
            case enPattern.X: DoX(); break;
            case enPattern.ROW: DoRow(); break;
            case enPattern.COL: DoCol(); break;
            case enPattern.ROW2: Do2Rows(); break;
            case enPattern.COL2: Do2Cols(); break;
            case enPattern.FULL: DoFull(); break;
        }
    }

    // Update is called once per frame
    void Update()
    {

        if (Input.GetKeyDown("1"))
        {
            m_bChangePattern = true;
            m_enPattern = enPattern.CORNERS;
            DoUpdatePattern();
        }
        else if (Input.GetKeyDown("2"))
        {
            m_bChangePattern = true;
            m_enPattern = enPattern.X;
            DoUpdatePattern();
        }
        else if (Input.GetKeyDown("3"))
        {
            m_enPattern = enPattern.ROW;
            DoUpdatePattern();
        }
        else if (Input.GetKeyDown("4"))
        {
            m_enPattern = enPattern.COL;
            DoUpdatePattern();
        }
        else if (Input.GetKeyDown("5"))
        {
            m_enPattern = enPattern.ROW2;
            DoUpdatePattern();
        }
        else if (Input.GetKeyDown("6"))
        {
            m_enPattern = enPattern.COL2;
            DoUpdatePattern();
        }
        else if (Input.GetKeyDown("7"))
        {
            m_bChangePattern = true;
            m_enPattern = enPattern.FULL;
            DoUpdatePattern();
        }

        m_fDeltaTime += Time.deltaTime;
        if (m_fDeltaTime >= 1.5f)
        {
            m_fDeltaTime = 0.0f;
            DoUpdatePattern();
        }
    }

    void DoChangePattern(enPattern enPatternID)
    {
        m_enPattern = enPatternID;
    }

}

PatternManager.DoChangePattern is defined as taking 1 argument of type ‘enPattern’.

When you call ‘SendMessage’ you do so with the following:

m_gameobjPatternManager.SendMessage("DoChangePattern",(int)m_enPattern);

Note how you cast ‘m_EnPattern’ to an int.

It’s not finding the correct method based on the type of the argument passed in, because no ‘DoChangePattern’ exists that takes an int, only one that takes an ‘enPattern’.

Or so I assume. I don’t particularly use ‘SendMessage’ very much, but I would not be surprised if it’s type sensitive when it comes to the argument. Otherwise how would it choose between methods if there were multiple overloads…

Do you need SendMessage? ExecuteEvents is the modern replacement and tends to be better in most situations. At the very least it will throw compile time errors instead of runtime errors.

I didn’t read down far enough in the explanation for SendMessage(…)
It won’t work on inactive gameobjects, and the gameobject I was trying to send the message to was inactive.
All I had to do was re-order the function calls, SendMessage(…) and SetActive(…), and it worked.

1 Like

SendMessage also as a final bool parameter which when set to false it won’t error when it doesn’t find functions to latch to.

I, however, prefer to use interfaces. its more direct to the reader in whats going on and is far faster. its just more code