3d für Anfänger - Pixelgenaue Auswahl von Objekten

    • GM 6

    Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

    • 3d für Anfänger - Pixelgenaue Auswahl von Objekten

      Pixelgenaue Auswahl von Objekten


      Dieses Tutorial beschäftigt sich mit einer Methode, 3 oder 2 -dimensionale Objekte pixelgenau mit der Maus anzuwählen. So lassen sich z.B. Schalter in Spielen leicht realisieren.
      Im Anhang findest du eine Grundgerüst-Datei, mit der du dieses Tutorial bearbeiten kannst.

      Theorie:



      Der Kern dieser Methode besteht darin, sogenannte "Hitboxes" in einem zweiten View zu zeichnen. Im anderen wird ganz normal das Level dargestellt.
      Jede Hitbox bekommt ihre eigene Farbe, damit sie dem jeweiligen Objekt zugeordnet werden kann.
      Nun wird jeden Step überprüft, ob der Mittelpunkt des Bildschirms die Farbe der jeweiligen Hitbox hat.
      (vorrausgesetzt das Spiel ist ein FPS. Andererseits wären es die Mauskoordinaten)
      Wenn ja, ist das Objekt angewählt.



      Vorbereitungen:

      Bevor wir nun zum Wesentlichen kommen, müssen einige Vorbereitungen getroffen werden.
      Da wir nun mehrere Views benutzen, müssen diese zuerst aktiviert werden.
      View[0] wird der View sein, in dem die Hitboxes nacher gezeichnet werden, in view[1] das eigentliche Level.
      Diese Anordnung sorgt dafür, dass die Hitboxes für den Spieler nicht sichtbar sind, da view[0] vom anderen verdeckt wird.

      Desweiteren müssen wir darauf achten, dass unser Level ausschließlich in view[1] gezeichnet wird und unsere Hitboxes nur in view[0].
      Daher prüfen wir immer bevor wir etwas zeichnen, ob wir uns im richtigen View befinden:

      GML-Quellcode

      1. if(view_current == 1)
      2. {
      3. //Hier kann gezeichnet werden
      4. }


      Achten wir nicht darauf, könnten Objekte die Hitboxes überdecken, sodass falsche Farbwerte übermittelt werden.

      Praxis:

      Zuerst erstellen wir ein Objekt "obj_color".
      Dieses wird nun jeden Step den Farbwert des Bildschirm-Mittelpunkts ermitteln.
      Wir deklarieren also eine Variable "mCol" und stellen den depth-Wert auf -10, damit wir sicher gehen können, dass bereits alle Hitboxes gezeichnet wurden, wenn wir die Farbe ermitteln.

      Im Drawevent passen wir mCol entsprechend an:

      GML-Quellcode

      1. if(view_current == 0) //Wichtig: Wir befinden uns in view[0]
      2. {
      3. mCol = draw_getpixel(mouse_x,mouse_y); //Die Funktion gibt den Farbwert des Pixels wieder
      4. }


      Jetzt folgen noch zwei Scripte, die sich um die Farbgebung und das Vergleichen der Farben kümmern:

      d3d_selection_request()

      GML-Quellcode

      1. //Wenn die globale Zählervariable "xCol" noch nicht existiert, wird sie hier erstellt
      2. if(!variable_global_exists("xCol"))
      3. variable_global_set("xCol",0);
      4. global.xCol+=1;
      5. return make_color_rgb(global.xCol,100,100);


      Als Rückgabewert wird eine Farbe aus den Werten rot, grün und blau gebildet.
      Grün und blau sind in diesem Fall statisch. Der Rot-Wert wird jedoch durch die Zählervariable "xCol" bestimmt.
      Die Funktion kann daher 255 mal aufgerufen werden (Maximalwert).
      255 auswählbare Objekte sollten normalerweise mehr als ausreichend sein, wenn nicht kannst du die grün und blau Werte auch variabel machen.

      Dieses Script kommt ins Create-Event eines auswählbaren Objekts.
      Da die Farbe der künftigen Hitbox als Wert zurückgegeben wird, speichern wir sie in einer Variable, ich benutze dafür "sCol" (Selection Color).
      Ein "request" sähe also wie folgt aus:

      GML-Quellcode

      1. sCol = d3d_selection_request();


      Nachdem ich nun die ganze Zeit von Hitboxes geredet habe, zeig ich mal ein kleines Beispiel:

      Angenommen, wir zeichnen in view[1] folgenden Würfel,

      GML-Quellcode

      1. if(view_current == 1)
      2. {
      3. d3d_draw_block(x-4,y-4,0,x+4,y+4,8,tex,1,1);
      4. }


      wäre die passende Hitbox dazu:

      GML-Quellcode

      1. if(view_current == 0)
      2. {
      3. draw_set_color(sColA)
      4. d3d_draw_block(x-4,y-4,0,x+4,y+4,8,-1,1,1);
      5. draw_set_color(c_white);
      6. }


      Wichtig: Hitboxes dürfen keine Texturen haben, da sie nur die zugewiesene Farbe haben dürfen.
      Schreibt also einfach anstelle einer Textur "-1".
      Auch die Benutzung von Lichtern oder Fog (Nebel) kann die Farben und somit das Ergebnis beeinflussen - stellt sie also vorher ab, und danach wieder ein.

      Die Funktion "d3d_selection_get()" überprüft lediglich, ob "sCol" der Farbe mCol entspricht.

      Zur Erinnerung:

      sCol = Farbe der Hitbox, die durch ein "request" erhalten wird.
      mCol = Farbe des Bildschirm-Mittelpunkts (befindet sich in "obj_color")

      d3d_selection_get()

      GML-Quellcode

      1. return argument0 == obj_color.mCol;


      Wenn der Rückgabewert true ist, ist das Objekt angewählt, bei false nicht.

      Nun sind alle Grundlagen vorhanden, und wir können uns jetzt allerlei Objekte basteln.
      Zum Abschluss noch ein kleines Beispielobjekt.
      Das Objekt soll eine einfache Kugel sein, die hell wird wenn wir sie mit der Maus berühren.

      Create-Event:

      GML-Quellcode

      1. sCol = d3d_selection_request();
      2. col = c_gray; //Die Farbe der Kugel. Ist die Farbe grau, erscheint sie dunkel, bei weiß hell
      3. tex = background_get_texture(tex_floor);


      Step-Event:

      GML-Quellcode

      1. if(d3d_selection_get(sCol)) //Ist das Objekt angewählt wird col die Farbe c_white zugewiesen, sonst c_gray
      2. col = c_white;
      3. else
      4. col = c_gray;


      Draw-Event

      GML-Quellcode

      1. //Hier sollte alles klar sein
      2. if(view_current == 1)
      3. {
      4. draw_set_color(col)
      5. d3d_draw_ellipsoid(x-2,y-2,5,x+2,y+2,9,tex,1,1,30);
      6. draw_set_color(c_white)
      7. }
      8. if(view_current == 0)
      9. {
      10. draw_set_color(sCol)
      11. d3d_draw_ellipsoid(x-2,y-2,5,x+2,y+2,9,-1,1,1,30);
      12. draw_set_color(c_white);
      13. }
      Alles anzeigen


      Bei mir sieht das Ganze dann so aus:




      Das war's auch schon wieder. Im Anhang findet ihr wie immer eine ausführliche und auskommentierte Beispieldatei mit Anwendungsbeispielen, außerdem noch die Grundlagen-Datei, auf deren Basis ihr mit dem Tutorial arbeiten könnt.
      Viel Spaß beim ausprobieren und Danke für's Lesen, hier noch ein paar Screenshots aus der Beispieldatei:

      Die Technik wird hier benutzt um ...

      ... ein Produkt auszuwählen und die Dose aus dem Auffangbehälter zu nehmen

      ... die Blöcke auszuwählen und wegzuklicken (Ja, ganz offensichtlich an Minecraft angelehnt)

      ... den Schalter umzulegen, der wiederrum die Lampe anstellt
      Dateien
    • Sehr schön mal wieder :)
      Die Methode kannte ich zwar schon, allerdings wird es wohl noch dem ein oder anderen User hier helfen.
      Danke, das du dir die Mühe machst. Die Tutorials sind sehr hilfreich!

      Btw, gm-d ist im Minecraft-Fieber - und das alles nur wegen dem GameJolt-Demake-Contest :3 (nichts gegen Minecraft, ich mag Minecraft auch sehr :O)
    • Wie immer genial, einfach und gut erklärt... :thumbup:
      Wer den Unterschied besser sehen möchte in view 1, kann auch das hier verwenden:

      GML-Quellcode

      1. if(!variable_global_exists("xCol"))
      2. variable_global_set("xCol",0);
      3. global.xCol+=1;
      4. return make_color_hsv(global.xCol mod 256,255-(global.xCol div 256),100);

      Damit sind übrigens statt 256Objekten, sogar 65.536Objekte möglich ;)

      MfG Whiterock

      edit:

      Wie könnte ich es machen, dass er erkennt, von welcer seite er angeklickt wird?
      (am einfachsten wäre es, wenn man die seiten des blocks verschieden einfärbt, nur wie?)

      Danke im vorraus

      Dieser Beitrag wurde bereits 2 mal editiert, zuletzt von whiterock () aus folgendem Grund: dickes fettes Edit!

    • Benutzer online 1

      1 Besucher