Skip to content
Techniques & Technology

BOBs: Blitter Objects

Software sprites on the Amiga

BOBs used the Amiga's Blitter to draw sprites into the playfield—offering unlimited objects at the cost of CPU coordination and flicker-free rendering.

commodore-amigagraphicsspritesamigablitter

The Amiga has only 8 hardware sprites, each 16 pixels wide. For games needing more objects—or larger, more colourful characters—programmers used BOBs (Blitter OBjects). The Blitter copied sprite graphics into the playfield bitplanes, with masking to preserve the background. More flexible than hardware sprites, but requiring careful buffer management.

The name is Commodore’s. The 1985 ROM Kernel Manual calls the playfield objects its animation system moves with the blitter “Bobs, for ‘blitter objects’”, and describes the save–draw–restore cycle below as what the system does for you. Game programmers borrowed the word for their own routines: Dave Jones, writing up Menace for Amiga Format in 1990, explains that “many people refer to software sprites on the Amiga as BOBS, short for Blitter OBjectS, as they tend to be drawn using the blitter”, and that in Menace “the main ship is made up of hardware sprites, but all of the aliens are software sprites”.

BOBs vs hardware sprites

Feature Hardware sprites BOBs
Count 8 (or 4 attached) Unlimited*
Width 16 pixels fixed Any size
Colours 3 or 15 (attached) Playfield depth
Speed Zero CPU Blitter time
Background Automatic Requires save/restore

*Limited by Blitter time and frame budget.

The BOB rendering process

1. Save background

Before drawing, save what’s underneath:

save_background:
    ; Copy screen area to save buffer
    move.l  bob_x,d0
    move.l  bob_y,d1
    jsr     calc_screen_address

    ; Blit from screen to save buffer
    move.w  #$09f0,BLTCON0(a6)  ; A->D copy
    move.l  screen_addr,BLTAPT(a6)
    move.l  save_buffer,BLTDPT(a6)
    move.w  #(height<<6)|words,BLTSIZE(a6)

2. Draw BOB

Cookie-cut the sprite onto the screen:

draw_bob:
    ; A = mask data
    ; B = sprite data
    ; C = screen (background)
    ; D = screen (destination)

    move.w  #$0fca,BLTCON0(a6)  ; cookie cut minterm
    move.l  mask_ptr,BLTAPT(a6)
    move.l  image_ptr,BLTBPT(a6)
    move.l  screen_addr,BLTCPT(a6)
    move.l  screen_addr,BLTDPT(a6)

    ; Set modulos for screen width
    move.w  screen_mod,BLTCMOD(a6)
    move.w  screen_mod,BLTDMOD(a6)
    move.w  #0,BLTAMOD(a6)
    move.w  #0,BLTBMOD(a6)

    ; Start blit
    move.w  #(height<<6)|words,BLTSIZE(a6)

3. Restore background (next frame)

Before drawing at new position, restore old background:

restore_background:
    ; Copy save buffer back to screen
    move.l  last_screen_addr,BLTDPT(a6)
    move.l  save_buffer,BLTAPT(a6)
    move.w  #$09f0,BLTCON0(a6)
    move.w  #(height<<6)|words,BLTSIZE(a6)

Double buffering with BOBs

Essential for flicker-free BOBs:

; Frame N:
; - Display buffer A
; - Clear BOBs from buffer B (restore backgrounds)
; - Draw BOBs to buffer B
; - Swap: B becomes display, A becomes draw

frame_update:
    ; Wait for VBlank
    jsr     wait_vblank

    ; Swap display pointers
    move.l  draw_buffer,d0
    move.l  display_buffer,draw_buffer
    move.l  d0,display_buffer

    ; Update copper to show new display buffer
    jsr     update_copper

    ; Now safe to modify draw_buffer
    jsr     restore_all_bobs
    jsr     update_bob_positions
    jsr     draw_all_bobs

Pixel-accurate positioning

The Blitter works on word boundaries. For sub-word positioning:

draw_bob_shifted:
    ; Calculate shift amount (0-15)
    move.w  bob_x,d0
    and.w   #$000f,d0       ; pixel offset within word

    ; Put shift value in BLTCON0/1
    lsl.w   #4,d0           ; shift to position
    lsl.w   #8,d0
    or.w    #$0fca,d0       ; add minterm
    move.w  d0,BLTCON0(a6)

When shifting, you need an extra word:

  • 32-pixel BOB shifted = 3 words instead of 2

Sorting for draw order

BOBs must be drawn back-to-front (painter’s algorithm):

sort_bobs_by_y:
    ; Simple bubble sort (fine for small counts)
    ; Or use insertion sort as positions change incrementally
    ...

draw_sorted_bobs:
    lea     sorted_list,a0
.loop:
    move.w  (a0)+,d0        ; bob index
    bmi     .done           ; -1 = end of list
    jsr     draw_single_bob
    bra     .loop
.done:
    rts

Interleaved blitting

Overlap Blitter operations with CPU work:

; Don't wait after every blit
; Queue multiple operations

draw_multiple:
    jsr     start_bob1_blit  ; start blitter
    jsr     do_game_logic    ; CPU works while blitter runs
    jsr     wait_blitter     ; ensure done before next
    jsr     start_bob2_blit
    ; ...

Memory requirements

Component Size
BOB image width × height × planes
BOB mask width × height
Save buffer Same as BOB (per BOB)
Second screen Full screen size

Example: 32×32 BOB, 5 planes

  • Image: 32×32×5 = 640 bytes
  • Mask: 32×32 = 128 bytes
  • Save: 32×32×5 = 640 bytes per instance

Performance considerations

Factor Impact
BOB size Larger = slower
BOB count More = slower
Bitplane depth More planes = slower
Shifting Adds a word to every row: a 2-word BOB blits as 3
Screen width Affects modulo

Blitter cycle estimates

The Hardware Reference Manual gives the cost per word: a blitter cycle is four clock ticks minimum, plus two if channel B is enabled and two more if both C and D are. A cookie-cut (A, B, C and D) is therefore eight ticks per word, and an A→D copy four; the manual’s formula is t = n × H × W / 7.09 microseconds on PAL, with n the ticks per cycle and H and W the height and width in words, ignoring setup and DMA contention. For a 32×32 pixel BOB on a 5-bitplane playfield:

  • 32 pixels = 2 words horizontally (3 if shifted to an arbitrary pixel position)
  • 32 lines tall × 5 bitplanes = 160 line-passes
  • Draw: 2 words × 160 passes × 8 ticks = 2,560 ticks, about 360 microseconds — 1.8% of a 20ms frame
  • Save and restore: two A→D copies of 2 × 160 × 4 = 1,280 ticks each

The full save–draw–restore cycle for that BOB is about 5,100 ticks, roughly 720 microseconds or 3.6% of the frame, so blitter time alone caps a screen of such BOBs in the high twenties before the playfield, the CPU’s own chip-RAM accesses and game logic take their share. Dave Jones’s Menace aliens were 32×24 in three planes, which is why the game could afford a screenful of them.

Hybrid: hardware sprites alongside BOBs

Many games combine both: hardware sprites for the player (always visible, never flickers, automatic background priority) + BOBs for enemies, bullets, and items (unlimited count, full bitplane colour). The two approaches cooperate:

  • Hardware sprites override BOBs at the pixel level via the playfield-vs-sprite priority bits in BPLCON2
  • The hardware-sprite count budget (8 total, paired into 4 attached for 15-colour sprites) usually goes to the protagonist
  • Everything else is BOB territory

Menace is the textbook layout — hardware sprites for the ship, BOBs for the aliens. Codetapper’s Sprite Tricks analyses document the opposite arrangement in later games: Risky Woods builds its 16-colour background layer from all eight hardware sprites repositioned across the screen, R-Type 2 uses the eight sprites for a 64-pixel repeating background pattern on most levels, and Jim Power draws its static background with two sprites repositioned across the line, keeping the rest for the main character, the status bar and player bullets. In each case the actors are BOBs and the sprites, freed from bookkeeping against the playfield, become scenery.

See also

Not yet fact-checked. This entry was drafted by an AI and nobody has verified it. The dates, figures and technical details may be wrong. Use it to find your bearings, then confirm anything that matters against a primary source.