2D Wasserwelle

    • Skript

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

    • 2D Wasserwelle

      Also. Sicherlich kennen einige New Super Mario Bros. für Wii/DS, egal. Auf jeden Fall gibt es in diesem Spiel einige Wasser-Level und wenn man auf oder unter die Oberfläche des Wassers springt, gibt es einen schönen Wellen-Effekt. Nunja, da ich im Moment an einem Platformer arbeite, habe ich mir gedacht auch solch einen Effekt in mein Spiel einzubauen. Das ersparrt einerseits lästiges Animieren und andererseits sieht es einigermaßen cool aus.

      Funktionsweise:
      Kommen wir nun zur eigentlichen Sache. Wie soll das Ganze funktionieren? Als allererstes werden einige Parameter an die Scripte übergeben, die ich erstellt habe, als da wären die Anfangsposition und die Endposition der Welle/ des Wassers, den Y-Wert der Oberfläche und die Höhe/Tiefe (nennt es wie Ihr wollt) des Wassers. Ok, dann wird noch ein Hilfsobjekt ("water_point" im Example), die Genauigkeit der Welle ("precision") und eine, ich habe es, "friction", genannt, benötigt. Nun wird ein Array erstellt, welches mit Hilfsobjekten gefüllt wird, erstellt. Dadurch erhält man Punkte auf der Wasseroberfläche, die man benutzen kann um ein Welle zu erzeugen. Das Ganze wird dann mit Hilfe von draw_primitive_begin_texture(pr_trianglestrip, texture); gezeichnet. D.h. in meinem Script müsst ihr einen Hintergrund übergeben von dem die Textur geladen wird, um diese anschliessend in einer Wellenform zu zeichnen. Das ganze kann man auch ohne Texturen lösen.

      Naja, genug geredet hier sind ein paar Screenies:



      Ok und hier sind die Scripts:

      wave_init(xStart,xEnd,yPosition,height,obj,precision,friction);
      Spoiler anzeigen

      GML-Quellcode

      1. //Initialisiert ein Array mit der Länge arrayLength = (xStart-xEnd)/precision.
      2. //In das Array kommen obj-Objekte und werden von xStart bis xEnd in den Room gesetzt.
      3. //Der jeweilige Abstand zum nächsten obj-Objekt ist precision, d.h. desto höher precision ist, desto ungenauer wird
      4. //die Welle später sein.
      5. //yPosition ist die Y-Koordinate im Raum, wo die obj-Objekte erstellt werden.
      6. //height ist die Höhe des Wassers.
      7. //friction bestimmt wie schnell die Welle sich in den Ruhezustand versetzt, d.h. desto höher friction umso
      8. //schneller wird die Welle in die Ruhephase kommen, bei friction = 0, wird die Welle nie in die Ruhephase kommen.
      9. //////////////////////////////////////
      10. // argument0 - xStart //
      11. // argument1 - xEnd //
      12. // argument2 - yPosition //
      13. // argument3 - height //
      14. // argument4 - obj //
      15. // argument5 - precision //
      16. // argument6 - friction //
      17. //////////////////////////////////////
      18. length = abs(argument0-argument1);
      19. xx = argument0;
      20. xxEnd = argument1;
      21. yy = argument2;
      22. height = abs(argument3);
      23. obj = argument4;
      24. precision = abs(argument5);
      25. fr = abs(argument6);
      26. arrayLength = round(length/precision)+1;//+1 weil es sonst einen leeren Rand auf der rechten Seite gibt.
      27. strength = 0;
      28. wave_points[] = noone;
      29. wave_points_init();
      Alles anzeigen


      wave_points_init();
      Spoiler anzeigen

      GML-Quellcode

      1. //Initialisierung der einzelnen WasserPunkte
      2. var i;
      3. for(i = 0; i <= arrayLength; i+=1){
      4. wave_points[i] = instance_create(xx+precision*i,yy,obj);
      5. wave_points[i].control = instance_id;
      6. wave_points[i].index = i;
      7. wave_points[i].amplitude = 0;
      8. }
      9. //Holt sich die einzelnen instanzen
      10. for(i = 0; i <= arrayLength; i+=1){
      11. with (wave_points[i]){
      12. if (index == 0) {
      13. leftIndex = -1;
      14. rightIndex = index+1;
      15. right = control.wave_points[rightIndex];
      16. }
      17. else if (index == control.arrayLength) {
      18. leftIndex = index-1;
      19. rightIndex = -1;
      20. left = control.wave_points[leftIndex];
      21. }
      22. else {
      23. rightIndex = index-1;
      24. leftIndex = index+1;
      25. left = control.wave_points[leftIndex];
      26. right = control.wave_points[rightIndex];
      27. }
      28. }
      29. }
      Alles anzeigen


      wave_create(xPosition, strength);
      Spoiler anzeigen

      GML-Quellcode

      1. //Erstellt eine Welle an x = xPosition mit der Höhe/Stärke strength und der Geschwindigkeit speed.
      2. //Wenn speed >= 30 ist, dann sieht die Welle nicht wirklich schön aus, also passt auf was für Werte ihr einsetzt
      3. //////////////////////////////////////
      4. // argument0 - xPosition //
      5. // argument1 - strength //
      6. //////////////////////////////////////
      7. var tempX,i,dist;
      8. tempX = argument0;
      9. strength = argument1;
      10. for(i = 0; i <= arrayLength; i+= 1){
      11. dist = round(abs(tempX-wave_points[i].x)/precision);
      12. if (dist < 10) { // Create a wave for a single water part.
      13. if (dist == 0) dist = 1;
      14. wave_points[i].vspeed += strength/(dist*2);
      15. }
      16. }
      Alles anzeigen


      wave_points_update();
      Spoiler anzeigen

      GML-Quellcode

      1. ///Gehört ins Step-Event der WaterPoint-Objekts.
      2. //Aktualisiert die Y-Positionen der Objekte im Array.
      3. //////////////////////
      4. // No arguments //
      5. //////////////////////
      6. amplitude = y-control.yy;
      7. wave_point_fix_distance();
      8. var dist;
      9. dist = amplitude;
      10. if (instance_exists(left)) {
      11. dist = (left.amplitude-amplitude);
      12. vspeed += dist/50;
      13. }
      14. if (instance_exists(right)) {
      15. dist = (right.amplitude-amplitude);
      16. vspeed += dist/50;
      17. }
      18. dist = amplitude;
      19. vspeed -= dist/50;
      20. if (abs(vspeed) > 0) {
      21. vspeed /= control.fr;
      22. }
      Alles anzeigen


      wave_point_fix_distance();
      Spoiler anzeigen

      GML-Quellcode

      1. //Falls die Amplitude zu groß oder zu klein wird.
      2. if(abs(amplitude) > 5)
      3. y -= sign(amplitude)/2;
      4. if(round(abs(amplitude)) <= 1 && abs(vspeed) <= 0.5)
      5. y = control.yy;


      wave_draw(background,alpha);
      Spoiler anzeigen

      GML-Quellcode

      1. //Gehört in das Draw-Event des Controller-Objekts.
      2. //Die Textur wird von background geladen und anschliessend mit dem Alpha-Wert alpha gezeichnet.
      3. /////////////////////////////////
      4. // argument0 - background //
      5. // argument1 - alpha //
      6. /////////////////////////////////
      7. draw_set_color(c_white);
      8. draw_set_alpha(argument1);
      9. var i, tex, back;
      10. back = argument0;
      11. tex = background_get_texture(argument0);
      12. draw_primitive_begin_texture(pr_trianglestrip,tex);
      13. for(i = 0; i <= global.arrayLength; i += 1){
      14. draw_vertex_texture(global.wave_points[i].x,global.wave_points[i].y,(i*texture_get_width(tex)/global.arrayLength),0);
      15. draw_vertex_texture(global.wave_points[i].x,global.yy+global.height,(i*texture_get_width(tex)/global.arrayLength),texture_get_height(tex));
      16. }
      17. draw_primitive_end();
      18. draw_set_alpha(1);
      Alles anzeigen


      An dieser Stelle möchte ich noch sagen, dass mit diesen Scripten das erstellen von mehreren Wellen etwas komisch aussieht, komisch im Sinne von nicht realistisch. Falls jemand weiß wie man die Scripts verbessern könnte...nur zu ;).

      Und zu guter Letzt ein Beispiel, wie man die Scripts verwenden sollte.
      Die .gmk:
      wave_texture.rar
      und die Executable .

      Neue Version:
      wave_texture_extended.rar, Executable

      MfG Trixt0r und viel Spaß mit den Wellen.

      Albert Einstein schrieb:

      Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind.

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

    • Es gibt Neuigkeiten (auch wenn es Niemanden interessieren mag xD). Ich habe meine Skripte überarbeitet und nun funktioniert die Welle unabhängig vom Einschlag eines Objektes. Die Performance hat sich dadurch auch ein wenig verbessert, da das Controller-Objekt nicht mehr in jedem Step durch das ganze Array durchläuft. Naja, schaut es euch an, die neue Version ist im ersten Post.

      MfG Trixt0r ;)

      Albert Einstein schrieb:

      Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind.
    • Wirklich schönes und dazu performantes Skript.

      Nur leider gibt es einige Fehler, wenn man große Welle auf der gleichen Stelle erstellt.


      -Tobi97
    • Ja, das Problem kenne ich, aber ich hatte keine Lust das weiter zu behandeln, weil es eigentlich nur auftritt, wenn man, wie du sagtest, auf der selben Stelle sehr oft oder zu starke Wellen erzeugt. Es liegt mehr oder weniger am wave_points_update()-Skript und am wave_create()-Skript:

      Spoiler anzeigen

      GML-Quellcode

      1. //Gehört ins Step-Event der WaterPoint-Objekts.
      2. //Aktualisiert die Y-Positionen der Objekte im Array.
      3. //////////////////////
      4. // No arguments//
      5. //////////////////////
      6. amplitude = y-control.yy;
      7. wave_point_fix_distance();
      8. var dist;
      9. dist = amplitude;
      10. if (instance_exists(left)) {
      11. dist = (left.amplitude-amplitude);
      12. vspeed += dist/50;//Wenn man 50 durch eine größere Zahl ersetzt, sollte das Problem nicht mehr auftreten
      13. }
      14. if (instance_exists(right)) {
      15. dist = (right.amplitude-amplitude);
      16. vspeed += dist/50;
      17. }
      18. dist = amplitude;
      19. vspeed -= dist/50;
      20. if (abs(vspeed) > 0) {
      21. vspeed /= control.fr;
      22. }
      Alles anzeigen


      Außerdem habe ich den wave_create()-Skript noch etwas geändert:

      Spoiler anzeigen

      GML-Quellcode

      1. //Erstellt eine Welle an x = xPosition mit der Höhe/Stärke strength und der Geschwindigkeit speed.
      2. //Wenn speed >= 30 ist, dann sieht die Welle nicht wirklich schön aus, also passt auf was für Werte ihr einsetzt
      3. //////////////////////////////////////
      4. // argument0 - xPosition //
      5. // argument1 - strength //
      6. //////////////////////////////////////
      7. var tempX,i,dist,w;
      8. tempX = argument0;
      9. strength = argument1;
      10. //strength kann auch durch ein Maximum beschränkt werden, damit der Fehler nicht auftritt
      11. //strength = min(MAX,strength); //wobei MAX einen nicht all zu großen Wert annehmen sollte bspw. 20
      12. w = instance_nearest(tempX,yy,obj);
      13. w.vspeed += cos(0)*strength;
      14. for(i = 0; i <= arrayLength; i+= 1){
      15. dist = round(abs(tempX-wave_points[i].x)/precision);
      16. if(dist <= precision*10){
      17. if (dist == 0) dist = 1;
      18. if(wave_points[i] != w)
      19. wave_points[i].vspeed += cos(degtorad(abs(w.index-i)*10))*(strength/dist);
      20. }
      21. }
      Alles anzeigen


      Danke für das Feedback ;)

      MfG Trixt0r

      Albert Einstein schrieb:

      Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind.
    • nagut ... realistisches wasser ist was anderes ^^ ... aber genial ... kann ich vill iwan mal gebrauchen ...
      aber das prob mit den vielen wellen ist immernoch extrem ... das "wasser" schaukelt sich extrem hoch bis die wellen nicht mehr runter kommen ...

      dennoch respeckt XD
      ---- wer fehler findet darf sie behalten ---
    • Ja, aber ich glaube nicht, dass wenn du diesen Wellenskript in dein Spiel mit einbeziehst, der Bug auftreten wird. In meinem Projekt habe ich die Wasserwellen schon implementiert und da ist sowas noch nicht aufgetreten. Von daher werde ich es auch in nächster Zeit dabei belassen ;)

      MfG

      Albert Einstein schrieb:

      Probleme kann man niemals mit derselben Denkweise lösen, durch die sie entstanden sind.