Husi's Surface Tutorial

      Husi's Surface Tutorial

      Hi, vielleicht hast du schon im GameMaker von Surfaces gehört.
      Mit ihnen kann man eine einfache Lichtquelle oder sogar ein Malprogramm erstellen.
      Schaut man sich Beispiele dazu an, versteht man aber größten Teils einfach nur Bahnhof.
      In diesem Tutorial werde ich versuchen dir beizubringen, wie man so etwas benutzt.

      Der Begriff Surface bedeutet im Deutschen soviel wie Oberfläche und das ist es im großen und ganzen auch.
      Statt sich eine Leinwand in einem Laden zu kaufen und dafür Geld auszugeben, müssen wir nur einen Befehl ausführen, der uns diese Leinwand in beliebiger Größe gibt.

      GML-Quellcode

      1. surface = surface_create(width,height);

      Hinweis: ich schreibe den Code (die Variablen und eigentlich auch die Kommentare) in englisch, da ich der Meinung bin, dass dies besser und cooler ist :)
      Ich erstelle damit eine Variable, die mehr oder weniger die ganze Leinwand besitzt (die freut sich bestimmt :D). width und height ist hierbei Breite und Höhe in Pixeln.
      Die Leinwand möchte ich erst einmal zum Malen gebrauchen, wozu mir eine Größe von 640x480 reicht (in dem Fall so groß wie mein Room).

      GML-Quellcode

      1. surface = surface_create(640, 480);

      Wenn ich mit meiner Maus auf der Oberfläche der Leinwand klicke/gedrückt halte, will ich einfach nur einen Kreis drauf zeichnen, der meinen „Pinsel“ darstellen soll.
      Um zu schauen ob die Maus auf der linken Taste gedrückt wird, kann ich diesen Code benutzen:

      GML-Quellcode

      1. if(mouse_check_button(mb_left)){
      2. //code
      3. }

      Fragt sich jetzt nur, wie man die Leinwand bemalt. Dies ist jedoch gar nicht so schwer.
      Man sagt dem Computer, dass man jetzt mit dem Zeichnen beginnen möchte, indem man diesen Befehl ausführt:

      GML-Quellcode

      1. surface_set_target(surface);

      Und jetzt darf ich sogar etwas machen, was man sonst nicht macht:
      draw_* Funktionen kannst ich zu diesem Zeitpunkt außerhalb des Draw's verwenden!
      Das heißt, dass du jetzt einen Kreis zeichnen kannst, der aber erstmals nur auf der Leinwand erscheint, jedoch nicht auf dem Bildschirm.

      GML-Quellcode

      1. draw_circle(mouse_x,mouse_y, 5, false);

      In dem Fall zeichne ich einen Kreis mit dem Radius 5 an der Mausposition.
      Wenn ich mit dem zeichnen fertig bin, kann ich die Arbeiten abschließen (muss gemacht werden), indem ich diesen Befehl ausführe:

      GML-Quellcode

      1. surface_reset_target();


      Zurzeit kann man aber so viel klicken, wie man will und man zeichnet nichts auf die Leinwand.
      Das ist so, weil die Leinwand erst im Draw gezeichnet werden muss.
      Dies geht aber ganz einfach mit

      GML-Quellcode

      1. draw_surface(surface, x,y);

      x und y sind natürlich die Koordinaten, die in diesem Fall 0 und 0 sind.

      GML-Quellcode

      1. draw_surface(surface, 0,0); //zeichne die Leinwand an x=0 und y=0


      Nun kann man auf der Leinwand zeichnen!

      Ich habe aber eine wichtige Sache noch nicht gesagt:
      Das Surface/die Leinwand ist in der Grafikkarte gespeichert. Manchmal, wenn man beispielsweise das Programm/Fenster minimiert, wird es einfach so mir nichts dir nichts aus dem Speicher gelöscht.
      Will ich es dann zeichnen oder etwas darauf zeichnen, bekommst ich dann einen Fehler von GameMaker, dass das Surface nicht existiert.
      Da müsste ich also noch am Code etwas machen. Bis jetzt sieht er im Step so aus:

      GML-Quellcode

      1. if(mouse_check_button(mb_left)){ //wenn Maustaste gedrückt wird
      2. surface_set_target(surface); //beginne auf der Leinwand zu zeichnen
      3. draw_circle(mouse_x,mouse_y, 5, false); //zeichne einen Kreis
      4. surface_reset_target(); //beende das zeichnen
      5. }

      Die Abfrage, ob ein Surface existiert bzw. noch da ist funktioniert so:

      GML-Quellcode

      1. if(surface_exists(surface)){
      2. //code
      3. }

      Wenn es nicht mehr existiert kann ich es einfach wieder neu erstellen und die Variable ist wieder stolzer Besitzer einer neuen Leinwand:

      GML-Quellcode

      1. if(surface_exists(surface)){ //wenn Leinwand nicht existiert
      2. surface = surface_create(640, 480); //erstelle eine neue
      3. }

      Zusammengefügt:

      GML-Quellcode

      1. if(mouse_check_button(mb_left)){ //wenn Maustaste gedrückt wird
      2. if(surface_exists(surface)){ //wenn Leinwand nicht existiert
      3. surface = surface_create(640, 480); //erstelle eine neue
      4. }
      5. surface_set_target(surface); //beginne auf der Leinwand zu zeichnen
      6. draw_circle(mouse_x,mouse_y, 5, false); //zeichne einen Kreis
      7. surface_reset_target(); //beende das zeichnen
      8. }


      Das selbe müsste ich noch beim zeichnen der Leinwand machen:

      GML-Quellcode

      1. if(surface_exists(surface)){ //wenn Leinwand nicht existiert
      2. surface = surface_create(640, 480); //erstelle eine neue
      3. }
      4. draw_surface(surface, 0,0); //zeichne die Leinwand an x=0 und y=0


      Jetzt bin ich fertig!

      Man kann theoretisch noch eine Löschfunktion einbauen, die alles gemalte zurücksetzt. Dies macht man beim Zeichnen der Leinwand:

      GML-Quellcode

      1. draw_clear_alpha(c_white, 0); //überzeichne alles mit einer unsichtbaren weiß: alles ist transparent




      Zu Anfangs erwähnte ich auch noch, dass man eine kleine Lichtquelle erstellen kann.
      In der Theorie geht man dabei so vor:
      Leinwand komplett schwarz oder stark dunkel machen und an den Positionen der Lampen das Schwarze einfach ausstanzen, damit diese Stelle transparenter wird.


      Ganz zu Anfangs muss also über

      GML-Quellcode

      1. draw_rectangle(x1,y1, x2,y2, outline);

      Schwarzes Rechteck über das Surface gezogen werden:

      GML-Quellcode

      1. draw_set_colour(c_black); //zeichne mit der Farbe schwarz
      2. draw_rectangle(0,0, width,height, false); //zeichne das Rechteck über das Surface


      Später muss dann das Rechteck mit einer Lichtquelle ersetzt werden, damit man dort durchschauen kann.
      Als erstes setzt man den sogenannten blendmode auf subtract, wodurch man die jeweiligen Stellen ausstanzen kann.

      GML-Quellcode

      1. draw_set_blend_mode(bm_subtract);

      Danach muss einfach nur das gezeichnet werden, was die Fläche ausstanzen soll:

      GML-Quellcode

      1. draw_sprite(spr_light,0, light_x,light_y);

      Das wars schon fast. Zum Schluss muss der Modus aber wieder zurück gestellt werden:

      GML-Quellcode

      1. draw_set_blend_mode(bm_normal);



      So das war's. Wenn du Fragen hast, frag sie einfach hier, als PN oder über Discord(Link in Signatur).
      Ich wünsche dir noch einen schönen Tag ;)

      Weitere Tutorials:
      Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
      Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

      Willst du mit mir auf Discord Chatten/Quatschen?
      Meine Husi's Tutorial Reihe

      Dieser Beitrag wurde bereits 4 mal editiert, zuletzt von „Husi012“ ()

      @Husi012

      hy tolles tütorial wahnsinnig güt doch eine frage hab ich noch also ich hab ein player objekt im raüm was keinen code enthält nür ein sprite ünd ich kann am sürface drawen aber nicht über den player objekt nür darünter wieso?


      ünd wie kann ich es machen das er nür eine gewisse zeit lang aüf dem sürface drawt..müss ich dafür dann diese fünktion benützen
      draw_clear_ext(c_white, 0); //überzeichne alles mit einer unsichtbaren weiß: alles ist transparent
      oder müss ich das sürface löschen ünd neü erstellen

      in einem alarm?? weil sagen wir ich will spüren machen die vom ball entstehen...doch soll der raüm nicht damit überflütet werden sondern wenn eine gewisse zeit oder menge gezeichnet würde soll es wieder resetet werden..



      EDIT: also anscheinend gibt es die fünktion draw_clear_extnicht mehr gibt es eine andere? ich seh grad es gibt draw_clear noch werds mal testen
      passt geschafft!!!


      eins noch könntest dü mir ein paar anregüngen geben was man alles noch mit sürfaces machen kann

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „acidrain833“ ()

      Oh Entschuldigung.
      Die Funktion heißt draw_clear_alpha.

      Mit

      GML-Quellcode

      1. draw_clear_alpha(c_white, 0);

      kannst du den Screen "resetten". Um das zeitlich zu bewerkstelligen gebrauchst du dann, wie du sagtest, beispielsweise einen Alarm.

      Als Anregung hätte ich Partikel wie Munition oder Blutspritzer.
      Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
      Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

      Willst du mit mir auf Discord Chatten/Quatschen?
      Meine Husi's Tutorial Reihe

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „Husi012“ ()

      @Husi012

      danke dir aber kannst dü mir sagen wieso nicht aüf dem player objekt gedrawt wird..ich dachte das sürface ist über den ganzen room...also so hab ich die größe gemacht gehabt.ich konnte übreall zeichnen aüsser dort wo der player war(ja konnte doch dort zeichnen aber nür ünter ihm sodass man es nicht sah...wie mach ich es das ich aüch aüf ihm zeichnen kann???)
      Das liegt an der Depth (je kleiner desto höher auf der Oberfläche). Wenn du die vom Spieler niedriger legst oder die der Instanz, die das Surface drawst höher legst, kann man es wieder sehen.
      Andernfalls ist es auch möglich das DrawGui zu verwenden. Da zeichnest du ja über allem, was im normalen Draw gezeichnet wird. Beachte aber, dass du da nur auf den jeweiligen Ausschnitt (meistens View) drawst und nicht auf den "ganzen Room"
      Ein Bug ist mehr als nur ein Bug, es ist ein... Käfer!
      Egal, wie gut du eine Mauer baust, sie fällt um.... der klügere gibt nach :D

      Willst du mit mir auf Discord Chatten/Quatschen?
      Meine Husi's Tutorial Reihe