Jump to content
Unity Insider Forum

Funktion per GUI starten


Recommended Posts

Hallo zusammen,

 

Früher benutzte ich hauptsächlich die Unreal Engine, bin aber wegen der Portabilität und weiteren kleinen Details, in denen mich Unity besser dünkt, auf Unity 3D umgestiegen. Ich arbeite jetzt seit ca. einer Woche mit der Unity Engine.

 

Nun bin ich jedoch auf ein kleines Problem gestossen. Wenn ich versuche, eine Funktion zu starten bei einem Buttondruck, geschieht nichts. die funktion selber habe ich static markiert,damit ich keine Instanz der Klasse erzeugen muss.

 

Hier der Abschnitt, der eine Funktion in einem weiteren Skript starten soll:

 

GUILayout.BeginArea(Rect(820, 560 + 150,100,100));

if(GUILayout.Button("Spielen")) {

GUI.Box(Rect(700,700,700,700),"Test");

GUICharacterChoice.OnGUI();

}

GUILayout.EndArea();

 

 

 

 

Hier der Source von GUICharacterChoice()

 

function OnGUI() {

GUICharacterChoice();

}

 

 

static function GUICharacterChoice() {

GUI.Label(Rect(300,300,300,300),"Test");

}

 

 

Wenn ich nun auf den Button drücke, wird GUICharacterChoice() nicht gestartet. Die GUICharacterChoice Funktion befindet sich in einem separaten Skript welches ebenfalls GUICharacterChoice.js heisst. Was mach ich falsch? Kann ich eigentlich pro Script immer eine OnGUI Funktion haben oder sollte diese auf ein Script beschränkt sein?

 

Gruss,

 

Eidgenosse

Link zu diesem Kommentar
Auf anderen Seiten teilen

Die Funktion die ausgeführt werden soll wird nur 1x aufgerufen, nachdem der Button gedrückt wird, sie wird ausgeführt das Label ist aber nur 1x sichtbar, genau 1 Frame lang.

 

Du müsstest also dafür sorgen dass die Funktion jeden Frame ausgeführt wird nachdem der Button gedrückt wurde, wenn das denn dein Ziel ist.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Und wie erreiche ich das genau?

 

Mein Ziel ist es, die verschiedenen Menues in Scriptdateien auszulagern und die jeweilgen Funktionen je nach Interaktion des Users zu starten. So soll zb. wenn der User auf "Start" drückt,, der alte Content gelöscht und die Funktion mit der neuen GUI gezeichnet werden. Ich weiss, dass es auch möglich ist, die GUIs in Szenen auszulagern un diese dann zu laden, doch mir scheint dies nicht die sauberste Lösung, zumal man so den Code schlecht wiederverwenden kann, wenn ich richtig liege.

 

Mache ich irgendwelche Denkfehler? In Java gibt es ja die songenannten EventListener, wie verhält sich das mit Unity 3d?

 

Danke für eure Hilfe

 

Eidgenosse

Link zu diesem Kommentar
Auf anderen Seiten teilen

Du brauchst keinen EventListener, weil das, was bei Knopfdruck passieren soll, als Code direkt unter den Button-Aufruf kommt.

Java:

button.addActionListener(new ActionListener()
{
 @Override
 public void ActionPerformed(ActionEvent e)
 {
   //code
 }
});

JS-Äquivalent in Unity:

if(GUI.Button( ... ))
{
 //code
}

Das ist halt das, was man sich in Unity erlauben kann, weil OnGUI ein Zyklus ist und nicht wie in Java eine Zuweisungsorgie bei der Initialisierung.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hallo Sascha,

 

Genau das probiere ich, doch irgendwas will nicht so recht klappen. Wenn ich zb. ein Script schreibe :

 

#pragma strict

 

function OnGUI () {

 

if(GUI.Button(Rect(100,100,200,40),"Drück mich")) {new GUI.Label(new Rect(400,400,200,30),"Hello World");}

 

 

dann geschieht bei Knopfdruck nichts,das Label wird nicht ausgegeben. Wie müsste ich da vorgehen, wenn ich bei Knopfdruck dieses Label ausgeben möchte? Muss ich irgendwie mit der update() funktion arbeiten?

 

Gruss

 

Eidgenosse

Link zu diesem Kommentar
Auf anderen Seiten teilen

Das ist ja das, was ich schrieb, was viele am Anfang nicht verdaut kriegen.

OnGUI ist keine Initialisierung, sondern ein fortlaufender Zyklus, der idR öfter aufgerufen wird als Update.

GUI.Label ist eine Methode, kein Konstruktor.

Du erstellst damit kein Label, das sich von nun an selber zeichnet, sondern du zeichnest für den Bruchteil einer Sekunde das Label.

Wenn dui bei dem Script nur oft genug auf den Button hämmerst, nimmst du es sogar wahr.

 

Ich hoffe, das hilft?

Link zu diesem Kommentar
Auf anderen Seiten teilen

Wenn ich das in diesem Falle recht verstanden habe, ist es so gar nicht möglich, ein Label auszugeben? Besteht nicht die Möglickeit, irgendein Text oder ähnliches bei Knopfdruck auszugeben oder eine funktion aufzurufen? müsste ich dies in der update() funktion machen? wie würdest du ein menue erstellen mit mehreren interfaces? per scenes?

 

gruss

Link zu diesem Kommentar
Auf anderen Seiten teilen

Natürlich kann man das.

Anstatt aber ein Label erzeugen zu wollen, wenn der Knopf gedrückt wird, setzt du stattdessen einen Schalter um, und wenn dieser auf "an" steht, wird in OnGUI ein Label gezeichnet.

 

var labelAnzeigen : boolean = false;

function OnGUI()
{
 if(GUI.Button( ... ))
 {
labelAnzeigen = true;
 }
 if(labelAnzeigen)
 {
GUI.Label( ... );
 }
}

Link zu diesem Kommentar
Auf anderen Seiten teilen

Ah so dann muss man dies quasi über eine bool variable machen um den zustand zu definieren. Werd ich gleich ausprobieren, thx!

Ich hab halt noch absolut keine Erfahrung in unity 3d ich find die Engine auch wirklich toll, aber so manches ist wirklich eine Umstellung. Ich werd auf alle fälle sicher noch viel hier reinschauen und hoffentlich später ebenfalls dem ein oder anderen Neuankömmling eine Hilfe sein, wenn ich Unity 3d denn mal etwas beherrsche :)

 

waaah jetz wär ich um ein Haar bei deinem Blockgame hängen geblieben, tu das nie wieder ;)

 

bis dann!

Link zu diesem Kommentar
Auf anderen Seiten teilen

Okay,

 

Das klappt alles. Nun müsste ich jedoch noch auch den alten Content löschen können, da die aufgerufene Funktion das neue UI über das alte zeichnet.gibts so etwas wie eine clear() methode oder muss ich ab diesem Zeitpunkt doch mit Szenen arbeiten?

 

Code :

 

function addAccountButtons() {

 

GUILayout.BeginArea(Rect(820, 560 + 150,100,100));

if(GUILayout.Button("Spielen")) { bttnchoice = 1;}

GUILayout.EndArea();

 

 

GUILayout.BeginArea(Rect(430, 560 + 300, 100,100));

if(GUILayout.Button("Optionen")) {bttnchoice = 2;}

GUILayout.EndArea();

 

GUILayout.BeginArea(Rect(1350, 560 + 300 ,100,100));

if(GUILayout.Button("Spiel beenden")) {bttnchoice = 3;}

GUILayout.EndArea();

 

switch(bttnchoice)

{

case 1:

UICharacterChoice.OnGUI();

break;

case 2:

GUI.Label(Rect(0,0,200,30),"Optionen");

break;

case 3:

GUI.Label(Rect(0,0,200,30),"Spiel beenden");

break;

default:

GUI.Label(Rect(0,0,200,30),"Nichts");

break;

}

 

}

 

Was ist eigentlich die normal gängige Methode? User Interfaces in externe Funktionen auszulagern und diese bei Bedarf aufzurufen, oder das Erstellen von einzelnen Menuepunkten per Szenen und das Nachladen dieser?

 

Kann man nicht soetwas wie Klassen erstellen? Es irritiert mich, dass es keine Konstruktoren gibt...

 

gruss

Link zu diesem Kommentar
Auf anderen Seiten teilen

Du hast leider immernoch nicht das Prinzip hinter OnGUI verstanden.

OnGUI wird immer wieder aufgerufen und jede GUI.Blub-Methode zeichnet ein Mal etwas, und das hält dann bis zum nächsten OnGUI-Zylus, der ein Bruchteil einer Sekunde dauert.

Wenn du also ein Mal etwas in OnGUI zeichnest, dann ist es sofoert wieder weg.

 

Das bedeutet zweierlei Dinge: Wenn du etwas hinzufügen willst, musst du einen Schalter umlegen, der dafür sorgt, dass die Methode, die dein neues Element zeichnet, von jetzt an in jedem OnGUI gezeichnet wird.

Wenn du dann etwas nicht mehr gezeichnet haben willst, musst du nichts weiter tun als dafür zu sorgen, dass es in OnGUI von nun an nicht mehr aufgerufen wird.

 

var an : boolean = false;

function OnGUI()
{
 if(!an)
 {
   if(GUI.Button(Rect(10,10,100,25), "an"))
  an = true;
 }
 else
 {
   if(GUI.Button(Rect(120,10,100,25), "aus"))
  an = false;
 }
}

Link zu diesem Kommentar
Auf anderen Seiten teilen

Hoi Sascha,

 

Danke für deine Antwort. So hab ich das jedoch auch verstanden, GUI wird bei jedem Zyklus aufgerufen und zeichnet genau das, was in dem Zyklus gezeichnet werden soll. vielleicht hätte ich erwähnen sollen, dass dieser Code in der On_GUI Funktion aufgerufen wurde. Oder habe ich sonst irgendwas noch falsch gemacht, das ich wirklich nicht verstehe? Hier nochmal der ganze Code :

 

var bttnchoice : int = 0;

 

 

function OnGUI () {

 

UIMenueGeneralFrame.addUIMenueGeneralFrame();

addAccountBox();

addAccountFelder();

addAccountButtons();

}

 

 

function addAccountBox() {

 

GUI.Box(Rect(780, 560, 300,200),"");

}

 

 

function addAccountFelder() {

 

GUILayout.BeginArea(Rect(820, 560 + 35,100,100));

GUILayout.BeginVertical();

GUILayout.Label("Benutzername");

GUILayout.Label("Passwort");

GUILayout.EndVertical();

GUILayout.EndArea();

 

GUILayout.BeginArea(Rect(940, 560 + 35 ,100,100));

GUILayout.BeginVertical();

GUILayout.TextField("");

GUILayout.TextField("");

GUILayout.EndVertical();

GUILayout.EndArea();

}

 

 

function addAccountButtons() {

 

GUILayout.BeginArea(Rect(820, 560 + 150,100,100));

if(GUILayout.Button("Spielen")) { bttnchoice = 1;}

GUILayout.EndArea();

 

 

GUILayout.BeginArea(Rect(430, 560 + 300, 100,100));

if(GUILayout.Button("Optionen")) {bttnchoice = 2;}

GUILayout.EndArea();

 

GUILayout.BeginArea(Rect(1350, 560 + 300 ,100,100));

if(GUILayout.Button("Spiel beenden")) {bttnchoice = 3;}

GUILayout.EndArea();

 

switch(bttnchoice)

{

case 1:

UICharacterChoice.OnGUI();

break;

case 2:

GUI.Label(Rect(0,0,200,30),"Optionen");

break;

case 3:

GUI.Label(Rect(0,0,200,30),"Spiel beenden");

break;

default:

GUI.Label(Rect(0,0,200,30),"Nichts");

break;

}

 

}

 

Bis dann

Link zu diesem Kommentar
Auf anderen Seiten teilen

Es war dieser Satz, aus dem ich geschlossen habe, dass da was noch nicht richtig sitzt:

Nun müsste ich jedoch noch auch den alten Content löschen können, da die aufgerufene Funktion das neue UI über das alte zeichnet.

Und solche Fragen entfallen dann:

gibts so etwas wie eine clear() methode oder muss ich ab diesem Zeitpunkt doch mit Szenen arbeiten?

Aber ok, wenn du es verstanden hast... der Code sieht zumindest danach aus :)

Dann verstehe ich aber, glaube ich, die Frage nicht.

Link zu diesem Kommentar
Auf anderen Seiten teilen

Es war dieser Satz, aus dem ich geschlossen habe, dass da was noch nicht richtig sitzt:

 

Und solche Fragen entfallen dann:

 

Aber ok, wenn du es verstanden hast... der Code sieht zumindest danach aus :)

Dann verstehe ich aber, glaube ich, die Frage nicht.

 

 

Der Fehler den ich mache ist vermutlich, dass ich in der OnGUI Funktion erst 2 Funktionen aufrufe die etwas hinzuadden, und die letzte Funktion macht dann das Switch case. Die ersten 2 Anweisungen werden bei jedem Zyklus neu gezeichnet, wohingegen die letzte Funktion, die das switch beinhaltet, je nach switch den contend abbildet. Ich müsste daher die switch anweisung bereits in der On_GUI Funktion programmieren und dort die Zustände abfragen,noch bevor die 2 funktionen andauernd gezeichnet werden.. Ich teste das später mal aus und geb dir Bescheid obs geklappt hat.

 

Auf alle Fälle schonmal herzlichen Dank dir!

Link zu diesem Kommentar
Auf anderen Seiten teilen

Archiviert

Dieses Thema ist jetzt archiviert und für weitere Antworten gesperrt.

×
×
  • Neu erstellen...