Da das Thema eher hier hin als in die Projektecke
www.delphi-forum.de/....php?p=471218#471218 passt, führe ich es mal hier weiter:
Marc. hat folgendes geschrieben: |
| Aber etwas Anderes: Ich eigne mir gerade selbst OpenGL an, stehe allerdings noch ganz am Anfang und muss ehrlich sagen, dass mich Dein Programm bereits sehr beeindruckt hat. Könntest Du mir eventuell Einblicke in den SourceCode gewähren? Einfach um zu sehen, wie etwas aufwendigeres OpenGL-Spiel letzendlich von innen ausschaut. |
Das kann ich gern machen. Ich legs mal gleich in diesen Thread falls es noch jemanden interessiert. Im Prinzip ist OGL gar nicht schwer. Aber wenn man sich die ganzen Tutorials anschaut und daraufhin ein eigenes Projekt bauen will, dann hat man ganz fix Spaghetti-Code. Ich will damit sagen, dass man sich eine Menge Hilfsklassen suchen oder selbst schreiben muss. Ich denke da in meinem Fall an:
Einen Menucontroller(GUI), Fontmanager (GUI, ingame), Soundmanager, Texturmanager, 3D-Modelloader, 3D-Szenenverwaltung, Partikelengine und natürlich etwas, was den Netzwerkkram handhabbar macht. Sowas kann man nich allein schreiben (also ich zumindest nicht (Arbeit, Haus, Kinder und Hobbies gehen nun mal vor

). Daher stammen z.B. die GUI von Kollegen aus dem DelphiGL-Forum. Den passenden Controller rundrum hab ich wiederum gebaut, da hat jeder seine Vorlieben. Weiterhin sind der 3D-Loader und die Partikelengine (Fireblade) im Kern nicht von mir. Wenn man sich den ganzen Kram erstmal zusammengeschustert hat, dann ist es recht angenehm. Man hat dann also eine Mainloop:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| game.initgame; while ( Done <> -1 ) do begin glHandleEvents; Render(FALSE); ProcessGame(NIL); Inc(FPSCount); game.FrameElapsedTime := GetTimeNeeded(game.TimeStruct); while GetTimeNeeded(game.TimeStruct) <0.01500 do sleep(1); game.FrameElapsedTime := GetTimeNeeded(game.TimeStruct); BeginCounting(game.TimeStruct); if Game.gameEnds then Done := -1; end; game.settings.SaveToFile; |
Beim Rendern passiert folgendes (ich kürze mal stellenweise)
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81:
| glDisable(GL_LIGHTING); glPushMatrix; glEnable(GL_CULL_FACE);
for stein:=0 To Pred(Steine.count) do begin if Picken then begin glDisable(GL_TEXTURE_2D); glColor4b(KlickOffset+stein, 0, 0, 0); glTranslatef( Steine.steine[stein].Posi.x+Steine.steine[stein].Offset.x, Steine.steine[stein].Posi.y+Steine.steine[stein].Offset.y, Steine.steine[stein].Posi.z+Steine.steine[stein].Offset.z); glRotatef( Steine.steine[stein].Posi.rx, Steine.steine[stein].Posi.rx, Steine.steine[stein].Posi.ry, Steine.steine[stein].Posi.rz); if Steine.Steine[stein].aktiv then glCallList(Steine.GetDispListe(stein)); end else begin glEnable(GL_TEXTURE_2D); glEnable(GL_BLEND); glColor4f(1,1,1,Steine.Steine[stein].transparenz); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glTranslatef( Steine.steine[stein].Posi.x+Steine.steine[stein].Offset.x, Steine.steine[stein].Posi.y+Steine.steine[stein].Offset.y, Steine.steine[stein].Posi.z+Steine.steine[stein].Offset.z); glRotatef( Steine.steine[stein].Posi.rx, Steine.steine[stein].Posi.rx, Steine.steine[stein].Posi.ry, Steine.steine[stein].Posi.rz); if Steine.Steine[stein].aktiv then glCallList(Steine.GetDispListe(stein)); glDisable(GL_BLEND); end; glPopMatrix; glPushMatrix; end; if not Picken then Partikel.ParticleEffect(FrameElapsedTime); glPopMatrix; ...
for PlayerNum := 0 to Pred(steine.Players.GetNumPlayer) do begin if PlayerNum = steine.Players.GetActivePlayer then begin ZeitOffset := MilliSecondsBetween(ZeitMesspunkt,now); end else begin ZeitOffset := 0; end;
score := steine.Players.GetScoreOfPlayer(PlayerNum); zeit := steine.Players.GetTimeOfPlayer(PlayerNum);
if GameState = gsInGame then begin try ShowPlayerInterface(PlayerNum,score, zeit+ZeitOffset) except sleep(2); end; end else begin try ShowPlayerInterface(PlayerNum,score, zeit); except sleep(2); end; end; end; |
Der nächste große Punkt ist das Spiel selbst. Dort läuft alles über Gamestates ab. Ich habe das anfangs nicht gemacht. Man programmiert sich tot. Mit der Statusmaschine wird das ganze zum Kinderspiel. (Der Knackpunkt ist eine Prozedure, welche die Gamestates wechselt. Dort kann man beim verlassen eines Gamestates notwendige Aktionen veranlassen
Beispiel: Intro --> Hauptmenu
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20:
| ChangeGameState(gsmainmenu);
...
procedure TGame.ChangeGameState(NewState: TGameState); begin if NewState <> GameState then begin case Gamestate of gsIntro: end; case Newstate of gsMainmenu: end; Gamestate := NewState; end; end; |
Im Moment laufen 4 oder 5 Statemachines im Spiel. Eine für's Spiel selbst, eine für den Spielerzug, eine für den Computergegner, eine für die 3D-Szenenverwaltung und eine entsteht grade noch für das Netzwerk.
Ich merke aber grade, das wird ein Mordsthema. Hast Du evtl. schon was mit OpenGL probiert? Was willst Du machen? Hast Du evtl. spezielle Fragen? Gehts Dir mehr um das Rendern, oder um das Design des Grundgerüsts allgemein?
Grüße, DNA
Moderiert von
Narses: Code- durch Delphi-Tags ersetzt