• Skip to main content
  • Skip to header right navigation
  • Skip to site footer
Retro Game Coders

Retro Game Coders

Retro computer/console game + dev community

  • About
    • Retro Computer Collection
    • Contact
  • Blog
  • Retro Resources
    • Retro Gaming Timeline
    • Online Retro IDE
    • Retro Pixel Art Editor
    • Dungeon Loom Map Editor
    • 6502 Programmer’s Reference
    • Emulators
      • Acorn Electron
      • Amstrad CPC Emulator
      • Online BBC Micro Emulator
      • Commodore PET Emulator
      • Browser C64 Emulator
      • DOSBox/DOS PC emulator
      • Tandy CoCo/Dragon
    • Best Retro YouTube Channels
    • New Retro Books
    • Raspberry Pi Amiga Emulation
    • MiSTer FPGA Tutorial
    • BMC64 C64 Pi
  • Community

Home » Retro Game Coders Blog » Programming

Pet-Type: Commodore PET Horizontal Shootemup in C

PET-Type Commodore PET Shoot-em-up

Picking back up my R-Type clone for the Commodore PET – converted to C using the CC65 compiler

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.

Join Retro Game Coders Community
Join the Retro Game Coders Community

Capturing the Spirit of a Classic

My project draws inspiration from Irem’s iconic 1987 arcade game R-Type, though obviously with significant adaptations for the PET’s limited hardware.

IREM arcade flyer for R-Type in Japan
IREM arcade flyer for R-Type in Japan

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.

PET-Type Commodore PET Shoot-em-up
PET-Type now using CC65/C

Commodore PET Technical Constraints

  • 1MHz CPU vs Irem’s 16-bit M72 arcade system with co-processors in the original
  • Character-based movement and collision vs pixel-perfect sprites and scrolling via hardware
  • Limited to no sound capabilities vs Yahama synthesised sound with dedicated z80 co-processor

Core Mechanics (classic “dodge and shoot” gameplay loop):

R-Type Arcade System
R-Type Arcade System

R-Type had smooth pixel-perfect scrolling, I’m implementing character-by-character scrolling and using PETSCII characters creatively to suggest a sci-fi environment.

The scrolling still creates a sense of progression and discovery, even without the colours and details.

  • Player ship that move in 4 directions and can shoot
  • Pre-set enemy patterns and movement – Players learn the patterns to make significant progress.
  • Basic collision detection

My planned tile system will allow for R-Type-style level layouts, but not be as large or as detailed.

Key Missing Features

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.

  • No Force pod (R-Type’s iconic drone-like power-up system)
  • Simpler enemy patterns due to character-grid movement and lack of memory
  • No charge-up beam system (though I could implement a more basic version)

💬 Questions or comments? Head over to the community to discuss!

The Conversion Journey: Assembly to C

Converting from TRSE and 6502 assembly to C using CC65 was an interesting challenge. My original assembly code used direct hardware access for screen manipulation and keyboard input. I needed to preserve what was good while making it more readable and extendable for me by porting the logic to C.

Key Challenges:

Memory Management

My original assembly code, by nature of assembly, used direct memory access via labels, and especially used zero-page locations. Most of the code switched over to using named variables, but I kept zero page usage for: text pointer (0x68), destination (0x6A), map pointer (0x6C), and screen destination (0x6E)

Screen Handling

Assembly version had direct screen memory manipulation using PETSCII character codes. I kept the direct screen memory access at 0x8000 but converted to an easier to read and understand functional approach.

I am also experimenting with double buffering for smoother, flicker-free screen updates / animation.

Maintained the 40×20 character display constraints to give the widescreen effect and also keep screen processing to a minimum.

Had to map key PET hardware registers in C:

  • Interrupt flag (0xe813)
  • Timer location (0xe840)

So why use C if the assembly obviously worked?

Yes, the assembly and TRSE development environment worked to get an initial demo working, I increasingly was getting lost or refactoring just so I understood my own project. Using a more familiar higher level language, with the option to drop down to low-level assembly, provides quality of life and maintainability benefits.

  1. Structured Data Types

    • Introduced proper C structures for game entities:

      struct Enemy {
      int x, y;
      unsigned char active;
      unsigned char sprite;
      unsigned char move_type;
      unsigned char move_counter;
      };

  2. Function Organization

    • Broke down my monolithic assembly code into logical C functions and header files
    • Created clear separation between screen management, game logic, and input handling
    • Maintained direct hardware/memory access where needed for performance

New Features

The C conversion allowed me to add several features that would have been more challenging in assembly:

Enemy movement system
Enemy movement system
  1. Enhanced Enemy System

    • Multiple enemy types with different movement patterns
    • Proper enemy state management
    • Movement counter for timing animations
  2. Improved Bullet System

    • More sophisticated projectile handling
    • Better collision detection
    • Active state management
  3. Better Screen Management

    • The option of double buffering implementation
    • More efficient screen updates
    • Better vsync handling

While C code is naturally thought of as being less efficient than hand-crafted assembly, a lot of the bloat is highly dependent on the specific compiler, plus I’ve implemented several optimizations to maintain good-enough performance:

  1. Memory Access

    • Strategic use of zero page for critical variables
    • Direct memory writes for screen updates
    • Efficient buffer management
  2. Display Updates

    • Synchronized with vertical blank
    • Character-based sprite system rather than simulate “chunky pixels”
    • Optimized screen buffer copying

Current State of Play

The game right now has a fairly solid foundation in C while maintaining as much as possible of the performance of my original assembly version. The codebase is definitely more maintainable and easier to extend, while still taking into account the hardware limitations of the PET.

Planned Improvements

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.
};

  • Tile properties defined in the separate configuration above, with enemy placement via ID.
  • Simple text-based level files for easy visualisation and editing without having to make a map editor tool (yet).
  • Support for multiple levels with more memory-efficient tile and map storage (my original array stores a lot of unnecessary data but makes it quick and easy to render)
Original map was a huge array full of waste
Original map was a huge array full of waste

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.

Other Planned Features

  1. Simple sound effects using the PET’s single-bit audio output (basic beeps for shooting, collisions, etc.)
  2. More enemy types and patterns
  3. Power-up system
  4. Enhanced collision detection
  5. Level progression

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.

Technical Considerations

Memory Budget

  • Screen Memory: 800 bytes (40×20)
  • Tile Data: ~256 bytes for tile properties
  • Level Data: Variable based on map size
  • Game Logic: Remaining available RAM

Performance Impact

  • Need to optimize tile lookups
  • Efficient map scrolling algorithms
  • Careful memory access patterns
  • Balance between features and speed

The tile system will need careful optimization to maintain a smooth gameplay experience while adding the flexibility of proper level design.

Bottom Line

I am no more an expert in C than I am in 6502 but I can at least understand it better than I did, which counts for a lot. 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 difficult but fun exercise in working within the constraints of truly vintage hardware while attempting/implementing modern game design patterns!

Category: ProgrammingTag: commodore pet, Retro C/C++ Programming, TRSE (Turbo Rascal) Programming
Previous Post:C programming for the BBC MicroProgram the BBC Micro in C with VBCC for 6502 on MacOS Using Docker
Next Post:Commodore 64 Text Adventures: Objects and ActionsCommodore 64 Text Adventures Part 2

Retro Game Coders

Retro computer/console game + dev programming community by Chris Garrett

  • Bluesky
  • Threads
  • Facebook
  • Instagram
  • YouTube
  • Mastodon

Maker Hacks ・ D6Combat・chrisg.com

© Copyright 2026 Chris Garrett

Privacy ﹒ Terms of Service

Return to top