- Home /
test for SendMessage target existance
Hi,
is there an easy way to test in code, whether a target game object received a message via SendMessage (implemented the message function)?
I want to write some kind of event system, where events are sent to child gameobject's and the "bubble upwards" until they got delivered successfull.
As I see it, "SendMessageUpwards" will always deliver messages and does not stop sending the message if one game object received the message successfully.
I am more fluent in code. So an example:
public class Parent : MonoBehaviour
{
void OnFoobar()
{
// not called, since Child does implement OnFoobar as well
}
void OnBarfoo()
{
// will be called, since Child does not implement OnBarfoo
}
}
// not a child in terms of inheritance, but in terms of "transform.parent"
public class Child : MonoBehaviour
{
void OnFoobar()
{
}
}
// meanwhile somewhere else..
var childObj = GameObject.Find("...");
childObj.MyUberSendMessageUpwards("OnFoobar") // will only call Child.OnFoobar
childObj.MyUberSendMessageUpwards("OnBarfoo") // will only call Parent.OnBarfoo
I could implement "MyUberSendMessageUpwards" by myself, if I had an easy way to test whether the target game object actually received the message.
place a Debug.Log("Youhou it works"); inside the functions you are calling. If the message is received the message will show up in the console.
That's not the point. I want to check for the existance from within code at runtime.
Answer by aldonaletto · Apr 06, 2012 at 05:34 PM
SendMessage and similar functions don't give us any useful clue about the receivers - they only print a message error, but don't throw an exception (I tried the try-catch approach). Maybe some .NET feature could help you to write your own SendMessage, like InvokeMember (take a look at this article).
Another possibility - a lot less flexible, for sure - would be to use a static boolean flag and call SendMessage (with DontRequireReceiver option) for each parent. The function called via SendMessage should set this variable to true, signalling that a receiver was found and the loop could be ended - something like this:
// script SendMessageUp.js:
static var receiverFound: boolean;
function SendMsgUp(trf:Transform, func: String){
receiverFound = false; // initialize flag
while (!receiverFound && trf.parent){ // while flag==false and there's a parent...
trf = trf.parent; // go one level above in the hierarchy
// try to call the specified function
trf.SendMessage(func, SendMessageOptions.DontRequireReceiver);
// if receiver found, the function sets receiverFound to true
}
}
// Example call:
SendMsgUp(someObject.transform, "AnyFunction");
Remember that the function called must set receiverFound to true:
function AnyFunction(){ SendMessageUp.receiverFound = true; // code of AnyFunction }
Thank you for your suggestions. Your first idea is basically a re-implementation of Send$$anonymous$$essage. I hoped not to have to do this, but in the end, its probably not that bad either. Does anyone know whether I might run into problems with security access on web-platforms when calling private functions over reflection?
Your second solution is nice as well, but it has a couple of problems. First as you already mentioned, the receiver must not forget to set the boolean. Second it is not working with messages sent while other messages are delivered. An slightly different version would be to pass an event object as parameter that has some "handled" boolean field and require functions to set this to true ins$$anonymous$$d of the global static. This uses the parameter (so its not free for different use anymore) but does not have the second problem.
I'll leave the question unanswered a bit longer, maybe someone got another nice idea?
I think you will not have problems with messages setting the boolean while others are being sent. As far as I know, calling functions with Send$$anonymous$$essage is much like calling a local function: when any target function is found, it's immediately executed, and control is returned to Send$$anonymous$$essage only when the target function ends.
This feature is explored in the First Person Tutorial when shooting a character: the character's ApplyDamage is first called via Send$$anonymous$$essage, then the impact or explosion force is applied. If the character dies, ApplyDamage replaces it with a ragdoll - and this ragdoll receives the impact/explosion force, showing that the whole ApplyDamage function was executed before Send$$anonymous$$essage returned.
Answer by b1gry4n · Jun 09, 2018 at 02:33 AM
just realized this question is from 2012...oh well...
Maybe youre over thinking? Im sorry if im misunderstanding the question. If a child receives a message and has the receiver, that is your way of knowing if the child received the message.
this is my setup, each object has the "BubbleUp" script attached here is a script demonstrating how a message can be sent to a child object and have it "bubble up" to the parent. In the script the parent will send a message to the last child
using UnityEngine;
public class BubbleUp : MonoBehaviour {
[HideInInspector]
public int childIndex;
BubbleUp[] children;
bool isParent = false;
private void Start()
{
if (transform.parent == null)
{
isParent = true;
this.gameObject.name = "Parent";
children = GetComponentsInChildren<BubbleUp>();
for (int i = 0; i < children.Length; i++)
{
children[i].childIndex = i + 1;
children[i].gameObject.name = "Child" + children[i].childIndex.ToString();
}
children[children.Length - 1].SendMessage("Receiver", this.gameObject.name);
}
}
public void Receiver(string from)
{
if (!isParent)
{
Debug.Log(this.gameObject.name + " received message from " + from);
transform.parent.SendMessage("Receiver", from + " / " + this.gameObject.name);
}
else
{
Debug.Log(this.gameObject.name + " is the parent and received message from " + from);
}
}
}
and here is the result
Your answer
