Pages

Thursday, 27 December 2018

Digiloi: Action game with C64 default characters


Digiloi is a game I made for Commodore 64, using only the default character graphics (PETSCII) for visuals. For some time I've wanted to use this approach. Fort Django used PETSCII for the backgrounds, but all the gameplay worked with sprites.

There's nothing special about using PETSCII for games, it was done a lot back in the day. However, not many full screen action games were done using the technique, probably because sprites are far more useful and the clunky char-by-char movement was not that attractive.

This visual style is closer to ZX Spectrum game programming techniques, even if the Speccy does not have a character display. Many ZX games had movement restricted to the color grid, with big player "sprites" to compensate. Don Priestley used his unique techniques in Benny Hill, Popeye, Trap Door, Flunky etc.

Left: The old-style forest. Right: UFO attacks
Later, others made fast arcade type games with a more streamlined approach, for example Dan Dare IIISavage!, and Extreme. What I've done is a bit of a compromise between these, an arcade game following Priestley's non-scrolling style but ignoring the more complex aspects of his routines.

I could not achieve 50 frames per second for these big dudes. I wondered if I could stick to 1/2 or 1/4 framerate, knowing that each frame would add greatly to the amount of code that can be executed. I went for 1/3, which is something like 16.67 frames per second on a PAL machine.

I use 256-byte aligned buffers for holding the current screen background and building the screen for displaying. I discarded the idea of double-buffered page swapping routines as the color memory in this mode is fixed at $D800 anyway.

The visuals and game logic are orchestrated like this:

Frame 1:
The background screen & colors, which were built on entering the "room", are copied to the respective 256-byte aligned buffers using speedcode. Copying 2K of characters and colors takes nearly the entire frame.

+joystick poll, music/fx play

Frame 2:
The 8 x 8 character "sprites" are drawn over the 256-byte aligned buffers. Each large "sprite" graphic is stored in 143 reverse-ordered data bytes including color and line-padding zeroes. Some smaller graphic elements, like bullets, are drawn using hardcoded routines.

This uses something like third of a frame, depending on how many movable objects there are on screen.

+joystick poll, music/fx play

Frame 3:
The 256-byte aligned background buffer is copied to the visible screen using speedcode. Again, this is 2K and takes nearly the entire frame.

+joystick poll, music/fx play

During each frame the interrupt plays a GoatTracker SID tune and polls the joystick.

With this approach I balanced speed, memory and convenience. Especially I like convenience. The 256-aligned buffers are quite handy. When transfering the 8x8 character elements to the buffer, the writing address hi byte is INCed with self-modifying code to reach the next vertical line whereas X register handles the horizontal coordinate.

I already think I might have the graphic shapes erased with routines similar to drawing them, resulting in a faster screen clean-up. Also, I probably could use the X/Y registers without having to resort to the INC gimmick. But once I had my routines in place, I kind of prefer the 1/3 because it gives automatically a nice gameplay speed without having to slow things artificially. Convenience.

With the visuals, I took the easiest, black-background PETSCII approach. I noticed that PETSCII game visuals need a somewhat different approach than static screens: The overlaid "sprites" have to go well with the background without too large black outlines. I initially gave the main character a more rounded look as I would do in a picture, but this did not work with the background. I took most of the rounding off.

This not only influenced the character design but the backgrounds too, so there's more black empty space than would look good in a static picture.

2017? Well, um... I've been sitting on it for a while.
The game is pretty much 100% written in assembler, unlike Fort Django, which still had a fair amount of C code in it. There is still a short C scaffolding for initializing stuff, but after kicking off the main loop it's all asm.

I now feel it's not that much more difficult as the assembler can work quite easily with "variables" and tables, and the X and Y index registers make it easy to have array-like structures for game objects. Using the stack to store registers, it's possible to have hierarchical subroutines and sub-subroutines for various tasks and associated labeled memory locations as "local variables" if need arises.

Tools used:
  • CC65 cross-development package. This has C and assembler together. C is nice for initializing and testing ideas, though it seems I'm relying less and less on it. The included assembler has some things lacking in the code alignment and positioning department (stuff promised in the manual does not seem to work).
  • The text editor included with Linux Mint Mate, Xed or whatever it's called nowadays. Later in the project, I moved to Sublime Text with added 6502 asm highlighting.
  • VICE emulator. Obviously.
  • C64Debugger from Samar Productions. A neat tool for examining C64 memory content live as it is emulated. This was useful in getting the 256-byte aligned buffers working.
  • Marq's PETSCII editor. Not only it is good for creating static PETSCII screens, it does a good job with tiles and animated graphics. I did add custom ordered exporting code, though.
  • GoatTracker 2.73. Does the job well and has simple to understand sound fx routines (after understanding them, that is) and easy export.
  • Tiled. A friendly enough map editor that outputs csv. It's nice to be able to grab larger entities from the map or the tilesheet and paint with them. The tiles are exported as PNGs from the PETSCII editor straight into a tile sheet for Tiled.
  • Processing. For generating some of the tables and converting the Tiled csv directly into ordered room list in an assembler-friendly format. Also, the PETSCII editor modifications are made with Processing.

Commodore Plus/4 conversion note

As the game routine operates most heavily in an invisible back-buffer, there are not that many unique routines and addresses in use. So I could convert the game fairly fast to plus/4 simply by changing the speedcode to point to plus/4 character and color memory addresses.

The joystick reading needed a bit more investigating, but it's not that much more complex than on a C64. I added a keyboard key reading too to switch the music on and off. Sadly, there's only SID support on the sound side.

plus4 version
I re-painted the graphics using the PETSCII editor's plus/4 conversion as a starting point. Some coloring was hard-coded to the source (tut-tut!) but not at too many places. The result is not that different from the C64 original, but it has a bit more shine here and there.

It's more interesting to see that the code runs roughly 30% faster at places, even without trying any plus/4 specific tricks. More could be achieved with plus/4 on this type of game, than on a C64.

I can also see that despite having twice as fast processor, it does not mean a 2x speed. But, certainly the 1/2 framerate might be a more realistic goal even without modifying the routines too much.

*** 28.12.2018 plus/4 addition: The speed-up I'm talking about is not really present in the originally released Plus/4 conversion of the game. I have made a speeded up demo for plus/4 available at the download links below so you can see the game running at 25fps.

However this is a rough-at-the-edges implementation and I have no guarantee it works well all the time. Also, as the game runs faster it may be less playable. The plus/4 is quite a neat computer!


Some reflections

I've wondered why I don't finish more stuff. It's not really about available time.

My projects tend to follow this script:

1. Become enthusiastic about a visual/logical solution for graphics and animation routines, which are at first built with care and reason
2. Start building the game logic with fundamental routines, still maintaining neat hierarchy
3. Lose momentum. Become bored and make new additions without much thought, adding stuff outside the existing hierarchy, generating potential problems difficult to solve later
4. Hastily wrap up. Instead of creating more gameplay & narrative, be happy with finishing the thing

If something disturbs the game within phase 1-2, it's possible that the project never gets completed. If it gets past phase 2, I can at least stubbornly make a finished piece out of it.

One antidote is to try to make the start/game over/finishing logic fairly early on in the project, so it's basically "finished", although there might be a lot to do on the other parts. This is something I did here.

It might seem that more game content would be just incremental work. But again, creating and testing game content becomes increasingly painful as the game gains size. Add a level, it has to be tested. Add a monster type, all the rooms with it have to be tested. Add a weapon, all the areas have to be tested again.

No wonder games are sometimes pre-planned before coding anything. But I find it infinitely boring to try to design a whole game beforehand and then just code it, as lot of the fun arises from trying varieties and discovering things as I go along.

I'm also speculating that fatigue strikes because incremental work stages are boring. The first coding stages often bring an euphoria of seeing exponential results as a result of tiny amount of work or changes.

You'll need a Commodore 64 computer or a C64 emulator to play this game.

Direct download of D64 disk image with Commodore 64 and Plus/4 programs
Digiloi at csdb
At plus4world

Download the prg for the Commodore plus/4 speeded-up demo version here

Sunday, 23 December 2018

Chessboard modification


I received a 30cm chessboard box that was in a slightly poor condition. I have a better box in better shape (pictured above) so this was an opportunity to modify the damaged one.

The set is nostalgic for me as I played with similar pieces a lot during my childhood and youth in the 1980s-1990s. I believe these sets and likely the design itself originated somewhere in what was then the Soviet Union, and come in numerous variants and varying build quality. I have no idea how typical these might have been over there.

I am especially fond of the bishops, with no distracting "mitre" or knobs on them.

Admittedly the board is a bit dense for playing, although it looks visually pleasing to me and given the history I'm hardwired to accept this as a normal chessboard.

A board with slightly larger squares could still come handy. The goal at first was to increase the size of the playing squares, but I also became quite interested in the surface treatment.

Half board removed. The amount of dust is spectacular.
The box is 300 x 300 sized, with the original borders it makes the effective play area about 280 x 280 with 35 x 35 mm squares.

To fit this more with my blog theme, I used a Commodore 64 BASIC loop to calculate the measures. So, without the borders the square size becomes 300/8=37.5


The box is slightly deeper than it is wide, so I used 151.5/4 to get the other square dimension for each half-board, which was 37.875. Although this kind of precision is somewhat pointless for my handiwork, it is important for adding up the cumulative measures.

Sanding away the existing squares was the most boring work stage, although the actual sanding likely didn't take much more than 30 minutes altogether. The staining and lacquer treatment requires the surface to be well finished, and I used 80, 120, 240 and 320 grit sanding paper to get there.


Woodstaining

The measure marks were made to all edges of the board, then I used a paper knife along a ruler to pull grooves across and along the plywood. This means that when I brush in the dye, it won't be absorbed over the square edges.

Carefully testing the board, the pieces don't touch the stained parts yet
Still, the brushwork needs to be careful. It was better to allow the liquid to flood towards the edge instead of trying to brush directly along the grooves. Firstly, the absorption effect is quite forceful, and secondly, the brush could also easily touch the other square which would be "goodbye, board" to me.

The cuts across need to be quite deep whereas the cuts along can be shallow.


Lacquer

After letting the staining dry overnight, I applied urethane alkyd lacquer on the surface. One layer of the lacquer was nearly enough to make the kind of smooth surface I looked for. After 24h drying I made a light in-between sanding with the 320 grit paper, wiped out the dust with a moist rag, waited a bit and added another layer.

But after half an hour I dared to test the whole set. (This is still without the lacquer)
Afterwards I'm quite happy with the surface. I did get those tiniest bubbles for both layers. This might be unacceptable in a continuous table surface, but with this kind of checkered board it is not too visible. If you look for them they are there.

Can the bubbles be avoided? It turns out I had not heeded the instructions: the first layer ought to be thinned by 20% and multiple thin layers would be better than 1-2 thick layers. Also, a proper brush might have helped reduce the "bubbles".

Comparing the new width squares with the old.
The paper knife technique has the weakness that the grooves will remain visible. More often than not paints and lacquers tend to highlight scratches, dirt and unevenness, than smooth them out. Still, I don't think these grooves are ugly.

An alternative approach might have been to make a new board layer entirely from plywood and glue it on top of the existing one, this way I could have avoided the sanding. But it would have been a different project.



Thursday, 13 December 2018

Panasonic JR-200 emulation

Feeling a bit nostalgic, not only because it's an old computer, but because the early days of this blog was very much about Panasonic JR-200UP.

At that time I had hoped I could code something on the platform, especially as Marq went through the trouble of finding about most of the hardware and I spent time figuring out the tape format.

The lack of an emulator discouraged me, as I tend to code with extremely short build cycles, compiling the code every few seconds almost. The fun and nostalgia of tape loaded binaries fades quite rapidly.

Panyansonic by FIT.
At one point the solution could have been a device that helps transfer the data rapidly to the real computer. Although it showed promise it begun to feel a bit fiddly altogether, and somewhat slow to set up compared to an emulator.

There has been James the Animal Tamer's JR200 emulation that I have never seen running, as it only runs on some Windows version. Also, the scanline/vblank emulation is apparently non-existent. The JR200 quite probably does not have a software-accessible, simple way to track the screen refresh accurately.

The trick is to rig the interrupt to work with the internal timer in that capacity, using an address to catch the currently written attribute, as in the Panyansonic and SR-200 intros made by FIT. I felt the emulator ought to be able to somehow work with this trick.


The Emulator

My emulation project had a few false starts over the years. I had to learn 8-bit assembly a bit more in the meantime and something about how chips work before I begun to have the mindset necessary for building an emulation. Again, I work on Processing/Java.

I did some limited C64 emulation for myself in the recent past, which was a simpler task in the sense that I didn't set the bar very high and there are existing emulators to compare it to. (More about this, maybe, one day).

Left: Incomplete handling of Carry flag at one opcode caused glitching in the SR-200 scrollers. Right: opcode fixed
Here I had to enter the realm of the 6800 processor which is not as familiar to me as the 6502, and hardware that only has been properly documented by Marq, and even that documentation is not entirely complete.

The experience with 6502 was of course very helpful. One early issue was that in 6800, the C flag is treated differently in Subtract with Carry, i.e. the opposite of how it works in 6502. But all in all, the stack commands and how the stack works with JSR, RTS, is quite similar. 6800 stores 16-bit values in HI-LO format instead of LO-HI, which can make things a bit more intuitive.

Over the years I've thought you need to be a genius to write an emulator, but it's not rocket science in the end. To me the key was to make the emulator do something visible in the first hours. So I wrote a few opcodes like INC addr16 and JMP opcode, after which I could already start looking at video emulation.

No joystick yet...
After a preliminary video mode was complete, I made a 256-entry switch-case list that treats each and every opcode as a separate entity. Non-implemented opcodes freeze the emulation and print out the address together with a list of opcodes that have so far been executed. This list can be used to track problems.

As the 6800 is very orthogonal the emulation code could be made much smaller. But it might have resulted in code that either doesn't work at all or works completely, which can be a very frustrating situation. So I guess I'm using an "agile" approach. The downside can be that early errors may be left hanging in some opcodes while rest of the similar instructions work, and these can be difficult to track.

Mind you, the emulation is far, far from complete, which is where the real difficulty lies. For my current purposes it doesn't really have to be complete, as I only wanted to ease the development of JR-200 code, if I ever get interested in that again. So, at least for now, it won't be a public project. I thought if it could run the tiny Nyansonic demo, then all would be well. And it sort of does.