Tilemap Scrolling [mal wieder]
ich hab mal versucht aus nem game von mir das scrolling halbwegs zu isolieren:
..falls es zu wirr ist, kann ich auch noch was dazu brabbeln
.
mapwin\.. ist auch nicht unbedingt nötig.
Code: Alles auswählen
InitSprite()
InitKeyboard()
ww=400
wh=300
hWin=OpenWindow(0, 50,100,ww,wh, "")
OpenWindowedScreen( hWin, 0,0,ww,wh, 0,0,0)
#scollborder = 70
#scrollspeed = 0.06
; screen area, where the map is displayed (scolling will stop at these borders)
mapwin.RECT
mapwin\left =40
mapwin\top =40
mapwin\right =ww-40
mapwin\bottom=wh-40
; player pixel position
youX.l = ww/2
youY.l = wh/2
; map offset
offXf.f ;(for calculation)
offYf.f
offX.l ;(for further use)
offY.l
xmax= 60
ymax= 60
Dim map.l(xmax,ymax)
For i=0 To xmax
For k=0 To ymax
map(i,k) = Random(1)
Next
Next
Repeat
ExamineKeyboard()
If KeyboardPushed(#PB_Key_Right) :: youX+4 :: If youX>=(xmax+1)*16 : youX=(xmax+1)*16-1 : EndIf :: EndIf
If KeyboardPushed(#PB_Key_Left ) :: youX-4 :: If youX<0 : youX=0 : EndIf :: EndIf
If KeyboardPushed(#PB_Key_Up ) :: youY-4 :: If youY<0 : youY=0 : EndIf :: EndIf
If KeyboardPushed(#PB_Key_Down ) :: youY+4 :: If youY>=(ymax+1)*16 : youY=(ymax+1)*16-1 : EndIf :: EndIf
youMapI=((youX)/16)
youMapK=((youY)/16)
;{ scrolling
If offXf+youX > (mapwin\right-#scollborder)
offXf- #scrollspeed*( (offXf+youX) - (mapwin\right-#scollborder) )
If offXf < - (((xmax+1)*16)-mapwin\right)
offXf= -(((xmax+1)*16)-mapwin\right)
EndIf
ElseIf offXf+youX < (mapwin\left+#scollborder-16)
offXf+ #scrollspeed*( (mapwin\left+#scollborder-16) - (offXf+youX) )
If offXf>mapwin\left
offXf=mapwin\left
EndIf
EndIf
If offYf+youY > (mapwin\bottom-#scollborder)
offYf- #scrollspeed*( (offYf+youY) - (mapwin\bottom-#scollborder) )
If offYf < - (((ymax+1)*16)-(mapwin\bottom))
offYf= -(((ymax+1)*16)-(mapwin\bottom))
EndIf
ElseIf offYf+youY < (mapwin\top+#scollborder)
offYf+ #scrollspeed*( (mapwin\top+#scollborder) - (offYf+youY) )
If offYf>mapwin\top
offYf=mapwin\top
EndIf
EndIf
offX=offXf
offY=offYf
;}
; end scrolling
StartDrawing(ScreenOutput())
DrawingMode(#PB_2DDrawing_Outlined)
For i=0 To xmax
For k=0 To ymax
If map(i,k)
Box(offX+16*i +1,offY+16*k +1, 14,14,$ff2222)
EndIf
Next
Next
DrawingMode(#PB_2DDrawing_Default)
Box(offX+youMapI*16 ,offY+youMapK*16 , 15,15, $ff2222)
DrawingMode(#PB_2DDrawing_Outlined)
Circle(offX+youX,offY+youY,2,$88ff88)
;DrawingMode(#PB_2DDrawing_Outlined)
Box(offX,offY,(xmax+1)*16,(ymax+1)*16,$00ff00)
Box(mapwin\left+#scollborder, mapwin\top+#scollborder, (mapwin\right-mapwin\left)-2*#scollborder, (mapwin\bottom-mapwin\top)-2*#scollborder, $666666)
StopDrawing()
FlipBuffers()
ClearScreen($333333)
Delay(3)
Until KeyboardPushed(#PB_Key_Escape) Or WindowEvent()=#PB_Event_CloseWindow

mapwin\.. ist auch nicht unbedingt nötig.
- Rubiko
- Beiträge: 943
- Registriert: 25.02.2005 19:43
- Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti - Wohnort: Schwabach
@#NULL
Ist das nicht eher für Jump 'n' Runs?
Andere Frage an dich, hab mich mal ein bisschen mehr zum Thema
Kollision schlau gemacht und dabei folgenden Code von dir gefunden
(http://www.purebasic.fr/german/viewtopic.php?t=15363):
Du machst das doch genau so wie Kaeru Gaman, oder?
Zumindest konnte ich das so rauslesen... eben die
Kollisionspunkte an der Grafik überprüfen, aber wie
genau regelst du das mit dem Array? Wenn ich nämlich
anfange die Spielerkoordinaten für die Kollision durch
32 zuteilen, um dann im Map Array zu überprüfen ob
sich an den Kollisionspunkten ein nicht-passierbares Tile
befindet, krieg ich nur Fehlermeldungen, was wohl daran
liegt, dass so etwas wie 556 / 32 nicht aufgeht, und man
im Array keine Floats verwenden kann...
Da der Uploaded.to Link des Users im Thread nicht mehr
geht, kann ich das leider nicht genauer testen :/
Frage richtet sich natürlich auch an andere...
Wie kann ich überprüfen, ob an den Eckpunkten eine Kollision
stattfindet, wenn (in diesem Fall) bei (PlayerX+MapX)/32
ungerade Zahlen rauskommen? Lassen sich ja nicht im Array
benutzen
Ist das nicht eher für Jump 'n' Runs?
Andere Frage an dich, hab mich mal ein bisschen mehr zum Thema
Kollision schlau gemacht und dabei folgenden Code von dir gefunden
(http://www.purebasic.fr/german/viewtopic.php?t=15363):
Code: Alles auswählen
;
; Test-Animation
; mit Umgebungs-Kollision
;
;*****************************
;** Konstanten
;*****************************
#ResX = 800
#ResY = 600
#BPP = 32
#TileSize = 32
#playerWidth = 27
#playerHeight = 41
;*****************************
;** Define variablen
;*****************************
Global playerX.l = 400 ;- #playerWidth/2
Global playerY.l = 300 ;- #playerHeight/2
Global AnimFrame.l = 111
Global counter.l = 0
Global MapX.l = 0
Global MapY.l = 0
Global uPath.s
Global FineX.l
Global FineY.l
Global frametimer.l = 0
Global framedelay.l = 60
;*****************************
;** Enumuration
;*****************************
Enumeration
#Test00 = 0
#Test01
#Test02
#Test03
#Test04
#Test05
#Test06
#Test07
#Test08
#Test09
#Test10
#Test11
#Maus = 500
EndEnumeration
Enumeration
#Test12 = 12
#Test13
#Test14
EndEnumeration
;*****************************
;** Daten Laden
;*****************************
UsePNGImageDecoder()
;*****************************
;** Struktur & Arrays
;*****************************
Structure _Object
TileID.b
objID.b
objWalk.b
objAction.b
objSound.b
EndStructure
;*****************************
;** Proceduren
;*****************************
Procedure check(value.l, text.s)
If Value = 0
MessageRequester("error", text, 0)
End
EndIf
EndProcedure
Procedure Init()
check(InitSound(), "InitSound() failed")
check(InitKeyboard(), "InitKeyboard() failed")
check(InitMouse(), "InitMouse() failed")
check(InitSprite(), "InitSprite() failed")
SetRefreshRate(60)
win1Nr.l = OpenScreen(#ResX, #ResY, #BPP, "")
check( win1Nr, "OpenScreen() failed")
EndProcedure
Procedure initmap()
Global mapWidth.l
Global mapHeight.l
Global Dim map._Object(mapWidth, mapHeight)
EndProcedure
Procedure ShowLand(x.l, y.l)
Static grid.l = 0
If grid = 0
grid = CreateSprite(#PB_Any,32,32)
StartDrawing(SpriteOutput(grid))
DrawingMode(#PB_2DDrawing_Outlined)
Box(0,0,#TileSize,#TileSize,$444444)
StopDrawing()
EndIf
Protected t.l, n.l, k.l, i.l
;
; Zeigt den Mapauschnitt an
;
For t=0 To mapHeight
For n=0 To mapWidth
DisplaySprite(map(n,t)\TileID, (mapX + #TileSize*n),(mapY + #TileSize*t) )
If map(n,t)\objID > 0
DisplayTransparentSprite(map(n,t)\objID, 8+(mapX + #TileSize*n),8+(mapY + #TileSize*t) )
EndIf
DisplayTransparentSprite(grid, (mapX + #TileSize*n),(mapY + #TileSize*t) )
; StartDrawing(ScreenOutput())
; DrawingMode(#PB_2DDrawing_Transparent)
; DrawText( (#TileSize * n) - FineX, (#TileSize * t) - FineY, Str(map(MapX+n,MapY+t)\TileID) +","+ Str(map(MapX+n,MapY+t)\ObjID) +","+ Str(map(MapX+n,MapY+t)\ObjWalk) )
; StopDrawing()
Next
Next
EndProcedure
Procedure displayAnimation(startAnim.b, stopAnim.b)
While ElapsedMilliseconds() - frametimer > framedelay
frametimer = ElapsedMilliseconds()
AnimFrame + 1
If AnimFrame > stopAnim
AnimFrame = startAnim
EndIf
Wend
EndProcedure
Procedure isAccessible(x.l, y.l)
Static i.l, k.l
i = ((playerX-mapX+x)/#TileSize)
k = ((playerY-mapY+y)/#TileSize)
If i>=0 And i<=mapWidth And k>=0 And k<=mapHeight And map(i,k)\TileID < 10
ProcedureReturn 1
EndIf
ProcedureReturn 0
EndProcedure
Procedure Steuerung()
Static speed.l = 2
If KeyboardPushed(#PB_Key_Left) ;{
If AnimFrame > 114 And AnimFrame <= 118
If isAccessible(-speed-8,-6) And isAccessible(-speed+8,-6) And isAccessible(-speed-8,4) And isAccessible(-speed+8,4)
mapX+speed
EndIf
displayAnimation(115, 118)
Else
AnimFrame = 115
EndIf ;}
EndIf
If KeyboardPushed(#PB_Key_Right) ;{
If AnimFrame > 118 And AnimFrame <= 122
If isAccessible( speed-8,-6) And isAccessible( speed+8,-6) And isAccessible( speed-8,4) And isAccessible( speed+8,4)
mapX-speed
EndIf
displayAnimation(119, 122)
Else
AnimFrame = 119
EndIf ;}
EndIf
If KeyboardPushed(#PB_Key_Up) ;{
If AnimFrame > 122 And AnimFrame <= 126
If isAccessible(-8,-speed-6) And isAccessible(8,-speed-6) And isAccessible(-8,-speed+4) And isAccessible(8,-speed+4)
mapY+speed
EndIf
displayAnimation(123, 126)
Else
AnimFrame = 123
EndIf ;}
EndIf
If KeyboardPushed(#PB_Key_Down) ;{
If AnimFrame > 110 And AnimFrame <= 114
If isAccessible(-8, speed-6) And isAccessible(8, speed-6) And isAccessible(-8, speed+4) And isAccessible(8, speed+4)
mapY-speed
EndIf
displayAnimation(111, 114)
Else
AnimFrame = 111
EndIf ;}
EndIf
If KeyboardPushed(#PB_Key_LeftControl)
; #PB_Key_LeftControl
EndIf
If KeyboardPushed(#PB_Key_Escape)
End ;ProgrammAbbruch
EndIf
EndProcedure
Procedure.l mapLoad(mapName.s)
Protected t.l, n.l
;
; Level Laden
;
If OpenFile(0,mapName+".map")
mapWidth = ReadLong(0)
mapHeight = ReadLong(0)
objAnzahl = ReadLong(0)
initmap()
For t = 0 To mapHeight
For n = 0 To mapWidth
map(n,t)\tileID = ReadLong(0)
If Random(10) ::: map(n,t)\tileID = 1
Else ::: map(n,t)\tileID = 11
EndIf
map(n,t)\objID = ReadLong(0)
map(n,t)\objWalk = ReadLong(0)
Next
Next
CloseFile(0)
EndIf
EndProcedure
;*****************************
;** Sprites Laden
;*****************************
Init()
For i = 111 To 126
LoadSprite(i, ".\Grafik\" + Str(i) + ".png")
TransparentSpriteColor(i, RGB(0,255,255))
Next
uPath = GetCurrentDirectory()
LoadSprite(#Test00, uPath+"Grafik\000.png") ;{
LoadSprite(#Test01, uPath+"Grafik\001.png")
LoadSprite(#Test02, uPath+"Grafik\002.png")
LoadSprite(#Test03, uPath+"Grafik\003.png")
LoadSprite(#Test04, uPath+"Grafik\004.png")
LoadSprite(#Test05, uPath+"Grafik\005.png")
LoadSprite(#Test06, uPath+"Grafik\006.png")
LoadSprite(#Test07, uPath+"Grafik\007.png")
LoadSprite(#Test08, uPath+"Grafik\008.png")
LoadSprite(#Test09, uPath+"Grafik\009.png")
LoadSprite(#Test10, uPath+"Grafik\010.png")
LoadSprite(#Test11, uPath+"Grafik\011.png")
LoadSprite(#Test12, upath+"Grafik\Hag.png")
LoadSprite(#Test13, upath+"Grafik\Hag2.png")
LoadSprite(#Test14, upath+"Grafik\Schild.png")
TransparentSpriteColor(#Test12, RGB(255,103,139))
TransparentSpriteColor(#Test13, RGB(255,103,139)) ;}
TransparentSpriteColor(#Test14, RGB(255,103,139))
;*****************************
;** Loop
;*****************************
mapload("oli10")
Repeat
ClearScreen(0)
ExamineKeyboard()
Steuerung()
ShowLand(0,0)
DisplayTransparentSprite(AnimFrame,playerX-#playerWidth/2, playerY-#playerHeight+5)
StartDrawing(ScreenOutput())
Circle(playerX , playerY , 2,$ffffff)
Circle(playerX-8, playerY-6, 2,$0000ff)
Circle(playerX+8, playerY-6, 2,$0000ff)
Circle(playerX-8, playerY+4, 2,$0000ff)
Circle(playerX+8, playerY+4, 2,$0000ff)
StopDrawing()
FlipBuffers()
Until KeyboardPushed(#PB_Key_Escape)
End
Zumindest konnte ich das so rauslesen... eben die
Kollisionspunkte an der Grafik überprüfen, aber wie
genau regelst du das mit dem Array? Wenn ich nämlich
anfange die Spielerkoordinaten für die Kollision durch
32 zuteilen, um dann im Map Array zu überprüfen ob
sich an den Kollisionspunkten ein nicht-passierbares Tile
befindet, krieg ich nur Fehlermeldungen, was wohl daran
liegt, dass so etwas wie 556 / 32 nicht aufgeht, und man
im Array keine Floats verwenden kann...
Da der Uploaded.to Link des Users im Thread nicht mehr
geht, kann ich das leider nicht genauer testen :/
Frage richtet sich natürlich auch an andere...
Wie kann ich überprüfen, ob an den Eckpunkten eine Kollision
stattfindet, wenn (in diesem Fall) bei (PlayerX+MapX)/32
ungerade Zahlen rauskommen? Lassen sich ja nicht im Array
benutzen
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
-
- Beiträge: 17389
- Registriert: 10.11.2004 03:22
nicht "ungerade"....Wie kann ich überprüfen, ob an den Eckpunkten eine Kollision
stattfindet, wenn (in diesem Fall) bei (PlayerX+MapX)/32
ungerade Zahlen rauskommen? Lassen sich ja nicht im Array
benutzen
dann verwende keine floatsWenn ich nämlich
anfange die Spielerkoordinaten für die Kollision durch
32 zuteilen, um dann im Map Array zu überprüfen ob
sich an den Kollisionspunkten ein nicht-passierbares Tile
befindet, krieg ich nur Fehlermeldungen, was wohl daran
liegt, dass so etwas wie 556 / 32 nicht aufgeht, und man
im Array keine Floats verwenden kann...

du brauchst und willst die nachkommastellen doch auch garnicht.
du willst wissen, auf der wievielten tile sich etwas befindet.
Int( 556 / 32 ) = 17 => also auf der 17ten tile.
PlayerX ist integer, MapX ist integer;
das ergebnis von (PlayerX+MapX)/32 ist integer weil du es als index für ein array verwenden willst.
wenn du ungenauigkeiten reinbekommst, das deine spielfigur zu früh reagiert (oder zu spät)
dann musst du halt noch ein offset einbaun, damit regulierst du pixelweise,
wann rechnerisch das nächste tile betrachtet wird.
Code: Alles auswählen
TestX = ( PlayerX + MapX + OffsetX ) / 32
TestY = ( PlayerY + MapY + OffsetY ) / 32
TestTile = TileMap( TestX, TestY )
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Der Weise weiß, dass er ein Narr ist.
- Rubiko
- Beiträge: 943
- Registriert: 25.02.2005 19:43
- Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti - Wohnort: Schwabach
Wupps, meinte natürlich nicht ungerade...
Aber jetzt geht mir wirklich ein Licht auf... irgendwie meinte ich,
dass bei Verwendung von Floats (die zwangsweise rauskommen)
keine pixelgenaue Kollision mehr stattfinden kann,
jedenfalls vielen Dank
*peinlich*
Aber jetzt geht mir wirklich ein Licht auf... irgendwie meinte ich,
dass bei Verwendung von Floats (die zwangsweise rauskommen)
keine pixelgenaue Kollision mehr stattfinden kann,
jedenfalls vielen Dank

*peinlich*

Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
-
- Beiträge: 17389
- Registriert: 10.11.2004 03:22
- Rubiko
- Beiträge: 943
- Registriert: 25.02.2005 19:43
- Computerausstattung: Intel i7 2600k
8GB Ram
GeForce GTX 560 Ti - Wohnort: Schwabach
Habs jetzt so gemacht, wie du gesagt hast, d.h.
den Wert einer Long-Variable zugeordnet.
Klappt erstmal super, der Array-Fehler ist behoben.
Aber ein neues Problem hat es mit sich gebracht:
bei 575 / 32 kommt z.B.
17,96875 raus, die Variable geht aber immer
noch vom 17. Tile aus, bei 576 kommt das erste
mal 18 raus und ab hier geht er (logischerweise)
dann auch vom 18. aus, übrigens auch, wenn ich
deine 'Routinen' kopiere.
TestX und TestY gehen dabei natürlich auch nur
alle 32 Pixel 1 höher... 'ne Idee wie man da
Abhilfe schaffen könnte?
Code ist im Grunde der selbe
Vielen Dank im Voraus
Rubiko
den Wert einer Long-Variable zugeordnet.
Klappt erstmal super, der Array-Fehler ist behoben.
Aber ein neues Problem hat es mit sich gebracht:
bei 575 / 32 kommt z.B.
17,96875 raus, die Variable geht aber immer
noch vom 17. Tile aus, bei 576 kommt das erste
mal 18 raus und ab hier geht er (logischerweise)
dann auch vom 18. aus, übrigens auch, wenn ich
deine 'Routinen' kopiere.
TestX und TestY gehen dabei natürlich auch nur
alle 32 Pixel 1 höher... 'ne Idee wie man da
Abhilfe schaffen könnte?
Code ist im Grunde der selbe
Vielen Dank im Voraus

Rubiko
Ich wollte die Welt verändern, doch Gott gab mir nicht den Quelltext.
-
- Beiträge: 17389
- Registriert: 10.11.2004 03:22
das ist das, was ich mit dem Offset meinte....
wenn du ab 17.5 eine 18 haben willst, dann mach dein offset halb so groß wie die tilebreite, also hier 16.
letztendlich hängt das aber auch mit der breite des objekts zusammen,
weil ja die objektkoordinaten nicht in der mitte sondern an der linken oberen ecke sitzen...
also in den meisten fällen wirst du wohl nicht 16 nehmen sondern vllt 8 oder 6...
wenn du ab 17.5 eine 18 haben willst, dann mach dein offset halb so groß wie die tilebreite, also hier 16.
letztendlich hängt das aber auch mit der breite des objekts zusammen,
weil ja die objektkoordinaten nicht in der mitte sondern an der linken oberen ecke sitzen...
also in den meisten fällen wirst du wohl nicht 16 nehmen sondern vllt 8 oder 6...
Der Narr denkt er sei ein weiser Mann.
Der Weise weiß, dass er ein Narr ist.
Der Weise weiß, dass er ein Narr ist.
@rubiko
ich weiß leider nicht genau ob ich dich richtig verstehe, aber hier noch ein paar sachen, die du vielleicht übersehen hast:
- die procedure isAccessible(x,y) rechnet die player-position auf der map in pixel noch selbst hinzu. parameter x/y sind also nur die koordinaten / punkte auf dem tile, unabhängig davon wo player sich gerade befindet.
- playerX ist die position auf dem screen. auf der map ist die pixel position 'playerX-mapX'. die player-position auf der map in indices berechnest du also immer genau wie es auch in isAccessible() für i und k gemacht wird.
ich hoffe die das stimmt so. war ja auch nicht mein code, hatte ihn nur bearbeitet.
>> Da der Uploaded.to Link des Users im Thread nicht mehr
>> geht, kann ich das leider nicht genauer testen :/
ich hab bei mir noch das zip gefunden. kann ich dir schicken oder hochladen wenn du willst
ich weiß leider nicht genau ob ich dich richtig verstehe, aber hier noch ein paar sachen, die du vielleicht übersehen hast:
- die procedure isAccessible(x,y) rechnet die player-position auf der map in pixel noch selbst hinzu. parameter x/y sind also nur die koordinaten / punkte auf dem tile, unabhängig davon wo player sich gerade befindet.
- playerX ist die position auf dem screen. auf der map ist die pixel position 'playerX-mapX'. die player-position auf der map in indices berechnest du also immer genau wie es auch in isAccessible() für i und k gemacht wird.
ich hoffe die das stimmt so. war ja auch nicht mein code, hatte ihn nur bearbeitet.
>> Da der Uploaded.to Link des Users im Thread nicht mehr
>> geht, kann ich das leider nicht genauer testen :/
ich hab bei mir noch das zip gefunden. kann ich dir schicken oder hochladen wenn du willst
