Kostadin Chakarov / Mbed 2 deprecated el17kec

Dependencies:   mbed

Map/Map.cpp

Committer:
kocemax
Date:
2019-04-10
Revision:
7:cd3cafda3dd4
Parent:
6:39bda45efeed
Child:
8:9b77eea95088

File content as of revision 7:cd3cafda3dd4:

#include "Map.h"
#include "Ball.h"

void Level1::initBricks(Map & map)
{
    int w = 41;
    int h = 2;
    int gap = 1;
    int y = 0;
    for (int j = 0; j < 7; ++j) {
        int x = 0;
        for (int i = 0; i < 2; ++i) {
            Brick b;
            b.x = x;
            b.y = y;
            b.w = w;
            b.h = h;
            map.addBrick(b);

            x += w + gap;
        }
        y += h + gap;
    }
}

void Level2::initBricks(Map & map)
{
    int w = 5;
    int h = 1;
    int gap = 1;
    int y = 0;

    for (int j = 0; j < 15; ++j) {
        int x = 0;
        for (int i = 0; i < 14; ++i) {
            Brick b;
            b.x = x;
            b.y = y;
            b.w = w;
            b.h = h;
            map.addBrick(b);

            x += w + gap;
        }
        y += h + gap;
    }
}


// Constructor
Map::Map()
{
    levels.push_back(new Level1());
    levels.push_back(new Level2());
    reset();
}


// Destructor
Map::~Map()
{

}

void Map::initBricks()
{
    bricks.clear();

    Level* level = levels[currentLevel];
    level->initBricks(*this);
}

void Map::drawMap(N5110 &lcd)
{
    vector<Brick>::size_type end = bricks.size();
    for (int i = 0; i < end; i++) {
        const Brick& b = bricks[i];
        lcd.drawRect(b.x,b.y,b.w,b.h,FILL_BLACK);
    }
}
//See: https://stackoverflow.com/questions/31022269/collision-detection-between-two-rectangles-in-java
bool rectIntersect(
    int Ax, int Ay, int Aw, int Ah,
    float Bx, float By, float Bw, float Bh)
{
    return
        Bx + Bw > Ax &&
        By + Bh > Ay &&
        Ax + Aw > Bx &&
        Ay + Ah > By;
}

//Normals to each side of the rectangle
const Vector2D Up = {0, -1};
const Vector2D Down = {0, 1};
const Vector2D Left = {-1, 0};
const Vector2D Right = {1, 0};

//See: https://math.stackexchange.com/questions/13261/how-to-get-a-reflection-vector
// r = d - 2(d dot n)n
void reflect(Vector2D &d, const Vector2D &n)
{
    float dotProd = d.x * n.x + d.y * n.y;
    float s = 2 * dotProd;

    d.x = d.x - s * n.x;
    d.y = d.y - s * n.y;
}

void Map::resolveCollision(const Brick &b, GameObject &obj)
{
    // take velocity of the ball to determine direction and previous coords
    float vx = obj.getVelocity().x;
    float vy = obj.getVelocity().y;
    // take the previous x and y coords
    float x = obj.getPos().x - vx;
    float y = obj.getPos().y - vy;
    // sides of the bricks
    float leftX = b.x;
    float rightX = b.x + b.w;
    //float topY = b.y;
    //float bottomY = b.y + b.h;

    // mid of x and y coords
    //float cx = b.x + b.w/2.0f;
    float cy = b.y + b.h/2.0f;

    // distance between ball and rectangle center
    //float dx = x - cx;
    //float dy = y - cy;

    Vector2D &vel = obj.getVelocity();
    float thresh = 0.1;
    if (x > rightX - thresh) {
        // hit right
        reflect(vel, Right);
    } else if (x < leftX + thresh) {
        // hit left
        reflect(vel, Left);
    } else if (y < cy) {
        // hit top
        reflect(vel, Up);
    } else if (y > cy) {
        // hit bottom
        reflect(vel, Down);
    } else {
        if (vy > 0) {
            // hit top
            reflect(vel, Up);
        } else {
            // hit bottom
            reflect(vel, Down);
        }
    }
}

void Map::checkCollision(GameObject &obj)
{
    vector<Brick>::size_type end = bricks.size();
    for (int i = 0; i < end; i++) {
        const Brick& b = bricks[i];
        if (rectIntersect(b.x, b.y, b.w, b.h,
                          obj.getPos().x, obj.getPos().y, obj.getW(), obj.getH())) {
            resolveCollision(b, obj);
            bricks.erase(bricks.begin() + i);
            break;
        }
    }
}

bool Map::checkLevel()
{
    if (bricks.size() == 0) {
        // cleared level
        ++currentLevel;
        printf("cleared level! %d %d\n", currentLevel, hasWon());
        if (!hasWon()) {
            // initialize next level
            initBricks();
        }
        return true;
    }
    return false;
}

void Map::reset()
{
    currentLevel = 0;
    initBricks();
}