Don't give up on the standard LCD 2x16 or 2x20 displays. About twenty years ago, I designed a set of LCD screens for a line of home theatre processors; however, through careful design, I was able to make it appear that there were more than eight custom chars. I have attached some of these below. The display driver automatically updated the CGRAM using custom fonts, which made coding the screen much easier! I flagged the custom font characters in a shadow register the same size as the string written to the LCD. The custom fonts included true descenders for lowercase, small caps, reverse caps and reverse small caps, bold, plus special custom char categories. The 'big nums' used eight custom chars to put up two large nums, followed by a normal ASCII decimal point and tenth, plus dB, e.g., 12.4 dB, where the 12 is two rows high. The big numbers volume readout (easy to read at a distance) and the 5.1-channel VU meter were the most dynamic of these screens.

This looks like 9 custom characters are used. 6 for the symbol with 7 circles and 3 for the dts logo. How did you achieve that?
This one too:


This looks like way more than 8 custom characters!
The rest, I can understand how 8 CC was enough.
EDIT: No, I see it now. The 7 circles symbol is always symetrical, so only 4 CCs are needed. Very good!
Just to get it right. You have to store the bitmaps for the new characters in flash? You did not trick the display itself to use other characters?
Replying to PaulRB
Yes, that line is way more than 8! However, the complete set of 'big nums' is only for reference, as is the complete list of bar heights for the 6 dB resolution 5.1-channel VU meter. Everything else I showed is actual screen patterns. I am somewhat limited in my examples because I don't have a working example of the hardware. Indeed, as you have mentioned, symmetry and repetition are the keys to making pictures out of smaller graphical elements. None of the displays shown exceed eight custom characters. Indeed, the actual 'big nums' display, while you are changing the volume (using remote control vol up/down buttons), pops up a special screen with just the big nums volume, and when you stop changing the volume, the previous screen is restored. The process is fast enough that these screen popups and restores seem instantaneous. The big nums volume screen has something like this centered on the LCD: -26.5 dB
The 26 should be large (4 custom characters per digit), and the -, ., 5, d, and B are normal ASCII.
The custom characters driver automates writing a custom character bit map.
"Jay|"
"B L" (where B means use Bold custom font for J, L lowercase descender font for y)
This is displayed as Jay
If the required custom character is already in the CGRAM, the driver uses it without further ado. If it isn't present, it searches for a CGRAM location not currently displayed and rewrites that custom character with the required one. To aid in debugging and testing various screens, the driver flags the following conditions, writing '*' for CGRAM overflow (maximum custom characters = 8); '@' for Font not found; '#' for Custom character not found in font, by writing these flag chars onto the LCD screen so that you can see the problem. The screenwriting driver does all of the housekeeping. Essentially, you have to give it the screen position (0-39 for a 2x20 LCD) and a pointer to the string.
The 6-channel VU meter uses a Bar font containing eight custom character positions in the CGRAM, with 16 variations (and no bar for zero signal) loaded dynamically, as needed. It can do this without any visual glitches while updating several times a second, converting the highest audio waveform amplitude reported by the DSP chip since the last query sent to the DSP, then converting to dB by scanning the resulting 16-bit value for the highest bit position The bars are two chars wide, with the inter-character gap hidden by arranging for a gap in the center of each bar custom char. E.g., character Bar3 (-30 dB) of this font contains the following binary pattern: %00000 %00000 %00000 %00000 %00000 %11011 %11011 %11011. This is displayed in the top row, while a Bar8 (consisting of %11011 repeated eight times) is displayed in the bottom row. A zero channel signal is displayed using an ASCII space char (no custom char required). I have a page that explains this in a little more detail, which I could post here if you are interested in seeing it.
Replying to hmeijdam:
In my case, the bit maps (and program code) were stored in a 64 KiB EPROM. There are no CGRAM tricks that I know of, but the difference between manually manipulating CGRAM on the fly and having an automaton (a software driver) automate the process is night and day.
New edit:
Please let me know if anyone is interested in converting my 68HC11 assembly source to C for Arduino, which I would relish as my intro. into Arduino world. ![]()
To clarify my code fragment, the 17-byte stack frame pushed onto the stack is allocated to the 8- and 16-bit local variables for the SCREENS subroutine. The equ lines (equ stands for equate) allow me to access variables in the stack frame without remembering the numerical offset.
E.g., with index register x already pointed to the stack frame, instead of writing
staa 13,x
to store a byte in the CGRAM byte pointer, I can write
staa CGRAM,x
which makes the assembler code almost readable and much easier to debug!
(This HLL-like method of storing local subroutine variables on the stack is detailed in the book "Single- and Multiple-Chip Microcomputer Interfacing" by G. J. Lipovski)
;****************************************
;*
;* LCD Control Routines source file
;*
;*
;* Summary of subroutines:
;*
;* screen_position A=position (0-39)
;* Section_clear A=start position (0-39), B=end position (0-39), A < B
;* LCD_config Configure the LCD mode.
;* LCD_init Initialize display manager and clears screen.
;* LCD_init0 Initialize display manager only.
;* start_blinking Uses blink positions in 'blink_posns'
;* SCREENS A=position (0-39), Y=pointer to formatted string.
;* screen_out Y=pointer to formatted 40-character string.
;* (Note: screen_out calls SCREENS twice, and also LCD_init.)
;*
;* Error characters:
;*
;* * --- CGRAM overload (more than 8 custom characters)
;* # --- Custom character not found.
;* @ --- Font not found.
;*
;*
;****************************************
<big snip>
;************************************************************************
;*
;* SCREEN MANAGER
;*
;* This routine loads relevant custom characters and displays a string.
;* The N-character string must end with a '|' marker followed by N
;* spaces or font characters.
;*
;* Example string:
;* 'Large LCD display|'
;* ' L RRR L L'
;*
;* There can be up to 40 display characters before the '|' character,
;* with the corresponding font characters following, which is convenient
;* when constructing a display string on the fly (e.g., the VU meter):
;*
;* 'This very long string takes two lines!|'
;* ' L L L '
;*
;* Error messages: '*' CGRAM overflow! (maximum custom chars = 8)
;* '@' Font not found!
;* '#' Custom character not found in font!
;*
;* Use as: ldaa #screen_posn (0-39)
;* ldy #string_ptr
;* jsr SCREENS
;*
;***
SCREENS:
;* Local variables allocated on the stack:
chars_ptr: equ 0 ;Pointer to screen-data string
attrb_ptr: equ 2 ;Pointer into attributes line
CC_id: equ 4 ;Custom Char identifier (e.g. 'gL')
font_beg: equ 6 ;Font beginning pointer
font_end: equ 8 ;Font end pointer
len: equ 10 ;String length
len2: equ 11 ;String length copy
CC_space: equ 12 ;Character number (0-7)
CGRAM: equ 13 ;CGRAM pointer
curr_posn: equ 14 ;Current position on screen
end_posn: equ 15 ;String end position on screen
start_posn: equ 16 ;String start position on screen
pshx
pshy
tsx
psha ;Save screen start position
xgdx
subd #17 ;Reserve stack space
xgdx
txs ;x points to local variables
sty chars_ptr,x ;Store screen data pointer
;* Determine length of string to be output and set positions
ldaa start_posn,x ;Get screen start position.
staa curr_posn,x ;Initialize current position
staa end_posn,x ; and end position
clr len,x
clr len2,x
string_len:
inc len,x ;Increment length of string
inc len2,x
inc end_posn,x ;Increment end position
iny ;Get new data
ldaa 0,y
cmpa #'|' ;Check for end of string character
bne string_len
ldaa start_posn,x
jsr screen_position ;Go to correct place on screen
;* Scan the section of the screen to be written over
;* for custom characters and modify CC_table.
scan_image:
ldy #screen_image ;Pointer into screen image
ldab start_posn,x
aby ;Add start position
ldab len2,x
decb
aby ;Go to end of string
ldab 0,y ;Get screen image character
cmpb #8
blo CC_table_update ;Custom character?
inc_image_ptrs:
dec len2,x ;Update pointer
bne scan_image ;Check if all done
bra write_string
CC_table_update:
ldy #CC_table_num ;Point into CC occurrences
aby
dec 0,y ;Decrement occurrences
bra inc_image_ptrs
write_string:
ldy chars_ptr,x
ldab len,x
incb
aby
sty attrb_ptr,x ;Set pointer into attributes line
write_loop:
ldy attrb_ptr,x ;Get attribute in B
ldab 0,y
ldy chars_ptr,x ;Get character in A
ldaa 0,y
cmpa #'|' ;Check for end of string
beq end_of_string
cmpb #$20 ;Check if custom or not
bne do_custom
write_char:
staa CC_space,x ;Save character
pshx
ldx #regbase
bclr tmsk1,x,#%10001000 ;Disable OC1,OC5 interrupts
;while output is going on to avoid blink
;conflicts
pulx
<another big snip>
The following equates may help this make sense:
;************************************************
;*
;* Global Constants Include File
;*
;************************************************
include "c:\1work\eos-i\build.i"
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
;%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%
;%%%%%%%%%%%%%%%%% G L O B A L C O N S T A N T S %%%%%%%%%%%%%%%%%
;%%%%%%%%%%%%%%%%%% %%%%%%%%%%%%%%%%%%
;%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
ram_end: equ $03ff ;Top of 68HC11F1 RAM
ram_start: equ $0000
regbase: equ $1000
good for you
Encouraged by the number of people creating some character LCD version of Arduino space invaders (e.g., on YouTube), I am posting the following. I created it for the same 2x20 LCD mentioned, both as a test of the automatic LCD screen font loading discussed in this thread and as an easter egg paying tribute to the team who designed the home theater system alluded to in my post. I wrote using the same 68HC11 assembler mentioned. However, having just ordered an Arduino Uno kit, I plan to port some of these things to it. The entire Space Invaders animation sequence lasts about a minute, of which I have uploaded only three frames (from a VFD version which unlike the LCD screens I posted previously, was limited to 5x7 characters). Feel free to request a copy from me via email if you want a copy of the video. The entire sequence used 46 custom characters, but only eight at a time. I did not have time to code the explosion, but the custom characters are included. The original animation also has sound that is faithful to the original arcade game soundtrack.
Here are those custom characters:
;******************************************************************
;******************************************************************
Invader_out:
dc.b '0'
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %10001
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b '1'
dc.b %00000
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %10001
dc.b %00000
dc.b %00000
dc.b %00000
dc.b '2'
dc.b %00000
dc.b %00000
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %10001
dc.b %00000
dc.b %00000
dc.b '3'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %10001
dc.b %00000
dc.b '4'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %10001
End_Invader_out:
;******************************************************************
;******************************************************************
Invader_in:
dc.b '0'
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %01010
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b '1'
dc.b %00000
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %01010
dc.b %00000
dc.b %00000
dc.b %00000
dc.b '2'
dc.b %00000
dc.b %00000
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %01010
dc.b %00000
dc.b %00000
dc.b '3'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %01010
dc.b %00000
dc.b '4'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %01110
dc.b %10101
dc.b %01110
dc.b %01010
End_Invader_in:
;******************************************************************
;******************************************************************
Laser:
Laser0: dc.b 'a'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00100
dc.b %01110
dc.b %11111
dc.b %11111
Laser1: dc.b 'b'
dc.b %00000
dc.b %00000
dc.b %00100
dc.b %00100
dc.b %00100
dc.b %01110
dc.b %11111
dc.b %11111
Laser2: dc.b 'c'
dc.b %00100
dc.b %00100
dc.b %00100
dc.b %00000
dc.b %00100
dc.b %01110
dc.b %11111
dc.b %11111
Laser3: dc.b 'd'
dc.b %00100
dc.b %00100
dc.b %00000
dc.b %00000
dc.b %00100
dc.b %01110
dc.b %11111
dc.b %11111
Laser4: dc.b 'e'
dc.b %00100
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00100
dc.b %01110
dc.b %11111
dc.b %11111
Explo1: dc.b 'p'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %01110
dc.b %01110
dc.b %00000
Explo2: dc.b 'q'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %10101
dc.b %01110
dc.b %01110
dc.b %10101
Explo3: dc.b 'r'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %10001
dc.b %00100
dc.b %00100
dc.b %10001
Explo4: dc.b 's'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %10001
dc.b %00000
dc.b %00000
dc.b %10001
Explo5: dc.b 't'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
Shield1:dc.b 'y'
dc.b %01111
dc.b %11111
dc.b %11100
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
Shield2:dc.b 'z'
dc.b %11110
dc.b %11111
dc.b %00111
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
End_Laser:
;******************************************************************
;******************************************************************
UFO:
M1a: dc.b 'A'
dc.b %00000
dc.b %00011
dc.b %00111
dc.b %01101
dc.b %11111
dc.b %00111
dc.b %00010
dc.b %00000
M1b: dc.b 'B'
dc.b %11110
dc.b %11111
dc.b %11111
dc.b %01101
dc.b %11111
dc.b %01100
dc.b %00000
dc.b %00000
M1c: dc.b 'C'
dc.b %00000
dc.b %10000
dc.b %11000
dc.b %01100
dc.b %11110
dc.b %11000
dc.b %10000
dc.b %00000
M1d: dc.b 'D'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
M2a: dc.b 'I'
dc.b %00000
dc.b %00001
dc.b %00011
dc.b %00101
dc.b %01111
dc.b %00011
dc.b %00001
dc.b %00000
M2b: dc.b 'J'
dc.b %01111
dc.b %11111
dc.b %11111
dc.b %01101
dc.b %11111
dc.b %00110
dc.b %00000
dc.b %00000
M2c: dc.b 'K'
dc.b %00000
dc.b %11000
dc.b %11100
dc.b %01110
dc.b %11111
dc.b %11100
dc.b %01000
dc.b %00000
M2d: dc.b 'L'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
M3a: dc.b 'Q'
dc.b %00000
dc.b %00000
dc.b %00001
dc.b %00011
dc.b %00111
dc.b %00001
dc.b %00000
dc.b %00000
M3b: dc.b 'R'
dc.b %00111
dc.b %11111
dc.b %11111
dc.b %01101
dc.b %11111
dc.b %10011
dc.b %00000
dc.b %00000
M3c: dc.b 'S'
dc.b %00000
dc.b %11100
dc.b %11110
dc.b %01101
dc.b %11111
dc.b %01110
dc.b %00100
dc.b %00000
M3d: dc.b 'T'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
M4a: dc.b 'a'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00001
dc.b %00011
dc.b %00000
dc.b %00000
dc.b %00000
M4b: dc.b 'b'
dc.b %00011
dc.b %11111
dc.b %11111
dc.b %01101
dc.b %11111
dc.b %11001
dc.b %10000
dc.b %00000
M4c: dc.b 'c'
dc.b %10000
dc.b %11110
dc.b %11111
dc.b %01101
dc.b %11111
dc.b %00111
dc.b %00010
dc.b %00000
M4d: dc.b 'd'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %10000
dc.b %00000
dc.b %00000
dc.b %00000
M5a: dc.b 'i'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00001
dc.b %00000
dc.b %00000
dc.b %00000
M5b: dc.b 'j'
dc.b %00001
dc.b %01111
dc.b %11111
dc.b %01101
dc.b %11111
dc.b %11100
dc.b %01000
dc.b %00000
M5c: dc.b 'k'
dc.b %11000
dc.b %11111
dc.b %11111
dc.b %01101
dc.b %11111
dc.b %10011
dc.b %00001
dc.b %00000
M5d: dc.b 'l'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %10000
dc.b %11000
dc.b %00000
dc.b %00000
dc.b %00000
M6a: dc.b 'q'
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
dc.b %00000
M6b: dc.b 'r'
dc.b %00000
dc.b %00111
dc.b %01111
dc.b %11101
dc.b %11111
dc.b %01110
dc.b %00100
dc.b %00000
M6c: dc.b 's'
dc.b %11100
dc.b %11111
dc.b %11111
dc.b %01101
dc.b %11111
dc.b %11001
dc.b %00000
dc.b %00000
M6d: dc.b 't'
dc.b %00000
dc.b %00000
dc.b %10000
dc.b %01000
dc.b %11100
dc.b %10000
dc.b %00000
dc.b %00000
End_UFO:
Here is the entire 'Invaders' code mentioned previously (in the posting with three sample screen shots). Using a demo inspired by the Space Invaders arcade game demonstrates the simplicity of using an automated CGRAM custom font system to code character-based graphics (compared to the complexity that handling 46 custom characters would impose without automation). While this is written in 68HC11 assembler, the screen definition strings (i.e., the data structures) and font loading should be easy to follow. These parts will probably look the same in my port to the Arduino Uno.
;***************************************************************
;* Inv.s
;*
;* Possible Improvements:
;*
;* Use local variable delay routine.
;* Allow invaders to be destroyed with the laser.
;* Accelerate the invaders with each invader destroyed.
;* Left-right movement of laser together with manual firing.
;* Keep the existing demo mode intact, but also have a playable mode.
;* Increment the score by 25s and 100s, as appropriate.
;* Decrement the number of spare laser bases with each one destroyed.
;*
;***************************************************************
CLIST OFF ;Only list assembled conditionals.
MLIST OFF ;Don't expand macros.
inv_flag: equ 0
XDEF Invade
include "c:\1work\eos-i\xrefs.i"
include "c:\1work\eos-i\equates.i"
include "c:\1work\eos-i\macros.i"
Inv_vbl: Section 79
;%% Static buffer space in CPU RAM:
inv_line_out: ds.b 23
inv_line_in: ds.b 23
laser: ds.b 3
explode: ds.b 3
UFO: ds.b 9
Invs: Section 77
Invade: jsr LCD_init
;%% Misc constants:
RH_side: equ 13 ;Defines RHS of screen.
final_inv_position: equ 24 ;Number of invader moves in each wave.
number_of_waves: equ 2 ;Number of invasion waves.
High_score_frames: equ 20 ;Determines duration of high score screen.
;%% Local variables dynamically allocated on stack:
LR_position: equ 0 ;8-bit counter.
LR_flag: equ 1 ;8-bit flag.
invaders: equ 2 ;16-bit pointer.
run_counter: equ 5 ;8-bit invader run counter
laser_position: equ 6 ;8-bit position register
wave_counter: equ 7 ;8-bit invasion wave counter
tsx
xgdx
subd #7 ;Allocate local variables on stack
xgdx
txs
splash_screen:
jsr splash
inv_init:
jsr LCD_init
ldy #Inv_screen
jsr screen_out
delay 1500*10
ldaa #number_of_waves
staa wave_counter,x
new_wave:
jsr init_strgs
ldy #inv_line_out
sty invaders,x
ldaa #28
staa laser_position,x
ldaa #final_inv_position
staa run_counter,x
ldaa #1
staa LR_flag,x ;Go right
ldaa #0 ;Allows for 1 leading space on aliens.
staa LR_position,x ;Start at LH end
;----------- MAIN LOOP ------------
inv_loop:
ldaa laser_position,x
ldy #laser
jsr SCREENS
ldaa LR_position,x
ldy invaders,x
jsr SCREENS
ldaa LR_flag,x
cmpa #1 ;Determine direction...
bne .left
.right: inc LR_position,x
inc LR_position,x
.left: dec LR_position,x
ldaa LR_position,x
RH_check:
cmpa #6 ;Reached RH end?
bne LH_check
ldaa #$ff ;Flag left move
staa LR_flag,x
jsr move_down
bra new_invs
LH_check:
cmpa #0 ;Reached LH_end?
bne new_invs
ldaa #1 ;Flag right move
staa LR_flag,x
jsr move_down
new_invs:
ldy invaders,x
cpy #inv_line_out
bne legs_out
legs_in:
ldy #inv_line_in
bra inv_line
legs_out:
ldy #inv_line_out
inv_line:
sty invaders,x
jsr tick
delay 800*10 ;Initial speed is approx. 1.25 Hz.
dec run_counter,x ;Have invaders reached final position?
beq final_stage ;Yes...
fire_laser:
ldy #laser ;No, continue firing laser...
ldaa 0,y
cmpa #'e' ;Last frame in animation sequence?
blt fire_next
reload_laser:
ldaa #'a'-1 ;First frame in animation sequence.
staa 0,y
fire_next:
inc 0,y
ldaa 0,y
cmpa #'b' ;Laser firing frame?
bne end_loop
jsr chirp ;Sound for laser beam.
end_loop:
jmp inv_loop
;---------- FINAL STAGE ------------
final_stage:
jsr explode_laser
delay 1000*10
jsr UFO_fly_by ;Occurs at the end of each wave.
dec wave_counter,x
beq finals
jmp new_wave ;Go get another invasion wave.
finals: delay 2000*10
jsr LCD_init
ldaa #High_score_frames
staa run_counter,x ;Using as a loop counter here.
ldy #high_scores
jsr screen_out
delay 400*10
score_loop:
ldaa #5 ;"o" in Scores
ldy #high_scores_I
jsr SCREENS
delay 400*10
ldaa #5 ;"o" in Scores
ldy #high_scores_O
jsr SCREENS
delay 400*10
dec run_counter,x
bne score_loop
jsr LCD_init
delay 500*10
jmp splash_screen
;------------------------------------
;Note: The following return locks up the main EOS_com.s code.
Never:
tsx
xgdx
addd #7 ;Deallocate local stack variables.
xgdx
txs
rts
;*******************************************************
;*
;* Move Down
;*
;***
move_down:
ldy #inv_line_out
ldaa 1,y
cmpa #4
beq move_end ;If all the way down, do nothing
ldab #5 ;Move 5 invaders down one row...
mve_loop:
inc 1,y ;Do outies (skip leading space)
inc 24,y ;Do innies (skip leading space)
iny
iny
decb
bne mve_loop
move_end:
rts
;*******************************************************
;*
;* Explode Laser
;*
;***
explode_laser:
ldaa laser_position,x ;wipe out laser.
tab
jsr Section_clear
rts
;replace the above with this code:
ldaa #0
ldab #16
jsr Section_clear ;Clear top row of LCD except 000.
delay 1000*10
ldy #laser+4 ;1st explosion frame.
explode_loop:
ldaa laser_position,x
jsr SCREENS
ldaa 0,y
cmpa #'t' ;Last frame in animation sequence?
beq explode_exit
inc 0,y
delay 350*10 ;Do explosion noise here later.
bra explode_loop
explode_exit:
rts
;*******************************************************
;*
;* UFO Fly By
;*
;***
UFO_fly_by:
ldaa #0
ldab #16
jsr Section_clear ;Clear top row of LCD except for 000.
ldy #laser ;Make sure main laser frame matches spares
ldd #'a|' ; during fly-by to conserve CGRAM.
std 0,y
ldaa laser_position,x
jsr SCREENS
ldaa #0
staa LR_position,x
UFO_loop:
jsr chirp
ldy #UFO
ldd #'AB'
std 0,y
ldd #'C '
std 2,y
stab 8,y ;Clear leading space font
ldaa #'U'
staa 5,y ;Make trailing space UFO font
ldaa LR_position,x
jsr SCREENS
delay 120*10
jsr chirp
ldd #'IJ'
std 0,y
ldd #'KL'
std 2,y
ldaa #'U'
staa 8,y ;Make leading space UFO font
ldaa LR_position,x
jsr SCREENS
delay 120*10
jsr chirp
ldd #'QR'
std 0,y
ldd #'ST'
std 2,y
ldaa LR_position,x
jsr SCREENS
delay 120*10
jsr chirp
ldd #'ab'
std 0,y
ldd #'cd'
std 2,y
ldaa LR_position,x
jsr SCREENS
delay 120*10
jsr chirp
ldd #'ij'
std 0,y
ldd #'kl'
std 2,y
ldaa LR_position,x
jsr SCREENS
delay 120*10
jsr chirp
ldd #' r'
std 0,y
staa 5,y ;Clear trailing space
ldd #'st'
std 2,y
ldaa LR_position,x
jsr SCREENS
delay 120*10
inc LR_position,x
ldaa LR_position,x
cmpa #RH_side ;Reached RH side?
beq UFO_exit
jmp UFO_loop
UFO_exit:
ldaa #0
ldab #16
jsr Section_clear ;Clear top row of LCD except for 000.
;(frees up some CGRAM for next wave).
rts
;*******************************************************
;*
;* Sound when invaders move.
;*
;***
tick: pshy
pshx
psha
ldy #2 ;Duration.
ldaa #100 ;Frequency.
bra .t1
;*******************************************************
;*
;* Sound when laser fires.
;*
;***
chirp: pshy
pshx
psha
ldy #8 ;Chirp length.
.t1: ldx #regbase
bset porta,x,#%01000000
.t2: deca
bne .t2
bclr porta,x,#%01000000
ldaa #50 ;Chirp pitch.
.t3: deca
bne .t3
dey
bne .t1
pula
pulx
puly
rts ;** Return **
;*******************************************************
;*
;* Initialize string variables
;*
;* inv_line_out: ' 0 0 0 0 0 |'
;* ' O O O O O '
;*
;* Inv_line_in: ' 0 0 0 0 0 |'
;* ' I I I I I '
;*
;* Laser: 'a|'
;* 'P'
;*
;* Explode: 'i|'
;* 'P'
;*
;* UFO: 'IJKL|', etc.
;* 'UUUU'
;***
init_strgs:
ldy #inv_line_out
ldd #' 0'
std 0,y
std 2,y
std 4,y
std 6,y
std 8,y
ldd #' |'
std 10,y
ldd #' O'
std 12,y
std 14,y
std 16,y
std 18,y
std 20,y
ldaa #' '
staa 22,y
ldy #inv_line_in
ldd #' 0'
std 0,y
std 2,y
std 4,y
std 6,y
std 8,y
ldd #' |'
std 10,y
ldd #' I'
std 12,y
std 14,y
std 16,y
std 18,y
std 20,y
ldaa #' '
staa 22,y
ldy #laser
ldd #'a|'
std 0,y
ldaa #'P'
staa 2,y
ldy #explode
ldd #'i|'
std 0,y
ldaa #'P'
staa 2,y
ldy #UFO
ldd #'IJ'
std 0,y
ldd #'KL'
std 2,y
ldaa #'|'
staa 4,y
ldd #'UU'
std 5,y
std 7,y
rts
;*******************************************************
;*
;* Put up splash screen, etc.
;*
;***
splash:
ldy #Inv_splash
jsr screen_out ;(Includes LCD_init)
delay 600*10
ldaa #25
ldy #score1
jsr SCREENS
jsr tick
delay 200*10
ldaa #25
ldy #score2
jsr SCREENS
jsr tick
delay 200*10
ldaa #25
ldy #score3
jsr SCREENS
jsr tick
delay 400*10
ldaa #34
ldy #score4
jsr SCREENS
jsr tick
delay 200*10
ldaa #34
ldy #score5
jsr SCREENS
jsr tick
delay 200*10
ldaa #34
ldy #score6
jsr SCREENS
jsr tick
delay 1500*10
ldy #Inv_get_ready
jsr screen_out ;(Includes LCD_init)
delay 3000*10
rts
;-------------------------------------
Inv_splash:
dc.b ' Space Invaders |'
dc.b ' BL B '
dc.b ' 1- ABC- |'
dc.b ' I UUU '
Inv_get_ready:
dc.b ' GET 000|'
dc.b ' '
dc.b ' READY! _aa|'
dc.b ' SPP'
Inv_screen:
dc.b ' 000|'
dc.b ' '
dc.b ' yz yz yz yz _aa|'
dc.b ' PP PP PP PP SPP'
high_scores:
dc.b 'Hi-Sc3rers: AJR SCR |'
dc.b 'BB BBOBBBB '
dc.b ' AR JSH |'
dc.b ' '
score1: dc.b '2 |' ;Position 25
dc.b ' '
score2: dc.b '25 |'
dc.b ' '
score3: dc.b '25 |'
dc.b ' '
score4: dc.b '1 |' ;Position 34
dc.b ' '
score5: dc.b '10 |'
dc.b ' '
score6: dc.b '100|'
dc.b ' '
high_scores_I:
dc.b '3|'
dc.b 'I'
high_scores_O:
dc.b '3|'
dc.b 'O'
;-------------------------------------
This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.



