Space invaders with a nRF2401A wireless joypad

Dependencies:   Gameduino mbed nRF2401A

Fork of Gameduino_Invaders_game by Chris Dick

Gameduino and an nRF2401A hooked up to an mbed on an mbeduino:

/media/uploads/TheChrisyd/2014-03-08_22.53.54.jpg

utils.h

Committer:
TheChrisyd
Date:
2014-03-09
Revision:
5:3ede9991d8e0
Parent:
2:20a89dc286d5

File content as of revision 5:3ede9991d8e0:

#ifndef COM_ARTLUM_GDUTILS_INCLUDED
#define COM_ARTLUM_GDUTILS_INCLUDED
#include "arduino.h"
#include "GD.h"
//#include "WProgram.h"

/*---------------------------------------------------
  Coprocessor controller - makes it easy to do
  raster effects (eg. split screens) without
  writing any FORTH.
  
  The way this works is that you build a list of
  instructions in memory (a "copperlist") and
  the coprocessor will execute the list on every
  video frame.
  
  Code samples:
  
  void setup() {
    ...
    // Make a copperlist to change a palette color on line 100
    // The copperlist is stored on the Gameduino at address 0x3f80
    Coprocessor::reset();
    CopperlistBuilder cp;
    cp.begin(0x3f80);
    cp.wait(100);
    cp.write16(PALETTE4A, 0x7fff);
    cp.end();  // And start using the new copperlist
  }
 
  Modifying an existing copperlist:
  
  // Make a copperlist to set the horizontal scroll register
  // on line 220 and modify the copperlist.
  // a) Build the list
  unsigned int XscrollInst;
  void setup() {
    ...
    CopperlistBuilder cp;
    cp.begin(0x3f80);
    cp.wait(220);
    XscrollInst = cp.position();    // Get current output location
    cp.write16(SCROLL_X, 0);
    cp.end();
  }
  // b) Modify the list with current 'xscroll'
  void loop() {
    CopperlistBuilder cp;
    cp.begin(XscrollInst)           // Where the 'write16()' instruction is
    cp.write16(SCROLL_X, xscroll);  // Overwrite the previous instruction
  }

  Notes: 
  The Coprocessor object uses the "COMM" block
  of memory at 0x2980 so don't mess with it.

  The coprocessor also provides support for the
  sound functions below.
---------------------------------------------------*/
class Coprocessor {
public:
  // This initializes everything and load the coprocessor code.
  // You should call this in your setup() function after "GD.begin();"
  //
  // The sample page is the page of Gameduino memory to
  // use as a buffer for sample playback. It *must* be
  // on a page boundry (ie. bottom 8 bits are 0) and
  // the whole page will be used so you can't use it
  // for anything else.
  static void reset(unsigned int samplePage=0x3f00);  // Default: Use memory from 0x3f00 to 0x3fff
  
  // Select a copperlist. The list will start running on the next video frame.
  // nb. The "CopperlistBuilder::end()" function normally calls this automatically
  // (unless you tell it not to...)
  static void setCopperlist(unsigned int addr);
  
  // Where the sample playback page is located
  static unsigned int samplePage();

  // Where the coprocessor is currently reading samples
  // from in the sample page. Use this info to keep the
  // page full of fresh sample data for playback
  static byte sampleReadPos();

  // A copy of the coprocessor YLINE register
  static int yline();
};

// This object helps you make a copperlist in memory
class CopperlistBuilder {
  unsigned int out,start;
  void put(byte);
  void put16(unsigned int);
public:
  // Available commands are:
  // * Wait for a raster line
  // * Write a byte to a memory location
  // * Write a 16-bit word to a memory location
  // * Copy a block of memory from one place to another
  void begin(unsigned int dest);
    void wait(int line);
    void write(unsigned int addr, byte val);
    void write16(unsigned int addr, unsigned int val);
    void copy(unsigned int src, unsigned int dst, unsigned int numBytes);
  void end(bool executeNow=true);

  // Where I'm currently outputting
  unsigned int position();
};


/*------------------------------------------------------------------
  Sound functions - play synthesized sounds and sound samples
  
  These functions require support from the Coprocessor object
  above. If you load different microcode they'll stop working...
------------------------------------------------------------------*/

/*------------------------------------------------------------------
  Synthesized sounds
------------------------------------------------------------------*/
#define SYNTHSOUNDS 0
#if SYNTHSOUNDS
// ADSR volume envelope
struct ADSR {
  byte attack;      // Attack time (in clock ticks)
  byte decay;       // Decay time (in clock ticks)
  byte sustain;     // Sustain level [0..255]
  byte release;     // Release time (in clock ticks)
  ADSR(byte a=4, byte d=4, byte s=90, byte r=30);
  byte evaluate(unsigned int elapsedTime, unsigned int releaseTime);
};

// Change pitch of a sound as it plays
struct PitchModulator {
  // Vibrato
  byte vibratoDelay;   // Delay before vibrato starts (in clock ticks)
  byte vibrato;        // Amount of vibrato (percentage of note pitch)
  char vibratoDelta;   // Added to 'vibrato' every clock tick 
  // Pitch Sweep
  byte sweepDelay;     // Delay before sweep starts (in clock ticks)
  byte sweep;
  char sweepDelta;
  PitchModulator() {
    vibratoDelay = 0;
    vibrato = 0;
    vibratoDelta = 0;
  }
  int evaluate(int startpitch, unsigned int time);
};

// All the parameters for a sound
struct Sound {
  ADSR adsr;
  PitchModulator pm;
};

class SoundPlayer {
  // Playback parameters
  Sound sound;
  byte volume;
  unsigned int pitch;
  unsigned int duration;
  // Internal vars
  unsigned int ticks;
  bool active, releasing;
  // Sound players form a linked list
  bool isLinked;
  SoundPlayer *link;
  // The SoundPlayer is updated from SoundController
  void update();
  friend class SoundController;
  // You can't copy me...
  SoundPlayer(const SoundPlayer&);
  void operator=(const SoundPlayer&);
public:
  SoundPlayer();
  
  // Set the sound parameters
  SoundPlayer& setSound(const Sound&);

  // Set playback volume in range [0..255], default = 255
  SoundPlayer& setVolume(byte);
 
  // Play a sound, pitch in Hz, duration in clock ticks.
  // If duration is 'infinite' then the sound plays until you call 'release()'
  // One "clock tick" is equivalent to one call to "SoundController::update()"
  enum { infinite=0x7fff };
  void play(unsigned int pitchHz, unsigned int duration=infinite);
  
  // Make the current sound enter the 'release' phase
  void release();
  
  // Stop sound playback immediately
  void stop();
};
#endif

/*------------------------------------------------------------------
  Main sound controller object
------------------------------------------------------------------*/
struct SoundController {
  // Reset all sounds, return to silence
  static void reset();

  // Update all sound - call this at least once every video frame.
  // The frequency at which you call this function is one "clock tick" for synthesised sounds
  static void update();

  // Play a sound sample from program memory
  // Samples are eight bits and will be played at
  // the system sample rate (see "Coprocessor").
  // if "numBytes" is negative, the sample will repeat until you play
  // another sample on the channel (eg. pass a null pointer to "playSample()"...)
  static void playSample(prog_char*, int numBytes, byte channel);
};



/*------------------------------------------------------------
  Useful little functions
------------------------------------------------------------*/
// Show a number on screen
void showNumber(int n, byte x, byte y);
void showHexNumber(unsigned int n, byte x, byte y);

// Send screenshot to serial port

void sendScreenshot();

// COM_ARTLUM_GDUTILS_INCLUDED
#endif