Wasser effekt

    • Skript

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

    • Wasser effekt

      Also, gestern morgen hat mich jemand gefragt ob ich einen Wassereffekt basteln könnnte. Dieser Aufgabe habe ich mir gestellt und es dann auch vollbracht.

      Funktionsweise:

      Als erstes wird ein 2 dimensionales netzt erstellt. Dieses netzt besteht aus punkten. Jeder punkt (als array gespeichert) hat ein paar werte:
      hspeed, vspeed, pos_x und pos_y.

      Diese Punkte können dann auf 2 verschidene Arten bewegt werden. Ein mal können die wellen ausgelöst werden, an einem bestimmten punkt. Zum anderen kann man generell wellen haben. D.h es sind überall Wellen, und sie werden nicht von einem bestimmten Punkt ausgelöst.

      Im draw event wird dann ein screenshot vom screen gemacht, dieser dann transformiert gedrawt, da der folgende schritt eine textur im 512x512 oder 1024x1024 u.s.w format brauch. Dieser wird dann wiederrum auch wieder fotografiert und dann als textur für ein primitve genutzt.

      Kommentar:

      Wenn man den schritt mit dem erstellen einer textur vom screen rausnimmt, und statt dessen nur eine fertige textur nutzt, ist diese Extention sogar relativ produktiv. Leider besitzt der Gamemaker keine funktion wie texture_set_width. Von daher muss ich viele zwischenschritte machen, die sowohl sehr auf die performance gehen, und auch die quallität sehr verringern. Wer einen view von 640x480 nutzt, muss die resolution auf 256 stellen. Man kann sich jetzt gut vorstellen, was für ein wischiwaschi das wird. Ich habe noch die option eingebaut, einzustellen ob man interpolation nutzten will. Dann wird aus dem wischiwaschi wenigsten ein retro pixel look. Wer will kann sich ja mal mit dem code auseinadersetzen. Ich schätzte jetzt einfach mal pi*daumen dass da mehr kommentare als wirklicher code ist :P . Hier ein screen:
      view: 640x480;
      resolution: 256;


      Wer noch probleme damit hatte, sich die Funktionsweise vorzustellen, dem hilft vieleicht das hier:


      Genug gequatscht. Hier also die 5 funktionen:

      [hide=water_set() - initalisiert alles oder ändert die Einstelungen]

      GML-Quellcode

      1. /*
      2. real - rgument0=gridsize - muss in die nächsten beiden arguemente aufgehen!
      3. real - argument1=width;
      4. real - arguemnt2=height;
      5. real - argument3=friction;
      6. real - argument4=stärke - gravitation - die stärke mit der das wasser wieder in die ursprüngliche position geht größer=langsamer;
      7. real - argument5=resolution; bitte nur 2potenz nutzen
      8. bool - argument6=interpolation;
      9. */
      10. grid_hspeed=0; // wird nachher als array genutzt um die geschwindichkeit der punkte zu speichern
      11. grid_vspeed=0; // wird nachher als array genutzt um die geschwindichkeit der punkte zu speichern
      12. grid_pos_x=0; // wird nachher als array genutzt um die absolute position des punktes zu speichern
      13. grid_pos_y=0; // wird nachher als array genutzt um die absolute position des punktes zu speichern
      14. // ab hier ändern
      15. gridsize=argument[0]; // die größe des grides in pixel - muss in width un heigth aufgehen!!!!
      16. width=argument[1]; // breite
      17. height=argument[2]; // höhe
      18. fric=argument[3]; // der wiederstand
      19. starke=argument[4]; // die stärke mit der das wasser wieder in die ursprüngliche position geht größer=langsamer
      20. resolution=argument[5]; // die auflösung.. bitte nur 2potenz nutzen
      21. interpolation=argument[6];
      22. //ende
      23. textur=0; // die textur, wird im draw genutzt um die textur zu speichern
      24. background=0; // temporär - für den screen;
      25. xmacher=0; // position des auslösen der wellen
      26. ymacher=0; // muss im step gesetzt werden
      27. prev_xmacher=0;// wichtig um die distance und
      28. prev_ymacher=0;// die geschwindichkeit der punkte
      29. pointx=0; // die position von xmacher im grid
      30. pointy=0; // die position von xmacher im grid
      31. vtimes=height/gridsize+1;
      32. htimes=width/gridsize+1;
      33. for(h=0;h<vtimes;h+=1) {
      34. for(w=0;w<htimes;w+=1) {
      35. grid_pos_x[w,h]=w*gridsize;
      36. grid_pos_y[w,h]=h*gridsize;
      37. grid_hspeed[w,h]=0; // array mit nichts füllen :P
      38. grid_vspeed[w,h]=0;
      39. }
      40. }
      Alles anzeigen
      [/hide][hide=water_calc1() - Der angesprochene 1. Effekt]

      GML-Quellcode

      1. /*
      2. typ: wellen auslöser;
      3. berechnet das wasser - im step event aufrufen
      4. real - argument0=x position des auslösers neuer wellen;
      5. real - arguemnt1=y positoon des auslösers neuer wellen;
      6. bool - arguemnt2=soll eine welle ausgelöst werden?
      7. real - argument3=die stärke: 0->1;
      8. */
      9. //bewegung des ganzen berechnen
      10. prev_xmacher=xmacher;
      11. prev_ymacher=ymacher;
      12. xmacher=argument[0];
      13. ymacher=argument[1];
      14. // den punkt finden, der am nächsten zum y/xmacher ist
      15. pointx=round(xmacher/gridsize);
      16. pointy=round(ymacher/gridsize);
      17. // die änderun dem punkt zufügen
      18. if (argument[2]) { // wenn die änderung sein soll
      19. grid_hspeed[pointx,pointy]+=(xmacher-prev_xmacher)*argument[3];
      20. grid_vspeed[pointx,pointy]+=(ymacher-prev_ymacher)*argument[3];
      21. }
      22. for(w=0;w<htimes;w+=1) {="" wollen="" wir="" jedem="" punkt="" noch="" friction="" und="" eine="" kraft="" verleihen,="" die="" punkte="" wieder="" an="" deren="" ursprünglichle="" position="" bewegt
      23. for(h=0;h<vtimes;h+=1) {=""
      24. grid_vspeed[w,h]+=(h*gridsize-grid_pos_y[w,h])/starke; // die kraft hinzufügen
      25. grid_hspeed[w,h]+=(w*gridsize-grid_pos_x[w,h])/starke;
      26. grid_hspeed[w,h]/=fric+1; // friction
      27. grid_vspeed[w,h]/=fric+1;
      28. // alle änderung auf die position übergeben
      29. grid_pos_x[w,h]+=grid_hspeed[w,h];
      30. grid_pos_y[w,h]+=grid_vspeed[w,h];
      31. }
      32. }
      Alles anzeigen


      [/hide][hide=water_calc2() - der 2. Effekt]

      GML-Quellcode

      1. /*
      2. typ: generell wellen;
      3. berechnet das wasser - im step event aufrufen
      4. real - arguemnt0=wellengang;
      5. */
      6. for(w=1;w<htimes-1;w+=1) {="" wir="" starten="" nicht="" mit="" dem="" ersten="" um="" machen="" auch="" den="" letzten,="" damit="" die="" äußersten="" punkte="" still="" bleiben.
      7. for(h=1;h<vtimes-1;h+=1) {=""
      8. //bewegung des ganzen berechnen
      9. prev_xmacher=xmacher;
      10. prev_ymacher=ymacher;
      11. xmacher=random(argument[0])-argument[0]/2;
      12. ymacher=xmacher;
      13. // die änderung dem punkt zufügen
      14. grid_hspeed[w,h]+=xmacher-prev_xmacher;
      15. grid_vspeed[w,h]+=ymacher-prev_ymacher;
      16. // die gravity hinzufügen
      17. grid_vspeed[w,h]+=(h*gridsize-grid_pos_y[w,h])/starke;
      18. grid_hspeed[w,h]+=(w*gridsize-grid_pos_x[w,h])/starke;
      19. grid_hspeed[w,h]/=fric+1; // friction
      20. grid_vspeed[w,h]/=fric+1;
      21. // alle änderung auf die position übergeben
      22. grid_pos_x[w,h]+=grid_hspeed[w,h];
      23. grid_pos_y[w,h]+=grid_vspeed[w,h];
      24. }
      25. }
      Alles anzeigen

      [/hide][hide=water_draw() - drawt den wasser effekt]

      GML-Quellcode

      1. /* drawt das wasser an der positon;
      2. real - argument0=x;
      3. real - argument1=y;
      4. bool - argument2=hilfsmittel - sollen auch hilfslinien oder punkte gedrawt werden?;
      5. */
      6. var xx,yy;
      7. xx=argument[0];
      8. yy=argument[1];
      9. background=background_create_from_screen(xx,yy,width,height,0,0,1); // screencapture
      10. draw_background_ext(background,0,0,resolution/width,resolution/height,0,-1,1); // draw im richtigen format
      11. textur=background_create_from_screen(0,0,resolution,resolution,0,0,1) // das capturen
      12. // lass uns alles drawen
      13. texture_set_blending(-1); // wichtig!
      14. texture_set_interpolation(interpolation); // nicht wichtig!
      15. draw_primitive_begin_texture(pr_trianglelist,background_get_texture(textur));
      16. for(w=0;w<htimes-1;w+=1) {
      17. for(h=0;h<vtimes-1;h+=1){
      18. draw_vertex_texture(grid_pos_x[w,h]+xx,grid_pos_y[w,h]+yy,w*gridsize/width,h*gridsize/height);
      19. draw_vertex_texture(grid_pos_x[w+1,h]+xx,grid_pos_y[w+1,h]+yy,(w+1)*gridsize/width,h*gridsize/height);
      20. draw_vertex_texture(grid_pos_x[w,h+1]+xx,grid_pos_y[w,h+1]+yy,w*gridsize/width,(h+1)*gridsize/height);
      21. // das erste dreieck.. wir brauchen aber 2, um ein 4eck zu bekommen
      22. draw_vertex_texture(grid_pos_x[w+1,h]+xx,grid_pos_y[w+1,h]+yy,(w+1)*gridsize/width,h*gridsize/height);
      23. draw_vertex_texture(grid_pos_x[w+1,h+1]+xx,grid_pos_y[w+1,h+1]+yy,(w+1)*gridsize/width,(h+1)*gridsize/height);
      24. draw_vertex_texture(grid_pos_x[w,h+1]+xx,grid_pos_y[w,h+1]+yy,w*gridsize/width,(h+1)*gridsize/height);
      25. }
      26. }
      27. draw_primitive_end(); // fertig
      28. background_delete(background); // speicher von der textur befreien
      29. background_delete(textur);
      30. if (argument[2]) {
      31. // das ganze ein mal ohne textur nur mit linien
      32. draw_primitive_begin(pr_linestrip);
      33. for(w=0;w<htimes-1;w+=1) {
      34. for(h=0;h<vtimes-1;h+=1){
      35. draw_set_color(c_lime);
      36. draw_circle(grid_pos_x[w,h]+xx,grid_pos_y[w,h]+yy,4,0);
      37. draw_set_color(c_blue);
      38. draw_vertex(grid_pos_x[w,h]+xx,grid_pos_y[w,h]+yy);
      39. draw_vertex(grid_pos_x[w+1,h]+xx,grid_pos_y[w+1,h]+yy);
      40. draw_vertex(grid_pos_x[w,h+1]+xx,grid_pos_y[w,h+1]+yy);
      41. draw_vertex(grid_pos_x[w,h]+xx,grid_pos_y[w,h]+yy);
      42. // das erste dreieck.. wir brauchen aber 2, um ein 4eck zu bekommen
      43. draw_vertex(grid_pos_x[w+1,h]+xx,grid_pos_y[w+1,h]+yy);
      44. draw_vertex(grid_pos_x[w+1,h+1]+xx,grid_pos_y[w+1,h+1]+yy);
      45. draw_vertex(grid_pos_x[w,h+1]+xx,grid_pos_y[w,h+1]+yy);
      46. draw_vertex(grid_pos_x[w+1,h]+xx,grid_pos_y[w+1,h]+yy);
      47. }
      48. }
      49. draw_primitive_end(); // fertig
      50. draw_set_color(c_red);
      51. draw_circle(pointx*gridsize+xx,pointy*gridsize+yy,4,0);
      52. }
      Alles anzeigen
      [/hide][hide=water_stop() - stoppt die wellen]

      GML-Quellcode

      1. /* stellt das wasser ruhich */
      2. for(h=0;h<vtimes;h+=1) {
      3. for(w=0;w<htimes;w+=1) {
      4. grid_pos_x[w,h]=w*gridsize;
      5. grid_pos_y[w,h]=h*gridsize;
      6. grid_hspeed[w,h]=0;
      7. grid_vspeed[w,h]=0;
      8. }
      9. }

      [/hide]

      Ich hoffe 1. dass es einigen Hilft. Aber vielmehr hoffe ich, dass jemand vieleicht noch ne bessere idee hat, wie man das problem mit der textur in den Griff zu bekommen. Vieleicht mit einer dll?

      Hier eine ZIP mit der .gmk und der .gml.
      Hier eine EXE für jene die nur lite/gar nichts haben.

      (irgendwas vergessen? - ne!)

      MfG SDX

      Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von SDX ()

    • Ist schön zu sehen, dass du dir die Mühe gemacht hast, auch alles ordentlich zu kommentieren und in Funktionen zu verpacken. So wird es wirklich einfach zu benutzen.
      Wollte an dieser Stelle mal anmerken, dass ich vor sehr langer Zeit auch mal sowas gemacht habe und ich das nahezu identisch umgesetzt habe. Falls es jemanden interessiert:
      Wasserwellen-Simulator (Quellcode im Post weiter unten)

      Wollte ich einfach mal loswerden, weil sich ja doch beides sehr ähnelt.
    • Schön zu sehen, dass du auch mal über diesen Thread gestolpert bisst ;)
      Jetzt rate mal was mich für diesen Script inspiriert hat.. Als ich deine exe auf deiner Seite gesehen habe, habe ich mich gleich gefragt ob ich es wohl noch besser hin bekomme..
      Allerdings sind da ein paar Sachen:
      • Deine Wellen sind richtige wellen.. also wenn ein punkt schwingt, wird das auf die Nachbarpunkte übertragen
      • Ein Problem das wir beide haben. Texturen sind immer rechteckig und funtzen auch nur in einer 2potenz.
      • Bei mir wird die Textur vom screen gemacht.. leider gibt das Probleme bezüglich Punkt 2 und der Performance.. merkwürdiger weise dauert es evig bis der GM eine Textur vom screen hat >.>
      Was allerdings sehr gut funktioniert ist nur ein kleiner bereich zu "wässern". Man bekommt zb einen schönen Effekt hin, wenn man einen bereich von 128x128px hinter dem Cursor wackeln Läst.

      MfG SDX