View Single Post
Old 22 February 2019, 19:42   #5
MickGyver
Registered User
 
MickGyver's Avatar
 
Join Date: Oct 2008
Location: Finland
Posts: 643
Vertical Scrolling Demo (updated: 2019-03-11)

I have managed to get vertical tilemap scrolling working (using a coppersplit) thanks to earoks Kiwi's Tale dev notes. There is a small glitch when bitmap wraps around for some reason, can't figure it out at the moment. splitline becomes negative for a tile height, I can't get everything to sync, probably something simple with bitmap heights etc. Maybe Erik the Genius or somebody else can see what's wrong?

EDIT1: I edited the code a little, I found a hack/solution to the problem I explained above, the offset y position can for sure be handled in a prettier way than it is now however.

EDIT2: I figured it out and have edited the code, it should now be good to go. 8-way scrolling next.

Only two tiles needs drawing every frame, or it's like 10 frames with two tiles drawn, 6 frames with no tiles drawn. Visible area is 320x208. Bitmap size needed is only 320x240. If using a width of 256 (16 tiles) instead of 320 (20 tiles) then only one tile needs to be drawn per step when scrolling.

(The code uses the same tilemap etc. as in the ScrollX example above.)

Code:
; ****************************************************
;
; Interleaved single buffer vertical scrolling demo (coppersplit)
; by MickGyver @ English Amiga Board 2019
; Based on http://aminet.net/package/dev/src/ScrollingTrick
; and earoks (English Amiga Board) dev notes for Kiwi's Tale
;
; MIT License, read license.txt
;
; 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 topmost and bottommost rows of the tilemap will never be visible,
; so you need to add one padding row to the top and bottom.
;
; ****************************************************

; 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=208  ; Height of visible screen
#ScreenMainDepth=5     ; The bit depth of the main screen
#ScreenMainColors=32   ; The number of colors for the main screen
#HudHeight=40          ; Height of HUD
#HudDepth=5            ; The bit depth of the HUD
#HudColors=32          ; The number of colors for the HUD
#TileWidth=16          ; Width of tiles
#TileHeight=16         ; Height of tiles
#TileDepth=5           ; The bit depth of the tiles (other bit depths than 5 is untested)
#TileXShift=4          ; Set according to #TileWidth (16->4, 32->5)
#TileYShift=4          ; Set according to #TileHeight (16->4, 32->5)
#MapWidth=20           ; Tilemap width (number of tiles wide)
#MapHeight=52          ; Tilemap height (number of tiles high)
#ScrollSpeed=1         ; Scroll speed, this equals the number of tiles that needs to be drawn every frame

; Calculated constants (from constants above)
#TileXAndNot=0-#TileWidth                      ; Used for inverted bitshift AND to get nearest multiple of #TileWidth
#TileYAndNot=0-#TileHeight                     ; Used for inverted bitshift AND to get nearest multiple of TileHeight
#TileHeight1P=#TileHeight*#TileDepth           ; The tileheight for an interleaved bitmap
#BufferDepth=#ScreenMainDepth                  ; The buffer bit depth, same as main screen depth
#BufferWidth=#ScreenMainWidth                  ; Buffer bitmap width (screen width)
#BufferHeight=#ScreenMainHeight+#TileHeight*2  ; Buffer bitmap height (screen height + padding)
#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     ; Camera max x position
#MapYMax=#MapHeight*#TileHeight-#ScreenMainHeight-#TileHeight*2 ; Camera max y position

; Keyboard etc. constants
#KeyUp=$4C
#KeyDown=$4D
#KeyLeft=$4F
#KeyRight=$4E
#KeyEscape=$45 
#DirNone=0
#DirUp=1
#DirDown=2
#DirLeft=3
#DirRight=4      

#BitmapTemp=0
#BitmapBuffer1=1
#BitmapBuffer2=2
#BitmapHud=3
#BitmapTiles=4
#BitmapVTiles=5
#BitmapVBuffer1=6
#BitmapVBuffer2=7

#PaletteMain=0
#PaletteHud=0
#CopListMain=0
#CopListHud=1

; 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
; Round down value to nearest tile height
; -16 is the same as ~(#TileHeight-1)
Macro RoundToBlockHeight
  (`1 & -#TileHeight)
End Macro
; This is a faster way of doing MOD #TileHeight
Macro ModNumSteps
  (`1 & (#TileHeight-1))
End Macro

Variables:
; ---------------------------------------------------------------
db.b=0                ; 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               
map_y=0
scroll_dir_prev.b=#DirNone
bp.l=0
videopos_y=0
show_y=0

ScreenSetup:
; ---------------------------------------------------------

; Create two bitmaps for double buffered display
BitMap #BitmapBuffer1,#BufferWidth,#BufferHeight,#BufferDepth
BitMap #BitmapHud,#ScreenMainWidth,#HudHeight,#HudDepth

; Convert the buffer bitmap to be interleaved
ConvertBMToIL{#BitmapBuffer1,#BufferWidth,#BufferHeight,#BufferDepth}

; 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*#BufferDepth,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,#TileDepth 
*bmt.bitmap = Addr Bitmap(#BitmapTiles)

; Load the tiles to bitmap 2
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, #TileDepth}

; 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 colours, 12 copper commands
InitCopList #CopListMain,44,#ScreenMainHeight,$10+#ScreenMainDepth,8,#ScreenMainColors,12    
; y=44, lores, smoothscroll, 5 bitplanes, 8 sprites, 32 colours, 12 copper commands
InitCopList #CopListHud,46+#ScreenMainHeight,#HudHeight,$10+#HudDepth,8,#HudColors,12 

; Create a display using the copperlists
CreateDisplay #CopListMain,#CopListHud

; Set up palettes
DisplayPalette #CopListMain,#PaletteMain 
DisplayPalette #CopListHud,#PaletteHud  

; Output text to HUD bitmap
BitMapOutput #BitmapHud
Colour 18,4
Use BitMap #BitmapHud
Cls 4

; Use virtual buffer 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

; Display HUD bitmap on HUD copperlist
DisplayBitMap #CopListHud,#BitmapHud,0,0

MainLoop:
; ---------------------------------------------------------
Repeat

  ; Wait for vertical blank
  VWait 1

  ; Set screen position
  show_y = (videopos_y+#TileHeight) MOD #BufferHeight
  splitline = #BufferHeight-show_y
 
  ; Show bitmap on copperlist
  DisplayBitMap 0,#BitmapBuffer1,0,show_y
  ; Reset the main copper list
  CopperReset 0, 0
  
  ; Are we displaying over the bottom edge
  If splitline < #ScreenMainHeight
    ; Wait until the bottom edge       
    CopperWait 0, splitline + 44         
    ; Reset the display to the top of the bitmap
    bp.l = *db1\_data[0]
    CopperMove $0e0, bp lsr 16
    CopperMove $0e2, bp & $ffff
    bp.l = *db1\_data[1]
    CopperMove $0e4, bp lsr 16
    CopperMove $0e6, bp & $ffff
    bp.l = *db1\_data[2]
    CopperMove $0e8, bp lsr 16
    CopperMove $0ea, bp & $ffff
    bp.l = *db1\_data[3]
    CopperMove $0ec, bp lsr 16
    CopperMove $0ee, bp & $ffff
    bp.l = *db1\_data[4]
    CopperMove $0f0, bp lsr 16
    CopperMove $0f2, bp & $ffff
  Else 
    ; If we're not displaying over the bottom edge, just wipe out our copper commands
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
    CopperMove $1fe, 0 : CopperMove $1fe, 0 : CopperMove $1fe, 0
  EndIf
  
  ; Scrolling up?
  If RawStatus(#KeyUp)
    JSR ScrollUp : JSR ScrollUp
  EndIf
  
  ; Scrolling down?
  If RawStatus(#KeyDown)
    JSR ScrollDown : JSR ScrollDown
  EndIf
  
  ;Locate 0,0 : Print "Y:",map_y,"  "

Until RawStatus(#KeyEscape)=-1

; Exit game
End

; ------------------------------------------------
; Scroll Up
; ------------------------------------------------
ScrollUp:
  If map_y > 0
    ; Decrease position first
    map_y-1
    videopos_y-1
    If videopos_y < 0 Then videopos_y+#BufferHeight
    ; Tile position
    tile_x = !ModNumSteps{map_y} LSL 1
    If tile_x < #BufferTilesX
      tile_y = map_y LSR #TileYShift
      x = tile_x LSL #TileXShift 
      y = !RoundToBlockHeight{videopos_y} * #BufferDepth
      !DrawTile{tile_x, tile_y, x, y}
      If tile_x+1 < #BufferTilesX
        !DrawTile{tile_x+1, tile_y, x+#TileWidth, y}
      EndIf
    EndIf
  EndIf
  RTS
  
; ------------------------------------------------
; Scroll Down
; ------------------------------------------------
ScrollDown:
  If map_y < #MapYMax
    tile_x = !ModNumSteps{map_y} LSL 1
    If tile_x < #BufferTilesX
      tile_y = #BufferTilesY + map_y LSR #TileYShift
      x = tile_x LSL #TileXShift 
      y = !RoundToBlockHeight{videopos_y} * #BufferDepth
      !DrawTile{tile_x, tile_y, x, y}
      If tile_x+1 < #BufferTilesX
        !DrawTile{tile_x+1, tile_y, x+#TileWidth, y}
      EndIf
    EndIf
    ; Increase position last
    map_y+1
    videopos_y+1
    If videopos_y >= #BufferHeight Then videopos_y-#BufferHeight
  EndIf
  RTS
Changelog
2019-03-12
- Added MIT license.txt
2019-03-11
- Changed to use interleaved bitmaps
- Optimisations and cleanup
2019-02-23
- Copper bug fixed (thanks to earok)
- Working HUD
2019-02-22
- First version
Attached Files
File Type: zip ScrollY.zip (41.6 KB, 92 views)

Last edited by MickGyver; 12 March 2019 at 11:45. Reason: Updated the demo source
MickGyver is offline  
 
Page generated in 0.04970 seconds with 12 queries