• Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
avatar image
2
Question by Statement · Mar 29, 2011 at 08:06 PM · errorsendmessage

Suggested workaround for SendMessage bug?

I ran into a problem with SendMessage. I was trying to make a message based targeting system for a question here at answers.unity3d.com. The problem is that when I attempt to pass a null parameter value into SendMessage, I get this quite unexpected message:

Failed to call function Test of class SendMessageReceiver Calling function Test with no parameters but the function requires 1.

  • UnityEngine.Component:SendMessage(String, Object)
  • SendMessageSender:Main() (at Assets/SendMessageNullTest/SendMessageSender.js:1)

I want to be able to send null values to clear out the current target but obviously this won't work for now. I sent a bug report to Unity3D. For the sake of simplicity, which workaround do you think is best, and why?

  • Add a new func called SetTarget that doesn't accept any params and handle null case.
  • Add a new func called ClearTarget that doesn't accept any params thats called when target is null.
  • Add a new type called TargetEvent that provides the value and pass that to SendMessage instead.
  • Other workaround I haven't thought of?

Below is the culprit code.


SendMessageSender.js

SendMessage("Test", null);

SendMessageReceiver.js

// This function isn't even called...
function Test(actual : GameObject) {
    if (actual == null)
        print ("Test PASSED!");
    else 
        print ("Test FAILED! (Expected null)");
}
Comment
Add comment · Show 4
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Statement · Mar 29, 2011 at 08:45 PM 0
Share

By the way, the question I answered is here: http://answers.unity3d.com/questions/47753/choosing-from-multiple-characters/49278#49278

avatar image Justin Warner · Mar 29, 2011 at 09:26 PM 0
Share

$$anonymous$$ake an actual "null" object and pass that through in place of null itself? =)

avatar image Statement · Mar 29, 2011 at 09:41 PM 0
Share

I could always make them target themselves :)

avatar image Justin Warner · Mar 29, 2011 at 10:02 PM 0
Share

That'd be just as well, haha.

3 Replies

· Add your reply
  • Sort: 
avatar image
2
Best Answer

Answer by Skjalg · Mar 29, 2011 at 08:28 PM

I reproduced the error with these c# scripts:

using UnityEngine;

public class TestSendMessage : MonoBehaviour { public GameObject SendMessageTarget;

 public void Start()
 {
     if (SendMessageTarget)
     {
         SendMessageTarget.SendMessage("Test", (GameObject)null);
     }
 }

}

and

using UnityEngine;

public class SendMessageReceiver : MonoBehaviour { public void Test(GameObject gameObject) { if (gameObject == null) { Debug.Log("passed"); } else { Debug.Log("failed, expected null"); } } }

The workaround I would use is to have two methods that you send messages to:

SetValidTarget(GameObject target);

ClearTarget();

It will make your code easier to read. Consider these two scenarios:

private void ProperWay() { if (SendMessageTarget) { SendMessage(SendMessageTarget, Target); } }

private static void SendMessage(GameObject sendMessageTarget, GameObject target) { if (target) { sendMessageTarget.SendMessage("SetValidTarget", target); } else { sendMessageTarget.SendMessage("ClearTarget"); } }

against

private void ImproperWay() { if (SendMessageTarget) { TargetWrapper wrapper = new TargetWrapper(Target); SendMessageTarget.SendMessage("SetValidTarget", wrapper); } }

public class TargetWrapper { public GameObject Target;

 public TargetWrapper(GameObject target)
 {
     Target = target;
 }

}

Try to imagine reading this code in a year or two.

The first way will immediately tell you that if you have the SendMessageTarget you will send a message to it, and on closer inspection you get a glimpse that if the gameobject is null you will clear the target on the other end (readability).

The second way however, will only tell you that if you have the SendMessageTarget you will send a message to it, not knowing if the null possibility is handled on the other side or not, only that you wrap it in a class. (By this point in time you might have even forgotten why you have wrapped it in a class, thinking yourself stupid for not removing it earlier, since it might be some left over code, you will remove that wrapper only to experience the same error you have now and have wasted a good 15 minutes.


*On a side note:

I would also suggest that you make an interface, then have all your classes that has a target implement this interface, then instead of using gameObject.SendMessage you can use gameObject.getComponents< TargetInterface >() and loop through that list and using the methods provided by the interface to do what you wish, since I have found that provides a significant speed increase to the fps.*

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Mike 3 · Mar 29, 2011 at 08:42 PM 1
Share

You actually can't do GetComponents(). GetComponents(typeof(Interface)) will work, but it'll spam error logs at you at runtime for objects not implementing the interface

avatar image Statement · Mar 29, 2011 at 08:44 PM 0
Share

I fully agree and didn't notice at first anyone replied when I came to the same conclusion and actually answered my own question.

avatar image Skjalg · Mar 29, 2011 at 08:50 PM 0
Share

Ah yes, you are correct about the interface. I normally just make an abstract class that inherits from monobehaviour and the interface, then do the getcomponents on that abstract class.

avatar image
1

Answer by Mike 3 · Mar 29, 2011 at 08:18 PM

Weird hack to get around it:

var go = GameObject.Find("GameObject which doesn't exist");
SendMessage("Test", go);

This works because GameObject.Find will always return an object, it just evaluates to null with the overloaded boolean operators

My bet is that you could store a reference (a static one maybe?) to the above gameobject reference and use that for the calls

Anyway, aside from that, I also like the idea of passing a wrapper object which stores your value

Either way - bug report it, that's fairly bad

Comment
Add comment · Show 4 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Skjalg · Mar 29, 2011 at 08:30 PM 0
Share

I would not recommend using GameObject.Find since it is a fairly slow procedure, also, even though passing a wrapper object is a good idea it will not only be slower than sending a different message (i.e ClearTarget), since it needs to pass a value to the object it will also reduce the readability of the code.

avatar image Mike 3 · Mar 29, 2011 at 08:41 PM 0
Share

As I said - do it once (in the entire app). Passing a wrapper object will be a LOT faster than calling a second object. Two reflection calls are far slower than one reflection call passing a reference

avatar image Statement · Mar 29, 2011 at 08:48 PM 0
Share

Well that is weird! :D +1 For random workaround :)

avatar image Fattie · Jul 05, 2015 at 08:47 AM 0
Share

Funnily enough $$anonymous$$ike, that doesn't work in UNity5 if you're passing an Action. Who knows!

avatar image
1

Answer by DaveA · Mar 29, 2011 at 08:34 PM

I would make a ClearTarget() function. Interesting note though from Skjalg, I would have thought that SendMessage did that same thing, and be very optimized about it as well, but if not, that's a good idea.

Comment
Add comment · Show 1 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image Skjalg · Mar 29, 2011 at 08:39 PM 0
Share

I think it bares some further research. If someone would take it upon themselves to research it I know I would be very glad to read the results :)

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Welcome to Unity Answers

If you’re new to Unity Answers, please check our User Guide to help you navigate through our website and refer to our FAQ for more information.

Before posting, make sure to check out our Knowledge Base for commonly asked Unity questions.

Check our Moderator Guidelines if you’re a new moderator and want to work together in an effort to improve Unity Answers and support our users.

Follow this Question

Answers Answers and Comments

No one has followed this question yet.

Related Questions

Remmember the spawner 2 Answers

Using Struct to SendMessage - Number of parameters error. 1 Answer

Rigidbody and collider Sendmessage delay error 1 Answer

SendMessage illogical errors 0 Answers

SendMessage StartSending has no receiver! 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges