Space Invaders - Embedded Systems Project 15/16 - Avinash Patel 200860407

Dependencies:   Joystick N5110 SDFileSystem mbed

main.cpp

Committer:
avi23
Date:
2016-03-13
Revision:
1:b300d052d549
Parent:
0:427469992efe
Child:
2:d34c95990605

File content as of revision 1:b300d052d549:

/*
Space Invaders - Avinash Patel 200860407

Week 19 - Set up joystick class
Week 20 - Changed to space invaders as constrained too much by screen resolution
        - Core cannon is drawn and can move, enemies are visible and they switch between states every second
*/
#include "mbed.h"
#include "N5110.h"

#define EMPTY 0

//Joystick Class
class Joystick
{
public:
    Joystick(PinName x_axis_pin, PinName y_axis_pin, PinName button_pin) {
        //Dynamically allocates the pins
        x_axis_ = new AnalogIn(x_axis_pin);
        y_axis_ = new AnalogIn(y_axis_pin);
        button_ = new InterruptIn(button_pin);
    }

    //Initalises the Joystick
    //Sets up the ISRs and grabs the offsets for each axis
    void init() {
        //Sets up the button ISR
        //DigitalOut* b = new DigitalOut(LED_BLUE);

        button_->mode(PullUp);
        //read_ticker_->attach(this, &Joystick::read_ticker_isr, time); //Samples joystick every second
        button_->fall(this, &Joystick::button_isr);

        //Initalises the vairables and flags
        x_offset_ = 0;
        y_offset_ = 0;
        g_read_flag_ = 0;
        g_button_flag_ = 0;

        //Samples the joystick 5 times and takes an average to get the offset
        float x_sum = 0;
        float y_sum = 0;

        for (int i = 0; i < 5; i++) {
            x_sum += x_axis_->read();
            y_sum += y_axis_->read();
        }

        x_offset_ = 0.5f - x_sum/5.0f;
        y_offset_ = 0.5f - y_sum/5.0f;
    }

    //Take 5 readings and returns the average measurement, accounting for joystick offset x and y values
    float GetXValue() {

        float x_sum = 0;

        for (int i = 0; i < 5; i++) {
            x_sum += x_axis_->read();
        }

        float x_value = x_sum/5.0f + x_offset_;

        //Caps the value for the POT between 0 and 1
        if (x_value < 0.0f) {
            return 0;
        } else if (x_value > 1.0f) {
            return 1;
        } else {
            return x_value;
        }
    }

    float GetYValue() {

        float y_sum = 0;

        for (int i = 0; i < 5; i++) {
            y_sum += y_axis_->read();
        }

        float y_value = y_sum/5.0f + y_offset_;

        //Caps the value for the POT between 0 and 1
        if (y_value < 0.0f) {
            return 0;
        } else if (y_value > 1.0f) {
            return 1;
        } else {
            return y_value;
        }
    }

    float ReadXAxis() {
        return x_axis_->read();
    }

    float ReadYAxis() {
        return y_axis_->read();
    }

    //Getter and setters for flags
    int get_read_flag() {
        return g_read_flag_;
    }

    void set_read_flag(int value) {
        g_read_flag_ = value;
    }

    int get_button_flag() {
        return g_button_flag_;
    }

    void set_button_flag(int value) {
        g_button_flag_ = value;
    }

    //Ticker ISR Method
    void read_ticker_isr() {
        g_read_flag_ = 1;
    }

private:
    //Button ISR Method
    void button_isr() {
        g_button_flag_ = 1;
    }

private:
    //Pin inputs
    AnalogIn* x_axis_;
    AnalogIn* y_axis_;
    InterruptIn* button_;

    //Ticker
    Ticker* read_ticker_;

    //Stores X and Y offsets
    float x_offset_;
    float y_offset_;

    //Stores interrupt flags
    volatile int g_read_flag_;
    volatile int g_button_flag_;
};

// K64F on-board LEDs
DigitalOut r_led(LED_RED);
DigitalOut g_led(LED_GREEN);
DigitalOut b_led(LED_BLUE);

// K64F on-board switches
InterruptIn sw2(SW2);
InterruptIn sw3(SW3);

// UART connection for PC
Serial pc(USBTX,USBRX);

//Joystick
Joystick joystick(PTC10, PTC11, PTB11);

//LCD object
//         VCC,    SCE,   RST,   D/C,   MOSI,  SCLK,   LED
N5110 lcd (PTE26 , PTA0 , PTC4 , PTD0 , PTD2 , PTD1 , PTC3);

//Ship bit-map and location
int cannon_xpos = 24;
const int cannon_ypos = 43;
Ticker move_cannon;
const bool cannon_bitmap[5][9] = {
    {0, 0, 0, 0, 1, 0, 0, 0, 0},
    {0, 0, 0, 1, 1, 1, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 1, 0},
    {1, 1, 1, 1, 1, 1, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1, 1}
};

//Enemies
Ticker move_enemies;
short screen[84][48];
bool enemies_in_state2 = true;
//Struct to store enemy data
struct Enemies {
    int x_pos;
    int y_pos;
    bool is_alive;
} small_invader[6], medium_invader[6], large_invader[6];
int no_of_small_invaders = 6;
int no_of_medium_invaders = 6;
int no_of_large_invaders = 6;
//Bitmaps for small invaders
const bool small_invader_bitmap_1[6][8] = {
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 0},
    {1, 1, 0, 1, 1, 0, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {0, 1, 0, 1, 1, 0, 1, 0},
    {1, 0, 1, 0, 0, 1, 0, 1}
};

const bool small_invader_bitmap_2[6][8] = {
    {0, 0, 0, 1, 1, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 0},
    {1, 1, 0, 1, 1, 0, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1},
    {1, 0, 0, 0, 0, 0, 0, 1},
    {0, 1, 0, 0, 0, 0, 1, 0}
};
//Bitmaps for medium invaders
const bool medium_invader_bitmap_1[6][10] = {
    {1, 0, 0, 1, 0, 0, 1, 0, 0, 1},
    {1, 0, 1, 1, 1, 1, 1, 1, 0, 1},
    {1, 1, 1, 0, 1, 1, 0, 1, 1, 1},
    {0, 1, 1, 1, 1, 1, 1, 1, 1, 0},
    {0, 0, 1, 0, 0, 0, 0, 1, 0, 0},
    {0, 1, 0, 0, 0, 0, 0, 0, 1, 0}
};

const bool medium_invader_bitmap_2[6][10] = {
    {0, 0, 0, 1, 0, 0, 1, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 1, 1, 0, 1, 1, 0},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {1, 0, 1, 0, 0, 0, 0, 1, 0, 1},
    {0, 0, 0, 1, 1, 1, 1, 0, 0, 0}
};
//Bitmaps for large invaders
const bool large_invader_bitmap_1[6][12] = {
    {0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
    {1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 0},
    {0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 0}
};

const bool large_invader_bitmap_2[6][12] = {
    {0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0},
    {0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0},
    {1, 1, 1, 0, 0, 1, 1, 0, 0, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 1, 1, 0, 1, 1, 0, 1, 1, 0, 0},
    {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1}
};

//int row_no = 6;
//int col_no = 12;

//ISR Flags
volatile bool g_move_ship_flag = true;
volatile bool g_move_enemies_flag = true;

// function prototypes
// error function hangs flashing an LED
void error();
// setup serial port
void init_serial();
// set-up the on-board LEDs and switches
void init_K64F();
// Added functions
void MoveShip();
void InitSmallInvaders();
void DrawSmallInvaders();
void InitMediumInvaders();
void DrawMediumInvaders();
void InitLargeInvaders();
void DrawLargeInvaders();
//ISR's
void move_ship_isr();
void move_enemies_isr();



int main()
{
    //Initalises the board and perhiperals
    init_K64F();
    init_serial();
    lcd.init();
    lcd.clear();

    move_cannon.attach(&move_ship_isr, 0.1);
    move_enemies.attach(&move_enemies_isr, 1);

    InitSmallInvaders();
    InitMediumInvaders();
    InitLargeInvaders();

    int col = 0;
    int row = 0;

    for (int i = 0; i < no_of_large_invaders; i++) {
        if (i == 0) {
            for (col = 0; col < 12; col++) {
                for (row = 0; row < 6; row++) {
                    if(large_invader_bitmap_1[row][col]) {
                        lcd.setPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
                    }
                }
            }
        } else {
            for (col = 0; col < 12; col++) {
                for (row = 0; row < 6; row++) {
                    if(large_invader_bitmap_2[row][col]) {
                        lcd.setPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
                    }
                }
            }
        }
    }

    lcd.refresh();

    while (true) {
        
        if (g_move_ship_flag) {
            g_move_ship_flag = false;

            MoveShip();

            lcd.refresh();
        }

        if (g_move_enemies_flag) {
            g_move_enemies_flag = false;

            DrawSmallInvaders();
            DrawMediumInvaders();
            DrawLargeInvaders();

            enemies_in_state2 = !enemies_in_state2;

            lcd.refresh();
        }
        
        sleep();
    }
}

void init_K64F()
{
    // on-board LEDs are active-low, so set pin high to turn them off.
    r_led = 1;
    g_led = 1;
    b_led = 1;

    // since the on-board switches have external pull-ups, we should disable the internal pull-down
    // resistors that are enabled by default using InterruptIn
    sw2.mode(PullNone);
    sw3.mode(PullNone);

}

void error()
{
    while(1) {  // if error, hang while flashing error message
        r_led = 0;
        wait(0.2);
        r_led = 1;
        wait(0.2);
    }
}

void init_serial()
{
    // set to highest baud - ensure terminal software matches
    pc.baud(115200);
}

void move_ship_isr()
{
    g_move_ship_flag = true;
}

void MoveShip()
{
    //Clears the ship
    for (int col = 0; col < 9; col++) {
        for (int row = 0; row < 5; row++) {
            if(cannon_bitmap[row][col]) {
                lcd.clearPixel(cannon_xpos+col, cannon_ypos+row);
            }
        }
    }

    //Changes the position of the ship when the joystick is moved, capping at 0 and 75 so it always fits on the screen
    if (joystick.GetXValue() < 0.25f) {
        cannon_xpos--;
        if (cannon_xpos < 0) {
            cannon_xpos = 0;
        }
    } else if (joystick.GetXValue() > 0.75f) {
        cannon_xpos++;
        if (cannon_xpos > 75) {
            cannon_xpos = 75;
        }
    }

    //Redraws the ship
    for (int col = 0; col < 9; col++) {
        for (int row = 0; row < 5; row++) {
            if(cannon_bitmap[row][col]) {
                lcd.setPixel(cannon_xpos+col, cannon_ypos+row);
            }
        }
    }
}

void move_enemies_isr()
{
    g_move_enemies_flag = true;
}

//Sets the position and aliveness of the small invaders
void InitSmallInvaders()
{
    for (int i = 0; i < no_of_small_invaders; i++) {
        small_invader[i].x_pos = 2+ (i*13);
        small_invader[i].y_pos = 7;
        small_invader[i].is_alive = true;
    }
}

void DrawSmallInvaders()
{
    //For each small invader clear and redraws them if they're alive
    for (int i = 0; i < no_of_small_invaders; i++) {
        //Clears the enemy position
        lcd.drawRect(small_invader[i].x_pos, small_invader[i].y_pos, 8, 6, 2);

        //Checks if the invader is alive
        if (small_invader[i].is_alive) {
            //Reads off the bitmap and sets the allowed pixels
            int col = 0;
            int row = 0;
            //Flips the bitmap everytime the function is called
            if (enemies_in_state2) {
                for (col = 0; col < 8; col++) {
                    for (row = 0; row < 6; row++) {
                        if(small_invader_bitmap_1[row][col]) {
                            lcd.setPixel(small_invader[i].x_pos + col, small_invader[i].y_pos + row);
                        }
                    }
                }
            } else {
                for (col = 0; col < 8; col++) {
                    for (row = 0; row < 6; row++) {
                        if(small_invader_bitmap_2[row][col]) {
                            lcd.setPixel(small_invader[i].x_pos + col, small_invader[i].y_pos + row);
                        }
                    }
                }
            }
        }
    }
}

//Sets the position and aliveness of the medium invaders
void InitMediumInvaders()
{
    for (int i = 0; i < no_of_medium_invaders; i++) {
        medium_invader[i].x_pos = 1 + (i*13);
        medium_invader[i].y_pos = 15;
        medium_invader[i].is_alive = true;
    }
}

void DrawMediumInvaders()
{
    //For each small invader clear and redraws them if they're alive
    for (int i = 0; i < no_of_medium_invaders; i++) {
        //Clears the enemy position
        lcd.drawRect(medium_invader[i].x_pos, medium_invader[i].y_pos, 10, 6, 2);

        //Checks if the invader is alive
        if (medium_invader[i].is_alive) {
            //Reads off the bitmap and sets the allowed pixels
            int col = 0;
            int row = 0;
            //Flips the bitmap everytime the function is called
            if (enemies_in_state2) {
                for (col = 0; col < 10; col++) {
                    for (row = 0; row < 6; row++) {
                        if(medium_invader_bitmap_1[row][col]) {
                            lcd.setPixel(medium_invader[i].x_pos + col, medium_invader[i].y_pos + row);
                        }
                    }
                }
            } else {
                for (col = 0; col < 10; col++) {
                    for (row = 0; row < 6; row++) {
                        if(medium_invader_bitmap_2[row][col]) {
                            lcd.setPixel(medium_invader[i].x_pos + col, medium_invader[i].y_pos + row);
                        }
                    }
                }
            }
        }
    }
}

//Sets the position and aliveness of the large invaders
void InitLargeInvaders()
{
    for (int i = 0; i < no_of_large_invaders; i++) {
        large_invader[i].x_pos = 0 + (i*13);
        large_invader[i].y_pos = 23;
        large_invader[i].is_alive = true;
    }
}

void DrawLargeInvaders()
{
    //For each small invader clear and redraws them if they're alive
    for (int i = 0; i < no_of_large_invaders; i++) {
        //Clears the enemy position
        lcd.drawRect(large_invader[i].x_pos, large_invader[i].y_pos, 12, 6, 2);

        //Checks if the invader is alive
        if (large_invader[i].is_alive) {
            //Reads off the bitmap and sets the allowed pixels
            int col = 0;
            int row = 0;
            //Flips the bitmap everytime the function is called
            if (enemies_in_state2) {
                for (col = 0; col < 12; col++) {
                    for (row = 0; row < 6; row++) {
                        if(large_invader_bitmap_1[row][col]) {
                            lcd.setPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
                        }
                    }
                }
            } else {
                for (col = 0; col < 12; col++) {
                    for (row = 0; row < 6; row++) {
                        if(large_invader_bitmap_2[row][col]) {
                            lcd.setPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
                        }
                    }
                }
            }
        }
    }
}