I am trying to use the event system in Unity (the C# way), but I am having problems to implement it.
Most of the examples, show one class, where you define the handler; then you write in the same class, the function that match the signature of the handler, and you write the events as static
public class EventExample : MonoBehaviour
{
public delegate void ExampleEventHandler();
public static event ExampleEventHandler OneDayPassed;
public static void NextTurn()
{
// do stuff then send event
if (OneDayPassed != null)
OneDayPassed();
}
}
Then in another class, you subscribe to the events, creating a function that actually do something
public class EntityWatcher: MonoBehaviour
{
void Start()
{
EventExample.OneDayPassed += this.PrepareNextDay;
}
public void PrepareNextDay()
{
// Do other stuff that happen after the day is done
}
}
So far no problems, but I am not sure how do I design this, so any GameObject of a particular type, will subscribe to this event. For example, if you have a staff category of GO, that is working 8 to 6, and you instantiate them at runtime; should I subscribe in the main class of this category, or should I create a script that I attach to the Game Object prefab, that subscribe to the event?
The objective is that all the staff members that should do a 8 to 6 shift at the sport center, know when the "day is done" event fire up, but I don't want to subscribe every single prefab that I instantiate.
From my understanding, I should attach a script with the needed code on the prefab, but I can't find a practical example that show if that is in fact the way to do it.
You must use UnityEvent.
public UnityEvent whoa;
It is dead easy.
Make a script BigScript.cs
using UnityEngine;
using System.Collections;
using UnityEngine.Events;
public class BigScript:MonoBehaviour
{
[Header("Here's a cool event! Drag anything here!")]
public UnityEvent whoa;
}
Put it on a game object. Now look at it in the Inspector.
You will see the "whoa" event.
Simply drag your other scripts to there, to make something happen, on those other scripts, when "whoa" happens.
It's that simple. To call the event in BigScript, it is just
[Header("Here's a cool event! Drag anything here!")]
public UnityEvent whoa;
private void YourFunction()
{
whoa.Invoke();
}
In rare cases you may need to add a listener via code rather than simply dragging it in the Editor. This is trivial:
whoa.AddListener(ScreenMaybeChanged);
(Normally you should never have to do that. Simply drag to connect. I only mention this for completeness.)
That's all there is to it.
Be aware of out of date example code regarding this topic on the internet.
The above shows how to connect simple functions that have no argument.
If you do need an argument:
Here is an example where the function has ONE FLOAT argument:
Simply add THIS CODE at the top of the file:
[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}
then proceed as normal. It's that easy.
// ...
using UnityEngine.Events;
// add this magic line of code up top...
[System.Serializable] public class _UnityEventFloat:UnityEvent<float> {}
public class SomeThingHappens : MonoBehaviour
{
// now proceed as usual:
public _UnityEventFloat changedLength;
void ProcessValues(float v)
{
// ...
changedLength.Invoke(1.4455f);
}
}
When you drag from your other function to the Editor slot on this function:
Be certain to use the section - "Dynamic float".
(Confusingly your function will also be listed in the "Static Parameters" section! That is a huge gotchya in Unity!)
Don't worry too much about the number of subscribers if you are only talking about a few dozens. Yes, once you get into the hundreds or thousands it might be a good idea to optimize this, but even then. First rule of optimization: don't optimize.
So: just have every instance subscribe to the event and be done with it.
Related
I have a game object and I'm generating a component for that object by
var arcGISMapViewComponent = gameObject.AddComponent<ArcGISMapViewComponent>();
under the Void Start()
However, I have another class that is
public void ReadStringInput(string s)
I also need to show there the existence of arcGISMapViewComponent but since it's not generated yet in the beginning I'm getting an error which is
'arcGISMapViewComponent' could not be found how can I solve this?
You can use Awake() {} to make sure some code (component creation in your case) is called before other Start code. If your different class is not a MonoBehaviour then you should create an event and Invoke it notifying that component was created and from your different class subscribe on that event.
I have this unity event
[Serializable]
public class UnityEventString : UnityEvent<string>
{
}
Which gets used in this MonoBehaviour
public class EventListenerString : MonoBehaviour, IEventListener<string>
{
//some more code
public EventString Event;
public UnityEventString Response;
//Some more code
}
Problem is, it doesn't show this method in inspector as dynamic.
public void Show(string key)
{
_Show(Animator.StringToHash(key));
}
public void Hide(string key)
{
_Hide(Animator.StringToHash(key));
}
I used to use this pattern for my other events too, and they worked fine until today.
Currently, there are the right methods in the inspector, from earlier this week when i programmed. But today everything stopped working for that.
It also stopped working on a plain test object with a test MonoBehaviour with just one method.
But it still works with that one here
What happened here?
I think unity 2019.2.5 is bugged, going down to 2019.2.4 fixed this for me, all dynamic events came back.
You're attaching a function to run when the event is fired, that function is on a class, the class is a script attached to a gameobject, unity serializes this hooked method as follows GameObject Instance ID -> Script ID -> Method Name -> Parameters.
Now if you move your script to another game object, the serialization system doesn't find said script on the old game object anymore. so the deserialization breaks on the second step, and so does your hooked method.
Hope that makes sense.
i need to declare a variable class in my code so i can access a function (having the same name in all classes) but doing each time a different behavior).
and this is my code:
using UnityEngine;
using System;
using System.Collections;
public class Bubble : ItemBehaviour
{
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
void OnMouseDown ()
{
theclass.Behaviour ();
}
}
knowing that (theclass gonna be variable ).
Thank you guys for your answer but it is a bit special.
My game is about interaction between player and game objects when the player approach any item that is "interactible" lets say, a bubble shows up, this bubble is a GameObject and it is the same for any object that allow interactions,
So since i am doing a 2D game i thought, it would be great if i make a "universal"
EmptyGameObject that contains all common aspects that anyObject would contain, and i grouped main functions and common ones in a general script and i added it to this emptyGameObject, then i added the Bubble prefab to this Game object and i a dded a code to it this code contains what i wrote in my firs post.
i was thinking that now each time i want an object i just drop this emptygameobject prefab and changes sprites and characteristics.
And each object have a different behavior (ex: i can delete an apple as if the character consumed it but i can not consume a door, the door would rather trigger an animation than being destructed ) i am specifying all this in a class for each item.
now whatever the class is (the object is) the trigger is in the bubble class (which i posted first) but the class will be different each time and i can not make a class that contains polymorphism because its not the same context each time.
I think you should create an interface that declares all the functions you would like to use in different classes.
interface IBehaviour
{
void Behaviour();
void AnotherBehaviour();
}
with this you define a behaviour what a class, which implements the interface, is capable of.
And then your classes would be:
class MyClass1 : Ibehaviour
{
}
class MyClass2 : IBehaviour
{
}
Apart from this you can use abstract classes. There are a lot of well-written articles about these topics on the Internet.
Firstly, I recommend to get familiar with OOP principles.
This link is a good way to start.
Good luck.
Thank you all,
The matter was solved by creating a global (abstract) gameOject that contains the class that we want to inherit from, and then each time the gameObject atached to this class calls (Behavior function) it trigger whatever the override is for this function for this object.
I'm currently working on an inventory system in Unity3D, and came upon a weird problem. I have created non-MonoBehaviour classes for my inventory system (in case that matters), so that I have an Inventory class which holds a list of Slot objects, which in turn holds a list of Item objects.
Then I added a component script to my "HudInventoryPanel", called "HudInventoryController", which looks like this:
using UnityEngine;
using System.Collections;
public class HudSlotController : MonoBehaviour {
private InventoryController ic;
// Use this for initialization
void Start () {
ic = GetComponent<InventoryController>();
}
// Update is called once per frame
void Update () {
}
}
However, inside the Start() method, the InventoryController (part of my Player) hasn't been created yet, and it seems to me like the gameobjects are created in alphabetical order...?
How should I deal with this problem?
You can specify script execution order in the project settings (Edit -> Project settings -> Script execution order), so use that to make sure your scripts are executed in the correct order. In addition to that, you can use the Awake() method as all Awakes are executed before any Start() method. Hope a combination of these helps you!
I solved this by creating an intermediate variable in my InventoryController script, plus creating a "manual" getter; https://gist.github.com/toreau/f7110f0eb266c3c12f1b
Not sure why I have to do it this way, though.
I am new to C# so this is probably me just not understanding something fundamental or missing out on some feature of the language. I've searched online but all the examples I seem to find have everything all in one class (in other words, they define the event as well as the method that executes when the event is triggered), which is not what I want.
For my scenario I'd like to define an interface of listener methods that can accept some custom parameters (this would be my own EventArgs right?) that provide instructions. Lets pretend its for a car, so I have methods named:
Start(MyCustomParameters par)
Accelerate(MyCustomParameters par)
Decelerate(MyCustomParameters par)
and then I want to be able to create classes that provide the actual implementation of these methods.
completely separate from all this, I have a single class that executes periodically based on an external process and I want it to be responsible for triggering these events (when the car starts and accelerates etc).
That's the basics of what I'm trying to get working but no luck so far. Also, one follow-up question. If my listener-implementation class needs to maintain any kind of state from a given call, how best to do that (e.g. say that when Accelerate is called it wants to be able to return the speed that it accelearted to back to the invoker of the event - e.g. 80 kph)
hope you can help SO, thank you very much
here is a simple example of event/listener in c# :
//your custom parameters class
public class MyCustomParameters
{
//whatever you want here...
}
//the event trigger
public class EventTrigger
{
//declaration of the delegate type
public delegate void AccelerationDelegate(MyCustomParameters parameters);
//declaration of the event
public event AccelerationDelegate Accelerate;
//the method you call to trigger the event
private void OnAccelerate(MyCustomParameters parameters)
{
//actual triggering of the events
if (Accelerate != null)
Accelerate(parameters);
}
}
//the listener
public class Listener
{
public Listener(EventTrigger trigger)
{
//the long way to subscribe to the event (to understand you create a delegate)
trigger.Accelerate += new EventTrigger.AccelerationDelegate(trigger_Accelerate);
//a shorter way to subscribe to the event which is equivalent to the statement above
trigger.Accelerate += trigger_Accelerate;
}
void trigger_Accelerate(MyCustomParameters parameters)
{
//implement event handling here
}
}
I hope it helps.