Registered User
Join Date: Oct 2008
Location: Finland
Posts: 643
|
Horisontal Scrolling Demo (updated: 2019-03-12)
I started experimenting with tilemap scrolling techniques and will upload working examples here as I finish them. I'm basing this on the scrolling tricks C demos from Aminet: http://aminet.net/package/dev/src/ScrollingTrick
First off is a horisontal only corkscrew scroll, full screen 320x256 display. At a scrolling speed of 1px/frame, only ONE tile needs to be drawn per frame when scrolling left or right. If direction changes, then TWO tiles need to be drawn in that single frame. Bitmap size needed is only 352x256 (+some marginal height depending on total map width)
The zip file contains the code, tiles, the map as binary file and for Tiled (.tmx)
Next up I will see if I can figure out vertical scrolling from earoks Kiwi's Tale dev-notes...
Code:
; ****************************************************
;
; Interleaved single buffer horisontal corkscrew scrolling demo
; by MickGyver @ English Amiga Board 2019
; Based on http://aminet.net/package/dev/src/ScrollingTrick
;
; MIT License, read license.txt
;
; For a scrolling speed of 1px/frame, only one tile
; per frame needs to be drawn. Tiles needed to be
; drawn per frame equals scrolling speed.
;
; In order to use the Bitmap newtype, include the resident file
; Blitzlibs:Bb2objtypes.res in the residents list in the compiler options.
;
; Notes about the tilemap:
; The leftmost and rightmost columns of the tilemap will never be visible,
; so you need to add one padding row to the left and right.
;
; ****************************************************
; Include other source files
INCLUDE "system.bb2"
; Enable running from Workbench
WBStartup
; Set default type to word
DEFTYPE .w
Constants:
; -----------------------------------------------------------
#ScreenMainWidth=320 ; Width of visible screen
#ScreenMainHeight=256 ; Height of visible screen
#ScreenMainDepth=5 ; The depth of the screen
#ScreenMainColors=32 ; The number of colours for the main screen
#TileDepth=5 ; Tile bit depth
#TileWidth=16 ; Width of tiles
#TileHeight=16 ; Height of tiles
#TileXShift=4 ; Set according to #TileWidth (16->4, 32->5)
#TileYShift=4 ; Set according to #TileHeight (16->4, 32->5)
#MapWidth=82 ; Tilemap width (number of tiles wide)
#MapHeight=16 ; Tilemap height (number of tiles high)
; Calculated constants (from constants above)
#ScreenXCount=10 ; Total number of screens horisontally in tilemap
#TileHeight1P=#TileHeight*#TileDepth ; Used to get pointer to bitmap buffer
#TOffsB=#TileHeight1P-#ScreenMainDepth ; Tile bottom offset for the interleaved bitmap
#BufferWidth=#ScreenMainWidth+#TileWidth*2 ; Buffer bitmap width (screen width + padding)
#BufferHeight=#ScreenMainHeight ; Buffer bitmap height (screen height)
#BufferTilesX=#BufferWidth/#TileWidth ; Number of tiles that fits horisontally on the buffer bitmap
#BufferTilesY=#BufferHeight/#TileHeight ; Number of tiles that fits vertically on the buffer bitmap
#MapXMax=#MapWidth*#TileWidth-#ScreenMainWidth-#TileWidth*2 ; Max X position on map
; Keyboard etc. constants
#KeyUp=$4C
#KeyDown=$4D
#KeyLeft=$4F
#KeyRight=$4E
#KeyEscape=$45
#DirNone=0
#DirUp=1
#DirDown=2
#DirLeft=3
#DirRight=4
#BitmapBuffer1=1
#BitmapBuffer2=2
#BitmapTiles=3
#BitmapVTiles=4
#BitmapVBuffer1=5
#BitmapVBuffer2=6
#BobTemp=0
#PaletteMain=0
#CopListMain=0
; Tiles bitmap
#TileCountX=229 ; The number of tiles horisontally in the tiles bitmap
#TileCountY=1 ; The number of tiles vertically in the tiles bitmap
Macros:
; ---------------------------------------------------------------
; Get a tile from the tilemap array
; The bitwise AND 255 is for reading the byte value as unsigned
Macro GetTile
(map(`1, `2) & 255)
End Macro
; Draw a tile
;!DrawTile{tileX,tileY,x,y}
Macro DrawTile
BlockScroll (map(`1, `2) & 255) LSL #TileXShift, 0, #TileWidth, #TileHeight1P, `3, `4, #BitmapVTiles
End Macro
Macro DrawTileTop
BlockScroll (map(`1, `2) & 255) LSL #TileXShift,0,#TileWidth,#TileDepth,`3,`4,#BitmapVTiles
End Macro
; #TOffsB=#TileHeight1P-#ScreenMainDepth = 16*5-5 = 75
Macro DrawTileBottom
BlockScroll (map(`1, `2) & 255) LSL #TileXShift,#TOffsB,#TileWidth,#TileDepth,`3,`4+#TOffsB,#BitmapVTiles
End Macro
; Round down value to nearest tile height
; -16 is the same as ~(#TileHeight-1)
Macro RoundToBlockWidth
(`1 & -#TileWidth)
End Macro
; This is a faster way of doing MOD #TileWidth
Macro ModNumSteps
(`1 & (#TileWidth-1))
End Macro
Variables:
; ---------------------------------------------------------------
db.b=1 ; Keeps track of double buffer bitmap used (not in use currently)
x=0
y=0
tile_x=0
tile_y=0
map_w=0
map_h=0
map_x=0
scroll_dir_prev.b=#DirNone
ScreenSetup:
; ---------------------------------------------------------------
; Create one bitmap for a single buffered display
BitMap #BitmapBuffer1,#BufferWidth,#BufferHeight+#ScreenXCount,#ScreenMainDepth
; Convert the bitmap to be interleaved
ConvertBMToIL{#BitmapBuffer1,#BufferWidth,#BufferHeight+#ScreenXCount,#ScreenMainDepth}
; Get a pointer to the background bitmap
*db1.bitmap = Addr Bitmap(#BitmapBuffer1)
; Set clipping limit to max to enable blitting ourside of bitmap
*db1\_xclip = $7FFF
; Create a "virtual" one plane bitmap for blitting to. We will still use the
; "normal" bitmap with the display command
CludgeBitMap #BitmapVBuffer1,#BufferWidth,(#BufferHeight+#ScreenXCount)*#ScreenMainDepth,1,*db1\_data[0]
; Get a pointer to the virtual bitmap
*dbv.bitmap = Addr Bitmap(#BitmapVBuffer1)
; Set clipping limit to max to enable blitting ourside of bitmap
*dbv\_xclip = $7FFF
*dbv\_yclip = $7FFF
; Create a bitmap for the tiles
BitMap #BitmapTiles,#TileCountX*#TileWidth,#TileCountY*#TileHeight,#ScreenMainDepth
*bmt.bitmap = Addr Bitmap(#BitmapTiles)
; Load the tiles
LoadBitMap #BitmapTiles,"tilesrow32.iff"
; Load the palette from the same image
LoadPalette #PaletteMain,"tilesrow32.iff"
; Convert the tiles bitmap to be interleaved
ConvertBMToIL{#BitmapTiles, #TileCountX LSL #TileXShift, #TileCountY LSL #TileYShift, #ScreenMainDepth}
; Create a virtual 1-plane bitmap from the tiles bitmap
CludgeBitMap #BitmapVTiles, #TileCountX LSL #TileXShift, #TileHeight1P, 1, *bmt\_data[0]
; Read the tile map
If ReadFile(0,"world.map")
; First two words are width and height of tilemap
ReadMem 0,&map_w,2
ReadMem 0,&map_h,2
; Create a two dimensional array for the tilemap
Dim map.b(map_w-1, map_h-1)
; Read the entire tilemap into the array
ReadMem 0,&map(0,0),map_w*map_h
; Close the tilemap file
CloseFile 0
EndIf
; Wait for disk activity to finish before going into Blitz mode
VWait 100
; Go into blitz mode and enable blitzkeys
BLITZ
BlitzKeys On
; Create copperlists for the display (y=44, lores, smoothscroll, 5 bitplanes, 8 sprites, 32 colors)
InitCopList #CopListMain,44,#ScreenMainHeight,$10+#ScreenMainDepth,8,#ScreenMainColors,0
; Create a display using copperlist
CreateDisplay #CopListMain
; Set up palette
DisplayPalette #CopListMain,#PaletteMain
; Use the virtual one plane bitmap
Use BitMap #BitmapVBuffer1
; Draw tiles to fill the whole bitmap
For y = 0 To #BufferTilesY-1
For x = 0 To #BufferTilesX-1
!DrawTile{x, y, x LSL #TileXShift, y * #TileHeight1P}
Next
Next
MainLoop:
; -----------------------------------------------------------
Repeat
; Wait for vertical blank
VWait 1
; Show bitmap on main copperlist
DisplayBitMap #CopListMain,#BitmapBuffer1,map_x+#TileWidth,0
; Scrolling right?
If RawStatus(#KeyRight) AND map_x < #MapXMax
JSR ScrollRight : JSR ScrollRight
Else
; Scrolling left?
If RawStatus(#KeyLeft) AND map_x > 0
JSR ScrollLeft : JSR ScrollLeft
EndIf
EndIf
Until RawStatus(#KeyEscape)=-1
; Quit game
End
; ------------------------------------------------
; Scroll Left
; ------------------------------------------------
ScrollLeft:
; Decrease position first
map_x-1
; Get blit position
x = !RoundToBlockWidth{map_x}
tile_y = !ModNumSteps{map_x}
y = tile_y * #TileHeight1P
; Blit tile
If tile_y < #BufferTilesY
tile_x = map_x LSR #TileXShift
!DrawTile{tile_x, tile_y, x, y}
; Repair broken tile if needed
If scroll_dir_prev = #DirRight
If tile_y+1 < #BufferTilesY
!DrawTileTop{tile_x, tile_y+1, x, y+#TileHeight1P}
EndIf
EndIf
EndIf
scroll_dir_prev=#DirLeft
RTS
; ------------------------------------------------
; Scroll Right
; ------------------------------------------------
ScrollRight:
; Get blit position
x = #BufferWidth + !RoundToBlockWidth{map_x}
tile_y = !ModNumSteps{map_x}
y = tile_y * #TileHeight1P
; Blit tile
If tile_y < #BufferTilesY
tile_x = map_x LSR #TileXShift + #BufferTilesX
!DrawTile{tile_x, tile_y, x, y}
; Repair broken tile if needed
If scroll_dir_prev = #DirLeft
If tile_y-1 >= 0
!DrawTileBottom{tile_x,tile_y-1,x,y-#TileHeight1P}
EndIf
EndIf
EndIf
; Increase position last
map_x+1
; Set right as previous scroll direction
scroll_dir_prev=#DirRight
RTS
Changelog
2019-03-12
- Added MIT license.txt
2019-03-11
- Changed to use interleaved bitmaps
- Optimisations and cleanup
2019-02-23
- Small optimisations
2019-02-21
- First version
Last edited by MickGyver; 12 March 2019 at 11:44.
Reason: Updated the source (including the zip)
|