FPS Einbußen

Anfängerfragen zum Programmieren mit PureBasic.
Defmaster
Beiträge: 130
Registriert: 26.12.2004 21:38
Kontaktdaten:

FPS Einbußen

Beitrag von Defmaster »

Also ich bin gerade dabei mein erstes kleien Jumü'n Run mit PB zu machen.

Geht auch erstmal alles soweit (naja der sprung sieht noch net ganz so gut aus)

Jedenfalls viel mir beim Testen auf, das auf einmal von 60FPS (per setframerate() festgelegt) auf 40 abgesackt sind.

So ich habe nen Screen von 800x600, dann 2 Array's für die Verschiedenen Objekte (1x für Normale,1x für welche wodurch man stirbt)
Nun habe ich auch 2 Proceduren um zu Prüfen ob man da gegen Trifft.
Bei den mit den Sterben habe ich Pixel genau Collision, weil dies Stachel sind
und deshalb auch transparant gezeichnet werden.
Würde dumm aussehen wenn man 10-20 Pixel vorm Stachel stirbt.
Bzw. wenn um stachel schwarzen Kästchen wäre.

Nun ist es so obwohl nicht viele Objekte sind (wie gesagt 800x600 Screen mit 32x32 großen Grafiken) das ich 20fps einbüße.

Ich weiß nicht ob es jetzt daran liegt dass zuviel bzw. die art wie es gezeichnet ist zuviel ist.
Oder ob meine abfragen zuviel sind bei der Bewegung (dürfte aber eigentlich nicht sein).

Ich hoffe ihr könnt mir helfen, denn schon bei einem so kleinem spiel so wenig fps.

(Bin noch Anfänger mit PB deshalb kann/wird es auch sein das ich vieles zu kompliziert gemacht habe)
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag von Ynnus »

Lass das festsetzen der Framerate durch diesen Befehl raus, das ist sowieso keine Übliche Art. Such dir im Forum stattdessen eine bessere Methode zur Framebasierten Bewegung. ;)

Ansonsten kommt es sehr auf den Code an, wie die FPS am Ende ausfallen. Das können auch nur wenige Objekte sein, nur ein paar Sprites, wenn man da was falsch macht beim Anzeigen kann man sich da flott ausbremsen.
Also wenn der Code noch nicht zu lang ist, kannst du ihn hier ja mal posten. Ich hab Erfahrungen damit gemacht, dass man auch gut 1000 Sprite-Objekte im 1024 x 768 Screen anzeigen kann ohne großer Einbüßen unterhalb der 60 FPS, kommt aber eben stark auf den Code an.
Defmaster
Beiträge: 130
Registriert: 26.12.2004 21:38
Kontaktdaten:

Beitrag von Defmaster »

Ok hier der erste Teil des code's (nich lachen bi nnoch anfänger :roll: )

Code: Alles auswählen

;{ Dim Welt_map1.b(25,18)
Dim Welt_map1.b(25,18)
MAP DATEN
;}

;{ Dim Tode_map1.b(25,18)
Dim Tode_map1.b(25,18)
MAP DATEN
;}

startposition_map1_y = 450

Procedure welt_map1_zeichnen()
  Shared spieler_x,spieler_y
  For x=0 To 25
    For y=0 To 18
      If Welt_map1(x, y) <> 0
        DisplaySprite(Welt_map1(x, y), x*32, y*32)
      EndIf
    Next y
  Next x
EndProcedure

Procedure tode_map1_zeichnen()
  Shared spieler_x,spieler_y
  For x=0 To 25
    For y=0 To 18
      If Tode_map1(x, y) <> 0
        DisplayTransparentSprite(Tode_map1(x, y), x*32, y*32)
      EndIf
    Next y
  Next x
EndProcedure 

Procedure CheckCollision(SpeedX.f, SpeedY.f)
  Shared spieler_x,spieler_y
  For x=0 To 25-1
    For y=0 To 19-1
      If Welt_map1(x, y) <> 0
        If SpriteCollision(#Spieler, Int(spieler_x + SpeedX), Int(spieler_y + SpeedY), Welt_map1(x, y), x*32, y*32)
          ProcedureReturn 1
        EndIf
      EndIf
    Next y
  Next x
EndProcedure 

Procedure CheckSterben(SpeedX.f, SpeedY.f)
  Shared spieler_x,spieler_y
  For x=0 To 25-1
    For y=0 To 19-1
      If Tode_map1(x, y) <> 0
        If SpritePixelCollision(#Spieler, Int(spieler_x + SpeedX), Int(spieler_y + SpeedY), Tode_map1(x, y), x*32, y*32)
          ProcedureReturn 1
        EndIf
      EndIf
    Next y
  Next x
EndProcedure 

Procedure bewegen()
  Shared spieler_x,spieler_y,speed_bewegung,spieler_aussehen,geschwindigkeit,strafe,maximal_geschwindigkeit
  
  If KeyboardPushed(#PB_Key_Right) And spieler_x < 785
    If CheckCollision(speed_bewegung, 0) = 0 And CheckSterben(speed_bewegung, 0) = 0
      spieler_x + speed_bewegung  ; Spieler bewegen
      spieler_aussehen = #Spieler ; Bildwechsel 
    ElseIf CheckSterben(speed_bewegung, 0) = 1
      spieler_x = 0
      spieler_y = startposition_map1_y
    EndIf 
  EndIf 
  
  If KeyboardPushed(#PB_Key_Left) And spieler_x > 0
    If CheckCollision(speed_bewegung-4, 0) = 0 And CheckSterben(speed_bewegung, 0) = 0
      spieler_x - speed_bewegung
      spieler_aussehen = #Spieler_2 ; Bild wechsel
    ElseIf CheckSterben(speed_bewegung-4, 0) = 1
      spieler_x = 0
      spieler_y = startposition_map1_y
    EndIf
  EndIf 
  
  If KeyboardPushed(#PB_Key_Up) And spieler_y > 0
    If CheckCollision(0, speed_bewegung-4) = 0 And CheckSterben(speed_bewegung, 0) = 0 ;And CheckCollision(0, speed_bewegung)
      
      If geschwindigkeit < maximal_geschwindigkeit And strafe = 0
        geschwindigkeit = geschwindigkeit + 1
      EndIf
      
      If geschwindigkeit = maximal_geschwindigkeit
        strafe = 1
      EndIf 
      
      If strafe = 1 And geschwindigkeit > 0
        geschwindigkeit = geschwindigkeit - 1
      ElseIf geschwindigkeit = 0 And CheckCollision(0, speed_bewegung)
        strafe = 0
      EndIf 
      
      If CheckCollision(0, speed_bewegung) = 1
        geschwindigkeit = 0
        strafe = 0
      EndIf 
      
      If strafe = 0 And CheckCollision(0, speed_bewegung-14) = 0
        spieler_y = spieler_y -  7
      EndIf 
      
    ElseIf CheckSterben(speed_bewegung-4, 0) = 1
      spieler_x = 0
      spieler_y = startposition_map1_y
    EndIf
  EndIf 
  
  If KeyboardReleased(#PB_Key_Up)
    geschwindigkeit = maximal_geschwindigkeit
    strafe = 1
  EndIf 
  
  If spieler_y > 600
    spieler_x = 0
    spieler_y = startposition_map1_y
  EndIf 
 
EndProcedure 

Procedure gravitation()
  Shared speed_bewegung,spieler_x,spieler_y,startposition_map1_y,geschwindigkeit
  If CheckCollision(0, speed_bewegung) = 0
    spieler_y = spieler_y + 2
  ElseIf CheckCollision(0, 1) = 0
    spieler_y = spieler_y + 1
  EndIf 
  If CheckSterben(0, speed_bewegung) = 1
    spieler_x = 0
    spieler_y = startposition_map1_y
  EndIf 
EndProcedure
Und hier wo es abgerufen wird:

Code: Alles auswählen

Procedure level1()
  Shared spieler_x,spieler_aussehen,spieler_y,level
  FlipBuffers()
  ClearScreen(255,0,0)
  ExamineKeyboard()
  DisplayTransparentSprite(spieler_aussehen,spieler_x,spieler_y)
  welt_map1_zeichnen() ; In map1.pb
  tode_map1_zeichnen() ; In map1.pb
  bewegen()
  gravitation()
  DisplaySprite(#Exit,768,64)
  If SpriteCollision(spieler_aussehen,spieler_x,spieler_y,#Exit,768,60)
    level = 2
  EndIf 
EndProcedure
k Das war, ich endschuldige mich schonmal falls da irgendwas nach totalem mist aussieht :freak:
Benutzeravatar
Ynnus
Beiträge: 855
Registriert: 29.08.2004 01:37
Kontaktdaten:

Beitrag von Ynnus »

Okay, also erstmal sollte man als Programmierer immer und überall optimieren, wenn es nicht zu Ungunsten der Übersicht geht und in Übersichtlosigkeit endet. Also ich sehe da schonmal 4 For-Schleifen die fast alle das gleiche machen, nämlich von 0 - 25 und von 0 - 18 zählen. Das so verschachtelt, dass letztendlich der Inhalt der Schleifen 494 mal ausgeführt wird. Das bei 4 Schleifen macht: 1976 Schleifendurchgänge pro Frame. Das halte ich schonmal für optimierbar. Zum Beispiel könntest du die ersten beiden Schleifen zusammenfassen zu einer und beide Dinge, die Welt und die Todeszonen in einem Durchgang zeichnen lassen. Dann formst du beide Prozeduren eben zu einer, die die Welt komplett zeichnet.
Auf Kollision und auf den Tot Checken kann man auch in einer Schleife, jeweils die Collision hintereinander prüfen. Da entfallen wieder eine Schleife, das macht insgesammt noch 2 Schleifen, von 4 ursprünglich. Eventuell könnte man diese 2 Schleifen auch noch zusammenlegen, muss man jetzt sehen, wie das mit der Überschaubarkeit des Codes passt.

Ansonsten, Pixelgenaue Spritecollision ist natürlich wesentlich langsamer als normale. Vielleicht solltest du jedem Stachel der zum Tot des Spielers führt einen Bereich auf der Karte zuweisen, in dem der Spieler stirbt. Dann musst du nur noch Variablen (die Koordinaten) vergleichen und keine volle Pixelkollision mehr. Die Box könnte dann auch so eng geschnitten sein, dass kein Teil über die Stacheln hinaus schaut.
Das wären nur so meine Vorschläge, groß angeschaut, ob da vielleicht ein kleiner Fehler irgendwo drinn ist, der das ausbremst, hab ich mir das nicht. Vielleicht hilft die Optimierung soweit auch erstmal aus.

Im übrigen würde ich flipbuffers() hinter die Sprite-Anzeigeroutienen setzen. Sonst zeigst du immer die Sprites des letzten Frame-Durchgangs an.
Defmaster
Beiträge: 130
Registriert: 26.12.2004 21:38
Kontaktdaten:

Beitrag von Defmaster »

k Danke erstmal.
ich hatte am anfang mal versucht die schleifen zu einer zu machen, ging nicht, jetzt habe ich mein Fehle rbemerkt denn ich damals gemacht habe.

Flipbuffers()
Habe ich am anfang weil das in den ganzen Tuts stand die ich mir angesehen, von selber hab ichs immer als letztes gemacht.

Ich werde das jetzt mal optmieren.
(Persönlich bin auch mehr ein optimier fReak, aber bei pb muß man das ja erstmal wissen)

Danke nochmal. Auf die Schleifen hät ich selber kommen können wenn ich vorher nich den fehler reingehauen hät >.<

EDIT:
Habe mal geteset also.
1 Schleife lässt sich zusammen fügen. Die andere geht Codebedingt nicht.
Wenn ich jetzt nicht Transparantzeichne dann läuft es mit 60fps.
Wenn ich transparent zeiche dann geht auf 40 runter.
Defmaster
Beiträge: 130
Registriert: 26.12.2004 21:38
Kontaktdaten:

Beitrag von Defmaster »

So ich bins nochmal.

Ich habe nun 1 Schleife zusammen gefügt (die mit dem zeichnen)
Die andere geht Codebedingt nicht.
Weil ich das auftreffen auf normalen boden und auf Sterbe sachen anders abfrage.

Nun habe ich mal die PixelCollision kommentiert.
Blieb immer noch bei 40fps.

Dann auskommentiert und dann das Zeichnen der Transparenten Sprites kommentiert, dann waren es wieder 60fps.

Code: Alles auswählen

Procedure welt_map1_zeichnen()
  Shared spieler_x,spieler_y
  For x=0 To 24
    For y=0 To 18
      If Welt_map1(x, y) <> 0
        DisplaySprite(Welt_map1(x, y), x*32, y*32)
      EndIf
      If Tode_map1(x, y) <> 0
        DisplayTransparentSprite(Tode_map1(x, y), x*32, y*32)
      EndIf
    Next y
  Next x
EndProcedure
So sieht die zeichnen Procedure aus.
Wenn ich das mit Tode_map1 weg mache dann gehts schnell.
Dabei zeichne ich nur 10 (11 mit spieler) Transparente Sprites.

Sollte ich nun diese Dinger einzeln setzen und kollision abragen lassen?
Wäre es dann schneller?

btw habe noch immer PB Demo weshalb Debugger an ist daran dürften es aber nicht liegen oder?
Benutzeravatar
iF
Beiträge: 84
Registriert: 17.07.2005 20:20
Wohnort: Berlin
Kontaktdaten:

Beitrag von iF »

Hallo Defmaster - hab den Thread nur überflogen - habe aber gesehen das Du von schwankenden FPS redest.

Bitte beachte auch das bei heutigen Prozessoren die MHZ nicht immer konstant ist. Besonders Notebooks schalten gerne eine Stufe niedriger wenn's zu warm wird.

Vielleicht erklärt das ja die Differenzen.

Salve, iF.
Achtung: kein PB'ler - habt bitte erbarmen. :mrgreen: /:->
Defmaster
Beiträge: 130
Registriert: 26.12.2004 21:38
Kontaktdaten:

Beitrag von Defmaster »

Nein das kann nicht sein.

Habe einen Amd 64 3000+ (kein notebook) keine Energiesparmodus und kein Cool' Quiet an.

Es leigt an den Transparenen sprites wie ich schrieb aber das bei 10 stück so doll runtergeht hätte ich nicht gedacht liegt auch an der Programmierweise :(

Also mit Mhz hat das nich zu tun.

Es ist halt so zeichne ich nicht Transparent -> 60fps
Zeichne ich Transparent -> um die 40fps
Benutzeravatar
Batze
Beiträge: 1492
Registriert: 03.06.2005 21:58
Wohnort: Berlin
Kontaktdaten:

Beitrag von Batze »

Bei sehr kleinen Tiles kannst du oft sogar bis auf 4 Kollisionsabfragen begrenzen.

@Admin: Ich hab nach Zaphod gepostet un d trotzdem ist sein Post hinter meinem. :?
Hier sind meine Codes (aber die Seite geht gerade nicht):
http://www.basicpure.de.vu
Benutzeravatar
Zaphod
Beiträge: 2875
Registriert: 29.08.2004 00:40

Beitrag von Zaphod »

es macht auch keinen sinn auf kollision mit jedem tile deiner karte zu vergleichen. du kannst über die position deines sprites doch ziemlich genau feststellen bei welchen koordinaten eine kollision möglicherweise auftreten könnte. teste doch nur gegen diese tiles.

wenn zb dein sprite nicht größer ist als ein tile, kann die kollision doch nur gegen die umgebenden tiles passieren:

* sprite
# mögliche kollision

###
#*#
###
Antworten