Back in 2021, I started working on a game for the Commodore PET. The original version was written in pure 6502 assembly, via TRSE - a challenging but rewarding experience.
Life happened, and the project sat dormant until this weekend when I decided to dust it off and give it new life by converting it to C using the CC65 compiler.
My project draws inspiration from Irem's iconic 1987 arcade game R-Type, though obviously with significant adaptations for the PET's limited hardware.
While I can't match the arcade's beautiful 16-bit graphics or complex sprite system, I can capture some of the core elements that made R-Type special:
Horizontal Scrolling
Core Mechanics
Level Design Philosophy
Technical Constraints
I can't recreate R-Type's technical achievements, but I can capture elements of what made it engaging:
My goal isn't to clone R-Type (even if that was possible), but to create an engaging shooter for the PET that pays homage to it.
Converting from assembly to C using CC65 was an interesting challenge. My original assembly code had direct hardware access for screen manipulation and keyboard input. I needed to preserve what was good while making it more readable and maintainable in C.
Memory Management
Screen Handling
Hardware Register Access
So why use C if the assembly obviously worked?
Using a higher level language, with the option to drop down to low-level assembly, gives us the quality of life and maintainability benefits.
Structured Data Types
struct Enemy {
int x, y;
unsigned char active;
unsigned char sprite;
unsigned char move_type;
unsigned char move_counter;
};
Function Organization
The C conversion allowed me to add several features that were challenging in assembly more easily:
Enhanced Enemy System
Improved Bullet System
Better Screen Management
While C code is generally less efficient than hand-crafted assembly, I've implemented several optimizations to maintain performance:
Memory Access
Display Updates
The game now has a solid foundation in C while maintaining much of the performance characteristics of my original assembly version. The codebase is more maintainable and easier to extend, while still taking into account the hardware limitations of the PET.
Currently, the game uses a hard-coded array for level data. My next major update will implement a proper tile-based map system:
Map Structure
struct MapTile {
unsigned char type; // Tile type (wall, floor, hazard, etc.)
unsigned char properties; // Collision, damage, etc.
};
Level Format
Map Loading
This will make it much easier for me to create and modify levels, as well as add different types of environments to the game.
The trick will be implementing this without causing any added slow-downs in gameplay.
Note about sound: The stock Commodore PET only has a single-bit output through the CB2 line, which means I'm limited to basic beeps and buzzes. While this is quite limiting compared to later Commodore machines like the C64 with its SID chip, I can still use simple sound effects to enhance the gameplay experience. These will need to be carefully timed using the CPU, as there's no dedicated sound hardware to offload to.
The tile system will need careful optimization to maintain a smooth gameplay experience while adding the flexibility of proper level design.
Converting from assembly to C has opened up new possibilities for extending my game while teaching me valuable lessons about both languages.
The planned tile system will significantly improve my current hard-coded approach, making the game more engaging and easier to expand.
This project continues to be a fun exercise in working within the constraints of truly vintage hardware while attempting/implementing modern game design patterns!