[GELÖST] Kollision: Image <-> Tilemap

Übersicht BlitzMax, BlitzMax NG Allgemein

Neue Antwort erstellen

 

CO2

ehemals "SirMO"

Betreff: [GELÖST] Kollision: Image <-> Tilemap

BeitragMo, Okt 12, 2015 18:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

ich habe mir vorgenommen, am BCC mitzumachen, deswegen kann ich nicht allzuviel verraten. Nur soviel: Ich habe eine Tilemap und ein Image. Nun möchte ich kontrollieren, ob das Image mit den Tiles, auf denen es "steht", kollidiert. Das Problem: Das Imagehandle ist nicht unbedingt an der linken oberen Ecke des Images - ich hätte aber den Offset zwischen Imagehandle und linker oberer Ecke. Als sei das alles nicht genug, ist das Bild auch noch gedreht...
Ich habe es mit ImagesCollide2 gemacht, nur scheint diese Funktion die Imagegröße nicht zu berücksichtigen.

Kollisioncode bisher:
BlitzMax: [AUSKLAPPEN]
Method MapObjectCollidesWithMap:Byte(MapObj:TMapObject)
If (MapObj = Null) Then Return False
If (MapObj.Pos.X < 0 Or MapObj.Pos.Y < 0 Or MapObj.Pos.X >= Self.Width Or MapObj.Pos.Y >= Self.Height) Then Return True

If (Self.Tiles[MapObj.Pos.X, MapObj.Pos.Y].Collision)
Return ImagesCollide2(MapObj.Image, MapObj.Pos.X, MapObj.Pos.Y, 0, MapObj.Rot, 1, 1, Self.TileSet, MapObj.Pos.X, MapObj.Pos.Y, Self.Tiles[MapObj.Pos.X, MapObj.Pos.Y].TileID, 0, 1, 1)
Else
Return False
EndIf
End Method

Zur Erläuterung:
- MapObj.Pos -> Ist eine TPosition, bestehtend aus X- und Y-Anteil
- MapObj.Offset -> Ist ebenfalls eine TPosition; gibt relativ zu MapObj.Pos die Position zur linken oberen Ecke des Bildes an.
- Self.Tiles[,] ist ein zweidimensionales Array vom Typ TTile. Der Type besitzt unter anderem das Feld Collision, welches True ist, wenn es sich um ein Collision-Tile handelt.
- Self.Tileset ist ein AnimImage
- Self.Tiles[,].TileID gibt den Frame auf Self.TileSet an.

Meine Frage: Wie kann ich es anstellen, dass bei der Ermittlung der Kollision die Imagegröße "mitgenommen" wird?

Vielen Dank schonmal im Voraus.
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti
  • Zuletzt bearbeitet von CO2 am Di, Okt 13, 2015 19:48, insgesamt einmal bearbeitet

Mathias-Kwiatkowski

BeitragMo, Okt 12, 2015 19:32
Antworten mit Zitat
Benutzer-Profile anzeigen
wie wäre es mit einer 4 kanten kollision

. .

Player

. .

das heisst du checkst jede kannte on die mit einem tile kollidiert. undzwar LinkeObere ecke - 1 = kollision then return



image kollide ist richtig zeitaufwändig bei grösseren maps usw...
Skype: Anarchie1984
http://projektworks.de/maxbase/
Icq - Erneuert am 21.08.2017
Yahoo - Erneuert am 21.08.2017
 

CO2

ehemals "SirMO"

BeitragMo, Okt 12, 2015 19:42
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

darüber hatte ich auch schon nachgedacht und habe es auch schon versucht umzusetzen, bin aber kläglich gescheitert Embarassed ...
Mein Ansatz war:
1. Zunächst Position der linken oberen Ecke des Images ermitteln
2. Anschließend die anderen 3 Eckpunkte ermitteln
3. Nun die Linien zwischen den Punkten rasterisieren via Bresenham
4. Prüfen, ob eins der Tiles ein Kollisionstile ist, falls ja: Kollision, sonst: keine Kollision

Das Problem dabei ist recht trivial: Wie komme ich von meinem Imagehandle auf die linke obere Ecke des Bildes? Ich habe es mit Trigonometrie versucht, kam aber auf keinen grünen Zweig...

EDIT: Zur Veranschaulichung ein kleines Bild:
user posted image
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Mathias-Kwiatkowski

BeitragDi, Okt 13, 2015 2:25
Antworten mit Zitat
Benutzer-Profile anzeigen
ähm keine ahnung was du ermitteln musst Very Happy

du hast bereits den punkt (links oben) den du hast den char oder was auch immer da abgelegt. drawimage char X,Y .... heisst links oben

also um dir zu helfen, habe ich nen bsp kurz herbeigezaubert.

ich erkläre auch gleich etwas dazu (unterhalb des codes)

Main Code kannst du so testen!
Code: [AUSKLAPPEN]
Graphics 1024, 768

Global TileW:Int = 1024 / 32
Global TileH:Int = 768 / 32


Global Map:Int[tilew, tileh]

Map[15, 15] = 1
Map[15, 5] = 1

Local CharX:Float, CharY:Float


Repeat
   For Local X:Int = 0 To TileW - 1
      For Local Y:Int = 0 To TileH - 1
         If Map[X, Y] = 1 Then SetColor 255, 0, 0 DrawRect X * 32, Y * 32, 32, 32 SetColor 255, 255, 255
            
      Next
   Next
   
   
   SetColor 0, 0, 255 DrawRect CharX, CharY, 32, 32 SetColor 255, 255, 255
   If KeyDown(KEY_RIGHT) Then
      If Kollide (CharX + 1 + 32, CharY) = 0 And Kollide (CharX + 1 + 32, CharY + 32) = 0 Then
         CharX = CharX + 1
      End If
   EndIf
   
   If KeyDown(KEY_LEFT) Then
      If Kollide (CharX - 1, CharY) = 0 And Kollide (CharX - 1, CharY + 32) = 0 Then
         CharX = CharX - 1
      End If
   EndIf
   
   If KeyDown(KEY_UP) Then
      If Kollide (CharX, CharY - 1) = 0 And Kollide (CharX + 32, CharY - 1) = 0 Then
         CharY = CharY - 1
      End If
   EndIf
   
   If KeyDown(KEY_DOWN) Then
      If Kollide (CharX, CharY + 32 + 1) = 0 And Kollide (CharX + 32, CharY + 32 + 1) = 0 Then
         CharY = CharY + 1
      End If
   EndIf
   

   Flip
   Cls
   if AppTerminate() Then end
Forever

Function Kollide:Int(X:Float, Y:Float)
   If (X / 32) < 0 Or (X / 32) > TileW - 1 Or (Y / 32) < 0 Or (Y / 32) > TileH - 1 Then Return 1
   
   If Map[(X / 32) , (Y / 32)] = 0 Then Return 0
   
   Return 1
End Function




Erklärrung:

die funktion Kollide prüft eigentlich nur ob der Char im spielbereich ist und ob er in der tilemap auf dem feld 1 trampellt wenn ja, soll er nicht weiterlaufen! (deine kollision die du brauchst)


ich erkläre nun nich jeden einzellnen Keyhit aber, grundprinzip is gleich
Code: [AUSKLAPPEN]
If KeyDown(KEY_RIGHT) Then
      If Kollide (CharX + 1 + 32, CharY) = 0 And Kollide (CharX + 1 + 32, CharY + 32) = 0 Then
         CharX = CharX + 1
      End If
   EndIf

insbesondere-> If Kollide (CharX + 1 + 32, CharY) = 0 And Kollide (CharX + 1 + 32, CharY + 32) = 0 Then

wir prüfen hiermit also charX+ 1 +32 beim rechtslaufen, wenn dort nichts ist also 0 dann ok darf er laufen, gleichzeitig prüfen wir charx +1 +32 und dazu chary + 32 sozusagen die komplette rechte seite des chars ob eine kollosion stattfindet. wenn ja dann nicht laufen wenn nein (0) dann laufen.

viel spass damit! und hoffe es hat geholfen!
Skype: Anarchie1984
http://projektworks.de/maxbase/
Icq - Erneuert am 21.08.2017
Yahoo - Erneuert am 21.08.2017
 

CO2

ehemals "SirMO"

BeitragDi, Okt 13, 2015 12:13
Antworten mit Zitat
Benutzer-Profile anzeigen
Hallo,

vielen Dank erstmal für deine Antwort.

Das Problem ist: Mein CharX und CharY unterscheiden sich von dem 0-Punkt des Bildes. CharX und CharY sind in meinem Fall vom Benutzer definierte Punkte auf dem Bild, die mit SetImageHandle() umgesetzt wurden. Sprich: Mein Bild dreht sich nicht um (0|0), sondern um einen anderen Punkt. Um eine Kollision mit der Tilemap also ermitteln zu können, brauche ich zunächst die vier Eckpunkte des Bildes. Drei davon sind kein Problem und ließen sich über Trigonometrie berechnen. Beim Vierten - also dem Punkt (0|0) des Bildes - weiß ich nicht, wie ich ihn ermitteln soll. Ich brauche aber zunächst diesen Punkt um die anderen drei berechnen zu können. Das Prinzip wollte ich eigentlich mit dem Bild oben erklären...

Ich hoffe so wird das Problem einigermaßen deutlich.
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Mathias-Kwiatkowski

BeitragDi, Okt 13, 2015 16:10
Antworten mit Zitat
Benutzer-Profile anzeigen
nunja wo ist genau das problem user sagt z.b. bild verschiebt sich um +5 dann ziehste bei der kollisionsprüfung eben 5 wieder ab ... du weisst immer wo sich dein bild befindet... du weisst auch immer wie gross dein bild ist.)
Skype: Anarchie1984
http://projektworks.de/maxbase/
Icq - Erneuert am 21.08.2017
Yahoo - Erneuert am 21.08.2017
 

CO2

ehemals "SirMO"

BeitragDi, Okt 13, 2015 17:41
Antworten mit Zitat
Benutzer-Profile anzeigen
Mhm,

ein weiteres Problem ist, dass sich Bildgröße und Tilegröße unterscheiden, sprich: Der Char kann durchaus mehrere Tiles verdecken. Zudem ist er nicht unbedingt quadratisch... Und da liegt der Hase im Pfeffer: dadurch, dass sich mein Nullpunkt des Bildes verschoben hat, kann ich nicht genau sagen, welche Tiles verdeckt sind - also geprüft werden müssen.
Das ist es ja, woran ich scheitere. Ich werde noch ein bisschen probieren und wenn ich eine Lösung habe, schreibe ich sie hier Wink

EDIT: Ok, habe es nun soweit, dass ich immerhin ein Rechteck zeichnen kann, von dem ich nur Mittelpunkt, Width, Height und Offset habe. Der Code BlitzMax: [AUSKLAPPEN]
' ### Position ####################################################################################
Type TPosition
' *** Instanz ****************************************************************
Field X:Double
Field Y:Double

' *** Konstruktion ***********************************************************
Function Create:TPosition(X:Double, Y:Double)
Local RetVal:TPosition = New TPosition
RetVal.X = X
RetVal.Y = Y
Return RetVal
End Function

' *** Methoden ***************************************************************
Method GetDistance:Double(Other:TPosition)
If (Other = Null) Then Return -1

Local DiffX:Double = Abs(Other.X - Self.X)
Local DiffY:Double = Abs(Other.Y - Self.Y)

Return (Sqr((DiffX * DiffX) + (DiffY * DiffY)))
End Method

Method GetAngle:Double(Other:TPosition)
Return ATan2(Other.X - Self.X, -(Other.Y - Self.Y))
End Method

Method DrawLineTo(Other:TPosition)
If (Other = Null) Then Return

DrawLine(Self.X, Self.Y, Other.X, Other.Y)
End Method
End Type

' ### Rectangle ###################################################################################
Type TRect
' *** Instanz ****************************************************************
Field Pos:TPosition
Field Off:TPosition
Field Width:Int
Field Height:Int
Field Rot:Double

' *** Konstruktion ***********************************************************
Function Create:TRect(Pos:TPosition, Handl:TPosition, Width:Int, Height:Int, Rot:Int)
Local RetVal:TRect = New TRect
RetVal.Pos = Pos
RetVal.Off = Handl
RetVal.Width = Width
RetVal.Height = Height
RetVal.Rot = Rot
Return RetVal
End Function

' *** Methoden ***************************************************************
Method CalcPos:TPosition(Corner:TPosition)
If (Corner = Null) Then Return Null

Local ResX:Double = Self.Pos.X + (Corner.x - Self.Pos.X) * Cos(Self.Rot) + (Corner.Y - Self.Pos.Y) * Sin(Self.Rot)
Local ResY:Double = Self.Pos.Y - (Corner.X - Self.Pos.X) * Sin(Self.Rot) + (Corner.Y - Self.Pos.Y) * Cos(Self.Rot)

Return TPosition.Create(ResX, ResY)
End Method

Method Draw()
' Positionen ohne Rotation:
Local UpperLeft:TPosition = TPosition.Create(Self.Pos.X - Self.Off.X, Self.Pos.Y - Self.Off.Y)
Local UpperRight:TPosition = TPosition.Create(Self.Pos.X + (Self.Width - Self.Off.X), Self.Pos.Y - Self.Off.Y)
Local BottomLeft:TPosition = TPosition.Create(Self.Pos.X - Self.Off.X, Self.Pos.Y + (Self.Height - Self.Off.Y))
Local BottomRight:TPosition = TPosition.Create(Self.Pos.X + (Self.Width - Self.Off.X), Self.Pos.Y + (Self.Height - Self.Off.Y))

' Nun die Rotation berücksichtigen:
Local ResUL:TPosition = Self.CalcPos(UpperLeft)
Local ResUR:TPosition = Self.CalcPos(UpperRight)
Local ResBL:TPosition = Self.CalcPos(BottomLeft)
Local ResBR:TPosition = Self.CalcPos(BottomRight)

ResUL.DrawLineTo(ResUR)
ResUR.DrawLineTo(ResBR)
ResBR.DrawLineTo(ResBL)
ResBL.DrawLineTo(ResUL)

DrawCross(Self.Pos, 10)
End Method

Method SetAngle(Set:Double)
Set = Set Mod 360
Self.Rot = Set
End Method

Method AddAngle(Add:Double)
Self.SetAngle(Self.Rot + Add)
End Method
End Type

' ### Main ########################################################################################
Graphics(800, 600)

Local MyRect:TRect = TRect.Create(TPosition.Create(300, 300), TPosition.Create(25, 150), 50, 200, 0)

Local FPS:TTimer = CreateTimer(60)

Repeat
Cls
WaitTimer(FPS)

MyRect.Draw()

If (KeyDown(KEY_D))
MyRect.AddAngle(1)
EndIf

If (KeyDown(KEY_A))
MyRect.AddAngle(-1)
EndIf

Flip 0
Until KeyHit(KEY_ESCAPE)

' ### Funktion ####################################################################################
Function DrawCross(Center:TPosition, Size:Int)
If (Center = Null) Then Return

Local HalfSize:Int = Size / 2

DrawLine(Center.X - HalfSize, Center.Y, Center.X + HalfSize, Center.Y)
DrawLine(Center.X, Center.Y - HalfSize, Center.X, Center.Y + HalfSize)
End Function


Das muss ich nun nurnoch auf mein Tileset-Image-Problem anwenden und fertig. Es scheint also doch was zu werden. Vielen Dank für die Antworten.
mfG, CO²

Sprachen: BlitzMax, C, C++, C#, Java
Hardware: Windows 7 Ultimate 64-Bit, AMX FX-6350 (6x3,9 GHz), 32 GB RAM, Nvidia GeForce GTX 750 Ti

Neue Antwort erstellen


Übersicht BlitzMax, BlitzMax NG Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group