Shmup Game First Steps

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.

Initial-ish Impressions: AMOS Pro vs Blitz Basic 2

I find the plethora of programming languages available for the Amiga fascinating. Especially so, the large amount of BASIC variants. The top two options for games specifically are definitely AMOS and Blitz Basic from what I can see.

Some other options such as HiSoft BASIC also seem to be of good quality (HiSoft BASIC actually does interest me quite a bit as it was advertised as being QuickBASIC compatible while not being mostly shit like Amiga BASIC from what I understand... but I will explore it later). However, it seems most people at the time settled with either AMOS or Blitz.

I've personally spent more time with AMOS so far, but this weekend I spent a bit of time with Blitz Basic and figured I'd jot down my initial thoughts about each.

None of the points below are listed in any particular order, and it is all just based on my impressions, opinions and experiences from only a limited amount of time looking at each thus far. Also note that the below screenshots show my own customizations, they are not how the "out of the box" experience is exactly.

AMOS Pro

  • Editor looks very polished. Especially as compared to the earlier (non-pro) versions. Lots of customization available with the ability to load "accessories", which, due to AMOS's overwhelming popularity back then, there are a great many to choose from.
  • The editor is not without it's quirks. For one I dislike the automatic formatting (which you cannot turn off, and is likely a result of the fact that the editor is obviously tokenizing your code as you type it in). More specifically, I don't like how it removes excess whitespace and uppercases variable names, e.g. if I type ship_x = foo + bar, it will always auto-format to SHIP_X=FOO+BAR.
  • AMOS Pro thankfully added INCLUDE support for modularizing your code, but even so, you'll probably end up with big source files. Luckily the editor allows you to collapse Procedures (though you might not actually want to use them in all cases, since this is a platform where the performance difference between GOSUB and a Procedure call can really matter!)
  • Following up on the above mentioned "accessories", the developer of AMOS provided some that serve as tools for sprite/image editors, map editors, font editors, and more. These are easily accessible from within the IDE.
  • Lots of documentation in the forms of a beefy user manual and many other published books and sample code. Even built in fully-browseable help within the editor itself.
  • Easily accessible "direct mode" available from the editor to allow quick experimentation (it also doubles as a debugging tool when your program encounters an error).
  • Very extensive set of functions with what looks like a decent abstraction over the underlying hardware (from my early impressions anyway). I personally think this is a pro and a con (a pro for when you're starting out as it's easier to jump into and a con because I suspect it won't help you that much if you move onto e.g. C/assembler later on). This abstraction covers things like asset loading as well which is certainly convenient.
  • The AMOS BASIC dialect is overall good, though lacking in some key areas. For example, no SELECT and TYPE. Somewhat odd syntax for calling Procedures (SUBs and FUNCTIONs from QBasic) and accessing the return value (if any). You cannot put comments just anywhere (well, unless you use REM I guess, though in my opinion, REM makes the code a bit harder to read). A comment written using ' must be on it's own line.
  • Quirky / annoying support for accessing system libraries, but it is somewhat workable.
  • Doesn't integrate with the OS, kind of does it's own thing with it's own totally custom GUI. This also extends to programs developed with it if they do things like pop up file requestors which will be quite alien-looking.

Blitz Basic 2

  • Much more powerful language that is clearly built to enable high performance as a primary goal. Blitz's BASIC dialect is excellent for the time in my opinion. Support for TYPE's, pointers, inline assembly, and more.
  • The language is built for a compiler and there doesn't appear to be any interpreter at all (even when running from the IDE, you can't just choose "Run" unless you've already compiled your program). Thus performance is higher from the get-go.
  • The editor is minimal, which is nice. Though it definitely is unique in a number of ways, and I don't mean that in a good way, at least not if you like me are accustomed to modern text editor standards. You cannot always hit Return to insert a new line (only if you're at the end of the current line), else you need to press Amiga+I to insert a new line or hit Shift-Return. Using the Backspace or Delete keys to remove lines is not possible, you instead must use a menu command (or press Amiga+D) to delete lines. Selecting text for copy+paste is kind of quirky, requiring you to select the text to be copied then go and find the location where you want it copied to (the paste location) and place the cursor there (moving the cursor does not unselect text) and then issue the menu copy command (or Amiga+C). There is a specific menu command for unselecting text. I'm sure you can get used to all this, but I point it out only as it's pretty different from what most people would be used to.
  • The editor has syntax highlighting! Only two colours though: regular text and tokens.
  • The editor has a side pane that pops up when your program has labels (for GOTO/GOSUB only, doesn't show Statement or Function names for some weird reason). Clicking the names in this pane scrolls immediately to that label. Thusly you can also use this as a "bookmark" list of sorts.
  • The editor is incredibly unstable. It crashes a lot, in a lot of different situations, forcing you to do a Ctrl-Amiga-Amiga reset. I've had the editor crash when clicking Project -> New, when switching back to the Workbench, when compiling a program, many times when debugging code with direct mode (in all cases, this was incredibly simple code, not even using "blitz mode"). Worth noting, I've tried four different versions of Blitz2, the 1.6 Amiga Format disk release, a 1.7 release, 2.0 and 2.1. I actually also tried installing Workbench 3 temporarily just so I could try the updated Ted version and also the "SuperTed" update, hoping that these would improve things. However, all of these also were incredibly unstable for me.
  • The standard library appears to be a bit "closer to the metal" then AMOS, but it still abstracts the hardware quite a bit. I suspect that moving from Blitz Basic to C/assembly would be a bit easier. In fact, the mere ability to use inline assembly with such ease basically anywhere in your code means that you possibly wouldn't even need to switch to C or go full-out with pure assembly unless your performance requirements were quite extreme.
  • The editor has built in help which is either limited to parameter lists only, or in later versions even has a browseable function index with descriptions and (few) examples.
  • There is not nearly as much documentation out there for Blitz Basic as there is for AMOS. A common complaint about Blitz Basic from what I've read is that it's harder to get started with, though I think for an experienced programmer that this difference is moot. Probably the smaller amount of example code that's out there would be the biggest annoyance.
  • The debugger and direct mode support looks a fair bit more unpolished than AMOS at first glance, but is definitely more advanced. Especially with a debugger update that is available for release 2.1 (though coincidentally I found this debugger update appeared to reduce stability somewhat).