Seite 1 von 3

spiele maps

Verfasst: 14.10.2006 11:35
von #NULL
weil immer wieder fragen bezüglich map-darstellung in topdown und in
letzter zeit auch wegen isometrie auftauchen, hab ich mal ein beispiel
gebastelt, in dem sowas gezeigt wird. es werden keine bilder zum laden
gebraucht. man kann mit F1-F3 umschalten zwischen topdown bzw
profilansicht(quadratische tiles, 64x64), isometrie (64x32) in schräger
darstellung und isometrie mit senkrechter map.
die unterschiede liegen in dem beispiel hauptsächlich in den berechnungen
für die tile-koordinaten innerhalb der map. hier ist auch ein 'mouse-hover'
eingebaut. der wird hier bei iso mit SpritePixellCollision() realisiert.
[ein viertel des codes ist nur die sprite-erstellung]

Code: Alles auswählen

#sw=1024 :: #sh=768
;#sw=1152 :: #sh=864
If Not InitSprite()   :: MessageRequester("error", "initsprite() failed!")   : End :: EndIf
If Not InitMouse()    :: MessageRequester("error", "initmouse() failed!")    : End :: EndIf
If Not InitKeyboard() :: MessageRequester("error", "initkeyboard() failed!") : End :: EndIf
If Not OpenScreen(#sw,#sh,32,"fllscrn") :: MessageRequester("error", "can't open screen!") : End :: EndIf


;Block Sprites
CreateSprite(0,64,64);rahmen
  StartDrawing( SpriteOutput(0) )
    Box(0,0,64,64,$cc5555)
  StopDrawing()
  
CreateSprite(1,64,64);tile 1
  StartDrawing( SpriteOutput(1) )
    Box(0,0,64,64,$aa3333)
  StopDrawing()
  
CreateSprite(2,64,64);tile 1
  StartDrawing( SpriteOutput(2) )
    Box(0,0,64,64,$aa6666)
  StopDrawing()
  
  
;Iso Sprites
CreateSprite(10,64,32);rahmen
  StartDrawing( SpriteOutput(10) )
    LineXY(0,15, 31,0,  $cc5555)
    LineXY(0,15, 31,30, $cc5555)
    LineXY(32,0, 63,15, $cc5555)
    LineXY(32,30,63,15, $cc5555)
    FillArea(32,15,$cc5555,$cc5555)
  StopDrawing()
  
CreateSprite(11,64,32);tile 1
  StartDrawing( SpriteOutput(11) )
    LineXY(0,15, 31,0,  $aa3333)
    LineXY(0,15, 31,30, $aa3333)
    LineXY(32,0, 63,15, $aa3333)
    LineXY(32,30,63,15, $aa3333)
    FillArea(32,15,$aa3333,$aa3333)
  StopDrawing()
  
CreateSprite(12,64,32);tile 2
  StartDrawing( SpriteOutput(12) )
    LineXY(0,15, 31,0,  $aa6666)
    LineXY(0,15, 31,30, $aa6666)
    LineXY(32,0, 63,15, $aa6666)
    LineXY(32,30,63,15, $aa6666)
    FillArea(32,15,$aa6666,$aa6666)
  StopDrawing()

;Cursor Sprite
CreateSprite(20,64,34);
  StartDrawing( SpriteOutput(20) )
    LineXY(0,0, 32,25,  $ff8888)
    LineXY(0,0, 25,32,  $ff8888)
    LineXY(32,25, 32,32,$ff8888)
    LineXY(25,32,32,32, $ff8888)
  StopDrawing()

;Cursor Pixel Sprite (1x1 - wird nicht gezeichnet; nur für kollisions-check)
CreateSprite(21,1,1);
  StartDrawing( SpriteOutput(21) )
    Plot(0,0,$ffffff)
  StopDrawing()

;karten-breite / -hoehe
w=20
h=40
Dim map.l(w,h)
For i=0 To w
  For k=0 To h
    map(i,k)=Random(1)+1 ;zufallskarte erstellen (enthält die sprite-nummern 0 oder 1)
  Next
Next

Repeat
  ExamineKeyboard()
  If KeyboardReleased(#PB_Key_F1) :: mode=0 : offX=100 : offY=100 :: EndIf
  If KeyboardReleased(#PB_Key_F2) :: mode=1 : offX=100 : offY=100 :: EndIf
  If KeyboardReleased(#PB_Key_F3) :: mode=2 : offX=100 : offY=100 :: EndIf

  ExamineMouse()
  ;maus-koordinaten erhalten und die karten-koordinaten scrollen (offX und offY)
  mx=MouseX()
  my=MouseY()
  If mx=0
    offX+8
  ElseIf mx=#sw-1
    offX-8
  EndIf
  If my=0
    offY+8
  ElseIf my=#sh-1
    offY-8
  EndIf

  Select mode
  
    Case 0;TopDown
      For i=0 To w
        For k=0 To h
          ;koordinaten fuer das akuelle map-tile berechnen (offX und offY sind die koordinaten für die map selbst)
          x=offX + i*64
          y=offY + k*64
          
          ;nur anzeigen, was im sichtbereich liegt
          If x>-65 And x<#sw And y>-65 And y<#sh
            DisplaySprite( map(i,k), x, y )
            If mx>=x And mx<x+64 And my>=y And my<y+64  ; ...und wenn die maus drüber steht (im Block-mode nur über koordinaten-checks)
              DisplayTransparentSprite(0, x,y); ...zeichne den ramen über das tile
            EndIf
          EndIf
        Next
      Next
      
    Case 1;Iso 1
      For i=0 To w
        For k=0 To h
          ;koordinaten fuer das akuelle map-tile berechnen (offX und offY sind die koordinaten für die map selbst)
          x=offX + i*32 - k*32
          y=offY + i*16 + k*16
          
          ;tile nur anzeigen, wenn es im sichtbereich liegt
          If x>-65 And x<#sw And y>-33 And y<#sh
            DisplayTransparentSprite( map(i,k)+10, x, y ) ;<< die +10 ist nur da, um auf die Iso-Sprite-Nummern zu kommen
            If mx>=x And mx<x+64 And my>=y And my<y+64
              If SpritePixelCollision(21, mx,my, map(i,k)+10, x,y)  ; ...und wenn der Cursor-Pixel mit dem tile kollidiert..
                DisplayTransparentSprite(10, x,y); ...zeichne den ramen über das tile
              EndIf
            EndIf
          EndIf
        Next
      Next
      
    Case 2;Iso 2
      For i=0 To w
        For k=0 To h
          ;koordinaten fuer das akuelle map-tile berechnen (offX und offY sind die koordinaten für die map selbst)
          x=offX + i*64 + (k%2)*32
          y=offY + k*16
          
          ;tile nur anzeigen, wenn es im sichtbereich liegt
          If x>-65 And x<#sw And y>-33 And y<#sh
            DisplayTransparentSprite( map(i,k)+10, x, y ) ;<< die +10 ist nur da, um auf die Iso-Sprite-Nummern zu kommen
            If mx>=x And mx<x+64 And my>=y And my<y+64
              If SpritePixelCollision(21, mx,my, map(i,k)+10, x,y)  ; ...und wenn der Cursor-Pixel mit dem tile kollidiert..
                DisplayTransparentSprite(10, x,y); ...zeichne den ramen über das tile
              EndIf
            EndIf
          EndIf
        Next
      Next
      
  EndSelect
  
  DisplayTransparentSprite(20, mx,my); den maus-pfeil zeichnen

  StartDrawing( ScreenOutput() )
    DrawingMode(#PB_2DDrawing_Transparent)
    DrawText(30,50, "F1 : TopDown" ,$226622)
    DrawText(30,65, "F2 : Iso 1"   ,$226622)
    DrawText(30,80, "F3 : Iso 2"   ,$226622)
  StopDrawing()
  
  FlipBuffers()
  ClearScreen(0)
  ;Delay(30)
Until KeyboardReleased(#PB_Key_Escape) 

;_______________________________________________________________________________________________________________________________________________

Re: spiele maps

Verfasst: 14.10.2006 11:43
von Kaeru Gaman
#NULL hat geschrieben: der wird hier bei iso mit SpritePixellCollision() realisiert.
HRRRCHMMM. *räusper*hust*hust*naseputz*

Verfasst: 14.10.2006 11:46
von #NULL
..hatten wir doch schon mal :wink: . nur vier mal pro frame (habs getestet), und das eine sprite ist 1x1 groß.

Verfasst: 14.10.2006 11:51
von Kaeru Gaman
ahja.. also zuerst noch ne auswahl per koordinaten-check. das ist natürlich schon ein fortschritt. ;)

... aber mich würde wirklich mal die formel für ISO-koordinaten-check interessieren.
ich bin der meinung es müsste gehen, aber ich hab mich seit der elften klasse
nicht mehr mit diesem teil von linearer algebra auseinandergesetzt,
und kann mir da jetzt nix aus den rippen schneiden.
NTQ ist doch so gut in mathe, er hatte doch auch für raytracing und
für 3D kollisionsberechnungen geschrieben, dann sollte ihm doch
eine kollision eines punktes mit einer regelmäßigen raute ziemlich leicht fallen.

Verfasst: 14.10.2006 11:56
von #NULL
fänd ich auch gut. wie gesagt ich habs mal probiert und nicht hingekriegt. das war aber als ich mit iso neu anfing.

Verfasst: 14.10.2006 21:06
von Thomas
#Null hat geschrieben:weil immer wieder fragen bezüglich map-darstellung in topdown und in
letzter zeit auch wegen isometrie auftauchen
Da meinste wohl unter anderem mich, oder?

:D

Verfasst: 14.10.2006 22:30
von Kaeru Gaman
@#NULL

erstaunlich, wie ein schwätzchen einem auf die sprünge helfen kann.
als du sagtest "nur vier mal pro frame", hatte ich im grunde sofort vor Augen,
wie das aussehen müsste.
Bild
Abb.1

Dürfte doch ungefähr hinkommen, nicht?
Auf jeden Fall, auf der Basis konnte ich weitermachen.

Wir haben also jetzt einen rechteckigen Bereich ermittelt, in dem sich die Maus befindet,
und seine obere linke Ecke nennen wir mal (TestX,TestY).

Nun kann ich ja den noch übrigen Abstand zur Maus als Differenz errrechnen,
um darüber dann das korrekte Viertel zu berechnen.
Es wird einfacher, wenn ich aus dem Testbereich ein Quadrat mache,
indem ich die X-Differenz halbiere. (s.u. Abb.2)

Code: Alles auswählen

DX = (MausX - TestX) /2
DY = MausY - TestY
Bild
jetzt kann ich mit zwei Abfragen herausfinden, wo die Maus sich genau befindet.

1. Die Maus befindet sich in der unteren rechten Diagonalhälfte,
wenn DX+DY >= 32 ist. (Abb.3)
2. Die Maus befindet sich in der linken unteren Diagonalhälfte,
wenn DY >= DX ist. (Abb.4)

aus diesen Informationen kann man jetzt ganz einfach Code machen,
kann sogar zusammenfassen:

Code: Alles auswählen

Check4 = 0       ; zurücksetzen
If DX+DY >= 32
  Check4 | 1     ; Bit 0 setzen
EndIf
If DY >= DX
  Check4 | 2     ; Bit 1 setzen
EndIf
Check 4 bezeichnet jetzt die Tileecke, in der sich die Maus befindet,
mit 0,1,2 oder 3.
Bild
Abb.5 : Check4-Werte

Damit sollte man eine rein mathematische Ermittlung der aktuellen ISO-Tile hinbekommen,
ohne auf SpritePixelCollision angewiesen zu sein.

Verfasst: 15.10.2006 01:37
von Zaphod
Ich nutze jetzt auch rein berechnete Koordinatenkonvertierung und bei mir hat letztendlich das hier funktioniert:

Code: Alles auswählen

Editor\DrawStartX= (Editor\MapW / 2)*#floorWidth + #floorWidth/2
; MapW ist die anzahl der tiles die dargestellt werden können, weil ich
; mit Dynamischer Screengröße arbeite.
; Die ganze übung dient nur herauszufinden, wo 
; die mitte des screens liegt
; DrawStartX ist also einfach die Screenmitte wo angefangen wird 
; zu zeichnen.
; Screen\MouseX enthält die Mausposition auf dem Screen 
; (für anwendungen im fenster nötig).

yMouse=((2*Screen\MouseY - (Screen\MouseX-Editor\DrawStartX))/2)
xMouse=((Screen\MouseX-Editor\DrawStartX) + yMouse)  
  
MouseMapY = ((yMouse*2)/#floorWidth)
MouseMapX = ((xMouse*2)/#floorWidth)-1
; in MouseMapX,Y stehen die koordinaten auf der Map
Teilweise hab ich an den Formeln ein wenig rumgefrikelt und experimentiert, also verlangt jetzt bitte keine mathematische Beweisführung ;)
Bei mir funktioniert es jedenfalls Pixelperfekt.

Verfasst: 15.10.2006 11:33
von #NULL
ich habs jetzt (auch) hingekriegt die punkte auf einer fläche einem parallelogramm zuzuordnen oder eben nicht, und ich glaub das ist mehr oder weniger das gleiche wie bei dir, zaphod. weiß aber nicht genau, weil ich deinen code ohne den context nicht richtig kapier'.

jedenfalls ist [i,k] der punkt, den die maus auf dem aktuell zu prüfenden tile hat (in dem fall ein 64x32 tile). die variable n, bzw die zeile mit dem ersten kommentar, ist nur dazu da, damit das parallelogramm eine gerad-zahlige breite bekommt, und nicht eine ungerade. ohne dies wird der senkrechte 'mittelbalken' des parall. 3 pixel breit und nicht 4.
und ein Abs()-macro is ja dann auch kein ding mehr.

ich weiß aber nicht, was für ein schema bei iso-tiles normal verwendet wird. bei mir reicht das parall. über die ganze breite, hat aber unten eine leerzeile. es berühren sich also die parall. nebeneinander, und nicht die übereinander.

Code: Alles auswählen

InitSprite()
hWin=OpenWindow(0, 50,50,532,276, "")

CreateImage(0,64,32)
StartDrawing( ImageOutput(0) )
  For i=0 To 63
    If i>31 ::: n=1 ::: Else : n=0 ::: EndIf ; <<<<< n 
    For k=0 To 31
      If Abs(i-31-n) + 2*Abs(k-15)  < 32 ; <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< ditt is de forml
        Plot(i,k,$0000ff)
      EndIf
    Next
  Next
StopDrawing()

; file$="c:\test\parall.bmp"
; SaveSprite(0,file$)
; RunProgram("C:\Windows\System32\mspaint.exe",file$, "" )
; End

Repeat
  StartDrawing( WindowOutput(0) )
    DrawImage( ImageID(0), 10,10, 512,256)
  StopDrawing()
  
  event=WindowEvent()
  Select event
    Case #PB_Event_CloseWindow
      quit=1
  EndSelect
  Delay(5)
Until quit
bei deinen überlegungen Kaeru, weiß ich nich richtig. nach dem man prüft, ob die maus über dem aktuell zu zeichnenden tile ist, hat man zwar so einen rechteckigen bereich. der ist aber aber genau versetzt, also so, dass sich ein ganzes tile innerhalb befindet. und dann muß man eben gucken, ob die maus auf den 'eck-dreiecken', oder auf den 'mittel-dreiecken' ist. wenn sie in der mitte ist, hat dieses tile den fokus. und das hab ich eben hier gemacht, indem ich den x- und den y- abstand von der tile-mitte addiert hab. die summe sagt aus ob es im parall. ist oder nicht. man brauch nur noch die 2* für y, weil die x-achse ja gestreckt ist.

so, ich hör mal auf zu brabbeln :)

Verfasst: 15.10.2006 12:14
von Kaeru Gaman
@Zaphod:
mit deinem code konnte ich mich noch nicht auseinandersetzen.
war einfach zu spät nachts, und heut muss ich auch ersma in die puschen kommen...

@#NULL
achso.
meine Überlegung ging davon aus, den gesamten screen in prüf-rects aufzuteilen,
halt etwas anders aufgeteilt, damit sich nix überschneiden muss.
aber egal.

auch bei deiner lösung kannst du die mathe hinter meinem benutzen.
auch hier halbierst du wieder DX (resp. i), um ein testquadrat zu bekommen.

linke obere ecke:
i + k < 16
rechte untere ecke:
i + k > 48
rechte obere ecke:
i > k + 16
linke untere ecke:
i < k - 16