Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

8.6KB

Technical Plan — Skirmish (C64 6502 Assembly)


1. Architecture Overview

┌─────────────────────────────────────┐
│         Main Loop (Interrupt)       │
├─────────────────────────────────────┤
│  1. Read Input                      │
│  2. Update Game State               │
│  3. Update Sprites/Screen           │
│  4. Check Win/Lose                  │
└─────────────────────────────────────┘
        ↓
┌─────────────────────────────────────┐
│      Game State Machine             │
├─────────────────────────────────────┤
│  WAITING_FOR_INPUT (player turn)    │
│  EXECUTING_MOVE (animate & check)   │
│  ENEMY_TURN (AI + animation)        │
│  CHECK_WIN (end condition)          │
└─────────────────────────────────────┘

2. Memory Layout (64 KB)

$0000–$00FF:  Zero page (save $F0–$FF for OS)
$0100–$01FF:  Stack
$0200–$1FFF:  BASIC ROM area (will be replaced by our code)
$2000–$2FFF:  Screen RAM (1000 bytes @ $2000)
$3000–$3FFF:  Color RAM (1000 bytes @ $3000)
$4000–$5FFF:  Game code + data
$6000–$CFFF:  Free (more game code, sprites, etc.)
$D000–$DFFF:  I/O (VIC-II, SID, CIA) — READ-ONLY, memory-mapped
$E000–$FFFF:  Kernal ROM (on-chip, can be banked out for RAM)

Key allocation:
  – Code (main + subroutines): $4000–$5FFF (~8 KB)
  – Sprite data: $5800–$5FFF (shared with code, or higher if we're careful)
  – Game state: $0200–$02FF (zero page + 256 bytes)
  – Lookup tables: $6000–$7FFF (grids, distances, etc.)

3. Zero-Page Variables (Critical Path)

$F0–$FE: Temporary registers (reusable per subroutine)

Game State Variables:
$30    INPUT_KEY        ; Last key pressed ($00 = none)
$31    GAME_STATE       ; 0=INPUT, 1=MOVE, 2=ENEMY, 3=CHECK
$32    SELECTED_UNIT    ; 0–2 (player unit index) or 255 (none)
$33    TURN_COUNTER     ; Turn number (0–255+)
$34    PLAYER_UNITS     ; Count of alive player units (0–3)
$35    ENEMY_UNITS      ; Count of alive enemy units (0–3)

Unit State Array (6 units × 4 bytes each = 24 bytes, $40–$57):
  Each unit:
    +0  X position (0–7)
    +1  Y position (0–7)
    +2  HP (0–3, or 0 = dead)
    +3  Team (0 = player, 1 = enemy)
    
Layout:
  $40–$43: Unit 0 (player)
  $44–$47: Unit 1 (player)
  $48–$4B: Unit 2 (player)
  $4C–$4F: Unit 3 (enemy)
  $50–$53: Unit 4 (enemy)
  $54–$57: Unit 5 (enemy)

$58    MOVE_DEST_X      ; Target X for current move
$59    MOVE_DEST_Y      ; Target Y for current move
$5A    MOVE_VALID       ; Flag: move is valid (0/1)

4. Grid Representation

Physical Grid: 8×8 = 64 cells
Occupancy Array: $6000–$603F (one byte per cell, index = Y*8 + X)

  • $FF = empty
  • 0–5 = unit index (0–5)

On each frame, rebuild occupancy from unit state array.

Sprite Rendering:

  • Each unit is a single C64 sprite (13×21 pixels, or 12×21)
  • Position calculation: X_pixel = (unit_x * 40) + offset, Y_pixel = (unit_y * 25) + offset
  • Adjust offsets to center sprite in grid cell

5. Main Game Loop

; Interrupt handler (triggered 60x/sec on NTSC, 50x on PAL)
IRQ_HANDLER:
  Save registers (A, X, Y)
  
  ; 1. Read input
  JSR INPUT_READ
  
  ; 2. Update game state
  CASE GAME_STATE
    0 => Player input → select/move/attack
    1 => Animate move, resolve collision/damage
    2 => Enemy AI, animate enemy moves
    3 => Check win/lose, advance state
  
  ; 3. Render sprites & text
  JSR SPRITE_UPDATE
  JSR TEXT_UPDATE
  
  Restore registers
  RTI

6. Subroutine Checklist

Input & Selection

Name In Out Cost
INPUT_READ $30 (key code) 10 cyc
UNIT_SELECT $30 (key) $32 (unit) 20 cyc
UNIT_MOVE $32, $58, $59 $5A (valid) 40 cyc
UNIT_ATTACK $32, target unit HP update 30 cyc

Game Logic

Name In Out Cost
FIND_CLOSEST_ENEMY $32 (player unit) $F0 (enemy idx) 50 cyc
ENEMY_MOVE $F0 (enemy idx) Update unit pos 80 cyc
ENEMY_AI Execute all enemies 300 cyc
CHECK_WIN Set GAME_STATE 20 cyc

Rendering

Name In Out Cost
SPRITE_UPDATE Unit state VIC-II regs 100 cyc
TEXT_UPDATE Game state Screen RAM 50 cyc
REBUILD_OCCUPANCY Unit state Occupancy array 60 cyc

7. Key Algorithms

Manhattan Distance

; Input: X in $F0, Y in $F1 (target); A (own X), $F2 (own Y)
; Output: A (distance)
MANHATTAN:
  SEC
  SBC $F0            ; A = own_x - target_x
  BPL +              ; If positive, skip
  EOR #$FF
  ADC #$01           ; Negate (two's complement)
+ STA $F3            ; Save |dx|
  
  LDA $F2
  SEC
  SBC $F1            ; A = own_y - target_y
  BPL +              ; If positive, skip
  EOR #$FF
  ADC #$01           ; Negate
+ CLC
  ADC $F3            ; A = |dx| + |dy|
  RTS

Grid Occupancy Check

; Input: X in $F0, Y in $F1
; Output: A = unit index (or $FF if empty)
GRID_OCCUPIED:
  LDA $F1
  ASL
  ASL
  ASL               ; A = Y * 8
  CLC
  ADC $F0           ; A = Y*8 + X
  TAX
  LDA $6000,X       ; Lookup in occupancy array
  RTS

8. State Transitions

WAITING_FOR_INPUT
  ↓ [Player selects unit]
  ↓ [Player moves/attacks]
EXECUTING_MOVE
  ↓ [Move resolves, damage applied]
ENEMY_TURN
  ↓ [Each enemy acts]
  ↓ [Wait for animations]
CHECK_WIN
  ↓ [If enemy count = 0 or player count = 0]
GAME_OVER (win/lose)
  ↓ [Display result, wait for restart key]
WAITING_FOR_INPUT [loop]

9. Build & Run

Development tools:

  • cc65 (C-to-6502 compiler, includes assembler ca65 and linker ld65)
  • VICE (Commodore 64 emulator, with debugger)
  • Makefile or shell script to assemble & link

Command sequence:

ca65 main.asm -o main.o           # Assemble
ld65 main.o -C c64.cfg -o game.prg  # Link
x64sc game.prg                      # Run in VICE

10. Implementation Order (MVP Priority)

  1. Kernel & Interrupt Handler — Get IRQ handler ticking
  2. Sprite Rendering — Display 6 units on screen
  3. Grid & Occupancy — Manage unit positions
  4. Input & Unit Selection — Player can select a unit
  5. Movement & Collision — Player can move units (no combat yet)
  6. Combat & Damage — Attack resolves HP
  7. Enemy AI — Simple greedy pathfinding
  8. Win/Lose Detection — Game ends correctly
  9. Polish — Text output, feedback, cleanup

11. Known Pitfalls & Mitigations

Risk Mitigation
Interrupt handler exceeds raster line Use raster-stable jitter removal; keep subroutines cycle-predictable
Sprite overlap (>8 on screen) Multiplex later; for now, 6 sprites fit without overlap
Occupancy array corruption Rebuild every frame from unit state; don't write directly
AI hangs/slowdown Limit enemy AI to 1 move each; use lookup tables for distance
Collision bugs Test grid occupancy before allowing move; confirm unit dies at 0 HP

12. File Structure

skirmish-game/
  src/
    main.asm          # Entry point, IRQ handler, main loop
    input.asm         # Input polling, key handling
    game-logic.asm    # Unit selection, movement, combat
    enemy-ai.asm      # Pathfinding, enemy turn
    render.asm        # Sprite updates, text output
    data.asm          # Lookup tables, sprite/tile data
  assets/
    sprites.chr       # C64 sprite design (binary)
    tiles.chr         # Tile data (if used)
  docs/
    GDD.md            # Game design (this file)
    TECHNICAL-PLAN.md # Technical details (this file)
    C64-CHEATSHEET.md # Quick register/memory reference
  Makefile            # Build script
  c64.cfg             # cc65 linker config (if using cc65)
  README.md           # Build & run instructions

13. Next Steps

  1. Choose assembler: cc65 + ca65/ld65 (recommended) or ACME
  2. Set up build environment on your machine
  3. Write skeleton main.asm (entry point + IRQ stub)
  4. Create sprite test (render 6 colored squares)
  5. Implement zero-page variables
  6. Add input handler (keyboard or joystick)
  7. Iterate gameplay logic

Powered by TurnKey Linux.