Declare ScrollBackround(Pixel.l) Declare CreateBackround() Declare StartGame() Declare HAUPTPROGRAMM() Declare OpenOptionWindow() Declare InitializeGameFull() Declare InitializeGame() Declare GameOver() Declare CreatePlayer(Radius.l, Name.s, RGB.l, PushKey.l) Declare NewUser() Declare MsgError(Value.l) RandomSeed(GetTickCount_()) Procedure MsgError(Value.l) MessageRequester("ERROR", "Fehler Nr." + Str(Value), 0) End EndProcedure ;- ;- CONSTANTS ;- - Fenster-Daten #MWidth = 320 #MHeight = 240 ;- - SpriteIDs #BackID = 1 #TmpID = 2 #TmpConst = 0 ;- - Sprite-Daten (Größe des eigentlichen Spielfeldes) #SWidth = #MWidth #SHeight = #MHeight ;- - Sonstiges Global Gravity.f #Gravity.f = 0.0981 ;Anziehungskraft #Schub.f = 0.16 ;Schubkraft des Raumschiffes #ChangeTendenz = 498 #URadius.f = 12 ;Durchmesser des "Schiffes" #MinRoom = #URadius + 16 ;Minimaler Abstand zwischen den Felsen #MaxChange = 5 ;Max. Änderung der Landschaft pro Pixel #JumpFrame = 2 ;Anzahl an Pixel, die pro Durchlauf übersprungen werden #PI.f = 3.141593 #MinRGB = 192 ;Minimale Helligkeit #MaxPunkte = 100 ;Maximale Anzahl an Punkten an der engsten Stelle #ChangeRGB = %011 ;1 = Blau, 2 = Grün, 4 = Rot #MaxRGBCh = 10 ;Maximale Änderung der in #ChangeRGB angegebenen Farben pro Frame #Demo = #False ;Wenn #Demo = #True, steuert das "Schiff" von selbst ;- ;- GLOBALS ;- - Farben Global Rot.l, Gruen.l, Blau.l, ChangeRGB.l ;Rot = Random(255 - #MinRGB) + #MinRGB ;Gruen = Random(255 - #MinRGB) + #MinRGB ;Blau = Random(255 - #MinRGB) + #MinRGB Rot = 255 Gruen = 127 Blau = 127 Global BackBr.l, FrontBr.l BackBr = 199 ;Helligkeit des Hintergrundes FrontBr = 255 ;Helligkeit des Vordergrundes BackRel.l = 0 FrontRel.l = 0 ;- ;- STRUCTURES ;- - User Structure User x.f ;Position y.f xt.f ;Beschleunigung yt.f Masse.f ;benutzerdefinierte Daten für jeden Spieler Schub.f Radius.f SprID.l ;SpriteID für das "Schiff" Still.l ;Wenn #True, bewegt sich das Schiff nicht RGB.l ;Farbe des Schiffes Punkte.l Key.l ;KeyboardPushed()-Code für Schub Dead.l ;Wenn #True, ist man tot Demo.l Name.s ;Name des Spielers EndStructure NewList User.User() ;- - Cave Structure Cave y1.f ;Anfang von oben der Höhle y2.f ;Ende von oben EndStructure NewList Cave.Cave() ;- If (InitSprite() And InitKeyboard()) = #False MsgError(1) EndIf Procedure NewUser() ;Erstellt ein neues Grundgerüst für einen Spieler If CountList(User()) SprID = User()\SprID + 1 Else SprID = 10 EndIf AddElement(User()) User()\x = #SWidth / 4 User()\y = #SHeight / 2 User()\xt = 0 User()\yt = 0 User()\Schub = #Schub User()\Radius = #URadius User()\SprID = SprID User()\Still = #True;#False User()\Punkte = 0 User()\Dead = #False User()\Demo = #Demo EndProcedure ;Erstellt einen neuen Spieler mit vorgegebenen Daten Procedure CreatePlayer(Radius.l, Name.s, RGB.l, PushKey.l) NewUser() User()\RGB = RGB User()\Masse = 1 User()\Key = PushKey User()\Name = Name ;"Schiff" erstellen If CreateSprite(User()\SprID, Radius * 2, Radius * 2) = #False MsgError(5) EndIf StartDrawing(SpriteOutput(User()\SprID)) DrawingMode(0) For a.l = Radius To 0 Step -1 R.f = Red(RGB) * Cos(#PI * a / (Radius * 2)) G.f = Green(RGB) * Cos(#PI * a / (Radius * 2)) B.f = Blue(RGB) * Cos(#PI * a / (Radius * 2)) Circle(Radius, Radius, a, RGB(R, G, B)) Next StopDrawing() EndProcedure ;MessageRequester mit Punkteinformationen von jedem Spieler Procedure GameOver() TmpS.s = "Spielstand:" + Chr(10) + Chr(10) ResetList(User()) While NextElement(User()) TmpS.s = TmpS + User()\Name + ": " + Str(User()\Punkte / 1000) + " Punkte" + Chr(10) Wend MessageRequester("Game Over!", TmpS, 0) End EndProcedure ;FrameRate setzen und Fenster öffnen Procedure InitializeGame() SetFrameRate(30) If OpenWindow(0, 0, 0, #MWidth, #MHeight, #PB_Window_Borderless | #PB_Window_ScreenCentered, "") = #False MsgError(2) EndIf If OpenWindowedScreen(WindowID(), 0, 0, #MWidth, #MHeight, #False, 0, 0) = #False MsgError(3) EndIf Createbackround() EndProcedure ;FrameRate setzen und FullScreen öffnen Procedure InitializeGameFull() SetFrameRate(30) If OpenScreen(#MWidth, #MHeight, 32, "") = #False MsgError(3) EndIf CreateBackround() EndProcedure ;Optionen-Fenster öffnen (noch nicht fertig) Procedure OpenOptionWindow() #OptWidth = 640 #OptHeight = 250 OpenWindow(1, 0, 0, #OptWidth, #OptHeight, #PB_Window_Systemmenu | #PB_Window_ScreenCentered, "Caveflight-Clone V2.0") If CreateGadgetList(WindowID(1)) Frame3DGadget(1, 0, 0, 300, #OptHeight - 22, "Player(s)") ListViewGadget(2, 10, 17, 100, #OptHeight - 47) DisableGadget(2, 1) ButtonGadget(3, 111, 17, 60, 20, "New Player") ButtonGadget(4, 111, 38, 60, 20, "Del Player") ; Frame3DGadget(100, ButtonGadget(5, 1, #OptHeight - 21, #OptWidth, 20, "Start") Else MsgError(7) EndIf EndProcedure ;- ;Events des Optionen-Fensters abfragen Procedure HAUPTPROGRAMM() OpenOptionWindow() Repeat EventID.l = WaitWindowEvent() Select EventID Case #PB_EventCloseWindow End Case #PB_EventGadget Select EventGadgetID() Case 0 End EndSelect EndSelect ExamineKeyboard() If KeyboardReleased(#PB_Key_Escape) : End : EndIf ForEver EndProcedure ;HAUPTPROGRAMM() ;End InitializeGame() CreatePlayer(#URadius, "NicTheQuick", RGB(255, 0, 0), #PB_Key_Up) StartGame() ;- ;Spiel selbst Procedure StartGame() Quit.l = #False Pause.l = #False Frames.l = 0 Time.l = GetTickCount_() Punkte.l = 0 Repeat ;nach 500 Frames neue FPS-Berechnung Frames + 1 If Frames > 500 Time = GetTickCount_() Frames = 0 EndIf ;Da keine Maus benutzt wird, nocht notwendig ;- Window-Handling ; If IsScreenActive() = #False ; ReleaseMouse(#True) ; Repeat ; Until IsScreenActive() = #True ; ReleaseMouse(#False) ; EndIf ;- Keyboard-Handling ExamineKeyboard() If KeyboardReleased(#PB_Key_Escape) : Quit = #True : EndIf If KeyboardReleased(#PB_Key_P) : Pause = #True : EndIf ;- Auto-Handling NotGameOver.l = #False ResetList(User()) ;Spieler durchgehen While NextElement(User()) ;Wenn Spieler Schub gibt If KeyboardPushed(User()\Key) : Schub = #True : Else : Schub = #False : EndIf ;Wenn Spieler schon tot ist If User()\Dead User()\x - #JumpFrame ;Wenn Spieler noch lebt Else ;Nimm die Daten der Höhle an der X-Position des Spielers SelectElement(Cave(), Int(User()\x)) ;Wenn Spieler Schub gibt und Demo aus ist If (User()\Still = #False Or Schub) And User()\Demo = #False ;Position des Spielers um xt- und yt-Wert bewegen und #JumpFrame miteinbeziehen User()\x + User()\xt * #JumpFrame User()\y + User()\yt * #JumpFrame ;Anhand von Masse und Schwerkraft Spieler fallen lassen User()\yt + User()\Masse * #Gravity ;Wenn Schub da ist, Spieler wieder hochheben If Schub User()\yt - User()\Schub EndIf ;Falls Still vorher #True war, wird es jetzt für immer auf #False gesetzt User()\Still = #False ;Wenn die Demo an ist ElseIf User()\Demo ;"Schiff" immer in die Mitte des Bildschirms setzen User()\y = (Cave()\y2 - Cave()\y1) / 2 + Cave()\y1 - User()\Radius EndIf ;Spieler Punkte dazurechnen in Bezug auf Höhlen"enge", #JumpFrame und #SHeight User()\Punkte + ((#SHeight - Cave()\y2 + Cave()\y1) * #JumpFrame * #MaxPunkte / #SHeight) ;Wenn der Spieler die Höhle berührt, wird er als TOT erklärt If User()\y + User()\Radius < Cave()\y1 Or User()\y + User()\Radius > Cave()\y2 User()\Dead = #True EndIf NotGameOver.l = #True EndIf Wend ;Falls NotGameOver.l bei keinem Spieler auf #True gesetzt wurde, wird das Spiel beendet If NotGameOver = #False FlipBuffers() GameOver() EndIf ;- Graphics FlipBuffers() ClearScreen(0, 0, 0) ;Plotte Hintergrund DisplaySprite(#BackID, 0, 0) ;Bwewege Hintergrund um #JumpFrame Pixel weiter ScrollBackround(#JumpFrame) ;Wenn überhaupt irgendeine Farbe geändert werden soll If ChangeRGB ;Wenn Rot = 255 ist, ändere die andere Farben um #MaxRGBCh If Rot = 255 If ChangeRGB & 2 : Gruen + Random(#MaxRGBCh * 2) - #MaxRGBCh : EndIf If Gruen < #MinRGB : Gruen = #MinRGB : EndIf If Gruen >= 255 And ChangeRGB & 4 : Rot - 1 : Gruen = 255 : EndIf If ChangeRGB & 1 : Blau + Random(#MaxRGBCh * 2) - #MaxRGBCh : EndIf If Blau < #MinRGB : Blau = #MinRGB : EndIf If Blau >= 255 And ChangeRGB & 4 : Rot - 1 : Blau = 255 : EndIf EndIf ;Das selbe für Grün If Gruen = 255 If ChangeRGB & 4 : Rot + Random(#MaxRGBCh * 2) - #MaxRGBCh : EndIf If Rot < #MinRGB : Rot = #MinRGB : EndIf If Rot >= 255 And ChangeRGB & 2 : Gruen - 1 : Rot = 255 : EndIf If ChangeRGB & 1 : Blau + Random(#MaxRGBCh * 2) - #MaxRGBCh : EndIf If Blau < #MinRGB : Blau = #MinRGB : EndIf If Blau >= 255 And ChangeRGB & 2 : Gruen - 1 : Blau = 255 : EndIf EndIf ;Das selbe für Blau If Blau = 255 If ChangeRGB & 4 : Rot + Random(#MaxRGBCh * 2) - #MaxRGBCh : EndIf If Rot < #MinRGB : Rot = #MinRGB : EndIf If Rot >= 255 And ChangeRGB & 1 : Blau - 1 : Rot = 255 : EndIf If ChangeRGB & 2 : Gruen + Random(#MaxRGBCh * 2) - #MaxRGBCh : EndIf If Gruen < #MinRGB : Gruen = #MinRGB : EndIf If Gruen >= 255 And ChangeRGB & 1 : Blau - 1 : Gruen = 255 : EndIf EndIf EndIf ;Plotte die einzelnen "Schiffe" ResetList(User()) While NextElement(User()) DisplayTransparentSprite(User()\SprID, User()\x - Radius, User()\y - Radius) Wend StartDrawing(ScreenOutput()) ;Zeichne einen roten Rand um das Spielfeld DrawingMode(4) Box(0, 0, #MWidth, #MHeight, RGB(255, 0, 0)) ;Debugger Drawing FrontColor(255, 255, 255) DrawingMode(1) ;Frames Per Second TTime.l = (GetTickCount_() - Time) Locate(10, 10) DrawText("FPS: " + Str(Int(Frames * 1000 / TTime))) ;Punkte Locate(#MWidth - 50, #MHeight - 50) DrawText(Str(User()\Punkte / 1000)) StopDrawing() ;- Pause ;Wenn Pause gedrückt wurde If Pause = #True Repeat Delay(100) DisplaySprite(#BackID, 0, 0) FlipBuffers() ExamineKeyboard() If KeyboardReleased(#PB_Key_P) : Pause = #False : EndIf If KeyboardReleased(#PB_Key_Escape) : Pause = #False : Quit = #True : EndIf Until Pause = #False EndIf Until Quit EndProcedure ;- ;- ACHTUNG ACHTUNG ACHTUNG ;Die folgenden Prozeduren sind sehr schwer zu verstehen, aber im Grundprinzip ziemlich gleich Procedure CreateBackround() ;Neues Hintergrundsprite erstellen If CreateSprite(#BackID, #SWidth, #SHeight) = #False MsgError(4) EndIf x.l y.l c.l c1.l c2.l c3.l c4.l Cavey1.l Cavey2.l StartDrawing(SpriteOutput(#BackID)) ;Erstelle eine neue Höhle (1 Element = 1 Pixel)... AddElement(Cave()) ;...mit den größten Maßen Cave()\y1 = 0 Cave()\y2 = #SHeight - 1 ;Setze die Anfangshelligkeit fest c = 255 ;Male in der ersten Spalte des Hintergrundbildes einen fließenden Farbeübergang For y = 0 To #SHeight - 1 If y < Cave()\y1 Or y > Cave()\y2 : Hell = FrontBr : Else : Hell = BackBr : EndIf c = (Random(255) + c) / 2 * Hell / 256 Plot(0, y, RGB(c, c, c)) Next ;Gehe die restlichen Spalten durch und generiere die angefangene Textur weiter For x = 1 To #SWidth - 1 ;Nimm die Daten des vorherigen Höhlenabschnittes (1 Pixel)... Cavey1 = Cave()\y1 Cavey2 = Cave()\y2 ;...und errechne für oben und unten eine(n) beliebigen Zuwachs oder Abnahme an Pixel Repeat Zy1add.f = (Random(200) - 100) / 100 Zy2add.f = (Random(200) - 100) / 100 ;Wenn der Zufall im gültigen Bereich ist, verlasse die Schleife Until Cavey2 + Zy2add - Cavey1 - Zy1add > #MinRoom And Cavey1 + Zy1add > 0 And Cavey2 + Zy2add < #SHeight - 1 ;Addiere eine neue Höhle AddElement(Cave()) Cave()\y1 = Cavey1 + Zy1add Cave()\y2 = Cavey2 + Zy2add ;Gehe jeden einzelnen Pixel der Spalte von oben nach unten durch und generiere die Textur weiter For y = 0 To #SHeight - 1 ;Nimm die benachbarten Farben der Spalte zuvor If y = 0 : c1 = Random($FFFFFF) : Else : c1 = Point(x - 1, y - 1) : EndIf c1 = c1 & $FF c2 = Point(x - 1, y) & $FF c2 = c2 & $FF If y = #SHeight - 1 : c3 = Random($FFFFFF) : Else : c3 = Point(x - 1, y + 1) & $FF: EndIf c3 = c3 & $FF c4 = Random(255) ;Nimm eine zufällige Verhältnismischung an z.l = Random(10) + 1 c = (c1 + c2 + c3) * z + c4 * 2 T.l = 3 * z + 2 ;Zeichne die Pixel, wenn sie Wand darstellen sollen in der Helligkeit FrontBr, ... If y < Cave()\y1 Or y > Cave()\y2 Hell = FrontBr c = (c / T) * Hell / 255 Plot(x, y, RGB(c * Rot / 255, c * Gruen / 255, c * Blau / 255)) ;Ansonsten in der Helligkeit BackBr. Else Hell = (BackBr * (Cave()\y2 - Cave()\y1)) / #SHeight c = (c / T) * Hell / 255 Plot(x, y, RGB(c, c, c)) EndIf Next Next StopDrawing() EndProcedure Procedure ScrollBackround(Pixel.l) ;Zeichne das Hintergrundbild um Pixel.l Pixel nach links verschoben in sich selbst hinein UseBuffer(#BackID) DisplaySprite(#BackID, -Pixel, 0) UseBuffer(-1) StartDrawing(SpriteOutput(#BackID)) ;Gehe zum ersten Höhlensegment und löschen Pixel.l Elemente FirstElement(Cave()) For a.l = 1 To Pixel DeleteElement(Cave()) Next ;Springe anschließend zum letzten Element LastElement(Cave()) ;Generiere Pixel.l neue Höhlensegmente, die sich relativ zum vorherigen Element bewegen (s. CreateBackround) For a.l = 1 To Pixel Cavey1 = Cave()\y1 Cavey2 = Cave()\y2 Repeat Zy1add.f = (Random(#MaxChange * 1000) - #ChangeTendenz * #MaxChange) / 1000 Zy2add.f = (-Random(#MaxChange * 1000) + #ChangeTendenz * #MaxChange) / 1000 Until Cavey2 + Zy2add - Cavey1 - Zy1add > #MinRoom And Cavey1 + Zy1add > 0 And Cavey2 + Zy2add < #SHeight - 1 AddElement(Cave()) Cave()\y1 = Cavey1 + Zy1add Cave()\y2 = Cavey2 + Zy2add Next ;Gehe wieder Pixel.l - 1 Elemente zurück For a.l = 2 To Pixel PreviousElement(Cave()) Next ;Lösche den übrig gebliebenen Rest des verschobenen Hintergrundbildes Box(#SWidth - 1 - Pixel, 0, Pixel, #SHeight - 1, 0) ;Mache das gleiche wie bei CreateBackround For a.l = Pixel To 1 Step - 1 x.l = #SWidth - a - 1 For y = 0 To #SHeight - 1 If y = 0 : c1 = Random($FFFFFF) : Else : c1 = Point(x - 1, y - 1) : EndIf c1 = c1 & $FF c2 = Point(x - 1, y) & $FF c2 = c2 & $FF If y = #SHeight - 1 : c3 = Random($FFFFFF) : Else : c3 = Point(x - 1, y + 1) & $FF: EndIf c3 = c3 & $FF c4 = Random(255) ;Farb-Mischung z.l = Random(10) + 1 c = (c1 + c2 + c3) * z + c4 * 2 T.l = 3 * z + 2 If y < Cave()\y1 Or y > Cave()\y2 Hell = FrontBr c = (c / T) * Hell / 255 Plot(x, y, RGB(c * Rot / 255, c * Gruen / 255, c * Blau / 255)) Else Hell = (BackBr * (Cave()\y2 - Cave()\y1)) / #SHeight c = (c / T) * Hell / 255 Plot(x, y, RGB(c, c, c)) EndIf Next ;Springe ein Höhlensegment weiter NextElement(Cave()) Next StopDrawing() EndProcedure ; ExecutableFormat= ; Executable=C:\Programme\PureBasic\Programme\Projekte\Caveflight - Clone\Caveflight V2 MB 640x480 Fullscreen.exe ; DisableDebugger ; EOF