Shobas Starfield

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

    • Shobas Starfield

      Morgen. In den letzten Tagen hab ich eine relativ witzige Starfield Simulation zusammengeschustert, welche ich euch nicht vorenthalten will. Das besondere an dieser Starfield Simulation ist, das die Geschwindigkeit der Darstellung nicht von der Anzahl der Sterne abhänig ist, was bei den meisten, gängigen Starfield Simulationen der Fall ist.




      Anstatt jeden Stern einzeln zu zeichnen erstelle ich am Anfang des Programms 30 relativ große Sprites in denen eine größere Anzahl von Sternen abgebildet ist. Diese werden dann mit Hilfe einer Funktion gezoomt, welche vom Strahlensatz abgeleitet ist, um so die Illusion von Dreidimensionalität zu erzeugen. Desweiteren werden diese Sprites immer öfters gezeichnet umso näher sie der Kamera kommen um einen Motion Blur Effekt zu erzeugen.

      Um das ganze zu realisieren brauchen wir folgende Funktionen:

      SCR_CreateStarfield:
      Diese Funktion erzeugt das Starfield Objekt.

      SCR_Starfield_Step
      Diese Funktion manipuliert das Starfield während des Step Events

      SCR_Starfield_Draw
      Ihr dürft raten was diese Funktion macht...

      SCR_RandStarfield
      Erzeugt eine neue Starfield Ebene, wenn eine Alte an der "Kamera" vorbei geflogen ist.

      SCR_CreateStarfield:
      Eine der Komplizierteren Funktionen in diesem System, da sie Tonnen von Parametern Futtert, um das Starfield gut Customizen zu können. Dazu gehören:

      argument 0:
      Anzahl der Sterne. Diese wird auf die Anzahl der Ebenen verteilt. Hat außer bei der Generierung der Starfield Surfaces keine Auswirkung auf die Performance.
      argument 1:
      Anzahl der Ebenen. Umso mehr Ebenen eine Starfield Simulation besitzt, umso dynamischer sieht sie aus. Normalerweise reichen 5 - 8 Ebenen, danach kämpft das System schon mit erheblichen Performance Problemen.
      argument 2:
      Tiefe. Die Maximale Sichtweite der Starfield Simulation.
      argument 3 und 4:
      die Fixierte und Zufällige größer der Einzelnen Sterne. Ein wert von 4 und 3 ergibt Sterne in der Größe von 4 - 7 Pixel.
      argument 5:
      Die Geschwindigkeit der Starfield Simulation.
      argument 6:
      Detailgrad. 1 Ist das Maximum, nach obenhin ist die skalierung offen. Um so höher der Wert, um so niedriger sind die Details. Hat Massive Auswirkungen auf die Performance.
      argument 7 und 8:
      größe der View in der sich die Simulation befinden soll.
      argument 9:
      Leerraum für Sterne. Bei 0% können sich Sterne auch im Zentrum der Kamera befinden (was oft störend wirkt), bei 99% sind sie nur am Rand der Simulation.

      GML-Quellcode

      1. {
      2. //argument 0 ... number of Stars
      3. //argument 1 ... number of Layers
      4. //argument 2 ... depth
      5. //argument 3 ... Starsize (fixed)
      6. //argument 4 ... Starsize (random)
      7. //argument 5 ... speed
      8. //argument 6 ... detail
      9. //argument 7 ... sizex
      10. //argument 8 ... sizey
      11. //argument 9 ... toCenter
      12. var spl;
      13. var sx,sy,sl,sw;
      14. var TmpObj;
      15. TmpObj = instance_create(0,0,OBJ_Starfield);
      16. with(TmpObj)
      17. {
      18. StarNumber = argument0;
      19. Layers = argument1;
      20. Depth = argument2;
      21. StarSize = argument3;
      22. StarRand = argument4;
      23. Speed = argument5;
      24. Detail = argument6;
      25. SizeX = argument7;
      26. SizeY = argument8;
      27. ToCenter = argument9;
      28. MoveX = 0;
      29. MoveY = 0;
      30. PosX = SizeX/2;
      31. PosY = SizeY/2;
      32. Size = max(SizeX,SizeY);
      33. SrfSize = (Size*2)/Detail;
      34. //Diese Schleife erzeugt 30 Verschiedene Sprites, auf denen die Sterne dargestellt werden
      35. for(i = 0; i < 30; i+=1)
      36. {
      37. SRF_Star = surface_create(SrfSize,SrfSize);
      38. surface_set_target(SRF_Star);
      39. draw_clear(c_black);
      40. spl = random(StarNumber/Layers )+StarNumber/Layers ;
      41. for(j = 0; j < spl; j+=1)
      42. {
      43. col = round(random(128)+127);
      44. col = make_color_rgb(col,col,col);
      45. sl = ( ((SrfSize/2)*(ToCenter/100))+random((SrfSize/2)*((100-ToCenter)/100)) );
      46. sw = random(360);
      47. sx = SrfSize/2+lengthdir_x( sl,sw);
      48. sy = SrfSize/2+lengthdir_y( sl,sw);
      49. draw_circle_color(sx,sy,(random(StarRand)+StarSize)/Detail ,col,col,false);
      50. }
      51. draw_point_color(0,SrfY,c_black);
      52. draw_point_color(0,SrfY-1,c_black);
      53. surface_reset_target();
      54. FogSprite[i] = sprite_create_from_surface(SRF_Star,0,0,SrfSize,SrfSize,0,1,0,1,SrfSize/2,SrfSize/2);
      55. surface_free(SRF_Star);
      56. }
      57. for(i = 0; i < Layers; i += 1)
      58. {
      59. CurPos[i] = i*(Depth/Layers);
      60. SCR_RandStarfield(i);
      61. }
      62. Timer = 0;
      63. }
      64. return TmpObj;
      65. }
      Alles anzeigen


      SCR_Starfield_Step:
      Diese Funktion überürpft ob eine Sternenebene an der Kamera vorbeigezischt ist bzw. im nichts verschwindet und erzeugt dann eine neue.

      GML-Quellcode

      1. {
      2. var i;
      3. for(i = 0; i < Layers; i+= 1)
      4. {
      5. CurPos[i]+=Speed;
      6. if(sign(Speed)==1)
      7. {
      8. if(CurPos[i]>Depth)
      9. {
      10. CurPos[i] = CurPos[i] mod Depth;
      11. SCR_RandStarfield(i);
      12. }
      13. }
      14. else
      15. {
      16. if(CurPos[i]<=0)
      17. {
      18. CurPos[i] = (CurPos[i] + Depth) mod Depth;
      19. SCR_RandStarfield(i);
      20. }
      21. }
      22. }
      23. }
      Alles anzeigen

      SCR_RandStarfield:
      Diese Funktion erzeugt eine neue Sternenebene

      GML-Quellcode

      1. {
      2. //argument 0 ... layer
      3. CurSprite[argument0] = FogSprite[floor(random(299)/10) ];
      4. CurColor[argument0] = make_color_rgb(random(64)+64,random(64)+64,random(32)+196);
      5. CurRot[argument0] = random(360);
      6. }


      SCR_Starfield_Draw:
      Und diese Funktion zeichnet das ganze

      GML-Quellcode

      1. {
      2. var i,j,CurFog;
      3. var dx,Alpha,Number,ox,oy;
      4. draw_set_blend_mode(bm_add);
      5. for(i = 0; i<Layers; i+=1)
      6. {
      7. CurFog = i;
      8. Number = ((Depth-CurPos[CurFog])/Depth)*(abs(Speed)*2);
      9. for(j = 0; j < Number; j+=1)
      10. {
      11. Alpha = (Depth-CurPos[CurFog]+((Number*2)-(j*2)))/Depth;
      12. dx = ((200/(CurPos[CurFog]+(j*2)+0.01))-0.1)*Detail;
      13. //X´=((A*X)/Z)Y´=((A*Y)/Z)
      14. ox = MoveX*(1-Alpha);
      15. oy = MoveY*(1-Alpha);
      16. draw_sprite_ext(CurSprite[CurFog],-1,x+PosX+ox,y+PosY+oy,dx ,dx ,CurRot[CurFog]+(CurPos[CurFog])/32,CurColor[CurFog]/*c_white*/,Alpha );
      17. }
      18. }
      19. draw_set_blend_mode(bm_normal);
      20. }
      Alles anzeigen


      Die Funktion SCR_Starfield_Step und SCR_Starfield_Draw gehören in das Step und Draw Event eines Objekt namens OBJ_Starfield.

      Durch Manipulation der Variablen MoveX und MoveY kann die Starfield Simulation Kurven fliegen, die Geschwindigkeit kann durch die Manipulation der Variable Speed verändert werden. Dabei ist aber anzumerken, das die Simulation bei einer Geschwindigkeit von 1/-1 unheimlich ... fad ... aussieht und bei 0 gänzlich verschwindet.

      Wenn sich irgendwer Fragt warum einige Variablen den Namen Fog haben, ursprünglich hätte das eine Nebel Simulation werden sollen ... ist dann aber irgendwie doch keine geworden.

      Das Ganze Teil ist mit der SGPL lizensiert (Shoba General Public License) :3.
      Dateien
      • starfield.zip

        (19,63 kB, 374 mal heruntergeladen, zuletzt: )
      ...
    • Das sieht auf den Screenshots schon mal sehr gängig aus.
      Würde das auch gerne mal in Aktion sehen. Hab allerdings nur GM 6.1.
      Könntest du eventuell noch eine gm6 datei anhängen? Könnte mir jetzt zwar die Mühe machen die ganzen Funktionen im GM zusammenzuwerfen, weiß aber auch nicht so recht wie wo wann die aufgerufen werden müssen. Danke!
    • Kann ich zwar nicht gebrauchen aber der Effekt gefällt mir :D Nur macht mein Computer nicht besonders gut mit, da es wohl ziemlich Rechenleistung benötigt, der kam bei deinem Beispiel schon leicht ins stockern... (intel pentium4 3.2ghz, 1gb ram, 256mb graka)
      Nur so aus Neugier, wie lange hast du in etwas gebraucht um die Script so weit fertigzustellen?

      Dragoon
      int (*x(*x(int))[5])(int*);
      Confused? Yes, it's C!
    • Wow... sieht auf nem HD-LCD im Vollbildmodus echt grandios aus...

      hmmm... wenn ich ne Weltraum-Sim oder was mit Hyperantrieb oder Wurmloch produziere, frag ich nochmal an ob ich klauen darf :D
    • @ Blackspark: Als GML Fortgeschrittener solltest du kein Problem haben meinen erklärungen zu Folgen, wo welche Funktionen hingehören (was übrigens im Example steht). Das mit der GM6 Datei hat den einfachen grund, das ich nach meinem Letzten System Crash gar keinen GM6 mehr installiert habe.

      @Dragoon: 2-3 Stunden. Den Hauptteil hatte ich schon nach ner 1/2, aber optimieren und verschönern kostet einiges an zeit. Wenn du den Detailgrad auf 5 und die ebenen auch auf 5 stellst, sollte es ohne gröbere probleme auch flüssig laufen.

      @Verwurster: Die Anzahl der Sprites hängt von der Anzahl der gewählten ebenen und der Geschwindigkeit hab. Umso näher eine Ebene bei der "Kamera" ist, und um so schneller sich diese bewegt, umso mehr Sprites werden gezeichnet, um den Blur besser darzustellen.

      @Jokohono: Ist "Leihbar" unter der SGPL, mit einem eintrag irgendwo in den Credits. Obs für ein Spiel brauchbar ist is fraglich, da es doch einiges an Resourcen frißt. Ich habs eher für Abspänne oder Intros entwickelt.
      ...
    • Original von Shoba
      @ Blackspark: Als GML Fortgeschrittener solltest du kein Problem haben meinen erklärungen zu Folgen, wo welche Funktionen hingehören (was übrigens im Example steht). Das mit der GM6 Datei hat den einfachen grund, das ich nach meinem Letzten System Crash gar keinen GM6 mehr installiert habe.


      mir gehts ähnlich wie bl@cksp@rk, ich bin nicht zu faul oder so, bloß mein key funktioniert einfach nicht... eventuell könnte ja jemand anders die .gmk in .gm6 machen, weil die screenshots sehen ja schon cool aus ^^

      ich würde sagen, da ja noch viele den GameMaker 6.* haben, sollte jeder auch eine gm6 Datei mit hinzufügen (sofern das möglich ist)
    • Das sieht wirklich super aus, aber ich versteh nicht, wieso dein Code so kompliziert ist?! Sowas kriegt man doch auch viel einfacher hin, und vor allem auch ohne Surfaces.
      █████ ██ █ ████ everything ███ █████ is █████ ████ ████ fine ████ ███ █ ██████ love.
      █████ ███████ ███ your █████ ████ government.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von mauge ()

    • Eigentlich könntest du den Teil mit den Surfaces ja auch weglassen und stattdessen auf den Bildschirm zeichnen, den Bildschirmausschnitt als Sprite speichern, alles mit schwarz übermalen usw. anstatt für jede neue Spritekreation eine Surface aufzubauen und dann wieder einzustampfen.
      Surfaces würde ich generell vermeiden, es sei denn sie sind unumgänglich oder geben einen GEWALTIGEN Geschwindigkeitsvorteil, was hier aber nicht der Fall ist.
    • Original von Verwurster
      Eigentlich könntest du den Teil mit den Surfaces ja auch weglassen und stattdessen auf den Bildschirm zeichnen, den Bildschirmausschnitt als Sprite speichern, alles mit schwarz übermalen usw. anstatt für jede neue Spritekreation eine Surface aufzubauen und dann wieder einzustampfen.
      Surfaces würde ich generell vermeiden, es sei denn sie sind unumgänglich oder geben einen GEWALTIGEN Geschwindigkeitsvorteil, was hier aber nicht der Fall ist.


      Genau das meine ich. Wenn du schlicht mit dem Blend Mode arbeitest, kannst du die Performance sicher noch etwas kitzeln. Ich für meinen Teil vermeide Surfaces grundsätzlich.
      █████ ██ █ ████ everything ███ █████ is █████ ████ ████ fine ████ ███ █ ██████ love.
      █████ ███████ ███ your █████ ████ government.
    • Hat irgendwer von euch den Source überhaupt verstanden? Zur laufzeit werden eh keine Surfaces benutzt. Die werden nur im Create Event erzeugt, um die Sprites darzustellen. Nachdem all diese Surfaces auch im Create wieder eingestampft werden, ist der rest irrelevant.
      ...
    • Sorry, du brauchst dich nicht angegriffen fühlen. Wir wollten lediglich darüber diskutieren, ob es nicht eine einfachere Methode gibt. Leider kann ich es momentan auch nicht testen, da ich den GM7 noch nicht benutze. Wie gesagt, das Ergebnis ist erstaunlich. Ich bin mir trotzdem sicher, dass man weniger umständlich etwa gleiche Ergebnisse erzielt.
      █████ ██ █ ████ everything ███ █████ is █████ ████ ████ fine ████ ███ █ ██████ love.
      █████ ███████ ███ your █████ ████ government.
    • Durch den restlichen Code blicke ich nicht durch, aber den Teil mit den Surfaces habe ich schon verstanden.
      Die Surfaces sind überflüssig, zeichne einfach auf den Bildschirm und verwende dann den Bildschirmausschnitt als Sprite.
      Dadurch wird zwar nichts schneller laufen jedoch funktioniert das Ganze dann auch auf Maschinen mit Grafikkarten die wenig speicher haben.
      Der grosse Nachteil an Surfaces ist deren bedarf an Videospeicher.
      Wenn der sehr gering ist, hat sich's bald ausgesurfaced und es kann einfach keine neue mehr erstellt werden. (das kann der Fall sein, wenn noch ein anderes System, das auch auf Surfaces basiert nebenher läuft)
      Deshalb sollte man die wenn möglich umgehen und in diesem Fall ist das sehr wohl möglich.

      Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von Verwurster ()

    • Sorry auch meinerseits, war gestern etwas gestresst, was für Sonntage ein ganz schlechtes Zeichen ist.

      Also, nur zur Erklärung: Die Surfaces werde nur benutzt um die Sprites, welche die Sterne beinhalten zu zeichnen.
      Der Grund warum es ohne Surface wahrscheinlich nicht funktioniert ist, das die Sprites bei einer Detailstufe von 1 doppelt so groß sind, wie die aktuelle View (also bei 320x240 sind sie 640x480, beu 800x600 1600x1200 und so weiter ... ). Weiters ist die Create_Sprite_from_Screen funktion unheimlich langsam ... was, sofern man das Starfield ganz am Anfang des Programms generiert, irrelevant ist.
      ...
    • Also wenn du die Surface nur ein einziges mal kreieren würdest, hättest du recht un das wäre wirklich schneller als es vom screen zu nehmen.
      1000 32x32 sprites vom screen zu bauen dauert 1.06 Sekunden, mit nur einer Surface dauert's 0.94 Sekunden.
      Jedoch wird bei deinem Code bei jedem Schritt eine neue Surface gebaut, daraus ein sprite erstellt und die surface dann freigegeben.
      Kreiert man nach dieser Methode 1000 32x32 Sprites, dauert der Spass auf einmal 2.37 Sekunden (im vergleich vom Screen nur 1.06).
      Also wäre es im Endeffekt doch schneller, vom screen aus zu arbeiten.
      Wenn du die Ergebnisse selber nachprüfen willst, hau diesen Code in ein Create event und schau dir die Message an:

      GML-Quellcode

      1. time=date_current_time();
      2. repeat(1000)
      3. {
      4. spr=sprite_create_from_screen(0,0,32,32,0,0,0,0,0,0);
      5. sprite_delete(spr);
      6. }
      7. time=date_second_span(time,date_current_time());
      8. time2=date_current_time();
      9. sur=surface_create(32,32);
      10. repeat(1000)
      11. {
      12. spr=sprite_create_from_surface(sur,0,0,32,32,0,0,0,0,0,0);
      13. sprite_delete(spr);
      14. }
      15. surface_free(sur);
      16. time2=date_second_span(time2,date_current_time());
      17. time3=date_current_time();
      18. repeat(1000)
      19. {
      20. sur=surface_create(32,32);
      21. spr=sprite_create_from_surface(sur,0,0,32,32,0,0,0,0,0,0);
      22. sprite_delete(spr);
      23. surface_free(sur);
      24. }
      25. time3=date_second_span(time3,date_current_time());
      26. show_message("Vom Screen: "+string(time)+"#Von einer Surface: "+string(time2)+"#Von vielen Surfaces: "+string(time3));
      Alles anzeigen


      Was die Grösse der Sprites angeht hast du recht, vom screen kann man nichts nehmen, was grösser als der Screen selbst ist.
      Aber warum sollte man das überhaupt wollen?
      Warum muss eine Sterngrafik unbedingt 4 Bildschirme füllen können, wenn sie nicht verkleinert wurde?
      Ich denke, die Qualität wird nicht allzusehr leiden, wenn du die maximale Sterngrösse auf die schmalste Bildschirmkante beschränkst oder?
    • Braucht man eh nicht, eine Detailstufe von 3 oder 4 tut es normalerweise auch. Ich hab jetzt mal das Surface_create aus der Schleife raus genommen, das sieht dann so aus:

      GML-Quellcode

      1. {
      2. //argument 0 ... number of Stars
      3. //argument 1 ... number of Layers
      4. //argument 2 ... depth
      5. //argument 3 ... Starsize (fixed)
      6. //argument 4 ... Starsize (random)
      7. //argument 5 ... speed
      8. //argument 6 ... detail
      9. //argument 7 ... sizex
      10. //argument 8 ... sizey
      11. //argument 9 ... toCenter
      12. var spl;
      13. var sx,sy,sl,sw;
      14. var TmpObj;
      15. TmpObj = instance_create(0,0,OBJ_Starfield);
      16. with(TmpObj)
      17. {
      18. StarNumber = argument0;
      19. Layers = argument1;
      20. Depth = argument2;
      21. StarSize = argument3;
      22. StarRand = argument4;
      23. Speed = argument5;
      24. Detail = argument6;
      25. SizeX = argument7;
      26. SizeY = argument8;
      27. ToCenter = argument9;
      28. MoveX = 0;
      29. MoveY = 0;
      30. PosX = SizeX/2;
      31. PosY = SizeY/2;
      32. Size = max(SizeX,SizeY);
      33. SrfSize = (Size*2)/Detail;
      34. SRF_Star = surface_create(SrfSize,SrfSize);
      35. for(i = 0; i < 30; i+=1)
      36. {
      37. surface_set_target(SRF_Star);
      38. draw_clear(c_black);
      39. spl = random(StarNumber/Layers )+StarNumber/Layers ;
      40. for(j = 0; j < spl; j+=1)
      41. {
      42. col = round(random(128)+127);
      43. col = make_color_rgb(col,col,col);
      44. sl = ( ((SrfSize/2)*(ToCenter/100))+random((SrfSize/2)*((100-ToCenter)/100)) );
      45. sw = random(360);
      46. sx = SrfSize/2+lengthdir_x( sl,sw);
      47. sy = SrfSize/2+lengthdir_y( sl,sw);
      48. draw_circle_color(sx,sy,(random(StarRand)+StarSize)/Detail ,col,col,false);
      49. }
      50. draw_point_color(0,SrfSize,c_black);
      51. draw_point_color(0,SrfSize-1,c_black);
      52. surface_reset_target();
      53. FogSprite[i] = sprite_create_from_surface(SRF_Star,0,0,SrfSize,SrfSize,0,1,0,1,SrfSize/2,SrfSize/2);
      54. }
      55. surface_free(SRF_Star);
      56. for(i = 0; i < Layers; i += 1)
      57. {
      58. CurPos[i] = i*(Depth/Layers);
      59. SCR_RandStarfield(i);
      60. }
      61. Timer = 0;
      62. }
      63. return TmpObj;
      64. }
      Alles anzeigen


      Geschwindigkeitsmäßig erkenne ich jetzt auf Anhieb keinen unterschied, da immer nur 30 Surfaces erschaffen wurden. Auch deren Anzahl könnte
      ...
    • Benutzer online 1

      1 Besucher