Diagonale Bewegung - Kollision funktioniert nicht

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

 

dom_dot

Betreff: Diagonale Bewegung - Kollision funktioniert nicht

BeitragMi, Mai 26, 2010 18:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich habe ein Problem mit der Bewegung in einer 2D Tile Engine.
Es funktioniert an sich alles super: Beim Richtungstasten druck bewegt sich die Spielerfigur fließend um die Tilegröße 32 in die jeweilige Richtung und das auch nur wenn sich dort keine Wand oder Ähnliches befindet.

Wenn man nun allerdings z.B. die Nach-Oben und Nach-Links-Taste gleichzeitig drückt bewegt sich der Spieler auch in blockierte Felder hinein, solange das Feld direkt über- und das Feld direkt links von der Spielerfigur nicht blockiert ist.
Das will ich natürlich nicht. Very Happy
Weis aber auch nicht wie ich das verhindern soll.

Hier mal mein Code für die Bewegung damit ihr direkt seht wie ich das ganze Umgesetzt habe:
Code: [AUSKLAPPEN]
;Spieler Steuern
If KeyDown(203) Then
   Frame = 2 ;Gibt die Blickrichtung an
   If Level(X1-1,Y1,1) = 0 Then ;Links
      
      If Links = 0 Then Links = 1
      If X1-SX/32 < 4 Then ;Scrollen
         SX = SX - 8
      EndIf
      
   EndIf
EndIf

If KeyDown(205) Then ;Rechts
   Frame = 3
   
   If Level(X1+1,Y1,1) = 0 Then
      If Rechts = 0 Then Rechts = 1
      If X1-SX/32 > 20-3 Then
         SX = SX + 8
      EndIf
   EndIf
   
EndIf

If KeyDown(200) Then ;Hoch
   Frame = 0
   If Level(X1,Y1-1,1) = 0 Then 
      If Oben = 0 Then Oben = 1
      If Y1-SY/32 < 4 Then
         SY = SY - 8
      EndIf
   EndIf
EndIf

If KeyDown(208) Then ;Runter
     Frame = 1   
   If Level(X1,Y1+1,1) = 0 Then
      If Unten = 0 Then Unten = 1
      If Y1-SY/32 > 15-3 Then
         SY = SY + 8
      EndIf
   EndIf
EndIf

;Bewegen
If Links > 0 Then
   PX1 = PX1 -8
   ani = (ani+1) Mod 12
   Links = Links + 1
   If Links = 5 Then
      Links = 0
   EndIf
EndIf

If Rechts > 0 Then
   PX1 = PX1 +8
   ani = (ani+1) Mod 12
   Rechts = Rechts + 1
   If Rechts = 5 Then
      Rechts = 0
   EndIf
EndIf

If Oben > 0 Then
   PY1 = PY1 - 8
   ani = (ani+1) Mod 12
   Oben = Oben + 1
   If Oben = 5 Then
      Oben = 0
   EndIf
EndIf

If Unten > 0 Then
   PY1 = PY1 + 8
   ani = (ani+1) Mod 12
   Unten = Unten + 1
   If Unten = 5 Then
      Unten = 0
   EndIf
EndIf

hazumu-kun

BeitragMi, Mai 26, 2010 18:57
Antworten mit Zitat
Benutzer-Profile anzeigen
Bei Tilebasierten Spielen ist es üblich diagonale Bewegungen zu verbieten:
BlitzBasic: [AUSKLAPPEN]

If KeyDown (OBEN) Then
;laufe nach Oben
ElseIf KeyDown (UNTEN) Then
;laufe nach Unten
ElseIf KeyDown (LINKS) Then
;laufe nach Links
ElseIf KeyDown (RECHTS) Then
;laufe nach Rechts
EndIf
Warum kann es keine omnipotente Macht geben?
Weil diese omnipotente Macht in der Lage sein müsste, einen so schweren Stein zu schaffen, dass sie ihn nicht heben kann
-> nicht omnipotent

Hubsi

BeitragMi, Mai 26, 2010 19:01
Antworten mit Zitat
Benutzer-Profile anzeigen
Es gab mal ein richtig gutes Tutorial für genau Dein Problem, nur finden kann ich es nirgends mehr. Daher poste ich einfach mal ein Stück Code aus meinem aktuellen Projekt. p\x und p\y sind dabei die Spielfigurkoordinaten und die Tiles 32*32 Pixel, ebenso wie der Spieler:

BlitzBasic: [AUSKLAPPEN]
u=map((p\x+16)/32,(p\y-2)/32,0)  ; oben / up
r=map((p\x+32)/32,(p\y+16)/32,0) ; rechts / right
d=map((p\x+16)/32,(p\y+32)/32,0) ; unten / down
l=map(p\x/32,(p\y+16)/32,0) ; links / left
m=map((p\x+16)/32,(p\y+16)/32,1) ; mitte / middle


Der dritte Wert im Array ist nur der Layer. Einfach rausschmeissen bei Bedarf. Rückgabewert ist die Nummer des Tiles rund um und unter der Spielfigur.
Den ganzen Doag im Bett umanandflagga und iaz daherkema und meine Hendl`n fressn...
 

dom_dot

BeitragMi, Mai 26, 2010 19:17
Antworten mit Zitat
Benutzer-Profile anzeigen
hazumu-kun hat Folgendes geschrieben:
Bei Tilebasierten Spielen ist es üblich diagonale Bewegungen zu verbieten


Wäre eine einfache Möglichkeit das Problem zu umgehen aber ich glaube für das Gameplay wäre das am Ende ein großer Verlust. Soll was action-lastiges mit Ausweichen usw. werden..

@ Hubsi
Schade! Very Happy
Aus deinem Code werde ich leider nicht ganz schlau.. Also ich versteh was er tut aber wie muss ich das einbringen damit es mein Problem löst?

Hubsi

BeitragMi, Mai 26, 2010 19:23
Antworten mit Zitat
Benutzer-Profile anzeigen
Du prüfst ob der Spieler nach oben gehen kann (bspw. If u=0) und die Figur wird bedarfsweise nach oben bewegt. Dann prüfst Du ob nach links frei ist und er bewegt sich bedarfsweise nach links. Wenn der Spieler jetzt nach links oben laufen will aber oben eine Mauer oder was weiß ich ist bewegt er sich nur links. Und so weiter eben.
Den ganzen Doag im Bett umanandflagga und iaz daherkema und meine Hendl`n fressn...
 

dom_dot

BeitragMi, Mai 26, 2010 19:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Argh! Ich glaub ich bin echt zu dumm! Very Happy
Tut mir leid, ein Beispiel wie du das einbauen würdest?

Soll ich erst deinen Code ausführen, dann die Tasten abfragen und in der Tastenabfrage dann die Variable abfragen? Und dann? Im Grunde frage ich in meinem Code ja auch nach der Tastenabfrage ab ob das Tile auf das sich bewegt werden würde begehbar ist.
 

Pousup

BeitragMi, Mai 26, 2010 20:20
Antworten mit Zitat
Benutzer-Profile anzeigen
Wenn du nicht zu 100% auf Tile-to-Tile-Bewegungen setzen willst, hat SpionAtom mir mal eine
schöne Lösung für Pixel-to-Pixel-Bewegungen gezeigt, die bei Tilemaps funktioniert und auch diagonale
Bewegungen zulässt.

Code: [AUSKLAPPEN]
Graphics 600, 600, 0, 2
SetBuffer BackBuffer()
timer = CreateTimer(58)

Data 10,10
Data 1,1
Data 1,1,1,1,1,1,1,1,1,1
Data 1,0,0,0,0,0,0,0,0,1
Data 1,0,1,0,1,0,1,0,1,1
Data 1,0,0,0,0,0,0,0,0,1
Data 1,1,0,1,0,1,0,1,0,1
Data 1,0,0,0,0,0,0,0,0,1
Data 1,0,1,0,1,0,1,0,1,1
Data 1,0,0,0,0,0,0,0,0,1
Data 1,1,0,1,0,1,0,1,0,1
Data 1,1,1,1,1,1,1,1,1,1

   ;Map laden
   Global mapw, maph, mapg, sx, sy, sg
   Read mapw, maph
   Read sx, sy
   Dim map(mapw, maph)
   For i = 0 To mapw * maph - 1
      Read map(i Mod mapw, i / mapw)       
   Next

   mapg = 60 ;Map-Tile-Größe
   sg = 25 ;Spieler-Größe
   speed = 6 ;Spieler-Geschwindigkeit

   
   ;Spielerposition
   sx = (sx + 0.5) * mapg
   sy = (sy + 0.5) * mapg

   Repeat
   
      If KeyDown(200) Then         
         If playerOnWall(sx, sy - speed) Then
            ;Bis zur Mauer gehen
            sy = sy / mapg * mapg + sg / 2
         Else
            ;Einen ganzen Schritt gehen
            sy = sy - speed
         End If
      End If
       
      If KeyDown(208) Then
         If playerOnWall(sx, sy + speed) Then
            ;Bis zur Mauer gehen
            sy = (sy / mapg + 1) * mapg - 1 - sg / 2
         Else
            ;Einen ganzen Schritt gehen
            sy = sy + speed
         End If
      End If
       
      If KeyDown(203) Then
         If playerOnWall(sx - speed, sy) Then
            ;Bis zur Mauer gehen
            sx = (sx / mapg ) * mapg + sg / 2
         Else
            ;Einen ganzen Schritt gehen
            sx = sx - speed
         End If
      End If

      If KeyDown(205) Then
         If playerOnWall(sx + speed, sy) Then
            ;Bis zur Mauer gehen
            sx = (sx / mapg + 1) * mapg - 1 - sg / 2
         Else
            ;Einen ganzen Schritt gehen
            sx = sx + speed
         End If
      End If

   
      Cls
      drawMap       
      Color 255, 255, 0
      Rect sx - sg / 2, sy - sg / 2, sg, sg
      Text 0, 0, playerOnWall(sx, sy)
      WaitTimer(timer)
      Flip 0   
   
   Until KeyDown(1)
   End
   

;Prüfe 4 Eckpunkte des Spielers auf Kollision mit Map()
Function playerOnWall(x, y)

   r = sg / 2
   If map((x - r) / mapg, (y - r) / mapg) = 1 Then Return True
   If map((x + r) / mapg, (y - r) / mapg) = 1 Then Return True
   If map((x - r) / mapg, (y + r) / mapg) = 1 Then Return True
   If map((x + r) / mapg, (y + r) / mapg) = 1 Then Return True
   Return False

End Function

Function drawMap()
   Color 255, 255, 255
   For i = 0 To mapw - 1
   For j = 0 To maph - 1
      If map(i, j) Then Rect i * mapg, j * mapg, mapg, mapg, 0
   Next
   Next
End Function


Ist wie gesagt nicht meine eigene Lösung, sondern die von SpionAtom!

Hubsi

BeitragMi, Mai 26, 2010 20:45
Antworten mit Zitat
Benutzer-Profile anzeigen
So in etwa würde ich das gestalten:

BlitzBasic: [AUSKLAPPEN]
; Pseudocode

Repeat ; hauptschleife

u=map((player_x+16)/32,(player_y-2)/32,0) ; oben / up
r=map((player_x+32)/32,(player_y+16)/32,0) ; rechts / right
d=map((player_x+16)/32,(player_y+32)/32,0) ; unten / down
l=map(player_x/32,(player_y+16)/32,0) ; links / left
m=map((player_x+16)/32,(player_y+16)/32,1) ; mitte / middle

If KeyDown(200) And u=0 Then ; u=0 -> keine Kollision nach oben
player_y=player_y-2 ; 2 Pixel nach oben bewegen oder wieviel Du halt willst
EndIf
If KeyDown(203) And l>500 Then
player_x=player_x-2
EndIf
; etc.

If m>0 And m<100 Then irrsinnig_geiles_powerup_aufgesammelt(m)


So oder so ähnlich Very Happy
Den ganzen Doag im Bett umanandflagga und iaz daherkema und meine Hendl`n fressn...
 

dom_dot

BeitragDo, Mai 27, 2010 15:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich verzweifle!

@ Pousup
Dein Code lässt sich nur sehr schwer mit meinem Gerüst für die Animation verbinden.. Außerdem ist das ja eher dafür gedacht bei Bewegungen um wenige Pixel genau die wände ab zu fragen, wenn ich das richtig verstanden habe. Aber ich habe ja im Grunde nur tileweise-Bewegung..

@Hubsi
Bei deinem Code hatte ich erst Probleme weil ich ein MidHandle benutze und meine Spielfigur 64px hoch ist. Musste erstmal darauf kommen deine Werte in der Abfrage entsprechend an zu passen. Very Happy
Blöderweise verhindert auch diese Abfrage nicht dass der Spieler, bei diagonaler Bewegung in Hindernisse hineinlaufen kann...

Wie gesagt: Ich verzweifle! Very Happy

Wenn der Spieler sich AUF, VOR und RECHTS von einem begehbaren Tile befindet, das Tile OBEN-LINKS von ihm aber nicht begehbar sein sollte fragt er bei gleichzeitigem Tastendruck (OBEN UND LINKS) ob er von seiner aktuellen Position aus nach LINKS gehen kann UND ob er nach OBEN gehen kann. Da beides mit ja beantwortet wird geht er dann nach OBEN UND LINKS also OBEN-LINKS, wo aber eigentlich ein blockiertes Feld ist.

Würde es eventuell Sinn machen in jede Richtungstastenabfrage noch jeweils andere Richtungstastenabfragen zu machen die dann überprüfen ob die diagonal liegenden Felder begehbar sind?
Wenn ja, wie würde man diese Abfrage am günstigsten umsetzen?

Sorry das ich so blöd frage, aber ich bin das Trial and Error sowas von satt! Very Happy
 

Blitzjockey

BeitragDo, Mai 27, 2010 15:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Hey, ich habe es noch lange nicht fertig geschrieben, aber es soll ja für Dich ja was übrig bleiben. So ganz Deine Code angepasst habe ich es auch noch nicht, aber was Folgendes macht, ist zumindest Dein Diagonal-problem lösen:

Code: [AUSKLAPPEN]


Local Horizontal = (KeyDown(205) - KeyDown(203))
Local Vertical    = (KeyDown(200) - KeyDown(208))

If level(x1 + Horizontal, y1 + Vertical, 1) = 0 Then
   SX = SX + 8 * Horizontal
   SY = SY + 8 * Vertical
end if


If Horizontal Then
   px = px + 8 * Horizontal
   ani = (ani + 1) Mod 12
End If

If Vertical Then
   py = py + 8 * Vertical
   ani = (ani + 1) Mod 12
End If


Hier sind L,R,O,U ersetzt worden mit Horizontal und Vertical. Hierbei gilt: Horizontal = 1 bei KeyDown(205) oder -1 bei Keydown(203) oder 0 wenn beide oder keine Taste gedruckt wird.
Das gleiche gilt für Vertical.

Abfrage dann x1 + Horizontal: Hor. = 1 dann gilt X1 + 1.
Hor. = -1 dann gilt X1 + (-1), ist ja mathematisch dass gleiche wie X1 - 1.
So auch für Vertical. Sollte nun Hor und Ver gleichzeitig bedient werden, werd automatisch dass feld X1 + 1, Y1 + 1 kontrolliert. Oder X1 + (-1), Y1 + (-1) u.s.w.

Dann die bewegung, auch hier dass gleiche: SX + 8 * 1 ist ja SX + 8. SX + 8 * -1 ist gleich SX - 8.
Evt. Kontrolle auf Boundary-überschreitungen, Scrollen und Animationen kommen dann danach.

Dass gleiche Prinzip für Bewegen, nur habe ich da Dein Links = Links + 1, bis 5, dann 0, noch nicht ersetzt durch irgendwass anderes, da ich nicht genau weiss was Du damit vorhasst. Aber wie gesagt, ein bisschen sollte was für Dich übrig bleiben! Wink

Ich hoffe es bringt Dir eine Lösung etwas näher?

Schöne Grüße,
BlitzJ.

(EDIT: Code etwas verlängert..)
 

GERMAX

BeitragDo, Mai 27, 2010 16:58
Antworten mit Zitat
Benutzer-Profile anzeigen
habe vor x jahren auch mal so ein game geschrieben. sowas wie atomix 2. bei mir war der ganze level in einer 2-d tabelle abgelegt. da braucht man dann nur von der aktuellen position (bei links-oben movement) eine zeile abzuziehen-1 (das funktioniert besonders gut, wenn der level von einer mauer umgeben ist). anschliessend in der tabelle nachgucken, welches tile da drinsteckt.

aber jeder hat halt ein eigenes system.
Smile
Erfolglos begonnene BB-Projekte:TRON/CONVOY/MYSTIC
 

dom_dot

BeitragDo, Mai 27, 2010 22:16
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich hab mich heute (zum Leidwesen der Philosophie Klausur morgen) wieder viele Stunden mit dem Problem befasst und all eure Ansätze in den verschiedensten Formen ausprobiert aber nicht das gewünschte Ergebnis erzielt, wobei Blitzjockeys Ansatz dennoch ziemlich interessant war. Wink

Das Problem besteht sogar weiterhin wenn ich das diagonale Laufen mit ElseIf in den KeyDown-Abfragen verhindere.
Das liegt, glaube ich daran, dass ich mit dem Druck einer Richtungstaste den Schritt nur "auslöse" und er dann von alleine weiter läuft. Das habe ich so gemacht damit ich eine flüssige Animation bekomme. Das kann man auch im von mir ganz am Anfang geposteten Quelltext sehen.
Das Problem ist dabei, dass, nachdem ich den Schritt nach oben aktiviert habe und dieser auch als "möglich" Bestätigt wurde ich ganz schnell einen Schritt nach links auslösen kann der dann die Kollision noch abfragt bevor die Spielfigur mit dem Schritt nach oben das obere Tile erreicht hat und dann brav beide Schritte abgearbeitet werden sodass man halt im eigentlich blockiertem Tile oben-links landet.

Wie ich das Problem jetzt löse weis ich aber immer noch nicht. Very Happy
Ich hab schon wirklich viele anscheinend nahe liegende Lösungen ausprobiert die aber meistens darin resultierten das man gar nicht mehr diagonal laufen kann oder im Fall des Doppeltastendrucks die Figur erst einen Schritt in die eine und dann den in die andere Richtung macht.

Ich hab jetzt keine Lust mehr mich damit auseinander zu setzen und fange mal an einen Leveleditor zu basteln..
Meine Hoffnung ruht jetzt tatsächlich darin, dass vielleicht einer von euch eine Lösung weis die auch auf mein Konstrukt mit den Animationen usw. anwendbar ist.
 

Blitzjockey

BeitragDo, Mai 27, 2010 22:36
Antworten mit Zitat
Benutzer-Profile anzeigen
Very Happy Ja, ich habe schon gedacht dass das der Hintergrund Deine "Links 5 mal ausführen"-trick ist - Welche mit meine Ansatz so auch nicht unbedingt mehr darstellbar war. Zumindest nicht ohne weiteres.

Zusätzlich habe ich da noch eine Frage zu Deine Animation. Du hast ja eh nur 4 Animationen? L,R,O,U aber kein Diagonal oder?

Wie Du schon gesagt hast, zumindest beim Diagonalen Loslaufen hätte mein Ansatz geklappt, nur in Dein Situation (Kurswechsel nach dem loslaufen) muss man da wohl ein extra Lösung suchen.

Ich habe zwar im Moment kein Code fertig, aber ich möchte das als Ansatz zum Nachdenken schon mal hinstellen:

Stell ein Ziel-Position fest. z.b. Beim loslaufen richtung Oben, stellst Du als ZielPosition (X, Y - 1) fest. Diese behälst Du bei, und kontrollierst jeden durchlauf ob diese noch "0" zurückgibt.
Der Trick kommt jetzt: Sollte nach dem loslaufen noch ein Kursänderung folgen, wird die Zielposition mitgeändert. z.b. Links: Jetzt gilt zusätzlich X - 1 --> (X - 1, Y - 1). Falsch das jetzt ein 1 zurück gibt, ist dieses neue Ziel nicht begehbar.

Nun hast Du 2 optionen:
Entweder Du verbietest nur den Links-schwenk,(Es bleibt bei (X, Y - 1) und Du ignorierst einfach den Links-taste (Er lauft weiterhin richtung Oben); Oder Du hällst den ganze Bewegung an. Aber ich denke Option 1 ist da den bessere Ansatz.

Viel Erfolg, und lass wissen ob es was gebracht hat!

BlitzJ.
 

GERMAX

BeitragDo, Mai 27, 2010 22:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Level(xpos,ypos,levelnr)?

BlitzBasic: [AUSKLAPPEN]

move=0
If KeyDown( 203 )=True Move=1
If KeyDown( 205 )=True move=move Or 2
If KeyDown( 208 )=True move=move Or 4
If KeyDown( 200 )=True move=move Or 8

Select move (hier alle sinnvollen reintun)
Case 1 : If Level(X1-1,Y1,1) = 0 Then gogogo!!!
Case 9 : If Level(X1-1,Y1-1,1) = 0 Then gogogo!!!
Case 10: If Level(X1+1,Y1-1,1) = 0 Then gogogo!!!
.
.
.
End Select

vllt hilft das weiter.
Erfolglos begonnene BB-Projekte:TRON/CONVOY/MYSTIC

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group