Tilemap Scrolling [mal wieder]

Anfängerfragen zum Programmieren mit PureBasic.
Benutzeravatar
Rubiko
Beiträge: 943
Registriert: 25.02.2005 19:43
Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti
Wohnort: Schwabach

Tilemap Scrolling [mal wieder]

Beitrag von Rubiko »

Nur lesen wer Zeit hat

Tag,
bin nach Schulstress in letzer Zeit endlich wieder zu meinem
Code gekommen, und hab versucht das Scrolling auf meiner
Tilemap einzubauen...
Um mich wieder reinzuarbeiten, habe ich mir einen schönen
Guide rausgesucht auf GameDev.net, nämlich diesen hier:

http://www.gamedev.net/reference/articl ... cle743.asp

Die untere Funktion habe ich dann in folgende umgewandelt:

Code: Alles auswählen

Macro MAP_Draw(map_drawx, map_drawy)
   MapX = map_drawx / 32
   MapY = map_drawy / 32
   map_xoff = map_drawx & 31
   map_yoff = map_drawy & 31

   For SY=0 To #SCREEN_Y/#TILESIZE
    For SX = 0 To #SCREEN_X/#TILESIZE
       DisplaySprite(Map(T_MapY+SY, T_MapX+SX), #TILESIZE*SX-map_xoff, #TILESIZE*SY-map_yoff)
    Next SX
  Next SY
EndMacro
Hier sehe ich erstmal keinen Fehler, nur die Variablennamen
sind anders, da mein Code auch schon etwas älter ist.

Ich hab jetzt folgenden Code:

Code: Alles auswählen

If InitSprite() And InitKeyboard() And InitMouse() = 0
  MessageRequester("Error", "DirectX could not be initialized.")
  
  End
EndIf


;- Constants
#SCREEN_X     = 1024
#SCREEN_Y     = 768
#SCREEN_DEPHT = 16

#TILESIZE     = 32

#GFX_PATH     = "Data\gfx\"
#GFX_FILETYPE = ".bmp"

#MAP_PATH     = "Data\map\"
#MAP_FILE     = 0
#MAP_FILENAME = "map.cdm"
#MAP_TILESX   = 32
#MAP_TILESY   = 24


;- Map Array


Global Dim Map(128, 128 )

Structure Tiles
  id.l
  walkable.b
  type.l
EndStructure

Global Dim MyTiles.Tiles(1)
MyTiles(0)\id = 0
MyTiles(0)\walkable = 0
MyTiles(0)\type = 0


MyTiles(1)\id = 1
MyTiles(1)\walkable = 1
MyTiles(1)\type = 1





;- Procedures

Procedure GFX_Load()
  For id = 0 To 2
    LoadSprite(id+1000, #GFX_PATH+Str(id+1000)+#GFX_FILETYPE)
  Next
EndProcedure

Procedure MAP_Load()

  For n=0 To 128
    For t=0 To 128
      Map(n, t) = MyTiles(1)\id+1000
    Next
  Next
EndProcedure


Macro MAP_Draw(map_drawx, map_drawy)


   Global MapX = map_drawx / 32
   Global MapY = map_drawy / 32
   Global map_xoff = map_drawx & 31
   Global map_yoff = map_drawy & 31




  For SY=0 To #SCREEN_Y/#TILESIZE
    For SX = 0 To #SCREEN_X/#TILESIZE
      DisplaySprite(Map(T_MapY+SY, T_MapX+SX), #TILESIZE*SX-map_xoff, #TILESIZE*SY-map_yoff)
    Next SX
  Next SY
EndMacro


;- Variables

PlayerX.l = 512
PlayerY.l = 320


If OpenScreen(#SCREEN_X, #SCREEN_Y, #SCREEN_DEPHT, "")

  TransparentSpriteColor(-1, RGB( 255, 0, 255 ))
  GFX_Load()
  MAP_Load()

  LoadSprite(0, #GFX_PATH+"char.bmp")
  LoadSprite(1, #GFX_PATH+"cursor.bmp")
 
  Repeat
    
    ExamineKeyboard()
    ExamineMouse()
    
    MausX = MouseX()
    MausY = MouseY()
    
    ActTileX = (MausX + FineX) / #TILESIZE + MapX
    ActTileY = (MausY + FineY) / #TILESIZE + MapY


    
    MAP_Draw(1, 1)
    
    DisplayTransparentSprite(0, PlayerX, 320)
    DisplayTransparentSprite(1, MausX, MausY)
    
    If KeyboardPushed(#PB_Key_Left)
    EndIf
    
    If KeyboardPushed(#PB_Key_Right)
    EndIf
    
    If KeyboardPushed(#PB_Key_Up)
    EndIf
    
    If KeyboardPushed(#PB_Key_Down)
    EndIf
    
  FlipBuffers()
    
  Until KeyboardPushed(#PB_Key_Escape)
  
EndIf
End

Sorry, falls der Code unübersichtlich sein sollte,
hab mich aber bemüht ihn so übersichtlich wie
möglich zu halten.

Zu meinem Problem:
Welche Werte muss ich denn hier jetzt ändern, damit die
Map Scrollt, wenn der Spieler sich bewegt?
Hab schon stundenlang beinahe alles probiert,
PlayerX - Map_xoff etc. und einen Fehler in meiner
Umsetzung der Funktion aus dem C++ Code kann ich
auch nicht finden.

Grafiken sind hier, sollte sie jemand brauchen.
http://rapidshare.com/files/94653981/Data.rar
http://www.megaupload.com/?d=18IA8751

Wie gesagt, einige wissen evtl. wie lange ich jetzt schon
hinter diesem Problem hänge, und es wäre wirklich toll,
wenn das Problem endlich gelöst wäre... keine Ahnung,
welche Hirnblockade ich da habe.

Sollten Schwierigkeiten bzgl. des Codes auftreten
oder der Grafiken einfach melden...

Schöne Grüße noch,
Rubiko[/u]
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
Benutzeravatar
KeyKon
Beiträge: 1412
Registriert: 10.09.2004 20:51
Computerausstattung: Laptop: i5 2,8 Ghz, 16GB DDR3 RAM, GeForce 555GT 2GB VRAM
PC: i7 4,3 Ghz, 32GB DDR3 RAM, GeForce 680 GTX 4GB VRAM
Win10 x64 Home/Prof
PB 5.30 (64bit)
Wohnort: Ansbach
Kontaktdaten:

Beitrag von KeyKon »

die frage ist ob sich die spielfigur überhaupt bewegen soll oder ob die einfach in der mitte bleibt und die bewgung rein durch das scrollen des hintergrundes erzeugt werden soll...
(\/) (°,,,°) (\/)
Benutzeravatar
Rubiko
Beiträge: 943
Registriert: 25.02.2005 19:43
Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti
Wohnort: Schwabach

Beitrag von Rubiko »

Hui, um diese Uhrzeit noch Antworten...

So eine Lösung hatte ich schon einmal, bei der sich nur der
Hintergrund verschiebt, aber damit lässt sich leider keine
ordentliche Kollisionsabfrage einbauen, ändert sich die
Spielerkoordinate nicht, kann ich auch nicht von ihr aus
überprüfen, ob Kollisionen stattfinden...

EDIT:

Würde dann übrigens so aussehen:

Code: Alles auswählen

If InitSprite() And InitKeyboard() And InitMouse() = 0
  MessageRequester("Error", "DirectX could not be initialized.")
  
  End
EndIf


;- Constants
#SCREEN_X     = 1024
#SCREEN_Y     = 768
#SCREEN_DEPHT = 16

#TILESIZE     = 32

#GFX_PATH     = "Data\gfx\"
#GFX_FILETYPE = ".bmp"

#MAP_PATH     = "Data\map\"
#MAP_FILE     = 0
#MAP_FILENAME = "map.cdm"
#MAP_TILESX   = 32
#MAP_TILESY   = 24


;- Map Array


Global Dim Map(128, 128 )

Structure Tiles
  id.l
  walkable.b
  type.l
EndStructure

Global Dim MyTiles.Tiles(1)
MyTiles(0)\id = 0
MyTiles(0)\walkable = 0
MyTiles(0)\type = 0


MyTiles(1)\id = 1
MyTiles(1)\walkable = 1
MyTiles(1)\type = 1





;- Procedures

Procedure GFX_Load()
  For id = 0 To 2
    LoadSprite(id+1000, #GFX_PATH+Str(id+1000)+#GFX_FILETYPE)
  Next
EndProcedure

Procedure MAP_Load()

  For n=0 To 128
    For t=0 To 128
      Map(n, t) = MyTiles(1)\id+1000
    Next
  Next
  

  
;   
;   If OpenFile(#MAP_FILE, #MAP_PATH+#MAP_FILENAME) <> 0
;    
;    For n = 0 To 128
;      For t = 0 To 128
;        
;        
;        Map(n, t) = ReadLong(#MAP_FILE)
;      
;      Next
;    Next  
;   
;   EndIf
EndProcedure


Macro MAP_Draw()
  For SY=0 To #SCREEN_Y / #TILESIZE
    For SX = 0 To #SCREEN_X / #TILESIZE
      DisplaySprite(Map(MapX+SX, MapY+SY), 32*SX - FineX , 32*SY - FineY )
    Next SX
  Next SY
EndMacro


;- Variables

PlayerX.l = 512
PlayerY.l = 320


If OpenScreen(#SCREEN_X, #SCREEN_Y, #SCREEN_DEPHT, "")

  TransparentSpriteColor(-1, RGB( 255, 0, 255 ))
  GFX_Load()
  MAP_Load()

  LoadSprite(0, #GFX_PATH+"char.bmp")
  LoadSprite(1, #GFX_PATH+"cursor.bmp")
 
  Repeat
    
    ExamineKeyboard()
    ExamineMouse()
    
    MausX = MouseX()
    MausY = MouseY()
    
    ActTileX = (MausX + FineX) / #TILESIZE + MapX
    ActTileY = (MausY + FineY) / #TILESIZE + MapY


    
    MAP_Draw()
    
    DisplayTransparentSprite(0, PlayerX, 320)
    DisplayTransparentSprite(1, MausX, MausY)
    
    If KeyboardPushed(#PB_Key_Left)
    FineX-2
    If FineX < 0
      FineX = 32
      MapX-1
      If MapX < 0
        MapX = 0
        FineX = 0
      EndIf
    EndIf
    EndIf 

    
    If KeyboardPushed(#PB_Key_Right)
    FineX+2
    If FineX > 32
      FineX = 0
      MapX+1
      If MapX > 1023-32
        MapX = 1023-32
        FineX = 32
      EndIf
    EndIf 
    EndIf
    
    If KeyboardPushed(#PB_Key_Up)
      FineY-2
      
      If FineY < 0
        FineY = #TILESIZE - finestep
        MapY-1
        If MapY < 0
          MapY = 0
          FineY = 0
        EndIf
      EndIf
    EndIf
    

    
    If KeyboardPushed(#PB_Key_Down)
      FineY+2
      
      If FineY > #TILESIZE-FineStep
        FineY = 0
        MapY+1
        
        If MapY > 128-#MAP_TILESY
          MapY = 128-#MAP_TILESY
          FineY = #TILESIZE - finestep
        EndIf
      EndIf

    EndIf
    
  FlipBuffers()
    
  Until KeyboardPushed(#PB_Key_Escape)
  
EndIf
End
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
Benutzeravatar
tobe
Beiträge: 146
Registriert: 14.09.2006 17:33
Wohnort: Oktoberfest

Beitrag von tobe »

hallo Rubiko,

die Spielerkoordinate ist PlayerX + MapX und PlayerY + MapY
mit

Code: Alles auswählen

    StartDrawing(ScreenOutput())
      DrawText(0, 0, "Pos: " + Str(PlayerX + MapX) + "/" + Str(PlayerY + MapY))
    StopDrawing()
vor FlipBuffers() wird die position links oben eingeblendet

mfG
tobe
PureBasic 4.40 (Windows - x86)
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

Rubiko hat geschrieben:So eine Lösung hatte ich schon einmal, bei der sich nur der
Hintergrund verschiebt, aber damit lässt sich leider keine
ordentliche Kollisionsabfrage einbauen, ändert sich die
Spielerkoordinate nicht, kann ich auch nicht von ihr aus
überprüfen, ob Kollisionen stattfinden...
grad umgekehrt...
die kollisionsabfrage wird einfacher, weil du nur prüfen musst,
welche tiles sich neben der zentralen tile befinden.

kollisionen mit tilemaps prüft man sowieso rein anhand der map-daten.
kollisionen mit objekten kann man auch einfach prüfen,
indem man die Map-koordinaten beid3er objekte vergleicht.
wenn beide auf der gleichen tile sitzen oder die gleiche tile betreten wollen, dann kollidieren sie,
da braucht man sich noch nicht mal mit den screenkoordinaten rumschlagen,
und schon garnicht mit irgendwelchen spritecollision()


PS:
falls du's nicht mehr zur hand hattest, hier nochmal mein beispiel
http://www.purebasic.fr/german/viewtopi ... 634#116634
und auch mit mouseover, rein aus koordinaten berechnet im folgepost.
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Rubiko
Beiträge: 943
Registriert: 25.02.2005 19:43
Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti
Wohnort: Schwabach

Beitrag von Rubiko »

SpriteCollision natürlich auf keinen Fall lahm und unnötig :wink:

Du hast mir doch schon einmal erklärt, wie ich die Kollision
per Map-Daten abfrage, soweit so gut - das Problem an der
ganzen Sache war aber, dass ich dabei vom Player Sprite
ausgehen muss, aber da sich hier die Koordinaten nicht
ändern...
Wie ich die Koordinaten des zentralen Tiles errechne,
hab ich auch schon mehr als genug ausprobiert, bin aber
leider nie darauf gekommen...

@Tobe:
Das kann doch nicht die Lösung sein? Oh Gott, echt peinlich
für mich und ich hab Monate dran rumgerätselt

Wenn das so ist, kann ich ja fröhlich weitermachen ;)

Vielen Dank!

//Edit: Achja.. falls ihr gerade schreibfreudig seid... für
Zusatzinformationen über Vor- und Nachteile bin ich auch
gerne dankbar :P

@Kaeru: Ja, vor allem das war 'ne gute Hilfe
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
Kaeru Gaman
Beiträge: 17389
Registriert: 10.11.2004 03:22

Beitrag von Kaeru Gaman »

Rubiko hat geschrieben:Wie ich die Koordinaten des zentralen Tiles errechne,
hab ich auch schon mehr als genug ausprobiert, bin aber
leider nie darauf gekommen...
nuja kommt drauf an, wie du deine map anzeigst.

also, du brauchst die halbe bildschirmbreite und die tilebreite,
das finescrolling brauchst du oft noch nicht mal.

wenn dein screen 800 breit ist, ist die mitte bei x=400.
wenn deine tiles 40 breit sind, befindet sich die bildmitte immer über dem 11ten tile,
egal wie das finescrolling ist.
bei 32 breite brauchst du doch das finescrolling:
400/32 = 12,5
daraus folgt: die bildmitte ist über dem 13ten sprite, bis das finescrolling über 16 hinaus geht,
dann ist sie über dem 14ten.

...soweit nachvollziehbar?

---------------------------------------------
> Ja, vor allem das war 'ne gute Hilfe

freut mich zu hören. :D
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Benutzeravatar
Rubiko
Beiträge: 943
Registriert: 25.02.2005 19:43
Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti
Wohnort: Schwabach

Beitrag von Rubiko »

Hmm... denke schon.
D.h. ich hätte das Problem nur bei 800x600 sofern ich 32x32 verwende,
die anderen Auflösungen (1024x768, 640x480) sind alle durch 32
teilbar woraus sich dann ganz einfach die Feinkoordinate errechnen
ließe
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
Benutzeravatar
KeyKon
Beiträge: 1412
Registriert: 10.09.2004 20:51
Computerausstattung: Laptop: i5 2,8 Ghz, 16GB DDR3 RAM, GeForce 555GT 2GB VRAM
PC: i7 4,3 Ghz, 32GB DDR3 RAM, GeForce 680 GTX 4GB VRAM
Win10 x64 Home/Prof
PB 5.30 (64bit)
Wohnort: Ansbach
Kontaktdaten:

Beitrag von KeyKon »

Da hätte ich übrigens noch einen Vorschlag:
Man kann die Playerposition und die Positionen der eigenen Teils ja auch mit Totalen koordinaten speichern/rumrechnen...
Dann muss man bei der einzeige lediglich so eine Art ScreenPosX und ScreenPosY von den entsprechenden Koordinaten abziehen, auf die artund weise kann man einige schöne effekte einbauen die das Scrolling weicher aussehen lassen...
(\/) (°,,,°) (\/)
Emily
Beiträge: 96
Registriert: 25.01.2008 13:14

Beitrag von Emily »

Wichtig ist eigentlich nur, die Spiellogik von der Darstellung getrennt zu betrachten. Aus der Spielerposition auf der Karte kann man recht leicht die Position auf dem Monitor errechnen, wenn man sie darstellt.
Das hat auch den Vorteil, dass du später noch deine Meinung ändern kannst wie du bestimmte Details handhabst.

Also am besten machst du das so, dass du eine Spielerposition hast und die Position einer "Kamera" die den Bildausschnitt festlegt,
Antworten