Introduction
============

This is an example game showing some of the things you can do with sprites
in NextBASIC. In particular it demonstrates:

* relative sprites (sprites that are defined in terms of x/y offsets from
  a preceding "anchor" sprite, and move around as the anchor is moved)
* automatic sprite movement, which occurs when a SPRITE MOVE command is issued
* collision detection
* batching updates and avoiding on-screen flicker

This game runs at 14MHz, so there is certainly some elbow room for more complex
games with the speed cranked up to 28MHz!


Sprite patterns
===============

The following sprite patterns are used (as can be seen by editing the
basicInvaders.spr file):

Patterns        Use
--------        ---
 0              Player
 1              Player's shot
 2.. 3          Invader's missile (2 frames)
 4..13          Invaders (5 types, 2 frames each)
14..23          Digits 0..9
24..27          Explosion (4 frames)
28              Saucer


Sprite ids
==========

The following sprite ids are used:

IDs             Use
---             ---
  0.. 34        Invaders ( 0=anchor for 1st row,  1.. 6=relative sprites)
                         ( 7=anchor for 2nd row,  8..13=relative sprites)
                                               ...
                         (28=anchor for 5th row, 29..34=relative sprites)
 35             Saucer
 64             Player
 65             Player's shot
 66             Explosion
 68.. 71        Invaders' missiles (up to 4 active at once)
 80.. 85        Score
126..127        Additional lives

Note that relative sprites are always referred to using negative sprite ids,
and are relative to the preceding sprite which was defined with a positive
number. So, in the program, sprites 1..6 and 8..13 are always referred to as
negative in any SPRITE command and are relative to the anchor sprites 0 and 7.


Variables
=========

Most variables used in the game are integer variables to help maintain speed.
Any variable seen within an expression starting with "%" is an integer variable.

The following variables are currently used (additionally, there are some
local variables used in individual procedures, not listed here):

Name    Type            Use
----    ----            ---
ctrls   floating-point  contains selected control type, used in PROC setInput()
%d      integer         sheet initial difficulty level (0..9)
%e      integer         current difficulty level (0..10)
%s      integer         current invader "slowness"
%z      integer         score/10
%p      integer         player x-position
%a      integer         number of lives remaining
%n      integer         number of invaders killed so far in current sheet
%h      integer         y-position of top row of invaders
%a()    integer array   id of anchor sprite for each invader row (0..4)
%e(y)   integer array   enable flag, indicating whether each invader row (0..4)
                        still contains any invaders
%l(y)   integer array   grid position (0..4) of leftmost remaining invader
                        in each row (0..4)
%r(y)   integer array   grid position (0..4) of rightmost remaining invader
                        in each row (0..4)
%l      integer         grid pos (0..4) of overall leftmost remaining invader
%r      integer         grid pos (0..4) of overall leftmost remaining invader
%t      integer         topmost remaining invader row (0..4)
%b      integer         bottommost remaining invader row (0..4)


Possible improvements
=====================

There are a number of ways the game could be improved, which you might want to
try as an exercise. Here are a few suggestions.


Increase the number of lives every 10000 points
-----------------------------------------------
Note that the score is held as points/10, so you actually need to check when
the score increases to (or past) a multiple of 1000.


Add shields
-----------
This could potentially be done by adding some sprite patterns in increasing
state of decay, so that when a player shot or invader missile hits it, the
pattern is incremented and then the sprite removed after it is fully decayed.
It's probably worth defining narrow sprites for this job and packing them
closely together so that only relatively narrow holes are made.


Increase the number of invaders on each row
-------------------------------------------
The number of invaders on each row is currently limited to 7, because each
invader is 20 pixels to the right of the previous one. An 8th invader can't
be trivially added because 20*7=140 which exceeds the maximum coordinate
offset available for relative sprites (-127..+127).

One possible solution is to change the anchor sprite to the middle invader
of the row, and have 5 invaders on each side. This would require quite a
bit of rework to the code, which is currently designed around the assumption
that the anchor sprite is always the leftmost one.

An alternative solution could be to switch to using "unified" sprites rather
than composite ones, and select 2x scaling in both the x and y directions.
Since the x/y offsets of relative sprites in a "unified" sprite are scaled
by the same value, effectively pixel offsets of -254..+254 are then available.
This would also require redefining the patterns as 8x8 designs (this might make
them pleasingly more blocky).


Have fun!
Garry Lancaster, 2020-03-25.
