Bun Runner Devlog -- 2025-02-09

February 9, 2025

This week was all about improving asset loading and drawing some warmup graphics. Before this week, the background graphics – the foreground columns and the background art – were imported directly into the output binary with INCBIN, just for simplicity in those early days when I was still flailing about with Amiga development. I decided to load those in dynamically as XPK compressed assets, much like how I load sprites.

I wanted to add unit tests for this, but ran into an issue with the XPK library and Vamos. Vamos fails to load the XPK library with the error libmgr:WARNING: xpkmaster.library: init resident failed!. This means that if I want to write tests against XPK, I need to run them on a “real” Amiga.

This was easy to set up in the test suite:

  if (strcmp(argv[1], "xpk") == 0) {
    printf("Running XPK tests, these only work on a real Amiga!\n");
    XPKLoaderSuite(suite);
    LevelDataReaderSuite(suite);
  }

It did mean that, if (when!) I wrote code that would crash the Amiga, the dev cycle was a lot slower. But at least I have tests around the loader code now.

The next part is warmup graphics. I want the rabbit to, at the start of the game, stretch a bit before starting to run. That would take about three or four seconds to go through the poses, and it’ll be cute. After the rabbit crashes and the level restarts, I want to pick only one pose, then the crouching pose, then get the game started, so you don’t have to sit through the whole warmup after each death. Here’s the sprites for the poses I have so far:

Sprites of rabbit stretching before running

Up to this point, this game has had no need for randomization, and I actually don’t want it for the level designs. I want them repeatable, to better facilltate muscle memory and speedruns. However, I do want to randomize the poses, so I needed something to help me generate randomness.

Last summer I went through a big FPGA practice experience, pushing my little Go Board as far as I could, then eventually getting a ULX3S to go further. I decided to put that aside to work on this game, but I did learn how FPGAs do randomization, and got reacquainted with it reading the Wikipedia arcicle on Xorshift. I implemented a very simple Xorshift in assembler that overwrites the seed value for later use, much like how you would want to use amiga.lib/FastRand but without needing to link in that library. Here’s the code. It’s super easy:

  MOVE.L #1000,RandomSeed
  MOVE.L #RandomSeed,A0
  BSR randomizeLong ;=> RandomSeed contains new "random" value
  RTS

RandomSeed DS.L 1

; Implement Xorshift LFSR
; https://en.wikipedia.org/wiki/Xorshift
; @inreg A0 uint32_t Memory location to randomize, using itself as the seed
randomizeLong:
  MOVE.L (A0),D0
  MOVE.L D0,D1

  ; 32 bit xorshift
  ; x ^= x << 13;
  LSL.L #8,D0
  LSL.L #5,D0
  EOR.L D0,D1
  MOVE.L D1,D0

  ; x ^= x >> 17;
  LSR.L #8,D0
  LSR.L #8,D0
  LSR.L #1,D0
  EOR.L D0,D1
  MOVE.L D1,D0

  ; x ^= x << 5;
  LSL.L #5,D0
  EOR.L D0,D1

  ; write it back
  MOVE.L D1,(A0)
  RTS