Jump to content
Unity Insider Forum
nordseekrabe

Koordinatenabgleich

Recommended Posts

Moin, moin,

habe wieder einmal eine Frage und hoffe auf eine freundliche Unterstützung. Habe ein kleines Puzzle als Spiel im Spiel gemacht. Zur Kontrolle, ob ein Puzzleteil richtig abgelegt wurde, wollte ich eine if-Abfrage machen: if (puzzle0.transform.position == cell0.transform.position) correctPuzzle = correctPuzzle+1; wenn dann correctPuzzle =25 ist, ist das Puzzle richtig gelöst worden. Leider funktioniert das alleine schon deswegen nicht, weil die Position der Cell0 andere x- und y-Werte hat als x und y des Puzzle0, obwohl beide übereinander liegen. Cell0-24 sind Gameobjects mit einem Slotsprite, von der gleichen Größe wie ein Puzzleteil. Wo liegt hier mein Gedankenfehler ? Wie kann ich das Problem angehen. Klar ist mir auch, dass der Abgleich beider Positionen problematisch ist, da ja so haargenau die Ablage selten gelingen dürfte. die Position der Cell müsste also einen kleine Toleranz erlauben.

Besten Dank schon einmal für Eure Hilfe

nordseekrabbe (Peter)

Share this post


Link to post
Share on other sites

Es ist mir gelungen, das Problem mit dem Koordinatenabgleich zu klären: alle Puzzles und alle Cells sind jeweils in einem Ordner zusammengefügt. Diese Ordner müssen beide in den Koordinaten 0-0 liegen und dann stimmen auch Cell0 und puzzle0 mit x und y überein, wenn sie übereinander liegen ! Die 2. Frage bleibt aber: wie kann man die Toleranz für die Puzzles erweitern, ohne die Cells in ihrer Position zu verändern. Also als Beispiel: Cell0 liegt auf x = -2.8 und y = 3.2; jetzt darf Puzzle0 nicht nur auf x=-2.8 und y=3.2 liegen müüsen, sonder so etwa x= -2.6-3.0 und y = 3.0-3.4. Wie das zu vercoden, ist mir noch nicht klar !

Gruß

nordseekrabbe (Peter)

 

Share this post


Link to post
Share on other sites

Das kannst Du z.B. lösen, indem Du die Differenz berechnest.

const float limit = 0.25f; //die maximale abweichung in beide Richtungen
var diff = Mathf.Abs(transform.position.x - otherTransform.position.x); //differenz ohne Vorzeichen
var valueInRange = diff <= limit; //wenn Differenz kleiner gleich limit, ist der Wert im Limitbereich

 

Share this post


Link to post
Share on other sites

Vielen, vielen Dank !! Habe heute nacht um 3 Uhr diese Idee auch umgesetzt; natürlich längst nicht so professionell sondern eher laienhaft:

                                               
        if ((cell0.transform.position.x - puzzle0.transform.position.x) < 0.01f && (cell0.transform.position.y - puzzle0.transform.position.y) < 0.01f ||
            (cell0.transform.position.x - puzzle0.transform.position.x) < -0.01f && (cell0.transform.position.y - puzzle0.transform.position.y) < -0.01f)
        {
            correctPuzzle = correctPuzzle + 1;
            Debug.Log("0 passt");
        }

Hatte zunächst den Gedanken, das ganze mit "Modulo kleiner als" zu gestalten, aber da wusste ich nicht, wie die Syntax auszusehen hätte.

Aber dennoch habe ich mich sehr über die Reaktion und Hilfe von "devandart" gefreut. Einfach super !

Gruß

nordseekrabbe (Peter)

Share this post


Link to post
Share on other sites

Habe jetzt die Methode "Mathf.Abs() von "devandart" übernommen; spare dann ja die oder-Abfrage, sodaß der Code nun so aussieht:

                     if (Mathf.Abs(cell0.transform.position.x - puzzle0.transform.position.x) < limit && Mathf.Abs(cell0.transform.position.y - puzzle0.transform.position.y) < limit)

Funktioniert sehr gut. Da diese Abfragen in void Update () aufgerufen werden, wird es schwierig den Output zu formulieren. Eigentlich wollte ich u.a. hier einfügen : correctPuzzle = correctPuzzle +1, aber in Update fügt das Programm dann 1 pro Frame hinzu, sodass die Bedingung if (correctPuzzle == 25 ) bereits beim 1. richtigen Puzzleteil erreicht wird. Auch Texte einfügen ist mit Textflackern verbunden. Naja, mal sehen.

nordseekrabbe (Peter)

Share this post


Link to post
Share on other sites

Moin, moin,

sieht insgesamt ganz ordentlich aus:

if (Mathf.Abs(cell24.transform.position.x - puzzle24.transform.position.x) < limit && Mathf.Abs(cell24.transform.position.y - puzzle24.transform.position.y) < limit)
        {
            valueInRange = true;
            puzzle24.transform.position = new Vector3(3.6f, -0.4f, 0);
            CheckPuzzleComplete();
        }

Das Puzzleteil "springt" jetzt in die passende Position, wenn die Differenz der Positionen von puzzle und cell klein genug ist. Damit hat der Spieler auch eine gewissen Kontrolle, dass das richtige Puzzle an der richtigen Stelle liegt. Es gelingt mir nicht, die Vollständigkeit des Puzzles zu prüfen.

private void CheckPuzzleComplete()
    {
        foreach (GameObject puzzle in puzzles)     //puzzles ist der Name der List<GameObject>
        {
            if (valueInRange == true)
            {
                winText.text = "Super, du hast das Puzzle gelöst. Natürlich wirst du belohnt!";
             }
        }
    }

Die Funktion klappt nicht,  vermutlich, weil "valueInRange" kein Property von Puzzle0 bis Puzzle24 ist ? Hat bitte jemand ein Tipp für mich ?

Gruß  nordseekrabbe (Peter)

Share this post


Link to post
Share on other sites

Ja, so wie es aussieht ist valueInRange einfach nur eine boolsche Variable die du da auf true setzt. Ich sehe da keinen zusammenhang mit irgendeinem Puzzleteil.

Warum zählst du nicht einfach einen Wert hoch, sobald ein Puzzleteil an richtiger Stelle ist?
Beim Puzzlestart hat der Zähler den Wert 0 und bei jedem einschnappen eines Puzzleteils erhöht sich dieser Wert um 1. Sobald die 25 (bei einem 25-teiligen Puzzle) erreicht ist, ist die Bedingung für deinen Text erfüllt. Da brauchst du nicht extra ne Liste für.

Share this post


Link to post
Share on other sites

Erst mal danke für den Hinweis. Aber, wie ich oben bereits geschrieben habe, funktioniert (bei mir)  dieser Weg nicht, da bereits nach der ersten korrekten Plazierung das Puzzle als vollständig gemeldet wird. Dabei habe ich die Funktion "CheckPuzzleComplete" (nochmals) wie folgt geändert

     private void CheckPuzzleComplete()
    {
        correctPuzzle = correctPuzzle + 1;
        if (correctPuzzle == 25)
        {
            winText.text = "Super, du hast das Puzzle gelöst. Natürlich wirst du belohnt!";
         }
     }

Diese wird natürlich in Update ständig ausgeführt und "correctPuzzle" ist fix gleich 25. Wo könnte ich denn das Hochzählen sonst plazieren oder, was mache ich falsch ?

Gruß und ein schönes Wochenende an alle

nordseekrabbe (Peter)

Share this post


Link to post
Share on other sites

Du darfst nicht im Check hochzählen, sondern da, wo du das Puzzleteil richtig platzierst. Das sollte ja für jedes Teil nur einmal passieren.

(Sollte, denn diese Positionsabfrage sollte nur dann kommen, wenn du das Teil loslässt. Also bei OnMouseUp, oder so.)

Aber es führen viele (alle) Wege nach Rom!
Versuche jedenfalls gewisse Sachen immer nur bei einem Ereignis auszuführen, nicht ständig in der Update. Wenn ein Puzzleteil einmal liegt, also an die entsprechende Position gebracht wurde, ist das Ereignis da. Aber eben nur dann. Und nur dann erhöhst du den Zähler.
Du kannst natürlich auch mit einer Liste oder einem Array arbeiten und dort etwas hinzufügen oder einen Wert einer Stelle ändern.

Aber niemals immer wieder duch den ganzen Code fahren, denn das kostet Leistung!
Das wäre nämlich so, als würdest du ein Buch lesen und bei jedem neuen Wort immer wieder von vorne anfangen, bis du beim nächsten neuen Wort bist, und dann wieder von vorne anfangen, usw. usw. Nur weil ein Rechner das irre schnell kann, heisst das nicht, dass es keine Zeit oder Leistung kostet.

 

Share this post


Link to post
Share on other sites

Danke, malzbie. Werde versuchen, diese Gedanken auch beim Scripting einzubauen und erforderliche Veränderungen zu entdecken.

Das ist meines Erachtens mein Hauptproblem, meine Alltagslogik als Nicht-Informatiker in das "Maschinenverständnis" umzusetzen. Und da fehlt halt ein Informatik-Studium und unendlich viel Erfahrung. Ein gutes Beispiel ist weiter oben zu sehen; dass eine Toleranz für den Spieler für das Platzieren des Puzzleteils mit der Subtraktion von Position Puzzle und Position Cell zu erreichen ist, ist mir über Alltagslogik aufgegangen. Dass man hierfür zur Vereinfachung des Codes eine "Mathf.Abs()" einsetzen kann, weiss der Fachmann (devandart). Da gibt es sicher tausend Sachen in Unity und c# , die mir völlig unbekannt sind, und daher dann einfach nicht zur Lösung von vermeintlich Problemen zum Einsatz kommen können.Was alles in Bibliotheken der Programmiersprache und der Game-Engine enthalten ist, kann man nicht so nebenbei wissen. Das muss man lernen, über Jahre, wie eine Fremdsprache. Und hier setzt der freundliche Helfer ein, dass man als Hobbyist nicht verzweifelt und alles wegschmeisst. Natürlich sucht man im Internet und in Tutorials nach vergleichbaren Situationen und sicher setzt man dann auch da und dort Codeschnipsel ein, die zwar passen, die man aber überhaupt nicht versteht.

Und dennoch macht es mir Spaß, ein Projekt durchzuackern, mal rauf, mal runter. Es regt den Geist an und gibt auch hin und wieder eine kleine Portion Genugtuung. 

Gruß Nordseekrabbe (Peter)  

Share this post


Link to post
Share on other sites

Ich kann dich voll verstehen. Auch zu meiner Zeit gab es noch kein Informatik Studium. Ich habe aus Interesse von alleine mit Basic auf dem VC20 angefangen. Alles ohne Internet!
Ich habe damals, vor 35 Jahren, schon viel gelernt, bin aber regelmäßig gescheitert.
Und trotzdem bin ich heute in der Lage komplette Spiele zu erstellen (Grafik, Sound, Musik, Objekte, Logik), weil ich an all den Dingen interesse hatte und im Lauf der Zeit immer mehr gelernt habe.

Was dir jetzt helfen könnte, ist Folgendes:

Geh einfach einmal davon aus, dass du nicht ein Ding baust, um ein Spiel zu erstellen, sondern viele unterschiedliche Dinge, die miteinander Kommunizieren können und als Ganzes dann ein Spiel ergeben.
Dei Puzzlespiel besteht aus vielen Dingen. Da ist der Ablageort, der 25 Bereiche hat, und da sind 25 Puzzleteile. Muss jedes Ding jetzt alles von den anderen Dingen wissen? Nein!
Dem einzelnen Puzzleteil ist es doch total egal, was mit den Anderen Puzzleteilen ist. Es muss auch nicht wissen, wo es aufgehoben wurde und wo es hingelegt wird.
Es muss aber wissen wenn es aufgehoben wird und wenn es hingelegt wird. Es sollte außerdem eine Identifikation haben und das Script kennen, welches die Auswertung macht, wo das Script auch immer liegt.
Alle 25 Puzzleteile sind von der Art her also gleich und haben somit alle das gleiche Script. Sie unterscheiden sich eigentlich nur in der Identifikation, also von der Puzzleteil-Nummer.

Wird jetzt eines dieser Puzzleteile mit der Maus angeklickt, weiss es, dass es etwas mit ihm passiert. Das Puzzleteil wacht also auf und könnte jetzt z.B. immer der Mausposition folgen, oder einfach nur seine Identifikationsnummer an das Auswertungsscript übergeben, oder, oder, oder.
Wird dieses Puzzleteil jetzt wieder gehen gelassen, dann wird es auf jeden Fall dem Auswertungsscript sagen, dass es so ist und wo es sich gerade befindet.
Es könnte also in eine Methode oder Funktion des Auswertungsscriptes rein springen und die wichtigen Daten gleich mit übermitteln. In dieser Funktion würde dann überprüft, ob das Teil nahe genug an seinem Soll-Ort liegt. Tut es das, dann würde das Teil an die exakte Position geschoben und sich irgendwie gemerkt, dass ein Teil richtig liegt.
Das Puzzleteil macht also nur dann etwas, wenn es aufgehoben wird bzw. ist oder wenn es abgelegt wird. Sonst macht es eigentlich nichts.
Das Auswertungsscript macht immer nur dann etwas, wenn das Puzzleteil in die Funktion oder Methode rein springt. Einmalig überprüft es, die richtige Position des Teils. Passt die Position, wird sich gemerkt, dass ein Teil richtig liegt und es wird zusätzlich überprüft, ob nun alle Teile richtig sind. Wenn ja, wird ein weiteres Ereignis gestartet, wobei der Erfolgstext angezeigt wird und dann auf beenden des Spiel gewartet wird. Wenn nein, passiert nichts.

Eine andere Möglichkeit wäre, dass jedes Puzzleteil seinen Bestimmungsort schon kennen würde. Dann würde das Teil beim Ablegen selber überprüfen, ob es richtig liegt und dann eben einfach nur den Erfolg an das Auswertungsscript senden. Das könnte etwas einfacher zu handhaben sein.

Wie dem auch sei. Du solltest dir einfach überlegen, was ein Ding alles können und wissen sollte um zu funktionieren. Welche Information ist für welches Ding wichtig und welche nicht.
Sind viele Dinge nahezu gleich und unterscheiden sich nur in wenigen Bereichen, dann sollte man sie so aufbauen, dass sie wiederverwendbar sind. Ein Puzzleteil beommt einfach nur eine eigene Nummer, evtl. einen Zielort und eine entsprechende Grafik. Alles Andere ist bei allen Puzzleteilen gleich.
Ein Informationsaustausch von einem Objekt zum Anderen sollte nur Ereignisgesteuert sein. Nur bei einer entscheidenden Änderung muss das andere Objekt etwas darüber wissen.
Und auch nur dann, muss etwas ausgewertet werden.
Ob jetzt ein Objekt eine Sache an ein anderes Objekt übermittelt, also z.B. in eine Methode rein springt, oder ob ein Objekt einen Variablen-Wert eines anderen Objektes zu gewissen Zeiten abfragt, ist eine Frage der Vorliebe, des Aufbaus und der Häufigkeit des Informationsaustausches. Beides geht und beides macht Sinn.

 

Share this post


Link to post
Share on other sites

Besten Dank, malzbie, für die sehr ausführliche Erklärung. Mit reichlich Information versorgt werde ich weiter versuchen, die erforderliche und richtige Gestaltung des Scriptings zu finden. Die Platzierung (Bewegung der Puzzleteile) sowie die Abklärung über Korrektheit der Puzzlelage scheinen ja schon zu funktionieren. Jetzt gilt es halt noch,  die Vervollständigung des Puzzles zu erkennen und dann zu Belobigen. Wird schon werden, aber nochmals danke für die Erläuterungen.

Schönes Wochenende und Gruß von der Ostseeküste

nordseekrabbe (Peter)

Share this post


Link to post
Share on other sites

Moin, moin,

falls Interesse besteht zum Abschluss meine Lösung des Puzzles: für jedes Puzzleteil habe ich ein Boolean deklariert (puzzle1ValueInRange, puzzle2...) und auf false gestellt. Mit dem Abgleich der Puzzleposition wird o.g. Variable auf true gesetzt. Zum Abschluss eine "if (alle 25 puzzles gleich true), voila , so klappt es. Zugegeben sieht der Code verdammt unprofessionell aus, aber es läuft erst einmal. Mit zunehmendem Wissen kann ich da sicher eine Menge verbessern. Aber wollen wir doch bescheiden sein.

Jetzt geht es an das große Projekt "Save and Load" für das gesamte Spiel mit ca. 45 Szenen, da habe ich mir was vorgenommen ?!

noch einen Schönen Sonntag für alle

Gruß nordseekrabbe (Peter)

 

  • Like 1

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...

×
×
  • Create New...