Shmup Game First Steps

June 11, 2017 —

After playing with both AMOS and Blitz Basic, I initially had an overall poor impression of Blitz Basic mostly due to stability issues. This was disappointing to me because it seemed pretty clear that AMOS was a little bit slower, but at least it did seem more approachable.

Ultimately though, when I reflected on the various game ideas I had floating around in my head, I really figured I would end up quickly outgrowing AMOS from a performance perspective. So I decided I would look at Blitz Basic again, but try to see what I could do (if anything) to work around the stability issues I had run into earlier. I should note at this point that yes, I did have the runtime debugger enabled, so I don't think that was the cause of any of the crashes I was seeing. That was the first thing I checked when I was having issues. Some of the crashes weren't even occurring while a program was running anyway...

First, I decided that I would not use the "mousable labels" support. Blitz's editor "TED" pops up a side navigation pane showing your program's labels for quick navigation only if your program has any. A "mouseable label" is just an ordinary label that you would use with GOTO or GOSUB with the exception that it should start with a period, e.g. .renderPlayfield: instead of renderPlayfield:. I had noticed some random crashing that would occur when I was fiddling around with some of the sample programs that included these types of labels. Additionally, I had encountered a severe problem with the updated TED version included in the Blitz Support Suite ("SuperTED" I believe it was called? Or might have been the update before that?) where it would immediately crash when opening a program with any of these types of labels. Definitely seemed to me that the editor support for it was at least partially broken... at least for me, though I'm not sure what I could have done to cause these issues, heh.

Second, I had finished completely reading through the user guide (which is honestly a quick read, less than 100 pages) and had run across the recommendations and warnings for using "Blitz mode" (which you will undoubtedly want to use for performance reasons). Most importantly, any disk access or other concurrent OS processing that occurs while a program is running in Blitz mode (or as it first enters Blitz mode) can cause crashes! How about that. I suppose it's possible that this accounts for at least some of the instability I was encountering before. The user guide recommends doing something like VWait 120 just before a BLITZ call to ensure that any disk buffers have had time to be flushed (evidently the OS does so every two seconds?). It notes that there is no software method to check for whether stuff like disk activity has completed so this seems like the only way to protect against this kind of crash. Also it is important to note that none of the sample programs that use Blitz mode do this, thus furthering my belief that this was at least part of the problem I had run into when previously toying about with Blitz Basic.

Anyway... so far so good! I've only had one crash all weekend, and I believe that actually was related to my misuse of Blitz mode and/or of some dual playfield slice functionality. For most of the weekend, I was booted up into a Blitz Basic 1.7 floppy and not using the hard disk functionality provided by my ACA500plus. I wanted to remove as much other possible factors as I could and that seemed like a big one. Late this afternoon I resumed using the ACA500plus and CF card hard disk and have so far been running completely stable as well with that configuration. Fingers crossed that it stays that way.

Without having to worry about crashes, I was able to get a lot of experimentation and learning done and got some very preliminary work done on a basic vertical shmup type game. Nothing fancy, but I'm happy for a few hours work with lots of flipping around through manuals slowing things down (really want to get a physical copy of the Blitz Basic Reference Manual... I hate having to constantly look up commands in PDFs).

I'll try not to make posting big code dumps a habit on this blog, but here's what I've got so far:

; shmup test

#KEY_ESCAPE = $45
#KEY_UP = $4c
#KEY_DOWN = $4d
#KEY_LEFT = $4f
#KEY_RIGHT = $4e
#KEY_SPACE = $40

#SPEED = 2
#STATUSBAR_HEIGHT = 32
#PLAYFIELD_HEIGHT = 256 - #STATUSBAR_HEIGHT

#PAL_GAME = 0

#BMP_STATUSBAR = 0
#BMP_PLAYFIELD = 1

#SLICE_STATUSBAR = 0
#SLICE_PLAYFIELD = 1

#SHAPE_LRG_ENEMY = 0
#SHAPE_MED_ENEMY = 2
#SHAPE_SML_ENEMY = 4
#SHAPE_PLAYER = 6
#SHAPE_BULLETS = 16
#SHAPE_EXPLOSION = 20
#SHAPE_POWERUPS = 25

ASSET_ROOT$ = "Projects:resources/"
ASSET_SHAPES$ = ASSET_ROOT$ + "shmup.iff"
ASSET_STARS_BG$ = ASSET_ROOT$ + "shmup_stars_bg.iff"

DEFTYPE .w

Statement ASSET_LoadPalette{pal}
  SHARED ASSET_SHAPES$
  LoadPalette pal,ASSET_SHAPES$
End Statement

Statement ASSET_LoadStarsBg{destBmp}
  SHARED ASSET_STARS_BG$
  BitMap destBmp,320,512,5
  LoadBitMap destBmp,ASSET_STARS_BG$
  Scroll 0,0,320,256,0,256,destBmp
End Statement

Statement ASSET_LoadShapes{}
  SHARED ASSET_SHAPES$
  BitMap 0,192,256,5
  LoadBitMap bmp,ASSET_SHAPES$

  GetaShape #SHAPE_LRG_ENEMY,0,0,32,32
  GetaShape #SHAPE_LRG_ENEMY+1,32,0,32,32

  GetaShape #SHAPE_MED_ENEMY,64,0,32,16
  GetaShape #SHAPE_MED_ENEMY,96,0,32,16

  GetaShape #SHAPE_SML_ENEMY,64,16,16,16
  GetaShape #SHAPE_SML_ENEMY,80,16,16,16

  For i=0 To 4
    GetaShape #SHAPE_PLAYER+i,0+(i*16),32,16,24
    GetaShape #SHAPE_PLAYER+i+5,0+(i*16),56,16,24
  Next i

  GetaShape #SHAPE_BULLETS,80,32,16,16
  GetaShape #SHAPE_BULLETS+1,96,32,16,16
  GetaShape #SHAPE_BULLETS+2,80,48,16,16
  GetaShape #SHAPE_BULLETS+3,96,48,16,16

  For i=0 To 5
    GetaShape #SHAPE_EXPLOSION+i,0+(i*16),80,16,16
  Next i

  GetaShape #SHAPE_POWERUPS,80,64,16,16
  GetaShape #SHAPE_POWERUPS+1,96,64,16,16
  GetaShape #SHAPE_POWERUPS+2,80,80,16,16
  GetaShape #SHAPE_POWERUPS+3,96,80,16,16

  Free BitMap 0
End Statement

Statement ASSET_Load{}
  NPrint "Loading palette ..."
  ASSET_LoadPalette{#PAL_GAME}
  NPrint "Loading stars background ..."
  ASSET_LoadStarsBg{#BMP_PLAYFIELD}
  NPrint "Loading shapes ..."
  ASSET_LoadShapes{}
  NPrint "Done loading assets!"
End Statement

; -------------------------------------------------------------------

Statement GAME_Init{}
  VWait 120
  BLITZ

  Buffer #BMP_PLAYFIELD,16384

  BitMap #BMP_STATUSBAR,320,#STATUSBAR_HEIGHT,5
  Slice #SLICE_STATUSBAR,44,320,#STATUSBAR_HEIGHT,$fff8,5,8,32,320,320
  Use Palette #PAL_GAME

  Slice #SLICE_PLAYFIELD,44+#STATUSBAR_HEIGHT,320,#PLAYFIELD_HEIGHT,$fff8,5,8,32,320,320
  Use Palette #PAL_GAME
End Statement

Statement DRAW_StatusBar{}
  Use Slice #SLICE_STATUSBAR
  Use BitMap #BMP_STATUSBAR
  BitMapOutput #BMP_STATUSBAR

  Cls 14
  Print "TODO: Awesome statusbar here"

  Show #BMP_STATUSBAR
End Statement

Statement DRAW_Playfield{}
  SHARED scrollY, playerX.q, playerTiltOffset, animateOffset
  Use BitMap #BMP_PLAYFIELD
  Use Slice #SLICE_PLAYFIELD

  UnBuffer #BMP_PLAYFIELD

  Show #BMP_PLAYFIELD,0,scrollY

  tile = #SHAPE_PLAYER+2+playerTiltOffset+(animateOffset*5)
  y = #PLAYFIELD_HEIGHT-32+scrollY
  BBlit #BMP_PLAYFIELD,tile,playerX,y

End Statement

;
; -------------------------------------------------------------------
;

ASSET_Load{}

GAME_Init{}

animateFrame = 0
animateOffset = 0

playerTiltOffset = 0
playerHorizAccel.q = 0
playerX.q = 320/2-32/2

scrollY = 0

DRAW_StatusBar{}
DRAW_Playfield{}

While NOT RawStatus(#KEY_ESCAPE)

  scrollY = QWrap(scrollY - #SPEED, 0, 256)

  animateFrame = QWrap(animateFrame+1, 0, 5)
  If animateFrame = 0
    animateOffset = QWrap(animateOffset+1, 0, 2)
  EndIf

  If RawStatus(#KEY_LEFT)
    playerHorizAccel - 1
  EndIf
  If RawStatus(#KEY_RIGHT)
    playerHorizAccel + 1
  EndIf
  playerHorizAccel = playerHorizAccel * 0.7
  playerX = QLimit(playerX + playerHorizAccel, 0, 320-16)
  playerTiltOffset = Int(playerHorizAccel)

  VWait
  DRAW_Playfield{}

Wend

End

So yeah, very basic and/or crude for now. It doesn't look very impressive running yet either:

All you can do is fly the ship back and forth (but hey, it animates and the ship tilts a bit from side-to-side as you move left and right... exciting, right!?). I'm using the art assets from this package on OpenGameArt. Packaged everything together with a separate simple star background and exported as an IFF.

Actually the asset management has been a slight bit of a pain so far. I first noticed that Photoshop has the ability to save as Amiga IFF, so I would pre-convert the image I was working with to indexed colour mode and set up a 32 colour table and then save as an IFF. This seems to produce something that always is loadable by Blitz Basic (and AMOS for that matter), but occasionally produces a file that Deluxe Paint says is "mangled." Also sometimes, when loaded in Blitz Basic, the palette is somewhat off. Some colours will be totally different, but most will be correct. In this case, I've noticed I can fix the problem by opening the IFF in Deluxe Paint, and if it doesn't complain that it's mangled, I can simply re-save the file and the problem goes away. My suspicion is that Photoshop saves the palette information in a different way then what Blitz Basic is expecting, but I have not investigated this fully yet. I also tried using XnConvert by exporting from Photoshop as a indexed colour PNG or GIF and then converting to Amiga IFF with XnConvert, but still have run into the same issue (I think? I might also have mixed up my working files, heh, so will need to confirm that first I guess). At any rate, I definitely still have lots to do to nail down my asset preparation process.

Next steps will be putting together some custom font routines (I'm not sure how to generate the "Blitzfonts" that Blitz Basic supports, but at any rate, I don't think that supports bitmap fonts which is what I really want to use anyway). Following that will be adding the ability for the player to shoot and then adding enemies. I'm really curious to see how quickly I run into slowdowns.