#3 Snippets - Globales Event System
Heyho Leute,
mal wieder habe ich ein neues Snippet oder Skript für euch am Start. Diesmal geht es um ein Globales Event System. Sprich ein Ort, wo ich Events ablegen kann, um später mit Listener darauf zu horchen, falls irgendwas ansteht. Z.B. der Charakter springt und es soll eine Audio Datei für das Springen abgespielt werden. Oder der Charakter hebt ein Item auf und der Sound des Items soll abgespielt werden.
Also mal direkt ins kalte Wasser. Hier ist das Skript für die Datei "GlobalEventSystem.js":
[CODE]
#pragma strict
import System;
public class GlobalEventSystem {
// Singleton / Class
private static var _instance : GlobalEventSystem = new GlobalEventSystem();
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
private function GlobalEventSystem() {
//if the constructor must be public, you can do this:
if (_instance != null) {
throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
}
}
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
}
[/CODE]
So hier kommt die Erklärung!
Der Anfang ist denk ich mal selbsterklärend. Wir definieren eine neue Klasse namens GlobalEventSystem und importieren System, da wir etwas daraus benötigen.
[CODE]
#pragma strict
import System;
public class GlobalEventSystem {
[/CODE]
Da wir ein Globales Event System wollen, darf das Objekt dieser Klasse im gesamten Spielablauf auch nur einmal vorkommen. Die einfachste Möglichkeit sowas zu realisieren, sind Singletons! Mehr zu Singleton erfahrt ihr von Dr. Google
Hier seht ihr auch, das wenn jemand versucht ein Objekt der Klasse durch den Kontruktor zu erzeugen, das eine Exception geworfen wird (dafür der Import von System).
[CODE]
// Singleton / Class
private static var _instance : GlobalEventSystem = new GlobalEventSystem();
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
private function GlobalEventSystem() {
//if the constructor must be public, you can do this:
if (_instance != null) {
throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
}
}
[/CODE]
Nun kommt der Interessante Part! Die Instance
[CODE]
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
[/CODE]
Wir definieren:[list]
[*]ein Attribut, das alle unsere Events und deren Listener festhält.
[*]eine Instanz Methode zum hinzufügen eines Listeners
[*]eine Instanz Methode zum senden eines Events
[/list]
Beim Triggern (absenden/auslösen) von Events können wir eine Hashtable mit Argumenten mit geben, welche an die Listener Funktionen übergeben wird. (das Löschen von Listenern, ist aktuell nicht vorgesehen )
Aber wir benutzen wir das ganze nun? Gute Frage!
Man stelle sich vor wir haben eine Datei "Example.js", welche darauf wartet eine Audio Datei abzuspielen. Dabei ruft sie vom Event System die Methode "On" mit einem Schlüssel (hier "PlaySoundEvent") auf und übergibt zusätzlich eine Callback Funktion. Eine Funktion die ausgeführt werden soll, wenn das Event ausgelöst wird.
[CODE]
#pragma strict
var anySound : AudioClip;
private var eventSystem : GlobalEventSystem = GlobalEventSystem.GetInstance();
private var audioSource : AudioSource;
function Start () {
audioSource = GetComponent(AudioSource);
eventSystem.On("PlaySoundEvent", function(args) {
PlaySound();
});
}
function PlaySound() : void {
audioSource.clip = anySound;
audioSource.Play();
}
[/CODE]
Irgendwo anders in unserem Spiel sagen wir, das wenn irgendwas passiert (z.B. die Leertaste gedrückt wird), dann soll dieses Event ausgelöst werden.
[CODE]
#pragma strict
private var eventSystem : GlobalEventSystem = GlobalEventSystem.GetInstance();
function Update() {
if(Input.GetKeyDown(KeyCode.Space)) {
eventSystem.Broadcast('PlaySoundEvent", new Hashtable());
}
}
[/CODE]
Und "BÄÄMMM" passiert es
Ich hoffe es gefällt euch.
Wieso ich das geschrieben habe?
Als ich über Unity und Events via Google auf dieser Seite gelandet bin: [url="http://unity3d.com/learn/tutorials/modules/intermediate/scripting/events"]http://unity3d.com/l...cripting/events[/url]
Las ich folgendes unter JS Source:
[quote]
[color=#708090]//Javascript doesn't have a built-in "event". Instead,[/color][color=#708090]//you will need to use C# to gain this functionality.[/color][color=#708090]//Other scripts written in Javascript can still subscribe[/color][color=#708090]//to events created in C#.[/color]
[/quote]
Schrecklich oder?
EDIT: 20.03.2015 - 21:12 Uhr
Heyho - ich hab wirklich nen miesen Bug in der ganzen Sache gefunden. Beim wieder laden von Szenen kann/wird es passieren das Instanzen der Singleton mehrfach existieren, da sie beim wechseln einer Szene nicht die Static Member eine Klasse entfernen xD ist das nicht schrecklich. Man glaub nen leeren/neuen Kontext zu bekommen, aber das ist nur augenscheinlich der Fall. Jedenfalls soll mich das nicht stören. Ich hab die Klasse wesentlich angepasst, damit es in die Kategorie MonoBehaviour Objekt fällt und somit vom GC beachtet wird.
Im groben sieht es nun so aus:
[CODE]
#pragma strict
import System;
import UnityEngine;
public class GlobalEventSystem extends MonoBehaviour {
// Singleton / Class
private static var _instance : GlobalEventSystem; // = new GlobalEventSystem()
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
function Awake() : void {
_instance = this;
}
// private function GlobalEventSystem() {
// //if the constructor must be public, you can do this:
// if (_instance != null) {
// throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
// }
// }
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String) {
Broadcast(eventName, null);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(args == null) args = new Hashtable();
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
}
[/CODE]
Damit das ganze läuft hab ich mir einfach ne System Prefab gebastelt, die alle meine Szenenweiten System Singleton Skripte hält ;-). Diese einfach in die Szene einzubinden sollte ja wohl easy sein xD
So Far - Nax
mal wieder habe ich ein neues Snippet oder Skript für euch am Start. Diesmal geht es um ein Globales Event System. Sprich ein Ort, wo ich Events ablegen kann, um später mit Listener darauf zu horchen, falls irgendwas ansteht. Z.B. der Charakter springt und es soll eine Audio Datei für das Springen abgespielt werden. Oder der Charakter hebt ein Item auf und der Sound des Items soll abgespielt werden.
Also mal direkt ins kalte Wasser. Hier ist das Skript für die Datei "GlobalEventSystem.js":
[CODE]
#pragma strict
import System;
public class GlobalEventSystem {
// Singleton / Class
private static var _instance : GlobalEventSystem = new GlobalEventSystem();
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
private function GlobalEventSystem() {
//if the constructor must be public, you can do this:
if (_instance != null) {
throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
}
}
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
}
[/CODE]
So hier kommt die Erklärung!
Der Anfang ist denk ich mal selbsterklärend. Wir definieren eine neue Klasse namens GlobalEventSystem und importieren System, da wir etwas daraus benötigen.
[CODE]
#pragma strict
import System;
public class GlobalEventSystem {
[/CODE]
Da wir ein Globales Event System wollen, darf das Objekt dieser Klasse im gesamten Spielablauf auch nur einmal vorkommen. Die einfachste Möglichkeit sowas zu realisieren, sind Singletons! Mehr zu Singleton erfahrt ihr von Dr. Google
Hier seht ihr auch, das wenn jemand versucht ein Objekt der Klasse durch den Kontruktor zu erzeugen, das eine Exception geworfen wird (dafür der Import von System).
[CODE]
// Singleton / Class
private static var _instance : GlobalEventSystem = new GlobalEventSystem();
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
private function GlobalEventSystem() {
//if the constructor must be public, you can do this:
if (_instance != null) {
throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
}
}
[/CODE]
Nun kommt der Interessante Part! Die Instance
[CODE]
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
[/CODE]
Wir definieren:[list]
[*]ein Attribut, das alle unsere Events und deren Listener festhält.
[*]eine Instanz Methode zum hinzufügen eines Listeners
[*]eine Instanz Methode zum senden eines Events
[/list]
Beim Triggern (absenden/auslösen) von Events können wir eine Hashtable mit Argumenten mit geben, welche an die Listener Funktionen übergeben wird. (das Löschen von Listenern, ist aktuell nicht vorgesehen )
Aber wir benutzen wir das ganze nun? Gute Frage!
Man stelle sich vor wir haben eine Datei "Example.js", welche darauf wartet eine Audio Datei abzuspielen. Dabei ruft sie vom Event System die Methode "On" mit einem Schlüssel (hier "PlaySoundEvent") auf und übergibt zusätzlich eine Callback Funktion. Eine Funktion die ausgeführt werden soll, wenn das Event ausgelöst wird.
[CODE]
#pragma strict
var anySound : AudioClip;
private var eventSystem : GlobalEventSystem = GlobalEventSystem.GetInstance();
private var audioSource : AudioSource;
function Start () {
audioSource = GetComponent(AudioSource);
eventSystem.On("PlaySoundEvent", function(args) {
PlaySound();
});
}
function PlaySound() : void {
audioSource.clip = anySound;
audioSource.Play();
}
[/CODE]
Irgendwo anders in unserem Spiel sagen wir, das wenn irgendwas passiert (z.B. die Leertaste gedrückt wird), dann soll dieses Event ausgelöst werden.
[CODE]
#pragma strict
private var eventSystem : GlobalEventSystem = GlobalEventSystem.GetInstance();
function Update() {
if(Input.GetKeyDown(KeyCode.Space)) {
eventSystem.Broadcast('PlaySoundEvent", new Hashtable());
}
}
[/CODE]
Und "BÄÄMMM" passiert es
Ich hoffe es gefällt euch.
Wieso ich das geschrieben habe?
Als ich über Unity und Events via Google auf dieser Seite gelandet bin: [url="http://unity3d.com/learn/tutorials/modules/intermediate/scripting/events"]http://unity3d.com/l...cripting/events[/url]
Las ich folgendes unter JS Source:
[quote]
[color=#708090]//Javascript doesn't have a built-in "event". Instead,[/color][color=#708090]//you will need to use C# to gain this functionality.[/color][color=#708090]//Other scripts written in Javascript can still subscribe[/color][color=#708090]//to events created in C#.[/color]
[/quote]
Schrecklich oder?
EDIT: 20.03.2015 - 21:12 Uhr
Heyho - ich hab wirklich nen miesen Bug in der ganzen Sache gefunden. Beim wieder laden von Szenen kann/wird es passieren das Instanzen der Singleton mehrfach existieren, da sie beim wechseln einer Szene nicht die Static Member eine Klasse entfernen xD ist das nicht schrecklich. Man glaub nen leeren/neuen Kontext zu bekommen, aber das ist nur augenscheinlich der Fall. Jedenfalls soll mich das nicht stören. Ich hab die Klasse wesentlich angepasst, damit es in die Kategorie MonoBehaviour Objekt fällt und somit vom GC beachtet wird.
Im groben sieht es nun so aus:
[CODE]
#pragma strict
import System;
import UnityEngine;
public class GlobalEventSystem extends MonoBehaviour {
// Singleton / Class
private static var _instance : GlobalEventSystem; // = new GlobalEventSystem()
public static function GetInstance() : GlobalEventSystem {
return _instance;
}
function Awake() : void {
_instance = this;
}
// private function GlobalEventSystem() {
// //if the constructor must be public, you can do this:
// if (_instance != null) {
// throw new Exception("This is a singleton class! Use GlobalEventSystem.GetInstance() instead!");
// }
// }
// Instance / Object
private var events : Hashtable = new Hashtable();
public function On(eventName : String, callback : Function) : void {
if(!events.ContainsKey(eventName)) {
events.Add(eventName, new Array());
}
var callbacks : Array = events[eventName] as Array;
callbacks.Push(callback);
}
public function Broadcast(eventName : String) {
Broadcast(eventName, null);
}
public function Broadcast(eventName : String, args : Hashtable) : void {
if(args == null) args = new Hashtable();
if(events.ContainsKey(eventName)) {
var callbacks : Array = events[eventName] as Array;
for(var index : int = 0; index < callbacks.length; index++) {
var callback : Function = callbacks[index] as Function;
callback(args);
}
}
}
}
[/CODE]
Damit das ganze läuft hab ich mir einfach ne System Prefab gebastelt, die alle meine Szenenweiten System Singleton Skripte hält ;-). Diese einfach in die Szene einzubinden sollte ja wohl easy sein xD
So Far - Nax
2 Kommentare
Recommended Comments