SendMessage is not working and I wonder if it’s because I’m running it with an editor script? The object is active. Anybody know why this wouldn’t work?
[MenuItem("Test")]
static void Test(){
GameObject obj = AssetDatabase.LoadAssetAtPath<GameObject>("somePath");
Debug.LogError(obj.activeSelf);
obj.GetComponent<MyTestScript>().Hi();
obj.SendMessage("Hi", null, SendMessageOptions.RequireReceiver );
}
Output:
True
Hi
SendMessage Hi has no receiver!
public class MyTestScript : MonoBehaviour{
public void Hi(){
Debug.LogError("Hi");
}
}
I don’t know the answer to the question exactly, but I’ve been working with Unity for more than 10 years and I’ve never used SendMessage, not once. It’s not marked as deprecated, but it is IMO an outdated, slow and error inducing design that’s been replaced by much better solutions.
You already have a reference to your component, why not call the method directly? SendMessage has to parse the string and dynamically invoke the message handler with an untyped argument. Or, if you really want the message pattern (to invoke the message handler on all components), use EventSystems.
AFAIK SendMessage only works for objects in the scene, but to be honest, I have never tried using it on assets. It seems a strange usage to be honest ^^. “activeSelf” only checks the setting of the object itself. To see if an object is actually active you should always use activeInHierarchy and I’m quite sure it probably will return false.
*** edit ***
Since I just had Unity open in the background I quickly created a test case and yes, activeInHierarchy returns false for assets since they are not active in the scene. Therefore assets can not receive messages.
Why do you even want to use SendMessage? Calling the method directly has several advantages. You don’t have a hardcoded string binding, the calling will be faster. You are not limited to a single parameter. You have more control over who actually receives the message. If you want a more general way of calling a certain method you can use interfaces to abstract this concept. So your target script simply implements that interface.
public interface ICanSayHi
{
void Hi();
}
// [ ... ]
public class MyTestScript : MonoBehaviour, ICanSayHi
{
public void Hi()
{
Debug.LogError("Hi");
}
}
// [ ... ]
if (obj.TryGetComponent<ICanSayHi>(out ICanSayHi csh))
{
csh.Hi();
}