Retro Invaders a space invaders clone by Chris Favreau. Written for the RetroMbuino development board from outrageouscircuits.com for the game programming contest.

Dependencies:   mbed

This is a space invaders clone written for the Retro Mbuino from outrageous circuits.

Development board: http://www.outrageouscircuits.com/shop/product/15 ).

The game itself is basic space invaders. Shoot them before they get to the bottom of the screen. It has a UFO saucer which you can shoot for extra points. You get 4 shields and each shield can be hit up to 4 times before it is gone. Hmm... as each level increases the speed of the invaders shots goes up. The invaders only speed up when there is less of them. You complete the level when you shoot all the invaders. The game ends when a) you run out of lives (you start with 3) or the invaders get to the bottom.

The LEDs turned out to be a pretty cool addition to the game. I wrote a class that blinks them and turns them on for a specified amount of time. They add a nice extra to the game. I use them on the intro screen and when the UFO is present.

The sound turned out to be really difficult for a few reasons. The biggest was that I had never written a sound engine before. The interrupt service routine working off the timer was the easier part. I also had a lot of trouble because there is no filter to filter out the PWM frequency to the speaker... so I had to run the PWM frequency way up there 30 kHz.

The graphics turned out to be a bit of a bear too. Thanks to Chris Taylor for his really great LCD API. I picked up a couple of frames per second from that. I had modified the DisplayN18 class for blitting a single line buffer to the LCD panel however his is a little faster for some reason? I used a different approach to doing the graphics (as I have very little experience with anything other than double buffered displays). I have a tile map and a list of sprites. Each tile/sprite is 1 bit 8x8. They could be bigger. I ran out of time. That much is not special. What is different from what I can tell is that I use a 1 line buffer that is 160 shorts long. The render function first adds the tile map data into the line buffer first. Then the sprites are added over the existing data. You can have a great deal of different sprites and maps going to the screen and just have to rewrite the LCD memory once per frame. After each line is composited, the line is then drawn to the LCD. Kind of like an Atari 2600. Each sprite/tile has a foreground and background color and can be different from the other tiles/sprites. There is one color reserved for Transparency.

There are 16 colors to choose from. I chose a palette based on the Macintosh OS 4.1 palette I found on WikiPedia. It is a very nice mix of colors.

I found a sprite editor called SpriteX ( https://code.google.com/p/spritesx-ed/ )... it works nicely except that the 16x16 sprites are in a weird format. Time limited me to 8x8 sprites. Oh well.

I used nokring to make the music. It makes RTTTL formatted ring tones which my sound api can play. Here is a useful site that has lots of arcade/video game ring tones with a link to nokring in the utilities page. http://arcadetones.emuunlim.com/files.htm

Other than all that stuff I used state machines to do most of the game logic. Please excuse the horrible coding as I tried to comment a lot of it however it is not very nice to look at. Lots of long functions...

Display/LCD_ST7735.h

Committer:
cfavreau
Date:
2015-03-03
Revision:
0:c79e1f29f029

File content as of revision 0:c79e1f29f029:

///////////////////////////////////////////////////////////////////////////////
// LCD_ST7735 - Driver for ST7735 LCD display controller
// Author: Chris Taylor (taylorza)
#include "mbed.h"
#include "BurstSPI.h"

#ifndef __LCD_ST7735__
#define __LCD_ST7735__

#define LCD_WIDTH        160
#define LCD_HEIGHT       128

/** LCD_ST7735 is a simple driver for the ST7735 LCD controller. It provides basic drawing primitives sa well as text and font capabilities.
 * The driver is currently hardcoded to support 65K colors using a 565 RGB pixel format.
*/
class LCD_ST7735
{   
    public:
        /** Orientation of the display */
        enum Orientation 
        {
            /** No rotation of the display image*/
            Rotate0, 
            /** Rotate the display image 90 degrees */
            Rotate90, 
            /** Rotate the display image 180 degrees */
            Rotate180, 
            /** Rotate the display image 270 degrees */
            Rotate270
        };
        
        /** Type of color filter of the panel */
        enum PanelColorFilter
        {
            /** RGB color filter panel */
            RGB = 0,
            
            /** BGR color filter panel */
            BGR = 8,
        };
        
    public:
        /**Creates an instance of the LCD_ST7735 driver
         * @param backlightPin pin used to control the backlight
         * @param resetPin pin used to reset the display controller
         * @param dsPin pin used to put the display controller into data mode
         * @param mosiPin SPI channel MOSI pin
         * @param misoPin SPI channel MISO pin
         * @param clkPin SPI channel clock pin
         * @param csPin SPI chip select pin 
        */
        LCD_ST7735(
            PinName backlightPin,
            PinName resetPin,
            PinName dsPin,
            PinName mosiPin,
            PinName misoPin,
            PinName clkPin,
            PinName csPin,
            PanelColorFilter colorFilter = BGR
            );
            
        /** Set the orientation of the display
         * @param orientation Orientation of the display.
         * @param flip Flips the display direction
         */
        void setOrientation(Orientation orientation, bool flip);
        
        /** Get the width of the display given the current orientation */
        int getWidth();
        
        /** Get the height of the display given the current orientation */
        int getHeight();
    
        /** Control the display's backlight 
         * @param state true to turn the backlight on, false to turn it off   
        */
        void setBacklight(bool state);
        
        /** Clear the screen 
         * @param color The color used to clear the screen. Defaults to black if not passed.
        */
        void clearScreen(uint16_t color = 0x0000);
        
        /**  Set a pixel on the display to the specified color 
         * @param x The X coordinate of the pixel (0..127)   
         * @param y The Y coordinate of the pixel (0..159)   
         * @param color Color to set the pixel to.
        */
        void setPixel(int x, int y, uint16_t color);
        
        /** Draw a line on the display
         * @param x1 The X coordinate of the starting point on the line
         * @param y1 The Y coordinate of the starting point on the line
         * @param x2 The X coordinate of the end point on the line
         * @param y2 The Y coordinate of the end point on the line
         * @param color The color used to draw the pixel
        */
        void drawLine(int x1, int y1, int x2, int y2, uint16_t color);
        
        /** Draw a rectangle on the display 
         * @param x1 The X coordinate of the upper left corner
         * @param y1 The Y coordinate of the upper left corner
         * @param x2 The X coordinate of the lower right corner
         * @param y2 The Y coordinate of the lower right corner
         * @param color The color used to draw the rectangle
        */
        void drawRect(int x1, int y1, int x2, int y2, uint16_t color);
        
        /** Draw a circle on the display
         * @param x The X coordinate of the center of the circle
         * @param y The Y coordinate of the center of the circle
         * @param r The radius of the circle
         * @param color The color used to draw the circle
        */
        void drawCircle(int x, int y, int r, uint16_t color);
        
        /** Draw an ellipse on the display
         * @param x The X coordinate of the center of the ellipse
         * @param y The Y coordinate of the center of the ellipse
         * @param rx The X radius of the ellipse
         * @param ry The X radius of the ellipse
         * @param color The color used to draw the ellipse
        */
        void drawEllipse(int x, int y, int rx, int ry, uint16_t color);
        
        /** Draw a filled rectangle on the display 
         * @param x1 The X coordinate of the upper left corner
         * @param y1 The Y coordinate of the upper left corner
         * @param x2 The X coordinate of the lower right corner
         * @param y2 The Y coordinate of the lower right corner
         * @param fillColor The color used to fill the rectangle
        */
        void fillRect(int x1, int y1, int x2, int y2, uint16_t fillColor);
        
        /** Draw a filled rectangle on the display 
         * @param x1 The X coordinate of the upper left corner
         * @param y1 The Y coordinate of the upper left corner
         * @param x2 The X coordinate of the lower right corner
         * @param y2 The Y coordinate of the lower right corner
         * @param borderColor The color used to draw the rectangle frame
         * @param fillColor The color used to fill the rectangle
        */
        void fillRect(int x1, int y1, int x2, int y2, uint16_t borderColor, uint16_t fillColor);
        
        /** Draw a filled circle on the display
         * @param x The X coordinate of the center of the circle
         * @param y The Y coordinate of the center of the circle
         * @param borderColor The color used to draw the circumference of the circle
         * @param fillColor The color used to fill the circle
        */
        void fillCircle(int x, int y, int r, uint16_t borderColor, uint16_t fillColor);
        
        /** Draw a filled ellipse on the display
         * @param x The X coordinate of the center of the ellipse
         * @param y The Y coordinate of the center of the ellipse
         * @param rx The X radius of the ellipse
         * @param ry The X radius of the ellipse
         * @param borderColor The color used to draw the circumference of the circle
         * @param fillColor The color used to fill the circle
        */
        void fillEllipse(int x, int y, int rx, int ry, uint16_t borderColor, uint16_t fillColor);
        
        /** Draw a bitmap on the screen 
         * @param x The X coordinate location to draw the bitmap.
         * @param y The Y coordinate location to draw the bitmap.
         * @param pbmp Pointer to the bitmap.
         * @note The bitmap is an single dimensional uint8_t (unsigned short) array. 
         * The first to elements of the array indicate the width and height of the bitmap repectively.
         * The rest of the entries int the array make up the pixel data for the array.
        */
        void drawBitmap(int x, int y, const uint16_t *pbmp);
        
        /** Extracts a portion of a bitmap and draws it on the screen 
         * @param x The X coordinate location to draw the bitmap.
         * @param y The Y coordinate location to draw the bitmap.
         * @param pbmp Pointer to the bitmap.
         * @param srcX X offset into the source bitmap of the portion to extract
         * @param srcY Y offset into the source bitmap of the portion to extract
         * @param srcWidth Width of the bitmap portion to draw
         * @param srcHeight Height of the bitmap portion to draw
         * @note The bitmap is an single dimensional uint8_t (unsigned short) array. 
         * The first to elements of the array indicate the width and height of the bitmap repectively.
         * The rest of the entries int the array make up the pixel data for the array.
        */
        void drawBitmap(int x, int y, const uint16_t *pbmp, int srcX, int srcY, int srcWidth, int srcHeight);
        
        /** Set the foreground color used to render text
         * @param color Color used when drawing text to the display
         * @note The color can be changed multiple times to render text in various colors on the display
        */
        void setForegroundColor(uint16_t color);
        
        /** Set the background color used to render text
         * @param color Color used when drawing background portions of the text
         * @note The color can be changed multiple times to render text with various background colors on the display
        */
        void setBackgroundColor(uint16_t color);        
        
        /** Draw a string to the screen using the currently active foreground and background colors
         * @param pFont Pointer to the font used to render the string to the display
         * @param x The X coordinate location to draw the string.
         * @param y The Y coordinate location to draw the string.
         * @param pString ASCIIZ string to draw to the display.         
        */
        void drawString(const uint8_t *pFont, int x, int y, const char *pString);
        
        /** Measure the width and height of the string when rendered with the specified font
         * @param pFont Pointer to the font used to measure the string         
         * @param pString ASCIIZ string to measure.
         * @param width Reference to the variable that will contain the width
         * @param height Reference to the variable that will contain the height         
        */
        void measureString(const uint8_t *pFont, const char *pString, uint8_t &width, uint8_t &height);
        
        /** Select the device on the SPI bus.
        selectDevice needs to be called before accessing the screen if there are multiple devices on the SPI bus.
        */
        void selectDevice();   
        
    protected:
        void writeCommand(uint8_t cmd);
        void write(uint8_t cmd, uint8_t data[], int dataLen);
        void write(uint8_t cmd, uint16_t data);        
        
        void beginBatchCommand(uint8_t cmd);
        void writeBatchData(uint8_t data);
        void writeBatchData(uint8_t dataHigh, uint8_t dataLow);
        void writeBatchData(uint16_t data);
        void endBatchCommand();
        
        void clip(int x, int y, int w, int h);
        void clipRect(int x1, int y1, int x2, int y2);
        
    private:
        void drawVertLine(int x1, int y1, int y2, uint16_t color);
        void drawHorizLine(int x1, int y1, int x2, uint16_t color);
        void drawChar(const uint8_t *pFont, int x, int y, char c, uint8_t w, uint8_t h, uint8_t offset, uint8_t leftPad, uint8_t rightPad, uint8_t topPad, uint8_t bottomPad);
        
    private:
        void swap(int &a, int &b);
        
    private:
        void initDisplay();
        void reset();        
        
    private:
        int         _width;
        int         _height;
        Orientation _orientation;
        PanelColorFilter _colorFilter;
        bool        _flip; 
        uint8_t    _foregroundColorHigh;
        uint8_t    _foregroundColorLow;
        uint8_t    _backgroundColorHigh;
        uint8_t    _backgroundColorLow;
        
    private:
        class LCDSPI : public SPI
        {
            public:
                LCDSPI(PinName mosi, PinName miso, PinName sclk) :
                    SPI(mosi, miso, sclk)
                {
                }
                
                void prepareFastSPI()
                {
                    #ifdef TARGET_LPC11U24
                    aquire();
                    #endif
                }
                
                void waitWhileBusy()
                {
                    #ifdef TARGET_LPC11U24
                    while (((_spi.spi->SR) & 0x10) != 0);
                    #endif
                }
                
                void fastWrite(uint8_t data)
                {       
                    #ifdef TARGET_LPC11U24
                        while (((_spi.spi->SR) & 0x01) == 0);
                        //while(((_spi.spi->SR) & 0x02) == 0);
                        _spi.spi->DR = data;
                    #else
                        SPI::write(data);
                    #endif 
                }       
                
                void clearRx()
                { 
                    #ifdef TARGET_LPC11U24
                        while (((_spi.spi->SR) & 0x14) != 0)
                        {
                            while (((_spi.spi->SR) & 0x04) == 0);
                            int data = _spi.spi->DR;
                        }                                         
                    #endif  
                }            
        };
        
    private:                
        DigitalOut  _backlight;
        DigitalOut  _reset;
        DigitalOut  _ds;
        DigitalOut  _cs;
        LCDSPI      _spi;
        
    protected:
        static const uint8_t CMD_SLPOUT     = 0x11;
        static const uint8_t CMD_DISPON     = 0x29;
        static const uint8_t CMD_CASET      = 0x2a;
        static const uint8_t CMD_RASET      = 0x2b;
        static const uint8_t CMD_RAMWR      = 0x2c;
        
        static const uint8_t CMD_MADCTL     = 0x36;
        static const uint8_t CMD_COLMOD     = 0x3a;
        
        static const uint8_t CMD_FRMCTR1    = 0xb1;
        static const uint8_t CMD_FRMCTR2    = 0xb2;
        static const uint8_t CMD_FRMCTR3    = 0xb3;
        static const uint8_t CMD_INVCTR     = 0xb4;
        
        static const uint8_t CMD_PWCTR1     = 0xc0;
        static const uint8_t CMD_PWCTR2     = 0xc1;
        static const uint8_t CMD_PWCTR3     = 0xc2;
        static const uint8_t CMD_PWCTR4     = 0xc3;
        static const uint8_t CMD_PWCTR5     = 0xc4;
        static const uint8_t CMD_VMCTR1     = 0xc5;
        
        static const uint8_t CMD_GAMCTRP1   = 0xe0;
        static const uint8_t CMD_GAMCTRN1   = 0xe1;
        
        static const uint8_t CMD_EXTCTRL    = 0xf0;                
};
 
#endif // __LCD_ST7735__