Jump to content
Unity Insider Forum
cncrete

Invoke ruft nicht auf

Recommended Posts

Hallöchen, 

Ich habe das problem das die Invoke methode nicht aufruft. Ind der start methode funktioniert es, aber wenn ich dann es in der update methode mache klappt es nicht mehr. 

Den code hab ich als bild hochgeladen. 

Kann mir bitte jemand helfen, ich sitze nun seit 2 stunden daran und kann sonst auch im internet nix finden😢😥

Danke 

 

1547659529484667215900.jpg

Share this post


Link to post
Share on other sites

Wird Invoke in der Update Methode dadurch nicht ständig aufgerufen? Das setzt den Timer von 3 Sekunden vielleicht ständig wieder zurück?

Edit: Ok, habs probiert, daran liegts nicht. Invoke bzw. ResetValues wird dann unzählige mal ausgeführt.

Wird scorePlayerLeft oder scorePlayerRight denn wirklich größer oder gleich 1?

Share this post


Link to post
Share on other sites

Ja, es ist pong und wenn der spieler 1 punkt erzielt dann ist der score auch 1,ich hab auch probiert nur den scenenwechsel zu haben und das funktioniert auch. Dann bleibt der text leider nur einen bruchteil stehen.

Share this post


Link to post
Share on other sites

Was willst du eigentlich erreichen? Der Text, wer gewonnen hat, soll eine gewisse Zeit sehen bleiben und dann weg gehen?

Wenn ja, dann machst du da was falsch, denn die Update Methode wird jedes Frame aufgerufen.
Sobald der linke oder der Rechte Player einen Punkt haben, wird jetzt jedes Frame das Canvas Objekt aktiviert, die Timescale auf 0 gesetzt und ein entsprechender Text übergeben.
Du rufst auch jedes Frame den Invoke Befehl auf.

Ob nun der rechte oder der Linke Player gewonnen hat, alles was innerhalb der If Abfrage steht sollte nur einmal ausgeführt werden. Also brauchst du eine boolsche Variable, die in der If Abfrage mit berücksichtigt wird. Du fragst also zusätzlich den Zustand dieser Variable ab. Z.B. ob sie false ist. Wenn es so ist, dann wird alles innerhalb der Abfrage abgearbeitet. Dort schaltest du diese eine Variable auf true, damit beim Nächsten Frame nicht wieder alles abgearbeitet wird. Denn nun ist sie ja nicht mehr false und die Bedingung ist nicht mehr erfüllt.

Wenn du jetzt eine Coroutine starten würdest, anstatt einer Methode, dann könntest du dort einen Wartebefehl einstellen, der 1-3 Sekunden wartet. Erst nach dieser Wartezeit würde die Coroutine die weiteren Einträge abarbeiten. Ja und da würdest du dann das Canvas Objekt wieder deaktivieren und das machen, was danach passieren soll.

bool showWinner=false;
void Update(){
 if(ball.scorePlayerLeft>=1 && !showWinner){
   showWinner=true;
   canvas.SetActive(true);
   Time.timeScale=0;
   text,text="Player left won!";
   StartCoroutine(WaitAndReset(1));
 }
}

IEnumerator WaitAndReset(float duration){
  yield return new WaitForSeconds(duration);
  canvas.setActive(false);
  Time.timescale=1;
  showWinner=false;
  // hier weitere Dinge einfügen, wie z.B. ein Laden einer neuen Szene.
  // oder evtl. die Punkte zurück setzen, denn der Score ist immer noch >=1.
}

 

  • Like 1

Share this post


Link to post
Share on other sites

Invoke benutzt Time.deltaTime, welches als Faktor Time.timeScale hat, welches wiederum 0 ist. Anders gesagt: Du hast die Zeit angehalten - und du kannst keine 2 Sekunden warten, wenn keine Zeit vergeht.

Invoke ist sowieso Käse. Die von @malzbie beschriebene Coroutine hilft hier leider auch nichts, da WaitForSeconds ebenfalls über skalierte Zeit läuft, aber Invoke setzt nochmal einen obendrauf, weil es strings benutzt. Ieh!

Nimm stattdessen meine Invoker-Klasse, die gibt's hier: https://gist.github.com/FlaShG/09b80bbc02a4bb6f9e2dda23ff9c5f8d. Einfach komplett herunterladen und irgendwo in deine Assets packen. Benutzt du dann wie Invoke, nur ohne Strings. Und damit das in Echtzeit abläuft, habe ich gerade noch InvokeInRealtime eingebaut.

Statt

Invoke("Methode", 2f);

machst du damit

StartCoroutine(Invoker.InvokeInRealtime(Methode, 2f));

Beachte: Der Name der Methode jetzt nicht mehr in Anführungsstrichen.

Ansonsten ist absolut richtig und wichtig, was @malzbie sagt - du musst nochmal über die ganze Sache rüberschauen, dass du den Invoke-Befehl nicht jeden Frame auf's Neue ausführst.

  • Like 1

Share this post


Link to post
Share on other sites

Das ist interessant! Ich mache durchaus regen Gebrauch von Invoke. Hat die Methode mit dem String als Methodenname irgendein oder wieso haben die Unity Entwickler das nicht bisher verbessert wenn es doch offenbar ohne großen Aufwand besser geht?

  • Like 1

Share this post


Link to post
Share on other sites

Ich glaube, die haben andere Prioritäten. Abhilfe ist halt schnell geschaffen, wie du selber sagst. Andererseits bin ich aber scheinbar auch etwas radikaler als die, was Code-Qualität angeht. Die sind inzwischen selber einigermaßen vom GameObject.Find(WithTag)-Kurs runter, aber das hat auch schon eine Weile gedauert. Ich glaube, das kam damals in den ersten Versionen von der JavaScript-Kultur, an der sie sich orientiert haben.

Naja, langer Rede kurzer Sinn: Strings sind bäh. Außer zum Ausgeben.

Ach ja, kleiner Nachtrag zu @malzbies Coroutine - Es gibt WaitForSecondsRealtime, damit wäre das ebenfalls eine funktionierende Lösung.

  • Like 1

Share this post


Link to post
Share on other sites

Ja, hast recht, @Sascha.
Ich habe garnicht darauf geachtet, dass die Spielzeit auf 0 gesetzt wird. Obwohl ich es ja selber geschrieben habe! :D
War zu spät gestern. ;)

  • Like 1

Share this post


Link to post
Share on other sites

Lasst uns das Thema nicht allzuweit von der ursprünglichen Frage entfernen, aber: Ich habe gehört, MEC soll ganz gut sein. Vor allem ist es kostenlos, also schadet's sicher nicht. Grundsätzlich gilt allerdings, dass man sich über Performance nicht zu viele Gedanken machen soll, bevor sie sich als Problem entpuppt. Für die drei Coroutines in einem kleinen Projekt also unbedingt MEC einzubauen, ist zwar kein Fehler, aber eben Zeitverschwendung.

Bei weiteren Fragen, die nicht allzu viel mit der Frage von @cncrete zu tun haben, gerne ein neues Thema aufmachen ;)

  • Like 2

Share this post


Link to post
Share on other sites

Danke sehr, ihr habt mir sehr geholfen, es ist schön wenn man Anfänger ist und einem geholfen wird. Sonst würde ich da noch Jahre dransitzen😉

 

Share this post


Link to post
Share on other sites
14 hours ago, Sascha said:

Ich glaube, die haben andere Prioritäten. Abhilfe ist halt schnell geschaffen, wie du selber sagst. Andererseits bin ich aber scheinbar auch etwas radikaler als die, was Code-Qualität angeht. Die sind inzwischen selber einigermaßen vom GameObject.Find(WithTag)-Kurs runter, aber das hat auch schon eine Weile gedauert. Ich glaube, das kam damals in den ersten Versionen von der JavaScript-Kultur, an der sie sich orientiert  @malzbiesmalzbiemalzbiesmalmalz

Ich habe auch die gameobjekt.find("")... 

Geschichte benutzt. Ist das ineffizient oder warum sollte man es nicht benutzen, bzw. warum bist du nicht begeistert davon? Und was sollte man stattdessen machen?

Share this post


Link to post
Share on other sites
vor 9 Minuten schrieb cncrete:

Ich habe auch die gameobjekt.find("")... 

Geschichte benutzt. Ist das ineffizient oder warum sollte man es nicht benutzen, bzw. warum bist du nicht begeistert davon? Und was sollte man stattdessen machen?

Es ist eine Suchfunktion. Alle GameObjects werden anhand ihres String Namens durchsucht. Wenn du viele Spieleobjekte hast und die Suchfunktion z.B. in der Update Funktion benutzt kann das unter Umständen die Performance beeinträchtigen.

Share this post


Link to post
Share on other sites
vor 17 Minuten schrieb cncrete:

Ist das ineffizient oder warum sollte man es nicht benutzen

Ich bin gar nicht mal so der Performance-Freak. Mein Hauptaugenmerk bei Code ist "Code-Qualität". Das beschreibt Vorzüge von Code, die über das reine Funktionieren hinausgehen. Wichtige Begriffe sind Lesbarkeit, Robustheit (dass man Code später ändern oder erweitern kann, ohne dass gleich alles kaputt geht), Modularität, und einige andere.

Strings haben generell das Problem, dass es Werte sind. "Player" ist ein String, und "PIayer" ist auch ein String. Siehst du den Unterschied? Beim zweiten folgt dem "P" ein großes "i". Der Compiler merkt sowas, denn er ist ein Computerprogramm... aber eben nicht bei Strings. Anders z.B. Klassen- oder Methodennamen. Wenn du so etwas schreibst:

GetComponent<Lighht>()

oder

GetComponnent<Light>()

dann wird dein Code nicht kompilieren und du kriegst eine Fehlermeldung, in welcher Zeile du etwas geschrieben hast, das nicht existiert. Oft sagt dir der Compiler bei solchen Fehlern sogar, welches Wort genau er nicht erkennt. Bei Strings kann er das nicht, da es Werte sind, und alle Werte sind erst einmal korrekt. Dein Code wird also kompiliert und ausgeführt. Dann kommt es zu "GameObject.Find" und er findet das Objekt nicht. Vielleicht, weil du dich vertippt hast und es dir keiner gesagt hat, vielleicht aber auch, weil irgendjemand in der Szene den Namen des Objekts kürzlich geändert hat, weil der neue Name besser passt - und schon funktioniert dein Code nicht mehr (Thema Robustheit, s.o.). Aber es kommt noch schlimmer: Bei solchen Funktionen kriegst du das gar nicht unbedingt direkt mit, wenn kein Objekt gefunden wurde. Oft geben die Dinger einfach null zurück und sind glücklich. Krachen tut es dann erst, wenn du das Objekt benutzt. Dann hast du als Fehlermeldung, dass du mit dem Objekt etwas machen wolltest, das dir rausgesucht wurde, das aber nicht ging, weil keines vorhanden ist. Der Fehler passiert also nicht bei GameObject.Find, sondern irgendwo später. Und dann darfst du suchen gehen, wo der Fehler ist.

Zusammengefasst also: Warum solltest du dir Fehler aufhalsen, bei denen du selber recherchieren musst, was los ist? Du hast eine mächtige Rechenmaschine unter deinen Fingern, die diese Aufgabe viel besser bewältigen kann als du. Du musst nur deinen Code so schreiben, dass sie ihren Job auch machen kann. Und es gibt immer elegante Wege, GameObject.Find zu ersetzen. Wenn du mal nicht weißt, wie, frage gerne nach ;)

vor 9 Minuten schrieb Lightstorm:

Es ist eine Suchfunktion. Alle GameObjects werden anhand ihres String Namens durchsucht. Wenn du viele Spieleobjekte hast und die Suchfunktion z.B. in der Update Funktion benutzt kann das unter Umständen die Performance beeinträchtigen.

Hast du das mal gebenchmarked? Ich wäre mit solchen Aussagen vorsichtig. Ich meine mich zu erinnern, dass Unity zumindest für Tags eine vernünftige Beschleunigungsstruktur im Hintergrund laufen hat. Aber wie gesagt... um Performance geht's mir sowieso nicht. Und deshalb stellt sich mir die Frage gar nicht erst, wenn diese Funktionen sozusagen schon "eine Runde früher ausscheiden".

  • Thanks 1

Share this post


Link to post
Share on other sites
vor 5 Minuten schrieb Sascha:

Hast du das mal gebenchmarked? Ich wäre mit solchen Aussagen vorsichtig. Ich meine mich zu erinnern, dass Unity zumindest für Tags eine vernünftige Beschleunigungsstruktur im Hintergrund laufen hat. Aber wie gesagt... um Performance geht's mir sowieso nicht. Und deshalb stellt sich mir die Frage gar nicht erst, wenn diese Funktionen sozusagen schon "eine Runde früher ausscheiden".

Es klingt zumindest logisch nicht ständig eine längere Suche durchzuführen. Vor allem wenn das eigentlich nicht zwingend so sein muss. In der Dokumentation schreibt Unity nur "For performance reasons, it is recommended to not use this function every frame".

https://docs.unity3d.com/ScriptReference/GameObject.Find.html

Ich arbeite aktuell an einem Lernprojekt und musste bisher kein einziges mal die Find Funktion nutzen. War bisher nicht nötig. Über ScriptableObjects und das Event System lässt sich das alles schön referenzieren bzw. Objekte miteinander kommunizieren.

Übrigens nochmal danke für dein Architektur Repo! Ist sehr nützlich.

  • Like 1

Share this post


Link to post
Share on other sites
vor 3 Minuten schrieb Lightstorm:

In der Dokumentation schreibt Unity nur "For performance reasons, it is recommended to not use this function every frame".

Naja, es ist immer noch mindestens ein Dictionary Lookup und damit in jedem Fall nicht so schnell und elegant wie die Verwendung einer direkten Referenz.

Aber... wie gesagt. Die Code-Qualität geht bei Verwendung von Strings immer nach unten (außer zum Ausgeben ;)), und damit ist diese ganze Palette von Funktionen für mich schon disqualifiziert.

Share this post


Link to post
Share on other sites
8 minutes ago, Sascha said:

Ich bin gar nicht mal so der Performance-Freak. Mein Hauptaugenmerk bei Code ist "Code-Qualität". Das beschreibt Vorzüge von Code, die über das reine Funktionieren hinausgehen. Wichtige Begriffe sind Lesbarkeit, Robustheit (dass man Code später ändern oder erweitern kann, ohne dass gleich alles kaputt geht), Modularität, und einige andere.

Strings haben generell das Problem, dass es Werte sind. "Player" ist ein String, und "PIayer" ist auch ein String. Siehst du den Unterschied? Beim zweiten folgt dem "P" ein großes "i". Der Compiler merkt sowas, denn er ist ein Computerprogramm... aber eben nicht bei Strings. Anders z.B. Klassen- oder Methodennamen. Wenn du so etwas schreibst:


GetComponent<Lighht>()

oder


GetComponnent<Light>()

dann wird dein Code nicht kompilieren und du kriegst eine Fehlermeldung, in welcher Zeile du etwas geschrieben hast, das nicht existiert. Oft sagt dir der Compiler bei solchen Fehlern sogar, welches Wort genau er nicht erkennt. Bei Strings kann er das nicht, da es Werte sind, und alle Werte sind erst einmal korrekt. Dein Code wird also kompiliert und ausgeführt. Dann kommt es zu "GameObject.Find" und er findet das Objekt nicht. Vielleicht, weil du dich vertippt hast und es dir keiner gesagt hat, vielleicht aber auch, weil irgendjemand in der Szene den Namen des Objekts kürzlich geändert hat, weil der neue Name besser passt - und schon funktioniert dein Code nicht mehr (Thema Robustheit, s.o.). Aber es kommt noch schlimmer: Bei solchen Funktionen kriegst du das gar nicht unbedingt direkt mit, wenn kein Objekt gefunden wurde. Oft geben die Dinger einfach null zurück und sind glücklich. Krachen tut es dann erst, wenn du das Objekt benutzt. Dann hast du als Fehlermeldung, dass du mit dem Objekt etwas machen wolltest, das dir rausgesucht wurde, das aber nicht ging, weil keines vorhanden ist. Der Fehler passiert also nicht bei GameObject.Find, sondern irgendwo später. Und dann darfst du suchen gehen, wo der Fehler ist.

Zusammengefasst also: Warum solltest du dir Fehler aufhalsen, bei denen du selber recherchieren musst, was los ist? Du hast eine mächtige Rechenmaschine unter deinen Fingern, die diese Aufgabe viel besser bewältigen kann als du. Du musst nur deinen Code so schreiben, dass sie ihren Job auch machen kann. Und es gibt immer elegante Wege, GameObject.Find zu ersetzen. Wenn du mal nicht weißt, wie, frage gerne nach ;)

Hast du das mal gebenchmarked? Ich wäre mit solchen Aussagen vorsichtig. Ich meine mich zu erinnern, dass Unity zumindest für Tags eine vernünftige Beschleunigungsstruktur im Hintergrund laufen hat. Aber wie gesagt... um Performance geht's mir sowieso nicht. Und deshalb stellt sich mir die Frage gar nicht erst, wenn diese Funktionen sozusagen schon "eine Runde früher ausscheiden".

Super👍👍😢 eine frage noch: wie lange programmierst du schon oder seit wann benutzt du unity? Würd mich mal interresieren, denn ich bin noch neu und habe vor in einem jahr ein spiel zu releasen.(nach einigen lernprojekten etc.)

Share this post


Link to post
Share on other sites

Programmieren seit ~20 Jahren. Unity seit ~10, glaube ich. Aber glaube nicht, dass du 10-20 Jahre brauchst, um "gut genug" zu sein. Du hörst nie auf, dich zu verbessern. Ich selbst habe mich gerade letzte Woche hier im Forum korrigieren lassen müssen, weil ich falsch lag :)

Ob es realistisch ist, in einem Jahr ein Spiel zu releasen, und das auch als anfänger, hängt komplett von dir, deiner Lernfähigkeit und deinem Projekt ab. Flappy Bird klatsche ich dir an einem Tag hin. Rechne das mal X weil du noch dies und das lernen willst oder musst, um das zu implementieren, und du bist vielleicht bei einer Woche. Wenn dein Projekt allerdings keine Kleinigkeit ist, dann kann's auch mehr als ein Jahr dauern, egal, wie gut du solo bist. Ich sitze jetzt seit etwas über einem Jahr an meinem aktuellen Projekt. Da geht zeitweise schonmal die Motivation flöten und dann wird eine Woche lang eher nur gezockt... aber naja. Anderes Thema. Solange du an den Erfolg deines Projekts glaubst, wirst du auch Fortschritte machen. Als Anfänger würde ich vielleicht nicht unbedingt deine finanzielle Sicherheit von einem Traumprojekt abhängig machen, aber solange du dir die Zeit nehmen kannst, weiter zu arbeiten, wirst du auch immer weiter kommen. Und dich währenddessen weiterentwickeln und verbessern.

  • Like 2

Share this post


Link to post
Share on other sites
7 hours ago, Sascha said:

Programmieren seit ~20 Jahren. Unity seit ~10, glaube ich. Aber glaube nicht, dass du 10-20 Jahre brauchst, um "gut genug" zu sein. Du hörst nie auf, dich zu verbessern. Ich selbst habe mich gerade letzte Woche hier im Forum korrigieren lassen müssen, weil ich falsch lag :)

Ob es realistisch ist, in einem Jahr ein Spiel zu releasen, und das auch als anfänger, hängt komplett von dir, deiner Lernfähigkeit und deinem Projekt ab. Flappy Bird klatsche ich dir an einem Tag hin. Rechne das mal X weil du noch dies und das lernen willst oder musst, um das zu implementieren, und du bist vielleicht bei einer Woche. Wenn dein Projekt allerdings keine Kleinigkeit ist, dann kann's auch mehr als ein Jahr dauern, egal, wie gut du solo bist. Ich sitze jetzt seit etwas über einem Jahr an meinem aktuellen Projekt. Da geht zeitweise schonmal die Motivation flöten und dann wird eine Woche lang eher nur gezockt... aber naja. Anderes Thema. Solange du an den Erfolg deines Projekts glaubst, wirst du auch Fortschritte machen. Als Anfänger würde ich vielleicht nicht unbedingt deine finanzielle Sicherheit von einem Traumprojekt abhängig machen, aber solange du dir die Zeit nehmen kannst, weiter zu arbeiten, wirst du auch immer weiter kommen. Und dich währenddessen weiterentwickeln und verbessern.

Ich denk mal finanzielle sorgen werd ich mir nicht machen müssen,bin noch schüler, aber danke , ich hab vor etwas in limbo art zu machen.

Share this post


Link to post
Share on other sites

Eine weitere Möglichkeit bei einem Invoke auf ein String zu verzichten ist die Methode nameof die es ab C# 6.0 gibt. Damit wird der Name der übergebenen Variable, Typ oder Methode als Zeichenkette zurückgegeben.

Statt Invoke("ResetValues", 1) schreibt man Invoke(nameof(ResetValues), 1).

So kann der Compiler die bei Invoke übergebenen Methode erfassen und die bereits genannten Schwierigkeiten vermeiden.

https://www.heise.de/developer/artikel/nameof-Operator-in-C-6-0-2391981.html

  • Thanks 1

Share this post


Link to post
Share on other sites

Witzig, damit ist mein Hauptkritikpunkt in der Tat beseitigt. Man könnte also mal Performance vergleichen. Verbleibende Vorteile meines Invokers sind, dass man die gestartete Coroutine manuell wieder abbrechen kann (kann man afaik bei Invoke nicht) - und die zusätzlichen Funktionen (sind ja nicht nur Invoke und InvokeRepeating). Aber jetzt wird's Geschmackssache :)

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

×