X/Y Koordinaten auf Staggered Map in Spalte/Reihe umrechnen

Übersicht BlitzBasic Allgemein

Neue Antwort erstellen

 

Kernel32

Betreff: X/Y Koordinaten auf Staggered Map in Spalte/Reihe umrechnen

BeitragSa, Jan 10, 2009 14:47
Antworten mit Zitat
Benutzer-Profile anzeigen
Ich zerbreche mir jetzt schon seit Stunden darüber den Kopf, wie ich Mauskoordinaten (x,y) auf einer "staggered map" in Spalte / Reihe-Koordinaten umwandeln kann.


Das hier ist meine "Iso"-Map (eigentlich nur eine staggered map, bei dem jede zweite Reihe eingerückt ist):


user posted image

Bei einer normalen Gittermap wäre das ja einfach:

Code: [AUSKLAPPEN]
col% = Floor((MouseX()-gridStartX) / tileSize)
row% = Floor((MouseY()-gridStartY) / tileSize)


Aber ich komme einfach nicht drauf, wie ich die X/Y Koordinaten eines Punktes auf der Map in die jeweilige Spalte und Reihe umrechnen kann. Muss man da erst mal alles in Dreiecke umwandeln oder gibt es da auch eine einfache Lösung, auf die ich noch gar nicht gekommen bin..? Confused
-------------
Wollte neulich Herrn Brot anrufen, aber da war belegt.
Dann hab ich bei Wheight Watcher's angerufen, aber niemand hat abgenommen.
Schliesslich hab ich im Irak angerufen, aber dort war besetzt o.O
  • Zuletzt bearbeitet von Kernel32 am Sa, Jan 10, 2009 18:52, insgesamt einmal bearbeitet

ZaP

BeitragSa, Jan 10, 2009 14:53
Antworten mit Zitat
Benutzer-Profile anzeigen
Vielleicht hilft dir das als Denkanstoss:
0,0 ist logischerweise an 0,0
0,1 liegt genau zwischen 1,0 und 0,2, d.h. es fängt an Hälfte von 0,0 an, und endet an der Hälfte von 1,0

Das Stichwort ist Hälfte. Vielleicht kannst du es dir besser vorstellen, wenn du dir Rechtecke anstatt Rauten vorstellst.
Starfare: Worklog, Website (download)

DAK

BeitragSa, Jan 10, 2009 15:03
Antworten mit Zitat
Benutzer-Profile anzeigen
vll hilft dir das was:

Code: [AUSKLAPPEN]
For x# = 0 To 10
   For y# = 0 To 10
      px# = x
      py# = y/2
      If y Mod 2 = 1 Then px#=px#+.5
      Text px#*100, py#*50, x+":"+y
   Next
Next
Gewinner der 6. und der 68. BlitzCodeCompo
 

Kernel32

BeitragSa, Jan 10, 2009 15:56
Antworten mit Zitat
Benutzer-Profile anzeigen
Nein, das hilft leider nicht.

Das Problem IST ja gerade, das alle Tiles im Grunde Rechtecke sind und sich somit ÜBERLAPPEN.

Jedes Tile wird also komplett von den Rechtecken seiner vier diagonal benachbarten Tiles überdeckt -woher soll man also wissen, auf welchem Tile sich die Maus gerade befindet, wenn man z.B. nahe an der (virtuellen) Trennlinie zwischen wei Tiles klickt (denn die verläuft ja diagonal, nicht geradlinig)? Sad
-------------
Wollte neulich Herrn Brot anrufen, aber da war belegt.
Dann hab ich bei Wheight Watcher's angerufen, aber niemand hat abgenommen.
Schliesslich hab ich im Irak angerufen, aber dort war besetzt o.O

coolo

BeitragSa, Jan 10, 2009 16:34
Antworten mit Zitat
Benutzer-Profile anzeigen
Mach es doch mit der Quick/n/dirty Variante mit Imagescollide. Und damit der Speed nicht absackt, grenze den Bereich ein, den du überürüfst.
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

Holzchopf

Meisterpacker

BeitragSa, Jan 10, 2009 17:18
Antworten mit Zitat
Benutzer-Profile anzeigen
Mach es unter keinen Umständen mit ImagesCollide Exclamation das führt nämlich auf einigen Grafikkarten (meines Wissens nach auf nVidia-Karten) unweigerlich zu nem MAV)

Moment, ich schreib kurz n Code, wie ichs machen würde (Prinzip: Die Mauskoordinate um den Kantenwinkel der Tiles, also ca 30°, nach oben und nach rechts klappen, diese Koordinaten sind dann sozusagen auf ein horizontales Raster projiziert). N paar Minuten Geduld bitte Wink

Edit 1:
Grad ganz so einfach ist mein Gedankengang nicht umzusetzen, wie ich eben feststellen musste, aber ein Ansatz wäre auch, bei jedem Tile zu Prüfen, ob abs( Tangens ) der Mauskoordinate zur oberen Ecke des Tiles => 0.5 ist. Das könnte man nämlich auch direkt beim zeichnen machen.
Code: [AUSKLAPPEN]
Graphics 800,600,0,2
SetBuffer BackBuffer()
Global TIMER = CreateTimer(60)

SeedRnd MilliSecs()

Global imgTile = LoadImage( "Tile.bmp" )
MaskImage imgTile, 255,255,255

Global mx, my, mhit
Global PickedTileX, PickedTileY

While Not KeyDown(1)
   mx = MouseX()
   my = MouseY()
   
   PickTile(mx,my)
   Drawmap()

   WaitTimer TIMER
   Flip 0
Wend
End

; Tilemap zeichnen
Function Drawmap()
   Local x,y, xpos, ypos
   For y=0 To 4
   For x=0 To 6
      xpos = x *92
      ypos = y *23
      ; jede zweite Zeile einrücken
      If (y Mod 2)
         xpos = xpos +46
      EndIf
      
      ; Tile zeichnen
      DrawImage imgTile, xpos, ypos
      Color 255,255,255
      If (x=PickedTileX) And (y=PickedTileY) Color 255,0,0
      Text xpos +46, ypos +23, x +"," +y, 1,1
   Next
   Next
End Function

; Über welchem Tile die Maus ist
Function PickTile( px, py )
   Local x,y, xpos, ypos, tg#
   For y=0 To 4
   For x=0 To 6
      xpos = x *92
      ypos = y *23
      ; jede zweite Zeile einrücken
      If (y Mod 2)
         xpos = xpos +46
      EndIf
      
      ; Maus auf Tile?
      tg# = (py -ypos)/Float(px -xpos -46)
      If Abs(tg#)=>0.5 And (py -ypos)=>0
         PickedTileX = x
         PickedTileY = y
      EndIf
   Next
   Next
End Function


Aber ich versuchs noch kurz weiter.
 

Kernel32

BeitragSa, Jan 10, 2009 18:37
Antworten mit Zitat
Benutzer-Profile anzeigen
Hm, mir sind inzwischen noch einige Methoden eingefallen, die evtl. funktionieren, aber ich habe die Hoffnung nicht aufgegeben, das es nicht doch eine "relativ" einfache und effektive Lösung gibt:

Methode 1
Das der Maus am nächsten gelegene "normale" (also nicht eingerückte) Tile finden:

col% = Floor(x / tileWidth)
row% = Floor(y / tileHeight)*2

Damit kann man schon mal alle "normalen" Reihen ansprechen, das Ergebnis ist ein Tile einer "nicht-versetzten" Reihe, das der Maus am nächsten liegt.

Um zu testen, ob die Maus aber auf ein Tile in einer versetzten Reihe geklickt hat, müsste man dann die Distanzen zwischen Maus und Mittelpunkt des gefundenen Tiles, sowie der vier daran diagonal angrenzenden Tiles vergleichen. Das Tile mit der kürzesten Distanz zwischen Mittelpunkt und Maus ist dann eigentlich das gesuchte.

Ich habe das mal eben probiert (habe hier leider kein Blitz installiert, kann das deshalb nur mit ActionScript 3.0 testen),da funktioniert es im Groben. Nur kommt es leider hin und wieder vor, das sich doch versehentlich ein Nachbartile angesprochen fühlt, obwohl gar nicht darauf geklickt wurde. Habe momentan keine Ahnung, warum Sad


Methode 2
Vielleicht würde es funktionieren, wenn man die Karte erst mal in Rechtecke zerlegt, die jeweils die Grösse eines Viertel Tiles haben:

user posted image

Das jeweilige Rechteck zu finden, wäre dann kein Problem. Da sich aber jeweils zwei Tiles eines dieser Rechtecke teilen, müsste man dann halt das gefundene Rechteck in zwei Dreiecke zerteilen und testen, in welchem der beiden Dreiecke sich die Maus befindet (pff... mal nach einem "point in triangle algo" kramen...).

Hab's noch nicht getestet, aber könnte vielleicht funktionieren, oder?



Methode 3
Nur die Eckpunkte der Tiles nehmen und mit einem "Point inside polygon"-Algo prüfen, ob die Maus sich in einem dieser Polygone befindet.


Ich bin jetzt seit Stunden am Suchen und kann einfach nicht glauben, das es im ganzen Internet nicht ein einziges Beispiel dafür gibt, wie man bei einer staggered Map die Mauskoordinaten in das jeweilige Feld umwandelt. Iso-Formeln gibt es einige, aber die lassen sich ja nicht auf eine staggered Map anwenden. Sad

Holzchopf

Meisterpacker

BeitragSa, Jan 10, 2009 19:07
Antworten mit Zitat
Benutzer-Profile anzeigen
So, ich habs:

Code: [AUSKLAPPEN]
; Über welchem Tile die Maus ist
Function PickTile( px, py )
   Local tg#, x, y, tx, ty
   ; Koordinaten transformieren
   x = Floor(( px +(py -23)*2 ) /92.0) ; 23 = Tilehöhe /2, 92 = Tilebreite
   y = Floor(( py -(px -46)*0.5 ) /46.0) ; 46 = Tilebreite /2, 46 = Tilehöhe
   ; Indizes transformieren
   tx = Floor((x-y)/2)
   ty = y +x
   ; Gepickte Koordinaten zuweisen
   PickedTileX = tx
   PickedTileY = ty
End Function


Zum testen einfach im Code von mir (weiter oben) mit der anderen PickTile() Funktion ersetzen. Das Tile hat die Abmasse 92 x 46 und kann hier gezogen werden.

Die Schwierigkeit war übrigens die Indizes richtig zu transformieren, da die Karte ja folgendermassen Indiziert ist:
Code: [AUSKLAPPEN]

               3,0
          2,0  2,1
     1,0  1,1  2,2
0,0  0,1  1,2  1,3  .-->  y=0
     0,2  0,3  1,4  |   X
          0,4  0,5  V
               0,6   Y


die Transformierten Koordinaten geben nämlich die Indizes dieser Matrix zurück (Nullpunkt bei 0,0) und wie man sieht, geht die y-Mässig ins negative und x wird nur bei jedem zweiter Feld grösser. Daher die Transformation.

mfG

iso, koordinaten, umrechnen, position
  • Zuletzt bearbeitet von Holzchopf am Do, Apr 02, 2009 20:41, insgesamt einmal bearbeitet
 

Kernel32

BeitragSo, Jan 11, 2009 11:54
Antworten mit Zitat
Benutzer-Profile anzeigen
Fett! Shocked Elegante Lösung, das funktioniert einwandfrei. Verbeuge mich!!! Very Happy Very Happy Very Happy

Neue Antwort erstellen


Übersicht BlitzBasic Allgemein

Gehe zu:

Powered by phpBB © 2001 - 2006, phpBB Group