[B3D] Genaue Kollision für Jump'n'Runs

Übersicht BlitzBasic FAQ und Tutorials

Neue Antwort erstellen

Noobody

Betreff: [B3D] Genaue Kollision für Jump'n'Runs

BeitragSo, Jan 25, 2009 20:49
Antworten mit Zitat
Benutzer-Profile anzeigen
Wie oft hat man sich nicht schon über die Kollision in einem Jump'n'Run den Kopf zerbrochen - zumindest ich schon oft genug.
Die Möglichkeiten sind viele - von ImagesCollide, was nicht auf allen Grafikkarten funktioniert, bis zu Linienkollision (auch Vektorkollision genannt), bei der man ab und an durch den Boden fällt.
Ich bin vor kurzem jedoch auf eine andere Methode gekommen, die relativ gut funktioniert und ein paar sehr praktische Eigenschaften zeigt - insbesondere für 2D Jump'n'Runs.

Wer das [B3D] im Titel gesehen hat, hat vielleicht schon eine Ahnung, wie diese funktioniert - sie verwendet nämlich die Blitzinterne 3D - Kollision.
3D Kollision für ein 2D - Spiel? Ungewohnt, aber es funktioniert.
Im Grunde genommen repräsentieren wir unsere Karte durch eine Ansammlung von Linien (ähnlich wie bei der Linienkollision).
Für jede Linie erstellen wir hinter den Kulissen ein 3D - Viereck, auf dem der Spieler stehen kann. Der Spieler selbst ist nämlich ein Würfel, dem ein seiner Grösse entsprechender EntityRadius verpasst wurde.
Leider lässt Blitz nur Kugel - X Kollisionen zu, und da unsere Karte definitiv ein Polygon ist, muss für den Spieler halt eine Kugel herhalten.

In der Hauptschleife nehmen wir nun die Spielereingaben entgegen, berechnen die Geschwindigkeit des Spielers und bewegen seinen entsprechenden Würfel per MoveEntity.
Dann führen wir einmal UpdateWorld aus und lassen die Kollision berechnen - falls der Spieler im Level steckt, so hat ihn UpdateWorld wieder dort hinausbewegt.
Die Koordinaten des Spieler lesen wir dann mit EntityX bzw. EntityY vom Würfel wieder aus - gab es keine Kollision, so sind seine neuen Koordinaten einfach NeuePosition = AltePosition + Geschwindigkeit. Fand aber eine Kollision statt, so hat Blitz die neuen Koordinaten berechnet und wir können sie auslesen.
Man muss jedoch beachten, dass die Koordinaten den Mittelpunkt des Spielers bezeichnen; man muss dann einfach noch die halbe Höhe und die halbe Breite subtrahieren.

Soweit, sogut.
Aber was ist, wenn wir den Spieler springen lassen wollen? Da müssen wir irgendwie herausfinden, ob der Spieler den Boden berührt.
Und das geht mit CollisionNY. Hat der Spieler nämlich mit seiner Unterseite irgendetwas berührt, so zeigt die Kollisionsnormale nach oben.
Zeigt die Kollisionsnormale nach unten, so hat der Spieler die Decke irgendwo berührt - dann sollten wir seine Y - Geschwindigkeit auf 0 setzen, da er sonst an der Decke klebt.
Berührt er weder oben noch unten, so beschleunigen wir ihn einfach mit der Gravitation nach unten.

Das wars!
Mit so wenig Aufwand erhalten wir eine leistungsstarke Kollision, mit der wir sogar schräge Flächen hochlaufen können.
Man muss jedoch beachten, dass die Kollisionsflächen nur auf eine Seite hin solid sind - von der anderen Seite her kann man durchlaufen.
Man muss also einfach beim erstellen der Kollisionsflächen aufpassen, in welche Richtung sie zeigt.
Ist eine Linie falschrum, so muss man einfach Start- und Endpunkt vertauschen und sie sollte wie erwartet funktionieren.
Der Vorteil hiervon ist, dass man Plattformen erstellen kann, in die man von unten her hineinspringen kann (wie man es von Super Mario etc. kennt) - mit einer normalen Linienkollision wird das nämlich schwierig.
Der einzige Nachteil an dieser Methode liegt daran, dass der Spieler nun halt durch eine Kugel angenähert wird und kein Würfel ist - das sieht ab und zu ein wenig blöd aus.

Um das ganze zu veranschaulichen, habe ich hier einen kleinen Beispielcode geschrieben: Code: [AUSKLAPPEN]
Graphics3D 800, 600, 0, 2
SetBuffer BackBuffer()

AppTitle "Kollisionsdemo"

Const GRAVITY# = 0.1
Const PLAYER_WIDTH = 20
Const PLAYER_HEIGHT = 40

Global CollMesh, CollSurface
Global PlayerMesh, PlayerX#, PlayerY#, PlayerVX#, PlayerVY#
Global TouchBottom, TouchTop, TouchLeft, TouchRight

Type TCollFace
   Field X1#
   Field Y1#
   Field X2#
   Field Y2#
   
   Field Index
End Type

Timer = CreateTimer( 60 )

InitCollision()

CreateCollisionFace( 0, 599, 800, 599 )
CreateCollisionFace( 200, 599, 500, 500 )
CreateCollisionFace( 500, 599, 500, 400 )
CreateCollisionFace( 200, 400, 500, 400 )

While Not KeyHit( 1 )
   Cls
   
   UpdatePlayerCollision()
   UserInput()
   Render()
   
   Color 255, 255, 0
   Rect PlayerX#, PlayerY#, PLAYER_WIDTH, PLAYER_HEIGHT
   
   Text 0, 0, TouchRight + " " + TouchTop + " " + TouchLeft + " " + TouchBottom
   
   Flip 0
   WaitTimer Timer
Wend
End

Function InitCollision()
   PlayerMesh = CreateCube()
   EntityRadius PlayerMesh, PLAYER_WIDTH/2., PLAYER_HEIGHT/2.
   EntityType PlayerMesh, 1
   PositionEntity PlayerMesh, 100, -200, 0
   
   CollMesh = CreateMesh()
   EntityType CollMesh, 2
   CollSurface = CreateSurface( CollMesh )
   
   Collisions 1, 2, 2, 2
End Function

Function CreateCollisionFace.TCollFace( X1#, Y1#, X2#, Y2# )
   Face.TCollFace = New TCollFace
      Face\X1# = X1#
      Face\Y1# = Y1#
      Face\X2# = X2#
      Face\Y2# = Y2#
   
   V1 = AddVertex( CollSurface, X1#, -Y1#, 1 )
   V2 = AddVertex( CollSurface, X2#, -Y2#, 1 )
   V3 = AddVertex( CollSurface, X2#, -Y2#, 0 )
   V4 = AddVertex( CollSurface, X1#, -Y1#, 0 )
   
   AddTriangle CollSurface, V1, V2, V3
   AddTriangle CollSurface, V1, V3, V4
   
   Face\Index = V1
   
   Return Face
End Function

Function UpdatePlayerCollision()
   MoveEntity PlayerMesh, PlayerVX#, -PlayerVY#, 0
   
   UpdateWorld
   
   PlayerX# = EntityX( PlayerMesh, True ) - PLAYER_WIDTH/2.
   PlayerY# = -EntityY( PlayerMesh, True ) - PLAYER_HEIGHT/2.
   
   PositionEntity PlayerMesh, PlayerX# + PLAYER_WIDTH/2., -PlayerY# - PLAYER_HEIGHT/2., 0, True
   
   TouchBottom = False
   TouchTop = False
   TouchLeft = False
   TouchRight = False
   
   For i = 1 To CountCollisions( PlayerMesh )
      If CollisionNY( PlayerMesh, i ) > 0 Then TouchBottom = True
      If CollisionNY( PlayerMesh, i ) < 0 Then TouchTop = True
      If CollisionNX( PlayerMesh, i ) >  0.5 Then TouchLeft = True
      If CollisionNX( PlayerMesh, i ) < -0.5 Then TouchRight = True
   Next
End Function

Function UserInput()
   PlayerJump = KeyHit( 200 )
   PlayerXDir = KeyDown( 205 ) - KeyDown( 203 )
   
   If TouchBottom Then
      If PlayerJump Then PlayerVY# = -5 ElseIf PlayerVY# > 0 Then PlayerVY# = GRAVITY#
   Else
      PlayerVY# = PlayerVY# + GRAVITY
   EndIf
   If TouchTop And PlayerVY# < 0 Then PlayerVY# = GRAVITY#
   If PlayerXDir < 0 And ( Not TouchLeft ) Then PlayerVX# = -2
   If PlayerXDir > 0 And ( Not TouchRight ) Then PlayerVX# = 2
   If Not PlayerXDir Then PlayerVX# = 0
End Function

Function Render()
   Color 255, 0, 0
   LockBuffer BackBuffer()
   
   For Face.TCollFace = Each TCollFace
      Line Face\X1#, Face\Y1#, Face\X2#, Face\Y2#
   Next
   
   UnlockBuffer BackBuffer()
End Function


Da man in Jump'n'Runs bisweilen auch Tilemaps verwendet, habe ich hier noch einen Code geschrieben, der eine Helferfunktion für TileMaps enthält: Code: [AUSKLAPPEN]
Graphics3D 800, 600, 0, 2
SetBuffer BackBuffer()

AppTitle "Kollisionsdemo"

Const GRAVITY# = 0.1
Const PLAYER_WIDTH = 20
Const PLAYER_HEIGHT = 40

Const MAP_WIDTH = 25
Const MAP_HEIGHT = 19
Const GRIDSIZE = 32

Global CollMesh, CollSurface
Global PlayerMesh, PlayerX#, PlayerY#, PlayerVX#, PlayerVY#
Global TouchBottom, TouchTop, TouchLeft, TouchRight

Dim MapData( MAP_WIDTH - 1, MAP_HEIGHT - 1 )

Type TCollFace
   Field X1#
   Field Y1#
   Field X2#
   Field Y2#
   
   Field Index
End Type

Timer = CreateTimer( 60 )

InitCollision()
LoadMap()

While Not KeyHit( 1 )
   Cls
   
   UpdatePlayerCollision()
   UserInput()
   Render()
   
   Color 255, 255, 0
   Rect PlayerX#, PlayerY#, PLAYER_WIDTH, PLAYER_HEIGHT
   
   Text 0, 0, TouchRight + " " + TouchTop + " " + TouchLeft + " " + TouchBottom
   
   Flip 0
   WaitTimer Timer
Wend
End

Function InitCollision()
   PlayerMesh = CreateCube()
   EntityRadius PlayerMesh, PLAYER_WIDTH/2., PLAYER_HEIGHT/2.
   EntityType PlayerMesh, 1
   PositionEntity PlayerMesh, 100, -200, 0
   
   CollMesh = CreateMesh()
   EntityType CollMesh, 2
   CollSurface = CreateSurface( CollMesh )
   
   Collisions 1, 2, 2, 2
End Function

Function LoadMap()
   For i = 0 To MAP_HEIGHT - 1
      For t = 0 To MAP_WIDTH - 1
         Read MapData( t, i )
      Next
   Next
   
   For X = 0 To MAP_WIDTH - 1
      For Y = 0 To MAP_HEIGHT - 1
         If MapData( X, Y ) Then
            If X > 0 Then
               If Not MapData( X - 1, Y ) Then CreateCollisionFace( X*GRIDSIZE, ( Y + 1 )*GRIDSIZE, X*GRIDSIZE, Y*GRIDSIZE )
            EndIf
            
            If Y > 0 Then
               If Not MapData( X, Y - 1 ) Then CreateCollisionFace( X*GRIDSIZE, Y*GRIDSIZE, ( X + 1 )*GRIDSIZE, Y*GRIDSIZE )
            EndIf
            
            If X < MAP_WIDTH - 1 Then
               If Not MapData( X + 1, Y ) Then CreateCollisionFace( ( X + 1 )*GRIDSIZE, Y*GRIDSIZE, ( X + 1 )*GRIDSIZE, ( Y + 1 )*GRIDSIZE )
            EndIf
            
            If Y < MAP_HEIGHT - 1 Then
               If Not MapData( X, Y + 1 ) Then CreateCollisionFace( ( X + 1 )*GRIDSIZE, ( Y + 1 )*GRIDSIZE, X*GRIDSIZE, ( Y + 1 )*GRIDSIZE )
            EndIf
         EndIf
      Next
   Next
End Function

Function CreateCollisionFace.TCollFace( X1#, Y1#, X2#, Y2# )
   Face.TCollFace = New TCollFace
      Face\X1# = X1#
      Face\Y1# = Y1#
      Face\X2# = X2#
      Face\Y2# = Y2#
   
   V1 = AddVertex( CollSurface, X1#, -Y1#, 1 )
   V2 = AddVertex( CollSurface, X2#, -Y2#, 1 )
   V3 = AddVertex( CollSurface, X2#, -Y2#, 0 )
   V4 = AddVertex( CollSurface, X1#, -Y1#, 0 )
   
   AddTriangle CollSurface, V1, V2, V3
   AddTriangle CollSurface, V1, V3, V4
   
   Face\Index = V1
   
   Return Face
End Function

Function UpdatePlayerCollision()
   MoveEntity PlayerMesh, PlayerVX#, -PlayerVY#, 0
   
   UpdateWorld
   
   PlayerX# = EntityX( PlayerMesh, True ) - PLAYER_WIDTH/2.
   PlayerY# = -EntityY( PlayerMesh, True ) - PLAYER_HEIGHT/2.
   
   PositionEntity PlayerMesh, PlayerX# + PLAYER_WIDTH/2., -PlayerY# - PLAYER_HEIGHT/2., 0, True
   
   TouchBottom = False
   TouchTop = False
   TouchLeft = False
   TouchRight = False
   
   For i = 1 To CountCollisions( PlayerMesh )
      If CollisionNY( PlayerMesh, i ) > 0 Then TouchBottom = True
      If CollisionNY( PlayerMesh, i ) < 0 Then TouchTop = True
      If CollisionNX( PlayerMesh, i ) >  0.5 Then TouchLeft = True
      If CollisionNX( PlayerMesh, i ) < -0.5 Then TouchRight = True
   Next
End Function

Function UserInput()
   PlayerJump = KeyHit( 200 )
   PlayerXDir = KeyDown( 205 ) - KeyDown( 203 )
   
   If TouchBottom Then
      If PlayerJump Then PlayerVY# = -5 ElseIf PlayerVY# > 0 Then PlayerVY# = GRAVITY#
   Else
      PlayerVY# = PlayerVY# + GRAVITY
   EndIf
   If TouchTop And PlayerVY# < 0 Then PlayerVY# = GRAVITY#
   If PlayerXDir < 0 And ( Not TouchLeft ) Then PlayerVX# = -2
   If PlayerXDir > 0 And ( Not TouchRight ) Then PlayerVX# = 2
   If PlayerXDir = 0 Then PlayerVX# = 0
End Function

Function Render()
   Color 255, 0, 0
   LockBuffer BackBuffer()
   
   For Face.TCollFace = Each TCollFace
      Line Face\X1#, Face\Y1#, Face\X2#, Face\Y2#
   Next
   
   UnlockBuffer BackBuffer()
End Function

.MapCollision
Data 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 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 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 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1
Data 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 0, 0, 1
Data 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1, 1, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 1, 0, 0, 1
Data 1, 0, 0, 0, 0, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 1, 1, 0, 0, 1
Data 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1
Data 1, 0, 0, 1, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 1, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1
Data 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
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun
  • Zuletzt bearbeitet von Noobody am So, Jan 25, 2009 21:37, insgesamt einmal bearbeitet

Firstdeathmaker

BeitragSo, Jan 25, 2009 21:27
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm, spring mal beim obigen Beispielcode von links gegen die Wand und halte die Links-Taste gedrückt. Der Spielerkasten klebt an der Wand.

Und wenn man von der oberen Linie nach links geht, sodass man runterfällt, dann aber sofort wieder nach rechts geht, wird der Spieler wieder auf die obere Linie gesetzt...

Aber vom Prinzip her nicht schlecht.
www.illusion-games.de
Space War 3 | Space Race | Galaxy on Fire | Razoon
Gewinner des BCC #57 User posted image

Noobody

BeitragSo, Jan 25, 2009 21:40
Antworten mit Zitat
Benutzer-Profile anzeigen
Hui, das mit dem an-der-Wand-kleben war ein kleiner Flüchtigkeitsfehler meinerseits - ich hatte aus Versehen den Modus 3 statt 2 bei Collisions verwendet. Razz
Ist nun nacheditiert, danke für den Hinweis.

Dass man wieder auf die Linie kommt, liegt daran, dass der Spieler eine Kugel ist und nicht ein Würfel.
Wenn man sich gegen eine Kante drückt, so rutscht der Spieler wegen seiner runden Oberfläche nach oben.
Das ist ein wenig ärgerlich, aber mir kam noch keine Idee, wie man das beheben könnte.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

coolo

BeitragSo, Jan 25, 2009 22:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Toll! Ich finde das Tutorial echt gut, hab nämlich sowas schon lange gesucht. Ich hoffe du machst in Zukunft mehr von dieser Sorte.
http://programming-with-design.at/ <-- Der Preis ist heiß!
That's no bug, that's my project!
"Eigenzitate sind nur was für Deppen" -Eigenzitat

ozzi789

BeitragMo, Jan 26, 2009 8:51
Antworten mit Zitat
Benutzer-Profile anzeigen
Topp, mehr kann ich da nicht sagen, deine Tuts sind eine Bereicherung für uns alle Cool
0x2B || ! 0x2B
C# | C++13 | Java 7 | PHP 5

orpheus_2003

BeitragDi, Feb 17, 2009 18:00
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich dachte immer ich kann proggen.
Aber nun. Steig ich nicht mehr durch. Das ist mir zu hoch.
Bin momentan auch gerade dran in meinem Jump & Run ne Tile Colli zu machen.
Aber das hier ist mir zu strange......

Aber Danke fürs erklären.
GazerStar - the beginning
http://gazerstar.lexigame.de/
Wizard (Worktitel)
http://wizard.lexigame.de

orpheus_2003

BeitragMo, Sep 21, 2009 18:33
Antworten mit Zitat
Benutzer-Profile anzeigen
@Noobody

Hi.

Ich probier gerade das in mein Game Wizard zu implementieren.
Aber irgendwie scheiter ich.
Hab es geschafft die Daten zu laden. Er rendert mir auch die Boxen.
Kollision funktioniert.

Aber lässt sich diese Kollision auch auf scrollende Tilemaps anwenden?
So siehts aus momentan:
user posted image

Noobody

BeitragMo, Sep 21, 2009 20:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Klar lässt sich die Kollision auch auf scrollende Tilemaps anwenden - die Frage ist nur, wie dein Scrolling aussieht Razz

Generell sollte das Scrolling ja nur bei der Zeichenroutine eine Rolle spielen und intern immer mit ungescrollten Koordinaten gerechnet werden - falls man es so macht, kann man den Code hier unverändert übernehmen.

Andernfalls muss man halt ein wenig tricksen. Entweder, man bewegt das Levelmesh um die Scrollwerte, oder man berechnet die Kollision wie gehabt und rechnet dann irgendwie nach der Kollision um.

Ich kann aber nur empfehlen, intern immer mit ungescrollten Werten zu arbeiten, da das sehr viel Arbeit erspart.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun

orpheus_2003

BeitragMo, Sep 21, 2009 21:14
Antworten mit Zitat
Benutzer-Profile anzeigen
Hmm.

Aber es ist doch so.
Das Level ist in einem Dim gespeichert. (200*200)
Die Kollisionsabfrage momentan läuft ja mit Grabimage.

Wenn ich jetzt auf Dimabfragen (Box collides) umstelle, muss ich doch die Verschiebung vom Level
mitberechnen?
Oder muss ich die Mesh jedes mal (das ich momentan im Loadmap gleich auf 200*200 rechne) neu berechnen lassen?

Ich bin confused. Kollision ist nicht meines. Pixelgenau geht noch einfach. Aber mit Matrizen, Vektoren und Vertexes. Das ist mir zu hoch. Hab keinen Hochschulabschluss...
Das nervt mich jetzt schon seit Anfang.

Da hab ich nun meine FPS und steig dafür bei der Kollision aus...

So sieht die Begung des Players und des Levels aus... Mapoffset ist die Verschiebung der Tiles..


Code: [AUSKLAPPEN]
f CharacterX > 472 Then
      If MapX < MapWidth-20 Then                     ; Check borders
         MapOffsetX = MapOffsetX - 4                 ; Offset for Mapscrolling
         CharacterX = 472
         If MapOffsetX < -30 Then                   ; Map border
         If Mapx<164 Then
            MapOffsetX = 0                         ; Offset to 0
            MapX = MapX + 1                        ; Map scrolling
         End If
         EndIf
      End If
   End If

; zeichnen
If MaptileX(X1,Y1)>-1 Or  MaptileY(X1,Y1)>-1 Then DrawImageRect ChipSet, x * 32 + MapOffsetX, y * 32 + MapOffsetY, (MaptileX(X1,Y1)*34)+2, (MaptileY(X1,Y1)*34)+2, 32, 32

GazerStar - the beginning
http://gazerstar.lexigame.de/
Wizard (Worktitel)
http://wizard.lexigame.de
 

BIG BUG

BeitragDi, Sep 22, 2009 0:02
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn Du nicht riesige Maps hast, dann ist es tatsächlich sinnvoll einfach feste Werte zu haben und nur die "Kamera" über das Level zu bewegen, also das Scrolling wird nur in der Zeichenroutine implementiert.

Bei riesigen Welten wie z.B. für ein Space-Game kann sich hier aber die begrenzte Genauigkeit von Float-Werten als Problem herausstellen, hier müsste man also tatsächlich die ganze Welt um den "Nullpunkt Spieler" bewegen.

Für eine einfache horizontale/vertikale Tile Kollision reicht übrigens reine Addition/Subtraktion, also Mathe der Grundschule aus. Das einzige was es sonst zu Verstehen gibt ist das Koordinatensystem, also dass es eine X- und eine Y-Postion im 2D-Raum gibt.
B3D-Exporter für Cinema4D!(V1.4)
MD2-Exporter für Cinema4D!(final)

orpheus_2003

BeitragDi, Sep 22, 2009 8:43
Antworten mit Zitat
Benutzer-Profile anzeigen
Hm.

Irgendwie steh ich auf dem Schlauch.

1. Wenn ich das Scrolling nur auf die Zeichenebene begrenze. Wie prüfe ich die Kollision.
Ich muss doch einen Bezug vom Player zu den Maptiles herstellen um Aktionen herbeizuführen
Das blöde daran ist die Ungenauigkeit. Da der Level mit einem Offset von +/- 32 scrollt ist die
Rückrechnung auf das entsprechende Teil sehr ungenau.
Also brauche ich die Mapverschiebung auch bei der Kollisionsabfrage. Daher hat mich die Aussage
von Nobody verwundert keine Scrollwerte bei der Kollision zu verwenden?
2. Mit dieser 3D Kollision würde die Kollision des Levels mit dem Player sehr gut funktionieren.
Auch die Annäherung mit der Kugel wäre Ideal, da der Player z.B über nen Abhang runterfallen würde.
Allerdings habe ich Schwierigkeiten das ganze zu bewegen, da ich mit 3D und Vertex keien Erfahrung habe.
3. Die Prüfung von Tiles zur Kollisionsabfrage des Levels mit dem Player ist mir momentan noch nicht gelungen.
Das ganze scheitert an der Ungenauigkeit....

##### EDIT NACHTRAG #####

Da ja die Imagescollide nicht so richtig geht hab ich mich nun entschieden
eine Version ohne Imagescollide zu machen.
Dank BIG BUG und seiner Funktion gehts nun prima, ohne Fehler und in Echtzeit mit massig Frames.
Hier noch der Code wer ihn braucht:
Code: [AUSKLAPPEN]

;replaces ImagesCollide because of MAV bug from BIG BUG
Function ImgCollide(image1,xpos1, ypos1, frame1, image2, xpos2, ypos2, frame2=0, mask=0)

   Local startx, starty, endx, endy, ix, iy

   Local width1  = ImageWidth(image1)
   Local height1 = ImageHeight(image1)
   Local width2  = ImageWidth(image2)
   Local height2 = ImageHeight(image2)

   xpos1   = xpos1 - ImageXHandle(image1)
   ypos1   = ypos1 - ImageYHandle(image1)
   xpos2   = xpos2 - ImageXHandle(image2)
   ypos2   = ypos2 - ImageYHandle(image2)

   startx = xpos2 - xpos1
   starty = ypos2 - ypos1
   start2x = startx
   start2y = starty

   endx   = startx + width2
   endy   = starty + height2

   If startx < 0       Then startx = 0
   If starty < 0       Then starty = 0
   If endx   > width1  Then endx   = width1
   If endy   > height1 Then endy   = height1

   endx = endx - 1
   endy = endy - 1

   If startx > endx Or starty > endy Then Return 0

   LockBuffer ImageBuffer(image1, frame1)
   LockBuffer ImageBuffer(image2, frame2)
   For ix = startx To endx
      For iy = starty To endy

         If mask <> (ReadPixelFast(ix, iy, ImageBuffer(image1, frame1)) And $00FFFFFF) Then
         If mask <> (ReadPixelFast(ix-start2x, iy-start2y, ImageBuffer(image2, frame2)) And $00FFFFFF) Then
            UnlockBuffer ImageBuffer(image1, frame1)
               UnlockBuffer ImageBuffer(image2, frame2)
               Return 1
         EndIf
         EndIf
      Next
   Next
   UnlockBuffer ImageBuffer(image1, frame1)
   UnlockBuffer ImageBuffer(image2, frame2)
End Function


Thx a lot.
Neue Version online...
 

Xawer23

BeitragSo, Jan 24, 2010 14:24
Antworten mit Zitat
Benutzer-Profile anzeigen
Boah, das passt gerade wie die Faust aufs Auge in mein Projekt.
Dürfte ich deinen Roh-Code (aus dem 1. post) für meine Zwecke modifizieren und weiterverwenden?
würde mir echt total helfen.

Megamag

BeitragSo, Jan 24, 2010 14:48
Antworten mit Zitat
Benutzer-Profile anzeigen
Das ist ein Tutorial und ein Tutorial baut darauf auf, dass LEute den Code nehmen, mit ihm experimentieren und ihn verstehen. Deshalb wird wohl auch keiner etwas dagegen haben, wenn du auf noobody's Code aufbaust Wink

Noobody

BeitragSo, Jan 24, 2010 17:21
Antworten mit Zitat
Benutzer-Profile anzeigen
Selbstverständlich darfst du das Wink
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun
 

Xawer23

BeitragFr, Jan 29, 2010 15:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich hab da mal eine Frage:

gibt es einen Unterschied zwischen 3D Koordinaten und 2D Koordinate(abgesehen von der Z-Achse)?

Denn wenn ich dieses Beispiel in mein Programm einbaue, bleibt die Spielfigur überhalb des Bildschirms hängen(Ywert = -135).

Wie kann mann das umrechnen oder mache ich einen anderen Fehler?

PS: Danke für das super Tutorial!

Noobody

BeitragFr, Jan 29, 2010 16:14
Antworten mit Zitat
Benutzer-Profile anzeigen
In 3D ist im Vergleich zu 2D die Y-Achse invertiert. Das heisst, dass eine 2D-Koordinate von 100, 100 in 3D zu 100, -100 umgewandelt werden muss, um den gleichen Punkt zu bezeichnen.

Das wird im Code von CreateCollisionFace und UpdatePlayerCollision ausgeglichen. Falls du die beiden Funktionen verändert hast, kann es sein, dass bei dir das Level gespiegelt ist - oben ist unten und umgekehrt. Ich würde daher diese beiden Funktionen nochmal durchschauen und überprüfen, ob da nicht irgendwo ein - fehlt. Wenn du den Fehler dann immer noch nicht findest, kannst du ja die relevanten Ausschnitte des Codes hier posten oder mir per PN zukommen lassen, wenn du ihn nicht öffentlich zeigen willst.
Man is the best computer we can put aboard a spacecraft ... and the only one that can be mass produced with unskilled labor. -- Wernher von Braun
 

Xawer23

BeitragFr, Jan 29, 2010 21:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Danke für die schnelle freundliche Hilfe.
Ich werde nochmal diesen Aspekt durchchecken und mich dann melden.

Neue Antwort erstellen


Übersicht BlitzBasic FAQ und Tutorials

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group