- Home /
Question on Events and Delegates
Hello everyone, I'm working on using Events and Delegates but I've hit a roadblock and was hoping if someone could tell me A) if what I'm looking for is possible and B) point me in the right direction for how to accomplish it.
What I'm trying to do: I've got a number of playable rooms, and when the play leaves those rooms, I would like all the audio from those rooms to turn off using a generic script that I can pass a int to and call the appropriate event.
My Problem: I'm not sure how to use this int value to call the appropriate event (aside from using a ton of IF statements...). I was not successful in making a array of events or calling the main delegate event by index, so how would this be accomplished?
I've also considered a script that calls a Manager that then calls an event, but that again ends up with many scripts instead of 1.
Below is a basic concept of what I'm trying to do, any help is appreciated.:
using UnityEngine;
using System.Collections;
public class MasterManager : MonoBehaviour {
public int roomNumber;
public delegate void TurnSoundsOff ();
public static event TurnSoundsOff turnOff1;
public static event TurnSoundsOff turnOff2;
void Update () //would be ontriggerenter or something similar
{
if (Input.GetKeyDown (KeyCode.P))
{
RelayMessage();
}
}
void RelayMessage ()
{
//call specific event based on roomNumber
}
}
I may be missing details of what you are trying to accomplish, but the way I might structure it is to have the player (or whatever deter$$anonymous$$es what room is the current one), send an event any time a new room is entered or left. That event would include the room number. The generic audio scripts would listen for that event. Since each script knows it's room number, it could compare the room number in the event with the sent room number and would take the appropriate action.
I had considered that, but I just thought it would be wasteful to have say 100 gameobjects with audio components on them checking a number passed in from an event when say only 10 really need to know. $$anonymous$$aybe it is not that big of a deal?
Events work this way - you're raising them, and one or more subscribers consume. Some of them might decide they were not the valid target, and just ignore the event - nothing wrong with this.
If you want a room to listen only to an event prepared specifically for it, then maybe you should just create a method TurnSoundsOff in the script attached to a room, and call it from your manager?
Answer by Berenger · Mar 19, 2014 at 08:33 AM
You could have a parent foreach of your rooms, and have their references in your MasterManager. When leaving a room, use that parent and GetComponentsInChildren() to disabled them all. Or search of your own script that knows what to disable and how.
If you still prefere events, have an array of them in MasterManager. The index represent a room. When something that can make sounds is created, have it subscribe the turn off sound function to the event corresponding to its room index. Something like :
// In a script attach to the thingy that makes sound
masterManager.SubscribeEvent(TurnOffSound(), roomIndex);
// In MasterManager
public void SubscribeEvent(TurnSoundsOff turnOff,int roomIndex)
{
onLeaveRoomArray[roomIndex] += turnOff;
}
I have been using the foreach method for other things (like keep track of and turning on and off gameobjects for each room). But its just...messy, you end up with large arrays of objects and then a jagged array so I can pass in either what room or what part of a room should be turning off. It just seems like events would be a much cleaner way of going about it.
Also, could you elaborate on your second part of your answer? I tried a few times to make an array of events but I always got errors from it.
Sure :
using ...
using System;
using System.Collection.Generic;
public class $$anonymous$$aster$$anonymous$$anager : $$anonymous$$onoBehaviour
{
// By using System.Action, no need to declare the delegate signature
Action[] onLeaveRoomArray = null;
// Call this from whatever is making a sound.
public void SubscribeEvent(Action turnOff,int roomIndex)
{
onLeaveRoomArray[roomIndex] += turnOff;
}
// Call this from the room you're leaving
public void RaiseEvent(int roomIndex)
{
onLeaveRoomArray[roomIndex]();
}
...
}
This implies that whatever makes a sound has a script able : to know the index of the rooms it's in, to have a reference to the master manager (or you can have use static / singleton), to call the SubscribeEvent function at Awake, and to know how to turn off the sound (likely audio.Stop())
Ok, so I think I've got everything, but I don't understand where TurnSoundsOff and turnOff come into this. (sorry to keep dragging this out, I'm not smart enough to figure out what I'm sure is a perfectly straight forward answer).
It's all right. There was a mistake in my script, the TurnSoundsOff is actually an Action. Anyway, how do you know when the player leaves the room ? If there is a trigger on the door, with a script implementing OnTriggerEnter, then you have to call RaiseEvent from there.
If you still have difficulties, could you tell me this :
How does the room know it's a room ? With a Room script attached maybe ?
Is there a script attached to the things making sound, on a jukebox or a radio for instance ?
The question above about leaving the room
About actions, here is a bit of code, put it in an awake or start function to see what it does and play around with it :
System.Action test = () => Debug.Log("A");
test += () => Debug.Log("B");
test += () => Debug.Log("C");
System.Action test2 = () => Debug.Log("D");
test2 += () => Debug.Log("E");
test += test2;
test(); // Should print from A to E
Good luck :)
Your answer
Follow this Question
Related Questions
Unity Events, Listeners, Delegates, etc. 1 Answer
Question about unsubscribing eventhandlers OnDisable and OnEnable 2 Answers
Multiple Cars not working 1 Answer
Distribute terrain in zones 3 Answers
Raise and Event with EventMessenger 0 Answers