Jay Balar / Mbed 2 deprecated 4180_Project_3

Dependencies:   4DGL-uLCD-SE Physac-MBED PinDetect SDFileSystem mbed-rtos mbed

hockey/hockey.cpp

Committer:
jstephens78
Date:
2022-11-30
Revision:
16:6cf744b2623a
Parent:
12:5d913b57da7c
Child:
17:3517251daf96

File content as of revision 16:6cf744b2623a:

#include "hockey.h"
#include "globals.h"

#define PHYSAC_NO_THREADS
#define PHYSAC_STANDALONE
#define PHYSAC_IMPLEMENTATION
#define _STDBOOL_H
#include "physac.h"

#define SCREEN_WIDTH 128
#define SCREEN_HEIGHT 128

// Controls size of gamepieces in the hockey arena. This influences both
// rendering and collision, so be careful adjusting dimensions too small
#define HOCKEY_PUCK_RADIUS 4
#define HOCKEY_PADDLE_W 8
#define HOCKEY_PADDLE_H 24

// Controls the dimensions of the arena. You can adjust the screen margin above
// and below the court, and the width of the goal.
#define HOCKEY_ARENA_TOP 16
#define HOCKEY_ARENA_BOT 127
#define HOCKEY_GOAL_HEIGHT 32

// Properties derived from other macros
#define _HOCKEY_ARENA_H (HOCKEY_ARENA_BOT - HOCKEY_ARENA_TOP)
#define _HOCKEY_GOAL_TOP ((_HOCKEY_ARENA_H - HOCKEY_GOAL_HEIGHT)/2 + HOCKEY_ARENA_TOP)
#define _HOCKEY_GOAL_BOT (_HOCKEY_GOAL_TOP + HOCKEY_GOAL_HEIGHT)

int blue_score = 0;
int red_score = 0;

PhysicsBody puck;
PhysicsBody paddle_a;
PhysicsBody paddle_b;

float input_sensitivity = 0.01f;

int maxOf(int a, int b)
{
    return (a > b) ? a : b;
}

int minOf(int a, int b)
{
    return (a < b) ? a : b;
}

void initPhysicsObjects()
{
    puck = CreatePhysicsBodyCircle((Vector2) {
        SCREEN_WIDTH/2, SCREEN_HEIGHT/2
    }, HOCKEY_PUCK_RADIUS, 1);
    puck->enabled = true;
    puck->useGravity = false;
    puck->restitution = 1.0;
    puck->dynamicFriction = 0.0;
    puck->velocity = (Vector2) {
        5, 0
    };

    paddle_a = CreatePhysicsBodyRectangle((Vector2) {
        32, 64
    }, HOCKEY_PADDLE_W, HOCKEY_PADDLE_H, 100);
    paddle_a->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions)
    paddle_a->useGravity = false;
    paddle_a->restitution = 1.0;
    SetPhysicsBodyRotation(paddle_a, 3.14159 / 6);

    paddle_b = CreatePhysicsBodyRectangle((Vector2) {
        96, 64
    }, HOCKEY_PADDLE_W, HOCKEY_PADDLE_H, 100);
    paddle_b->enabled = false; // Disable body state to convert it to static (no dynamics, but collisions)
    paddle_b->useGravity = false;
    paddle_b->restitution = 1.0;
    SetPhysicsBodyRotation(paddle_b, 3.14159 / 6);
}

/**
 * Draws the fixed graphics of the game. This is the border of the arena
 */
void drawStaticEnvironment()
{
    uLCD.line(0, _HOCKEY_GOAL_TOP, 0, HOCKEY_ARENA_TOP, BLUE);
    uLCD.line(0, _HOCKEY_GOAL_BOT, 0, HOCKEY_ARENA_BOT, BLUE);
    uLCD.line(0, HOCKEY_ARENA_TOP, 63, HOCKEY_ARENA_TOP, BLUE);
    uLCD.line(0, HOCKEY_ARENA_BOT, 63, HOCKEY_ARENA_BOT, BLUE);

    uLCD.line(127, _HOCKEY_GOAL_TOP, 127, HOCKEY_ARENA_TOP, RED);
    uLCD.line(127, _HOCKEY_GOAL_BOT, 127, HOCKEY_ARENA_BOT, RED);
    uLCD.line(64, HOCKEY_ARENA_TOP, 127, HOCKEY_ARENA_TOP, RED);
    uLCD.line(64, HOCKEY_ARENA_BOT, 127, HOCKEY_ARENA_BOT, RED);
}

/**
 * Redraws the puck and paddles
 * Each elements is erased, updated, and redrawn in as short of a window as
 * possible.
 */
void drawDynamicObjects()
{
    static int puck_x = SCREEN_WIDTH / 2,
               puck_y = SCREEN_WIDTH / 2;

    // Redraw puck if moved
    if (puck_x != puck->position.x || puck_y != puck->position.y) {
        // erase
        uLCD.filled_circle(puck_x, puck_y, HOCKEY_PUCK_RADIUS, BLACK);

        // update
        puck_x = puck->position.x;
        puck_y = puck->position.y;

        // redraw
        uLCD.filled_circle(puck_x, puck_y, HOCKEY_PUCK_RADIUS, GREEN);
    }

    // Redraw blue paddle
    static int pa_x1 = 64,
               pa_x2 = 64,
               pa_y1 = 64,
               pa_y2 = 64;

    float sinA = sin(-paddle_a->orient) / 2;
    float cosA = cos(-paddle_a->orient) / 2;
    uLCD.line(pa_x1, pa_y1, pa_x2, pa_y2, BLACK);
    pa_x1 = paddle_a->position.x + HOCKEY_PADDLE_H * sinA;
    pa_x2 = paddle_a->position.x - HOCKEY_PADDLE_H * sinA;
    pa_y1 = paddle_a->position.y + HOCKEY_PADDLE_H * cosA;
    pa_y2 = paddle_a->position.y - HOCKEY_PADDLE_H * cosA;
    uLCD.line(pa_x1, pa_y1, pa_x2, pa_y2, BLUE);

    // Redraw red paddle
    static int pb_x1 = 64,
               pb_x2 = 64,
               pb_y1 = 64,
               pb_y2 = 64;
    float sinB = sin(-paddle_b->orient) / 2;
    float cosB = cos(-paddle_b->orient) / 2;
    uLCD.line(pb_x1, pb_y1, pb_x2, pb_y2, BLACK);
    pb_x1 = paddle_b->position.x + HOCKEY_PADDLE_H * sinB;
    pb_x2 = paddle_b->position.x - HOCKEY_PADDLE_H * sinB;
    pb_y1 = paddle_b->position.y + HOCKEY_PADDLE_H * cosB;
    pb_y2 = paddle_b->position.y - HOCKEY_PADDLE_H * cosB;
    uLCD.line(pb_x1, pb_y1, pb_x2, pb_y2, RED);
}


void resetGame()
{
    if (red_score >= 5 || blue_score >= 5) {
        uLCD.cls();
        uLCD.printf("Game Over");

        if (red_score > blue_score) {
            uLCD.printf("Red Wins");
        } else {
            uLCD.printf("Blue Wins");
        }

        Thread::wait(2000);

        game2 = false;
    } else {
        uLCD.cls();
        drawStaticEnvironment();

        puck->position.x = SCREEN_WIDTH/2;
        puck->position.y = SCREEN_HEIGHT/2;
        paddle_a->position.x = 32;
        paddle_a->position.y = 64;
        SetPhysicsBodyRotation(paddle_a, 0);

        paddle_b->position.x = 96;
        paddle_b->position.y = 64;
        SetPhysicsBodyRotation(paddle_b, 0);
    }
}



/**
 *
 */
void runGameLogic()
{
    // If puck hits the ceiling or floor, reflect across the y component of
    // the velocity
    if (puck->position.y < HOCKEY_ARENA_TOP + HOCKEY_PUCK_RADIUS + 1) {
        puck->velocity.y *= -1;
        puck->position.y = maxOf(
                               puck->position.y,
                               HOCKEY_ARENA_TOP + HOCKEY_PUCK_RADIUS + 1);
    } else if (puck->position.y > HOCKEY_ARENA_BOT - HOCKEY_PUCK_RADIUS - 1) {
        puck->velocity.y *= -1;
        puck->position.y = minOf(
                               puck->position.y,
                               HOCKEY_ARENA_BOT - HOCKEY_PUCK_RADIUS - 1);
    }

    // true if the puck is in the y range corresponding to the goal
    bool puckInGoalRange =
        puck->position.y > _HOCKEY_GOAL_TOP &&
        puck->position.y < _HOCKEY_GOAL_BOT;

    // Puck collides with left or right walls
    if (puckInGoalRange == false) {
        if (puck->position.x < HOCKEY_PUCK_RADIUS + 1) {
            puck->velocity.x *= -1;
            puck->position.x = maxOf(
                                   puck->position.x,
                                   HOCKEY_PUCK_RADIUS + 1);
        } else if (puck->position.x > SCREEN_WIDTH - HOCKEY_PUCK_RADIUS - 1) {
            puck->velocity.x *= -1;
            puck->position.x = minOf(
                                   puck->position.x,
                                   SCREEN_WIDTH - HOCKEY_PUCK_RADIUS - 2);
        }
    }

    // Puck in goals
    else {
        // SCORE RED
        if (puck->position.x < -HOCKEY_PUCK_RADIUS * 2) {
            red_score += 1;
            uLCD.printf("Red Scores");
            uLCD.printf("   %i - %i", blue_score, red_score);
            Thread::wait(2000);
            resetGame();
        }

        // SCORE BLUE
        else if (puck->position.x > SCREEN_WIDTH + HOCKEY_PUCK_RADIUS*2) {
            blue_score += 1;
            uLCD.printf("Blue Scores");
            uLCD.printf("   %i - %i", blue_score, red_score);
            Thread::wait(2000);
            resetGame();
        }
    }
}

void hockeyGame(void)
{
    printf("Entering thread 2\r\n");
    while (true) {
        
        while (game2 == false) {
            printf("Waiting thread 2\r\n");
            Thread::wait(500);
        }
        
        printf("Starting Game 2 - Air Hockey\r\n");
        
        // Reset game variables
        red_score = 0;
        blue_score = 0;

        // Reset screen, draw arena
        uLCD.baudrate(BAUD_3000000);
        uLCD.cls();
        drawStaticEnvironment();

        // Set up Physac objects & simulation
        initPhysicsObjects();

        Timer timer;
        timer.start();

        deltaTime = 1.66;

        while (game2) {
            float dt = timer.read() * 1000;
            timer.reset();

            // Update the physics of the game
            accumulator += dt;
            if (accumulator >= deltaTime) {
                PhysicsStep();
                accumulator -= deltaTime;

                runGameLogic();
            }

            // Render the game
            drawDynamicObjects();
    
            // Process input from the game
            blue.parseMessage();
            if (blue.button[BUTTON_UP]) {
                paddle_a->position.y -= dt * input_sensitivity;
                printf("UP\r\n");
            }
            if (blue.button[BUTTON_DOWN]) {
                paddle_a->position.y += dt * input_sensitivity;
                printf("DOWN\r\n");
            }
            if (blue.button[BUTTON_LEFT]) {
                paddle_a->position.x -= dt * input_sensitivity;
                printf("LEFT\r\n");
            }
            if (blue.button[BUTTON_RIGHT]) {
                paddle_a->position.x += dt * input_sensitivity;
                printf("RIGHT\r\n");
            }
            if (blue.button[BUTTON_A]) {
                SetPhysicsBodyRotation(paddle_a, paddle_a->orient - dt * input_sensitivity * 0.05);
                printf("CW\r\n");
            }
            if (blue.button[BUTTON_B]) {
                SetPhysicsBodyRotation(paddle_a, paddle_a->orient + dt * input_sensitivity * 0.05);
                printf("CCW\r\n");
            }
            
            // Player 2 Input
            if (!(navSwitch & 0b00001)) { // Up
                paddle_b->position.y -= dt * input_sensitivity;
            }
            if (!(navSwitch & 0b01000)) { // down
                paddle_b->position.y += dt * input_sensitivity;
            }
            if (!(navSwitch & 0b00100)) { // left
                paddle_b->position.x -= dt * input_sensitivity;
            }
            if (!(navSwitch & 0b10000)) { // right
                paddle_b->position.x += dt * input_sensitivity;
            }
            if (!(navSwitch & 0b00010)) { // rotate
                SetPhysicsBodyRotation(paddle_b, paddle_b->orient + 3.14159 / 4);
            }
            
            Thread::yield();
        }

        ClosePhysics();       // Unitialize physics
    }
}