I have a central C# script that handles many different functions and I’d like it to be able to ping various different script as needed (mostly Javascript, although another C# script, too.)
So basically, I’d like this (pseudo-code)
In the Central c# function (let’s call it CentralScript)
public void RegisterCallBackForEvent( function passedFunction ) {
ArrayWithEventFunctions[xx] = passedFunction;
}
public void EventThatNeedsCommunicating() {
for all passedFunction in ArrayWithEventFunctions {
Invoke(passedFunction);
}
}
In the other JS / C# scripts
function HandleEvent() {
... do stuff ...
}
Function Start() {
CentralScript.RegisterCallBackForEvent( HandleEvent() );
}
Is this something that can be done, and if so, any easy to follow examples out there?
So the question is essentially can UnityScript functions be accepted as delegates by C#, I take it ?
All I can tell you is that I’ve avoided doing it because I’m terrified of the disconnect between UnityScript and C#, particularly when it comes to differing typing strengths.
I might give it a go tho. I take it you’re running into some brick wall or another tho? Does that mean you’ve tried this and it doesn’t work?
I’m in the middle of implementing Game Center into my iphone app. Now Game Center authentication can be available or not depending on a bunch of different conditions (user logs out explicitly via the Center while your app is in the background, user’s app loses network signal, etc.)
I have some UI elements that are only applicable to GC. Apple’s guidelines (rightly so) say that if GC isn’t available for whatever reason those UI and other elements that depend on GC shouldn’t be shown and/or available to the user.
So for me, I have a c# script where I handle all of my GC related communications (posting scores, authenticating, etc.) What I’d like to do is create a event that other scripts to subscribe to, to let them know if the authentication status changes. Those scripts, once receiving the event would then be able to toggle between their appropriate states.
So far I’ve tried a few different C# delegate method examples I’ve found online, but none of them seem to work. Furthermore, I still don’t know what the proper syntax is to just pass a method along, let alone store it in a array of some form and then invoke it later when the event is needed.
So, I have no idea what Game Center is. That said:
The last time I did any kind of event marshaling I did it in UnityScript only or C# only. I can show you what I did for the UScript version here:
public static var TARGET_ADDED: String = "targetAdded";
public static var TARGET_DESTROYED: String = "targetDestroyed";
public static var GAME_PAUSED: String = "gamePaused";
public static var GAME_UNPAUSED: String = "gameUnPaused";
public static var GAME_NEXT_LEVEL: String = "gameNextLevel";
//singletons
private static var eventListeners: Hashtable;
private static var instantiated: boolean = false;
public static function RegisterEventListener( eventString: String, listener ) {
if( !instantiated ) {
eventListeners = new Hashtable();
instantiated = true;
}
if( !eventListeners.Contains( eventString ) ) {
eventListeners.Add( eventString, new Array() );
}
eventListeners[eventString].Add( listener );
}
public static function TriggerEvent( eventString: String, eventData: Object ) {
if( !instantiated ) {
Debug.LogError( "EventManager received an event trigger for an unregistered event." );
return;
}
if( eventListeners[eventString].length <= 0 ) {
Debug.LogError( "EventManager received an event trigger for a registered event, but there are no listeners." );
}
for( var ii: int = 0; ii < eventListeners[eventString].length; ii++ ) {
eventListeners[eventString][ii]( eventString, eventData );
}
}
//this is unused, but Unity appears to complain when it's not here
function Update() {
}
I’m not sure if this helps you. I disliked this code for two reasons:
I couldn’t seem to throw exceptions in JS, and the public const pattern was not available, so I ended up using public vars. I was the sole writer, so I felt I could get away with it. If I were to do it again, I would do it in C#, no problem.
For C#, I don’t have an example that I know works and is ready to go, but you would want to do something like this:
public delegate eventListener( string eventString, SomeType eventData );
public class MyEventClass
{
//events:
public const string EVENT_TYPE_A = "eventTypeA";
public const string EVENT_TYPE_B = "eventTypeB";
//etc
//event listener map
private Dictionary<string, List<eventListener>>eventMap = new Dictionary<string, List<eventListener>>();
public void registerEventListener( string eventType, eventListener functionThatListens )
{
//add stuff to dictionary stuff, instantiate new list if eventstring not in dictionary, etc.
}
public void triggerEvent( string eventType, SomeType eventData )
{
//validate data before this line, then do:
for( int i = 0; i < eventMap[eventType].Length; i++ )
(eventMap[eventType])[i]( eventType, eventData );
}
public void clearListenersForEvent( string eventType ) { ... }
public void declareThatCakeIsDelicious{ Deb.LogError( "Let it not stand in doubt that cake is delicious." ); }
//etc
}
Now, if you’re talking about passing a UScript function to a C# script that tries to accept it as a delegate, I really have no clue if that works or not. And frankly I’m not even sure I’m answering your question, but if you’re having trouble getting delegates to work at all, that should get you started.
I’m definitely interested to hear your results. I may try some stuff these weekend focusing particularly on the crossover between Uscript and C#. I’d be interested to compare notes.
When the invoking class triggers that RaiseEvent call, we get the expected result:
“this works!”
So, it looks like you’re in the clear. Which is good news for me, because I’ve just run into something that desperately needs good events and talking between UnityScript and C#, so I was a little worried there for a bit.
Edit: I did want to draw your attention to the explicit typing in the eventListeningFunction declaration. I was worried C# might kill itself if it couldn’t resolve my delegate type declaration, so this is what I tried first. I don’t know if it works without explicit typing in UnityScript. It might, but I don’t know.
I have encountered a strangeness on the iPod regarding this approach whereby if you have a JavaScript function called when an event is raised by the C# EventManager, then you cannot do compound dereferences in the JavaScript function.
For instance:
//somewhere:
EventManager.RegisterEventListener( EventManager.EVENT_ONE, eEventListeningFunction );
//EventListeningFunction:
private function EventListeningFunction( eventName : String, tankAffected : SomeObject ) : void
{
//crashes the program on the ipod:
tankAffected.GetSomeObject().DoSomethingWithObject();
//works fine on the ipod
var tmp_obj : SomeObject = tankAffected.GetSomeObject();
tmp_obj.DoSomethingWithObject();
}
Both run just fine in the editor. Gonna file a bug report, but thought you might like to know if you happen to be building for iOS.