Colisionscode streikt?!

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Kaeru Gaman hat geschrieben:der befehl braucht die Spritenummer, um höhe und breite zu ermitteln.
zusammen mit der x/y-pos hat sie dann ein rechteck.
nun überprüft sie lediglich, ob sich die beiden rechtecke überlappen.
Genau so hätte ich es auch sagen können, aber der Geistesblitz war wohl so heiß dass er seine Spuren hinterlassen hat.

Boah, geil, mal etwas verstanden zu haben... <)

Wie funkt denn SpritePixelCollision() eigentlich? Die normale Version könnte ich ja noch nachproggen, aber mit Transparenz?
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

die nimmt eben die jeweilige texture als maske.
checkt erst die rechteck-koordinaten, und checkt dann für den überlappenden bereich jedes pixel einzeln, ob es von beiden sprites dorthin gezeichnet wird.

[edit]
eine viel einfachere methode ist BoundingCircle:

du ermittelst die mittelpunkte beider sprites, dann deren abstand, dann schaust du, ob der kleiner ist als die summe der beiden kollisionsradien.

für viele bilderchen ist ein kreis ein schönerer kollisionsbereich als ein rechteck.
für ballergames ist das ideal.

[edit2]
> Eine andere Möglochkeit zum Kollisionsabfrgen gibt es doch gar nicht.

doch, eben dementsprechend aufwendige koordinaten-prüfungen.
ok, bei 2D hast du schnell die performance so weit unten wie bei pixel-kollision,
aber im 3D-bereich sind alle möglichen Boundings (Sphere, Box, etc),
irgendwelche formeln für regelmäßige geometrische formen weit effektiver, als tausende von polygonen auf überschneidungen zu checken.
Zuletzt geändert von Kaeru Gaman am 01.06.2006 00:12, insgesamt 3-mal geändert.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
AND51
Beiträge: 5220
Registriert: 01.10.2005 13:15

Beitrag von AND51 »

Achso. Abe ist das denn wirklich so ein Performanceverlust? Eine andere Möglochkeit zum Kollisionsabfrgen gibt es doch gar nicht.
PB 4.30

Code: Alles auswählen

Macro Happy
 ;-)
EndMacro

Happy End
Ghost
Beiträge: 141
Registriert: 10.04.2006 09:10

Beitrag von Ghost »

sorry aber der Code Streikt wieder :oops:

also ich habe den Code jetzt so

Code: Alles auswählen

      ResetList(LGJaeger()) 
While NextElement(LGJaeger()) 
  ResetList(GatlingshootI()) 
While NextElement(GatlingshootI()) 
 If SpriteCollision(1,GatlingshootI()\x,GatlingshootI()\y,2, LGJaeger()\x, LGJaeger()\y) And LGJaeger()\Shield > 0
    DeleteElement(GatlingshootI())
   LGJaeger()\Shield - GatlingshootI()\Schildschaden
    EndIf 
 Wend
 Wend 
So eigentlich klappt alles eine Zeit lang aber mitten im Spiel bricht er ab und der Debugger springt ein. Er makiert mir die Zeile" LGJaeger()\Shield - GatlingshootI()\Schildschaden" und schreibt drunter "Pointer is null"
Ich hatte sonst nur einige Variabeln verändert.
(nutze v. 3.3)
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

muha... muss ich erstmal lesbar machen...

Code: Alles auswählen

ResetList(LGJaeger()) 
While NextElement(LGJaeger()) 
  ResetList(GatlingshootI()) 
  While NextElement(GatlingshootI()) 
    If SpriteCollision(1,GatlingshootI()\x,GatlingshootI()\y,2, LGJaeger()\x, LGJaeger()\y) And LGJaeger()\Shield > 0
      DeleteElement(GatlingshootI())
      LGJaeger()\Shield - GatlingshootI()\Schildschaden
    EndIf 
  Wend
Wend 
aalso...

ich hatte gesagt, du sollst den Schaden VOR dem löschen des schusses abziehen.
ist doch logisch, wenn du erst den schuss löscht, nimmst du für die rechnung den schaden von irgendeinem nächsten schuss, weil der, den du meinst, garnicht mehr existiert.

eventuell hängt auch daran der fehler, denn wenn du den letzten schuss gelöscht hast, hat die liste natürlich keine schüsse mehr, auf deren ()\Schildschaden du zugreifen kannst...

solche details sind ganz wichtig!

du musst dir immer bewusst sein, was du da grade im code anweist.
wenn du daten von einem listenelement verwenden willst, darfst du es nicht vorher löschen.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Ghost
Beiträge: 141
Registriert: 10.04.2006 09:10

Beitrag von Ghost »

Ups sorry hab ich übersehen (dachte wäre andersrum also erst dividieren dann löschen) :oops: :oops: :oops:
sorum scheint es jedenfalls zu klappen
Danke nochmals :)
(nutze v. 3.3)
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

> Danke nochmals

kein problem, jederzeit wieder. :D

freundlichen, lernbereiten anfängern zu helfen macht mehr spass, als von blöden scriptkiddies angebagger zu werden "gib ma code, ey"


PS:
kleiner tip am rande: überarbeite mal deine formatierungen. ich finds schlecht lesbar. eigentlich macht man einrückungen eher so wie in meinem beispiel....
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
DarkDragon
Beiträge: 6291
Registriert: 29.08.2004 08:37
Computerausstattung: Hoffentlich bald keine mehr
Kontaktdaten:

Beitrag von DarkDragon »

Ich habe vor einiger Zeit einen Code für Anfänger, die mich im ICQ kontaktierten geschrieben:

Code: Alles auswählen

; Sprite- und Keyboardfunktionen voreinstellen
If InitSprite() = 0 : MessageRequester("Error", "Can't init. screens and sprites") : End : EndIf
If InitKeyboard() = 0 : MessageRequester("Error", "Can't init. keyboard") : End : EndIf

; Geschwindigkeitskonstante
#SPEED = 2

; Diese Funktion prüft ob eine Kollision vorliegt
Procedure Collision(x.f, y.f)
  Result = 0
;   Gehe alle Tiles durch
  Restore Map
  
  For my=0 To 17
    For mx=0 To 24
      
      a.b
      Read a
;       Wenn der Tile-Typ 1(Mauer) ist, so prüfe auf eine Kollision mit diesem Tile...
      If a = 1
;         ... mit den entsprechenden Tile-koordinaten(IndexX*TileBreite, IndexY*TileBreite)...
;         ... und den entsprechenden Spieler-koordinaten(SpielerX, SpielerY)...
;         ... so, wie man es Zeichnen würde.
        If SpriteCollision(0, Int(x), Int(y), 1, mx*32, my*32)
;           Wenn ja: gib 1(True) zurück
          Result = 1
;           und springe aus beiden Schleifen(Anzahl: 2) raus
          Break 2
        EndIf
      EndIf
      
    Next
  Next
  
  ProcedureReturn Result
EndProcedure

; Öffne einen Screen
If OpenScreen(800, 600, 32, "Test") = 0 : MessageRequester("Error", "Can't open a screen") : End : EndIf

; Erstelle 2 Sprites
; Rotes viereck = Mauer
CreateSprite(0, 32, 32)
StartDrawing(SpriteOutput(0))
Box(0, 0, 32, 32, RGB(255, 0, 0))
StopDrawing()

; Blaues viereck = Spieler
CreateSprite(1, 32, 32)
StartDrawing(SpriteOutput(1))
Box(0, 0, 32, 32, RGB(0, 0, 255))
StopDrawing()

; Spielerposition genau in der Mitte des Bildschirms
X.f = 800/2
Y.f = 600/2

; Framerate auf 30 setzen(reich völlig)
SetFrameRate(30)

;- Hauptschleife
Repeat
;  Keyboardstatus erneuern und abfragen
  ExamineKeyboard()
  
  If KeyboardPushed(#PB_Key_Up)     ; laufe hoch
    If Collision(X, Y-#SPEED) = 0
      Y - #SPEED
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Down)   ; laufe runter
    If Collision(X, Y+#SPEED) = 0
      Y + #SPEED
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Left)   ; laufe links
    If Collision(X-#SPEED, Y) = 0
      X - #SPEED
    EndIf
  EndIf
  If KeyboardPushed(#PB_Key_Right)  ; laufe rechts
    If Collision(X+#SPEED, Y) = 0
      X + #SPEED
    EndIf
  EndIf
  
;   Beenden?
  If KeyboardPushed(#PB_Key_Escape)
    Quit = 1
  EndIf
  
;  Screeninhalt löschen und mit Schwarz überdecken
  ClearScreen(0, 0, 0)
;  Spieler anzeigen
  DisplaySprite(1, X, Y)
  
;  Mapdaten durchgehen
  Restore Map
  For my=0 To 17
    For mx=0 To 24
      
      a.b
      Read a
      If a = 1
;        Mauer = 1, also anzeigen
        DisplaySprite(0, mx*32, my*32)
      EndIf
      
    Next
  Next
;  Gefüllten Backbuffer zum Frontbuffer bringen
  FlipBuffers()
  
;  Eine kleine Verzögerung um den Prozessor nicht vollständig auszulasten
  Delay(5)
Until Quit = 1
End

; Mapdaten
DataSection
  Map:
  Data.b 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
  Data.b 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
EndDataSection
Das erklärt auch, warum ich X/Y getrennt voneinander auf Kollision überprüfe. Nämlich damit man beim schräg gegen eine Wand laufen immernoch an der Wand entlangläuft und nicht steckenbleibt.
Angenommen es gäbe einen Algorithmus mit imaginärer Laufzeit O(i * n), dann gilt O((i * n)^2) = O(-1 * n^2) d.h. wenn man diesen Algorithmus verschachtelt ist er fertig, bevor er angefangen hat.
Antworten