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

Dependencies:   Joystick N5110 SDFileSystem mbed

main.cpp

Committer:
avi23
Date:
2016-03-31
Revision:
4:a99953ef9e42
Parent:
3:544b59d60ab8
Child:
5:34855f712350

File content as of revision 4:a99953ef9e42:

/*
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
Week 21 - Begun to set up barriers
*/
#include "mbed.h"
#include "N5110.h"

//Direction invaders are travelling
#define LEFT 0
#define RIGHT 1

//Preprocessor for screen map
/*
#define EMPTY 0
#define CANNON 1
#define SMALL 2
#define MEDIUM 3
#define LARGE 4
#define BARRIER 5
#define UFO 6
#define CANNON_SHOT 7
*/

//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
        button_->mode(PullUp);
        button_->fall(this, &Joystick::button_isr);

        //Initalises the vairables and flags
        x_offset_ = 0;
        y_offset_ = 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;
        }
    }

    //Getter and setters for flags
    int get_button_flag() {
        return g_button_flag_;
    }

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

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

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

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

    //Stores interrupt flags
    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(PTB2, PTB3, PTB11);

//Shoot button
InterruptIn shoot_button(PTB18);

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

//Map holding pixel data of screen
int screen_map[84][48];
const int empty_pixel = 0;
const int cannon_pixel = 1;
const int first_barrier_pixel = 2;
const int first_large_invader_pixel = 5;
const int first_medium_invader_pixel = 10;
const int first_small_invader_pixel = 15;
const int ufo_pixel = 20;
const int cannon_shot_pixel = 21;

//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}
};

Ticker move_cannon_shot;
bool cannon_shot_on_screen = false;
int cannon_shot_x_pos = 28;
int cannon_shot_y_pos = 40;
bool game_over = false;

//Enemies
Ticker move_enemies;
bool invaders_in_state2 = true;
bool invader_direction = RIGHT;
//Struct to store enemy data
struct Invaders {
    int x_pos;
    int y_pos;
    bool is_alive;
} small_invader[5], medium_invader[5], large_invader[5];
int right_column_alive = 4;
int left_column_alive = 0;
enum LowestInvaderRow {small, medium, large};
LowestInvaderRow lowest_invader_row_alive = large;
//Limits the first invader can travel
int minimum_invader_x_pos = 0;
int maximum_invader_x_pos = 20;
//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, 1, 1, 1, 1, 1, 1, 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, 1, 1, 1, 1, 1, 1, 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}
};

//Barriers
struct Barriers {
    int x_pos;
    int y_pos;
    bool before_bitmap[8][14];
    bool after_bitmap[8][14];
} barrier[3];
int no_of_barriers = 3;
const bool barrier_bitmap[8][14] = {
    {0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {1, 1, 1, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1},
    {1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1},
    {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1},
    {1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1}
};

//TEST FOR SPEC UFO
const bool ufo_bitmap[5][14] = {
    {0, 0, 0, 0, 0, 1, 1, 1, 1, 0, 0, 0, 0, 0},
    {0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0},
    {0, 1, 1, 0, 1, 0, 1, 1, 0, 1, 0, 1, 1, 0},
    {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1},
    {0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0}
};

int row_no = 5;
int col_no = 14;

//ISR Flags
volatile bool g_update_screen_flag = true;
volatile bool g_move_cannon_flag = true;
volatile bool g_shoot_pressed_flag = false;
volatile bool g_move_cannon_shot_flag = false;
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();
//Init shoot button
void init_shoot();
// Added functions
void MoveCannon();
void InitSmallInvaders();
void ClearSmallInvaders();
void DrawSmallInvaders();
void ClearMediumInvaders();
void InitMediumInvaders();
void DrawMediumInvaders();
void InitLargeInvaders();
void CLearLargeInvaders();
void DrawLargeInvaders();
void InitBarriers();
void DrawBarriers();
void ShiftInvaderXPositions();
void ShiftInvaderYPositions(bool new_direction);
//void InitUFO();
void DrawUFO();
//void DrawEnemies(struct Invaders invader[], int no_of_invaders);

//ISR's
void update_screen_isr();
void move_cannon_isr();
void move_enemies_isr();
void shoot_pressed_isr();
void move_cannon_shot_isr();

int down_count = 0;

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

    update_screen.attach(&update_screen_isr, 0.05);
    move_cannon.attach(&move_cannon_isr, 0.05);
    move_enemies.attach(&move_enemies_isr, 0.5);

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

    lcd.refresh();

    while (true) {
        //IF the game is over detach all the tickers
        if (game_over) {
            move_cannon.detach();
            move_enemies.detach();

            lcd.clear();
            lcd.printString("Game Over", 1, 2);
        } else {
            //Updates pixels on the screen
            if (g_update_screen_flag) {
                g_update_screen_flag = false;

                //Loops through the screen map and sets pixels on the LCD
                for (int col = 0; col < 84; col++) {
                    for (int row = 0; row < 48; row++) {
                        if (screen_map[col][row]) {
                            lcd.setPixel(col, row);
                        } else {
                            lcd.clearPixel(col, row);
                        }
                    }
                }
            }
            //Controls cannon movement
            if (g_move_cannon_flag) {
                g_move_cannon_flag = false;

                MoveCannon();
                DrawBarriers();

                lcd.refresh();
            }
            //Spawns a player bullet if the shoot button is pressed and there isn't a bullet on the screen
            if (g_shoot_pressed_flag) {
                g_shoot_pressed_flag = false;

                if (!cannon_shot_on_screen) {
                    cannon_shot_on_screen = true;
                    
                    pc.printf("Shot Fired\n");

                    //Add 4 to cannon x_pos to get shot x_pos
                    cannon_shot_x_pos = cannon_xpos + 4;
                    cannon_shot_y_pos = 40;
                    move_cannon_shot.attach(&move_cannon_shot_isr, 0.05);
                }
            }
            //Move the cannon's shot
            if (g_move_cannon_shot_flag) {
                g_move_cannon_shot_flag = false;

                //Checks bullet will not go beyond the bounds of the screen map
                if (cannon_shot_y_pos > -1) {
                    //Loops throught the shot bitmap and clears the pixels in the screen map
                    for (int row = 0; row < 3; row++) {
                        //Clears the position where the bullet was
                        screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] = empty_pixel;
                    }

                    //Increments the shot going up the screen
                    cannon_shot_y_pos--;

                    //Checks to see what the shot hits. If it hits nothing the shot gets pushed to the screen map
                    for (int row = 0; row < 3; row++) {
                        int object_no;
                        if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] >= first_small_invader_pixel && screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] < (first_small_invader_pixel + 5))
                        {
                            object_no = screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] - first_small_invader_pixel;
                            small_invader[object_no].is_alive = false;
                            pc.printf("Small (%d) Hit\n", object_no);
                            cannon_shot_on_screen = false;
                            move_cannon_shot.detach();
                            break;
                        } else if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] >= first_medium_invader_pixel && screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] < (first_medium_invader_pixel + 5)) {
                            object_no = screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] - first_medium_invader_pixel;
                            medium_invader[object_no].is_alive = false;
                            pc.printf("Medium (%d) Hit\n", object_no);
                            cannon_shot_on_screen = false;
                            move_cannon_shot.detach();
                            break;
                        } else if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] >= first_large_invader_pixel && screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] < (first_large_invader_pixel + 5)) {
                            object_no = screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] - first_large_invader_pixel;
                            large_invader[object_no].is_alive = false;
                            pc.printf("Large (%d) Hit\n", object_no);
                            cannon_shot_on_screen = false;
                            move_cannon_shot.detach();
                            break;
                        } else if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] >= first_barrier_pixel && screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] < (first_barrier_pixel + 3)) {
                            object_no = screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] - first_barrier_pixel;   
                            pc.printf("Barrier (%d) Hit\n", object_no);
                            cannon_shot_on_screen = false;
                            move_cannon_shot.detach();
                            break;
                        } else if (screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] == ufo_pixel) {
                            pc.printf("UFO Hit\n");
                            cannon_shot_on_screen = false;
                            move_cannon_shot.detach();
                            break;
                        } else {
                            screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] = cannon_shot_pixel;
                        }
                    }  
                } else {
                    //Loops throught the shot bitmap and clears the pixels in the screen map
                    for (int row = 1; row < 3; row++) {
                        //Clears the position where the bullet was
                        screen_map[cannon_shot_x_pos][cannon_shot_y_pos + row] = empty_pixel;
                    }
                    cannon_shot_on_screen = false;
                }
            }
        }
        //Controls enemy movement
        if (g_move_enemies_flag) {
            g_move_enemies_flag = false;

            //Added stuff to move to function
            //Checks which columns of invaders are alive on the right and left sides and changes the limits of the first invader
            //MOVE TO COLLISION DETECTION WHEN IT'S DONE
            //Checking the left side
            for (int i = 0; i < 5; i++) {
                if (small_invader[i].is_alive || medium_invader[i].is_alive || large_invader[i].is_alive) {
                    left_column_alive = i;
                    break;
                }
            }
            minimum_invader_x_pos = 0 - left_column_alive*13;
            //Checking the right side
            for (int j = 4; j >= 0; j--) {
                if (small_invader[j].is_alive || medium_invader[j].is_alive || large_invader[j].is_alive) {
                    right_column_alive = j;
                    break;
                }
            }
            maximum_invader_x_pos = 72 - right_column_alive*13;

            //End of block

            //Clears the old bitmaps
            ClearSmallInvaders();
            ClearMediumInvaders();
            CLearLargeInvaders();

            ShiftInvaderXPositions();


            DrawSmallInvaders();
            DrawMediumInvaders();
            DrawLargeInvaders();
            //DrawUFO();

            invaders_in_state2 = !invaders_in_state2;

            lcd.refresh();

            //TEST CODE

            //END
        }

        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 init_shoot()
{
    shoot_button.mode(PullUp);
    shoot_button.fall(&shoot_pressed_isr);

}

void update_screen_isr()
{
    g_update_screen_flag = true;
}

void shoot_pressed_isr()
{
    g_shoot_pressed_flag = true;
}

void move_cannon_shot_isr()
{
    g_move_cannon_shot_flag = true;
}

void move_cannon_isr()
{
    g_move_cannon_flag = true;
}

void MoveCannon()
{
    //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);
                screen_map[cannon_xpos+col][cannon_ypos+row] = empty_pixel;
            }
        }
    }

    //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);
                screen_map[cannon_xpos+col][cannon_ypos+row] = cannon_pixel;
            }
        }
    }
}

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 < 5; i++) {
        small_invader[i].x_pos = 2+ (i*13);
        small_invader[i].y_pos = 1;
        small_invader[i].is_alive = true;
    }
}

void ClearSmallInvaders()
{
    for (int i = 0; i < 5; i++) {
        if (!invaders_in_state2) {
            for (int col = 0; col < 8; col++) {
                for (int row = 0; row < 6; row++) {
                    if(small_invader_bitmap_1[row][col] && small_invader[i].x_pos + col >= 0 && small_invader[i].x_pos + col < 84) {
                        //lcd.clearPixel(small_invader[i].x_pos + col, small_invader[i].y_pos + row);
                        screen_map[small_invader[i].x_pos + col][small_invader[i].y_pos + row] = empty_pixel;
                    }
                }
            }
        } else {
            for (int col = 0; col < 8; col++) {
                for (int row = 0; row < 6; row++) {
                    if(small_invader_bitmap_2[row][col] && small_invader[i].x_pos + col >= 0 && small_invader[i].x_pos + col < 84) {
                        //lcd.clearPixel(small_invader[i].x_pos + col, small_invader[i].y_pos + row);
                        screen_map[small_invader[i].x_pos + col][small_invader[i].y_pos + row] = empty_pixel;
                    }
                }
            }
        }
    }
}

void DrawSmallInvaders()
{
    //For each small invader clear and redraws them if they're alive
    for (int i = 0; i < 5; i++) {
        //Checks if the invader is alive
        if (small_invader[i].is_alive) {
            //Reads off the bitmap and sets the allowed pixels
            if (invaders_in_state2) {
                for (int col = 0; col < 8; col++) {
                    for (int 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);
                            screen_map[small_invader[i].x_pos + col][small_invader[i].y_pos + row] = first_small_invader_pixel + i;
                        }
                    }
                }
            } else {
                for (int col = 0; col < 8; col++) {
                    for (int 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);
                            screen_map[small_invader[i].x_pos + col][small_invader[i].y_pos + row] = first_small_invader_pixel + i;
                        }
                    }
                }
            }
        }
    }
}

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

void ClearMediumInvaders()
{
    for (int i = 0; i < 5; i++) {
        if (!invaders_in_state2) {
            for (int col = 0; col < 10; col++) {
                for (int row = 0; row < 6; row++) {
                    if(medium_invader_bitmap_1[row][col] && medium_invader[i].x_pos + col >= 0 && medium_invader[i].x_pos + col < 84) {
                        //lcd.clearPixel(medium_invader[i].x_pos + col, medium_invader[i].y_pos + row);
                        screen_map[medium_invader[i].x_pos + col][medium_invader[i].y_pos + row] = empty_pixel;
                    }
                }
            }
        } else {
            for (int col = 0; col < 10; col++) {
                for (int row = 0; row < 6; row++) {
                    if(medium_invader_bitmap_2[row][col] && medium_invader[i].x_pos + col >= 0 && medium_invader[i].x_pos + col < 84) {
                        //lcd.clearPixel(medium_invader[i].x_pos + col, medium_invader[i].y_pos + row);
                        screen_map[medium_invader[i].x_pos + col][medium_invader[i].y_pos + row] = empty_pixel;
                    }
                }
            }
        }
    }
}

void DrawMediumInvaders()
{
    //For each small invader clear and redraws them if they're alive
    for (int i = 0; i < 5; i++) {
        //Checks if the invader is alive
        if (medium_invader[i].is_alive) {
            //Reads off the bitmap and sets the allowed pixels
            if (invaders_in_state2) {
                for (int col = 0; col < 10; col++) {
                    for (int 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);
                            screen_map[medium_invader[i].x_pos + col][medium_invader[i].y_pos + row] = first_medium_invader_pixel + i;
                        }
                    }
                }
            } else {
                for (int col = 0; col < 10; col++) {
                    for (int 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);
                            screen_map[medium_invader[i].x_pos + col][medium_invader[i].y_pos + row] = first_medium_invader_pixel + i;
                        }
                    }
                }
            }
        }
    }
}

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

void CLearLargeInvaders()
{
    for (int i = 0; i < 5; i++) {
        //Reads off the bitmap and sets the allowed pixels
        if (!invaders_in_state2) {
            for (int col = 0; col < 12; col++) {
                for (int row = 0; row < 6; row++) {
                    if(large_invader_bitmap_1[row][col] && large_invader[i].x_pos + col >= 0 && large_invader[i].x_pos + col < 84) {
                        ///lcd.clearPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
                        screen_map[large_invader[i].x_pos + col][large_invader[i].y_pos + row] = empty_pixel;
                    }
                }
            }
        } else {
            for (int col = 0; col < 12; col++) {
                for (int row = 0; row < 6; row++) {
                    if(large_invader_bitmap_2[row][col] && large_invader[i].x_pos + col >= 0 && large_invader[i].x_pos + col < 84) {
                        //lcd.clearPixel(large_invader[i].x_pos + col, large_invader[i].y_pos + row);
                        screen_map[large_invader[i].x_pos + col][large_invader[i].y_pos + row] = empty_pixel;
                    }
                }
            }
        }
    }
}

void DrawLargeInvaders()
{
    //For each small invader clear and redraws them if they're alive
    for (int i = 0; i < 5; i++) {
        //Checks if the invader is alive
        if (large_invader[i].is_alive) {
            //Reads off the bitmap and sets the allowed pixels
            if (invaders_in_state2) {
                for (int col = 0; col < 12; col++) {
                    for (int 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);
                            screen_map[large_invader[i].x_pos + col][large_invader[i].y_pos + row] = first_large_invader_pixel + i;
                        }
                    }
                }
            } else {
                for (int col = 0; col < 12; col++) {
                    for (int 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);
                            screen_map[large_invader[i].x_pos + col][large_invader[i].y_pos + row] = first_large_invader_pixel + i;
                        }
                    }
                }
            }
        }
    }
}
/*
void DrawInvaders(struct Invaders invader[], int no_of_invaders, bool bitmap[][])
{
    //For each small invader clear and redraws them if they're alive
    for (int i = 0; i < no_of_invaders; i++) {
        //Clears the enemy position
        lcd.drawRect(invader[i].x_pos, invader[i].y_pos, 12, 6, 2);

        //Checks if the invader is alive
        if (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 (invaders_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);
                        }
                    }
                }
            }
        }
    }
}
*/


void InitBarriers()
{
    for (int i = 0; i < no_of_barriers; i++) {
        barrier[i].x_pos = 10 + (i*25);
        barrier[i].y_pos = 33;
        //Copies the bitmap into the structs
        memcpy(barrier[i].before_bitmap, barrier_bitmap, sizeof(barrier_bitmap));
        memcpy(barrier[i].after_bitmap, barrier_bitmap, sizeof(barrier_bitmap));
    }
}

void DrawBarriers()
{
    //Clears the barrier and redraws it with damage applied
    for (int i = 0; i < no_of_barriers; i++) {
        for (int col = 0; col < 14; col++) {
            for (int row = 0; row < 8; row++) {
                if (barrier[i].before_bitmap[row][col]) {
                    //lcd.clearPixel(barrier[i].x_pos + col, barrier[i].y_pos + row);
                    screen_map[barrier[i].x_pos + col][barrier[i].y_pos + row] = empty_pixel;
                }
                if (barrier[i].after_bitmap[row][col]) {
                    //lcd.setPixel(barrier[i].x_pos + col, barrier[i].y_pos + row);
                    screen_map[barrier[i].x_pos + col][barrier[i].y_pos + row] = first_barrier_pixel + i;
                }
            }
        }
        //Copies the after array to the before array
        memcpy(barrier[i].before_bitmap, barrier[i].after_bitmap, sizeof(barrier[i].after_bitmap));
    }
}

void ShiftInvaderXPositions()
{
    if (invader_direction == RIGHT) {
        //Checks the first large invader to see if it can travel anymore
        if (large_invader[0].x_pos < maximum_invader_x_pos) {
            for (int i = 0; i < 5; i++) {
                small_invader[i].x_pos += 2;
                medium_invader[i].x_pos += 2;
                large_invader[i].x_pos += 2;
            }
        } else {
            ShiftInvaderYPositions(LEFT);
        }
    } else {
        //Checks the first large invader to see if it can travel anymore
        if (large_invader[0].x_pos > minimum_invader_x_pos) {
            for (int i = 0; i < 5; i++) {
                small_invader[i].x_pos -= 2;
                medium_invader[i].x_pos -= 2;
                large_invader[i].x_pos -= 2;
            }
        } else {
            ShiftInvaderYPositions(RIGHT);
        }
    }
}

void ShiftInvaderYPositions(bool new_direction)
{
    //Checks to see which row of invaders are still alive to work out maximum y positions
    if (large_invader[0].is_alive || large_invader[1].is_alive || large_invader[2].is_alive || large_invader[3].is_alive || large_invader[4].is_alive) {
        lowest_invader_row_alive = large;
    } else if (medium_invader[0].is_alive || medium_invader[1].is_alive || medium_invader[2].is_alive || medium_invader[3].is_alive || medium_invader[4].is_alive) {
        lowest_invader_row_alive = medium;
    } else {
        lowest_invader_row_alive = small;
    }
    //If an invader touches the bottom the game ends, otherwise the invaders descend
    if (small_invader[0].y_pos < 39 - (7*lowest_invader_row_alive)) {
        for (int i = 0; i < 5; i++) {
            small_invader[i].y_pos += 3;
            medium_invader[i].y_pos += 3;
            large_invader[i].y_pos += 3;
            invader_direction = new_direction;
        }
    } else {
        game_over = true;
    }

    //TEST CODE
    down_count++;
}

/*
void InitUFO()
{

}
*/

void DrawUFO()
{
    //Draws the UFO
    int x_pos = 20;
    int y_pos = 25;
    for (int col = 0; col < col_no; col++) {
        for (int row = 0; row < row_no; row++) {
            if(ufo_bitmap[row][col]) {
                //lcd.setPixel(x_pos + col, y_pos + row);
                screen_map[x_pos + col][y_pos + row] = ufo_pixel;
            }
        }
    }
}