View Single Post
Old 21 February 2019, 15:53   #1
MickGyver
Registered User

MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 556
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
Attached Files
File Type: zip ScrollX.zip (41.7 KB, 51 views)

Last edited by MickGyver; 12 March 2019 at 11:44. Reason: Updated the source (including the zip)
MickGyver is offline  
 
Page generated in 0.04462 seconds with 12 queries