ECE 2035 AgarIO MiniProject

Dependencies:   4DGL-uLCD-SE ECE2035_Agar_Shell EthernetInterface Game_Synchronizer MMA8452 SDFileSystem Sound USBDevice mbed-rtos mbed wave_player

Fork of ECE2035_Agar_Shell by ECE2035 Spring 2015 TA

This program is a MiniProject given in ECE 2035. This is to design and program the multiplayer ethernet based AGAR.IO mbed game. Starting code is given by the instructor to aid student to complete the project. It utilize uLCD, Accelerometer, pushbuttons, sdFileSystem, ethernetBreakoutBoard, speaker in mBED LPC1768. It uses the similar concept to the Game http://agar.io/

main.cpp

Committer:
pkoirala3
Date:
2017-03-18
Revision:
1:e487713a5231
Parent:
0:9d6ea88b6d14

File content as of revision 1:e487713a5231:

// Student Side Shell Code
// By: Prana Koirala
// ECE 2035
// AGAR.GT Game
// For the baseline, anywhere you see ***, you have code to write.

#include "mbed.h"
#include "SDFileSystem.h"
#include "wave_player.h"
#include "game_synchronizer.h"
#include "misc.h"
#include "blob.h"
#include "playSound.h"
#include "uLCD_4DGL.h"
#include "TMP36.h"


#define NUM_BLOBS 22

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut led4(LED4);

DigitalOut RedLED(p15);
DigitalOut GreenLED(p14);
DigitalOut BlueLED(p13);

DigitalIn pb_u(p21);                        // Up Button
DigitalIn pb_r(p22);                        // Right Button
DigitalIn pb_d(p23);                        // Down Button
DigitalIn pb_l(p24);                        // Left Button
TMP36 TEMP(p15);
char hitTune[] = "/sd/score.wav";            // identifies a blob being eaten

Serial pc(USBTX, USBRX);                    // Serial connection to PC. Useful for debugging!
MMA8452 acc(p28, p27, 100000);              // Accelerometer (SDA, SCL, Baudrate)
uLCD_4DGL uLCD(p9,p10,p11);                 // LCD (tx, rx, reset)
SDFileSystem sd(p5, p6, p7, p8, "sd");      // SD  (mosi, miso, sck, cs)
AnalogOut DACout(p18);                      // speaker
wave_player player(&DACout);                // wav player
GSYNC game_synchronizer;                    // Game_Synchronizer
GSYNC* sync = &game_synchronizer;           //
Timer frame_timer;                          // Timer

int score1 = 0;                             // Player 1's score.
int score2 = 0;                             // Player 2's score.
int num_player = 0;
int const time_unit = 1000;                 // time for screen refresh


void display_Temp(void)
{
    float V = TEMP;  // Displaying Temp of chip so that player can quit game and cool it.
    uLCD.printf("\n\n\n\n\n\n\n\nTemp:%4.1F Deg F\n",V);
}


// This Display the game menu on the player 1 mbed to give option to play in single or multiplayer mode.
// They can use up and down button to make choice, some sound effect added.

int game_menu(void)
{
    uLCD.set_font(FONT_8X12);
    uLCD.background_color(BGRD_COL);
    uLCD.textbackground_color(BGRD_COL);
    uLCD.cls();
    uLCD.locate(0,0);
    uLCD.puts("Welcome to Agar");
    uLCD.printf("\n\n");
    wait(2.0);
    uLCD.printf("Loading Game...");
    uLCD.printf("\n\n\n\n\n\n");
    wait(3.0);
    display_Temp();
    BlueLED = 1;
    
    uLCD.cls();

// Print single player or multiplayer mode. Depending which button is pressed, return either SINGLE_PLAYER or MULTI_PLAYER.
    uLCD.set_font(FONT_7X8);
    uLCD.printf("Select Mode:\n\n");
    uLCD.printf("1P:Press up btn\n\n");
    uLCD.printf("2P:Press down btn\n");
    display_Temp();
    int Mode = 0;
    while(1) {
        if(!pb_u) {
            Mode = SINGLE_PLAYER;
            break;
        }
        if(!pb_d) {
            Mode = MULTI_PLAYER;
            break;
        }
    }
    return Mode;
}

// Initialize the game hardware.
// Call game_menu to find out which mode to play the game in (Single or MultiPlayer)
// Initialize the game synchronizer.
void game_init(void)
{
    led1 = 0;
    led2 = 0;
    led3 = 0;
    led4 = 0;

    pb_u.mode(PullUp);
    pb_r.mode(PullUp);
    pb_d.mode(PullUp);
    pb_l.mode(PullUp);

    pc.printf("\033[2J\033[0;0H");              // Clear the terminal screen.
    pc.printf("I'm alive! Player 1\n");         // Let us know you made it this far

    // game_menu MUST return either SINGLE_PLAYER or MULTI_PLAYER
    int num_player = game_menu();

    GS_init(sync, &uLCD, &acc, &pb_u, &pb_r, &pb_d, &pb_l, num_player, PLAYER1); // Connect to the other player.

    pc.printf("Initialized...\n");              // Let us know you finished initializing.
    srand(time(NULL));                          // Seed the random number generator.

    GS_cls(sync, SCREEN_BOTH);
    GS_update(sync);
}

// Function for displaying the string
void prints_string(char* text, int x, int y, int backgrnd, int foregrnd, bool clr)
{
    uLCD.background_color(backgrnd);
    uLCD.textbackground_color(foregrnd);
    uLCD.set_font(FONT_7X8);
    if (clr == 1) {
        uLCD.cls();
    }
    uLCD.locate(x,y);
    uLCD.puts(text);
    uLCD.printf("\n\n\n\n\n\n");
    display_Temp();
}


// Display who won!
int game_over(int winner)
{
    if (winner == WINNER_P1) {   // P1 wins
        char P1_WIN[10] = "P1 Won";
        prints_string(P1_WIN, 0, 0, BGRD_COL, RED, 0);
        char buzzer[] = "/sd/won.wav";
        playSound(buzzer);   // Play the sound in the board

    } else if (winner == WINNER_P2) {  // P2 OR AI wins
        if (num_player == SINGLE_PLAYER) {   // AI wins
            char AI_WIN[10] = "PC Won";
            prints_string(AI_WIN, 0, 0, BGRD_COL, RED, 0);
            char buzzer[] = "/sd/won.wav";
            playSound(buzzer);   // Play the sound in the board


        } else {   // P2 wins
            char P2_WIN[10] = "P2 Won";
            prints_string(P2_WIN, 0, 0, BGRD_COL, RED, 0);
            char buzzer[] = "/sd/won.wav";
            playSound(buzzer);   // Play the sound in the board
        }

    } else if (winner == WINNER_TIE) {  // Tied game
        char NO_WIN[10] = "TIE";
        prints_string(NO_WIN, 0, 0, BGRD_COL, RED, 0);
        char buzzer[] = "/sd/won.wav";
        playSound(buzzer);   // Play the sound in the board

    }
    while(1) {
        RedLED = 0;
        wait(0.75);
        RedLED = 1;

        if(!pb_r) {
            uLCD.printf("Loading new Game");
            wait(1.5);
            uLCD.cls();
            uLCD.printf("\n\n\n\n\n\n\n\n\n");
            display_Temp();
            return(1);
        }
    }
}

// Take in a pointer to the blobs array. Iterate over the array
// and initialize each blob with BLOB_init(). Set the first blob to (for example) blue
// and the second blob to (for example) red. Set the color(s) of the food blobs however you like.
// Make the radius of the "player blobs" equal and larger than the radius of the "food blobs".
void generate_blobs(BLOB* blobs)
{
    int sizePlayer = 15;
    int sizeFood = 8;
    for (int i = 0; i < NUM_BLOBS; i++) {
        int rad = (i == PLAYER1 || i == PLAYER2) ? sizePlayer : sizeFood;   // get the radius
        int col = (i == PLAYER1 || i == PLAYER2) ? ((i == PLAYER1) ? P1_COL : P2_COL) : FOOD_COL;   // get the color
        BLOB_init(&blobs[i], rad, col);         //void BLOB_init(BLOB* b, int rad, int color)
        BLOB_print(blobs[i]);
    }
}



int main (void)
{

Play_again:             // Option to play again
    int score1 = 0;                             // Player 1's score reseting
    int score2 = 0;                             // Player 2's score reseting

    int* p1_buttons;
    int* p2_buttons;

    float ax1, ay1, az1;
    float ax2, ay2, az2;

    float time_step = .01;

    int rect_bl_x, rect_bl_y, rect_ur_x, rect_ur_y;     // rect. boundary, bottom-left, top-right (x,y)
    float blob_x, blob_y;                                 // pos (x,y) for a blob


    // Ask the user to choose (via pushbuttons)
    // to play in single- or multi-player mode.
    // Use their choice to correctly initialize the game synchronizer.
    game_init();

    // Keep an array of blobs. Use blob 0 for player 1 and
    // blob 1 for player 2.
    BLOB blobs[NUM_BLOBS];

    // Pass in a pointer to the blobs array. Iterate over the array
    // and initialize each blob with BLOB_init(). Set the radii and colors
    // anyway you see fit.
    generate_blobs(blobs);


    while(true) {
        GS_background_color(sync, SCREEN_BOTH, BGRD_COL);       // paint background colors

        // In single-player, check to see if the player has eaten all other blobs.
        // In multi-player mode, check to see if the players have tied by eating half the food each.
        // ***
        // check based on food eaten
        if ((score1 + score2) >= (NUM_BLOBS-2) ) {
            if (score1 > score2 && blobs[PLAYER1].valid == 1) {
                // P1 wins
                game_over(WINNER_P1);
                game_over(WINNER_P1);
                goto Play_again;   // To play again
            } else if (score2 > score1 && blobs[PLAYER2].valid == 1) {
                //P2 || AI wins
                game_over(WINNER_P2);
                game_over(WINNER_P1);
                goto Play_again;   // To play again
            } else if (score1 == score2) {
                // Tie game
                game_over(WINNER_TIE);
                game_over(WINNER_P1);
                goto Play_again;   // To play again
            }
        }
        // check based on eating other player
        if (blobs[PLAYER2].valid == 0) {
            // P1  wins
            game_over(WINNER_P1);
            game_over(WINNER_P1);
            goto Play_again;   // To play again
        } else if (blobs[PLAYER1].valid == 0) {
            // P2 || AI wins
            game_over(WINNER_P2);
            game_over(WINNER_P1);
            goto Play_again;   // To play again
        }


        // In both single- and multi-player modes, display the score(s) in an appropriate manner.
        // ***
        if (num_player == SINGLE_PLAYER) {
            // disp score top right of screen
            char scoreBanner[40];
            sprintf(scoreBanner,"Score:%d ", score1);
            uLCD.background_color(BGRD_COL);
            uLCD.textbackground_color(RED);//BGRD_COL);
            uLCD.locate(10,0);
            uLCD.puts(scoreBanner);

            //GS_locate(sync, SCREEN_P1, 12,0);     // GS_locate(GSYNC* gs, char screen, int x, int y)
            //GS_puts(sync, SCREEN_P1, bannerScore, strlen(bannerScore));      // void GS_puts(GSYNC* gs, char screen, char* str, int strlen)
        } else if (num_player == MULTI_PLAYER) {
            // disp score top right of screen
            char bannerScore[40];
            sprintf(bannerScore,"MS: P1: %2d \n    P2: %2d ", score1, score2);
            GS_locate(sync, SCREEN_BOTH, 9,0);     // GS_locate(GSYNC* gs, char screen, int x, int y)
            GS_puts(sync, SCREEN_BOTH, bannerScore, sizeof(bannerScore));      // void GS_puts(GSYNC* gs, char screen, char* str, int strlen)
        }

        // Use the game synchronizer API to get the button values from both players' mbeds.
        p1_buttons = GS_get_p1_buttons(sync);
        p2_buttons = GS_get_p2_buttons(sync);

        // Use the game synchronizer API to get the accelerometer values from both players' mbeds.
        GS_get_p1_accel_data(sync, &ax1, &ay1, &az1);
        GS_get_p2_accel_data(sync, &ax2, &ay2, &az2);


        // If the magnitude of the p1 x and/or y accelerometer values exceed ACC_THRESHOLD,
        // set the blob 0 velocities to be proportional to the accelerometer values.
        // If in multi-player mode and the magnitude of the p2 x and/or y accelerometer values exceed ACC_THRESHOLD,
        // set the blob 0 velocities to be proportional to the accelerometer values.
        // ****/
        float scalFact = 1000*(5/3)/(blobs[PLAYER1].rad * 0.5);
        if (abs(ax1) >= ACC_THRESHOLD)
            blobs[PLAYER1].vx = ax1 * scalFact;
        else
            blobs[PLAYER1].vx = 0;

        if (abs(ay1) >= ACC_THRESHOLD)
            blobs[PLAYER1].vy = ay1 * scalFact;
        else
            blobs[PLAYER1].vy = 0;


        // Undraw the world bounding rectangle (use BGRD_COL).
        // ***
        rect_bl_x = 0 - blobs[PLAYER1].old_x;
        rect_bl_y = 0 - blobs[PLAYER1].old_y;
        rect_ur_x = WORLD_WIDTH  - blobs[PLAYER1].old_x;
        rect_ur_y = WORLD_HEIGHT - blobs[PLAYER1].old_y;
        GS_rectangle(sync, SCREEN_P1, rect_bl_x, rect_bl_y, rect_ur_x, rect_ur_y, BGRD_COL);
        // multi-player mode
        if (num_player == MULTI_PLAYER) {
            rect_bl_x = 0 - blobs[PLAYER2].old_x;
            rect_bl_y = 0 - blobs[PLAYER2].old_y;
            rect_ur_x = WORLD_WIDTH  - blobs[PLAYER2].old_x;
            rect_ur_y = WORLD_HEIGHT - blobs[PLAYER2].old_y;
            GS_rectangle(sync, SCREEN_P2, rect_bl_x, rect_bl_y, rect_ur_x, rect_ur_y, BGRD_COL);
        }


        // Loop over all blobs
        // ***
        for (int i = 0; i < NUM_BLOBS; i++) {
            // ***
            if (blobs[i].delete_now == 1) {
                blob_x = blobs[i].posx - blobs[PLAYER1].old_x;
                blob_y = blobs[i].posy - blobs[PLAYER1].old_y;
                GS_circle(sync, SCREEN_P1, blob_x, blob_y, blobs[i].rad, BGRD_COL);
                if (num_player == MULTI_PLAYER) {
                    blob_x = blobs[i].posx - blobs[PLAYER2].old_x;
                    blob_y = blobs[i].posy - blobs[PLAYER2].old_y;
                    GS_circle(sync, SCREEN_P2, blob_x, blob_y, blobs[i].rad, BGRD_COL);
                }
                blobs[i].delete_now = 0;
            }


            // Use the blob positions and velocities, as well as the time_step to compute the new position of the blob.
            // ***

            blobs[i].old_x = blobs[i].posx;
            blobs[i].old_y = blobs[i].posy;
            blobs[i].posx += blobs[i].vx * time_step;
            blobs[i].posy += blobs[i].vy * time_step;



            // If the current blob is blob 0, iterate over all blobs and check if they are close enough to eat or be eaten.
            // In multi-player mode, if the player 0 blob is eaten, player 1 wins and vise versa.
            // If blob 0 eats some food, increment score1.
            // ***
            if (i == PLAYER1) {
                for (int j = 1; j < NUM_BLOBS; j++) {
                    if (j == PLAYER1)   continue;           // skip self
                    if (blobs[j].valid == 0)    continue;   // skip invalid blobs
                    // get dist between two blobs
                    float dist2 = BLOB_dist2(blobs[i], blobs[j]);
                    if (sqrt(dist2) < blobs[i].rad) {
                        // danger zone, eat or be eaten
                        if (blobs[i].rad > blobs[j].rad) {
                            // P1 is bigger, so P1 eats
                            blobs[j].valid = 0;     // eaten blob is now invalid
                            blobs[i].rad = blobs[i].rad + 4;         // P1 inc. size and score
                            score1++;               // ...
                            playSound(hitTune);
                            // undraw smaller sized blob
                            // void GS_circle(GSYNC* gs, char screen, int x , int y , int radius, int color)
                            GS_circle(sync, SCREEN_P1, 0, 0, (blobs[i].rad-1), BGRD_COL);
                            if (num_player == MULTI_PLAYER) {
                                blob_x = blobs[i].posx - blobs[PLAYER2].old_x;
                                blob_y = blobs[i].posy - blobs[PLAYER2].old_y;
                                // void GS_circle(GSYNC* gs, char screen, int x , int y , int radius, int color)
                                GS_circle(sync, SCREEN_P2, blob_x, blob_y, (blobs[i].rad-1), BGRD_COL);
                            }

                            if (j == PLAYER2 && num_player == MULTI_PLAYER) {
                                pc.printf("NOT HERE\n");
                                game_over(WINNER_P1);       // P2 loses
                                game_over(WINNER_P1);
                                goto Play_again;   // To play again
                            }
                        } else if (blobs[i].rad < blobs[j].rad) {
                            // P1 is smaller, so P1 is eaten
                            blobs[i].valid = 0;     // eaten blob is now invalid
                            game_over(WINNER_P2);   // P2 || AI wins
                            game_over(WINNER_P1);
                            goto Play_again;   // To play again
                        }
                    }
                }
            }

            // If the current blob is blob 1 and we are playing in multi-player mode, iterate over all blobs and check
            // if they are close enough to eat or be eaten. In multi-player mode, if the player 1 blob is eaten, player 0 wins and vise versa.
            // If blob1 eats some food, increment score 2.
            // ***
            if (i == PLAYER2) {
                for (int j = 0; j < NUM_BLOBS; j++) {
                    if (j == PLAYER2)   continue;           // skip self
                    if (blobs[j].valid == 0)    continue;   // skip invalid blobs
                    // get dist between two blobs
                    float dist2 = BLOB_dist2(blobs[i], blobs[j]);
                    if (sqrt(dist2) < blobs[i].rad) {
                        if (blobs[i].rad > blobs[j].rad) {
                            blobs[j].valid = 0;
                            blobs[i].rad = blobs[i].rad + 4;
                            score2++;
                            playSound(hitTune);
                            GS_circle(sync, SCREEN_P2, 0, 0, (blobs[i].rad-1), BGRD_COL);
                            if (num_player == MULTI_PLAYER) {
                                blob_x = blobs[i].posx - blobs[PLAYER1].old_x;
                                blob_y = blobs[i].posy - blobs[PLAYER1].old_y;
                                GS_circle(sync, SCREEN_P1, blob_x, blob_y, (blobs[i].rad-1), BGRD_COL);
                            }

                            if (j == PLAYER1 && num_player == MULTI_PLAYER) {
                                game_over(WINNER_P2);
                                game_over(WINNER_P1);
                                goto Play_again;   // To play again
                            }
                        } else if (blobs[i].rad < blobs[j].rad) {
                            blobs[i].valid = 0;
                            if (j == PLAYER1 && num_player == MULTI_PLAYER) {
                                game_over(WINNER_P1);
                                game_over(WINNER_P1);
                                goto Play_again;   // To play again
                            }
                        }
                    }
                }
            }

            BLOB_constrain2world(&blobs[i]);
        }

        // Iterate over all blobs and draw them at their newly computed positions. Reference their positions to the player blobs.
        // That is, on screen 1, center the world on blob 0 and reference all blobs' position to that of blob 0.
        // On screen 2, center the world on blob 1 and reference all blobs' position tho that of blob 1.
        // ***
        for (int i = 0; i < NUM_BLOBS; i++) {
            if (blobs[i].valid == 1) {
                blob_x = blobs[i].posx - blobs[PLAYER1].posx;
                blob_y = blobs[i].posy - blobs[PLAYER1].posy;
                GS_circle(sync, SCREEN_P1, blob_x, blob_y, blobs[i].rad, blobs[i].color);
                if (num_player == MULTI_PLAYER) {
                    blob_x = blobs[i].posx - blobs[PLAYER2].posx;
                    blob_y = blobs[i].posy - blobs[PLAYER2].posy;
                    GS_circle(sync, SCREEN_P2, blob_x, blob_y, blobs[i].rad, blobs[i].color);
                }
            }
            blobs[i].delete_now = 1;
        }


        // Redraw the world boundary rectangle.
        // ***
        rect_bl_x = 0 - blobs[PLAYER1].old_x;
        rect_bl_y = 0 - blobs[PLAYER1].old_y;
        rect_ur_x = WORLD_WIDTH  - blobs[PLAYER1].old_x;
        rect_ur_y = WORLD_HEIGHT - blobs[PLAYER1].old_y;
        GS_rectangle(sync, SCREEN_P1, rect_bl_x, rect_bl_y, rect_ur_x, rect_ur_y, BORDER_COL);
        // multi-player mode
        if (num_player == MULTI_PLAYER) {
            rect_bl_x = 0 - blobs[PLAYER2].posx;
            rect_bl_y = 0 - blobs[PLAYER2].posy;
            rect_ur_x = WORLD_WIDTH  - blobs[PLAYER2].posx;
            rect_ur_y = WORLD_HEIGHT - blobs[PLAYER2].posy;
            GS_rectangle(sync, SCREEN_P2, rect_bl_x, rect_bl_y, rect_ur_x, rect_ur_y, BORDER_COL);
        }

        // Update the screens by calling GS_update.
        GS_update(sync);

        led1 = p1_buttons[0] ^ p2_buttons[0];
        led2 = p1_buttons[1] ^ p2_buttons[1];
        led3 = p1_buttons[2] ^ p2_buttons[2];
        led4 = p1_buttons[3] ^ p2_buttons[3];
    }

}