Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Map/Map.cpp
- Committer:
- kocemax
- Date:
- 2019-05-08
- Revision:
- 8:9b77eea95088
- Parent:
- 7:cd3cafda3dd4
- Child:
- 9:f720f5d87420
File content as of revision 8:9b77eea95088:
#include "Map.h"
#include "Ball.h"
// Levels
void Level1::initBricks(Map & map)
{
int w = 41;
int h = 2;
int gap = 1;
int y = 0;
for (int j = 0; j < 9; ++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 = 20;
int h = 2;
int gap = 1;
int y = 0;
for (int j = 0; j < 9; ++j) {
int x = 0;
for (int i = 0; i < 4; ++i) {
Brick b;
b.x = x;
b.y = y;
b.w = w;
b.h = h;
map.addBrick(b);
x += w + gap;
}
y += h + gap;
}
}
// Power-Ups
// rows,cols
int powerUpPaddleSizeSprite[PowerUpH][PowerUpW] = {
{ 0,1,0 },
{ 1,1,1 },
{ 0,1,0 },
{ 1,1,1 }
};
// rows,cols
int powerUpPaddleSpeedSprite[PowerUpH][PowerUpW] = {
{ 0,1,0 },
{ 0,1,0 },
{ 1,1,1 },
{ 1,1,1 }
};
// rows,cols
int powerUpBallSpeedSprite[PowerUpH][PowerUpW] = {
{ 0,1,0 },
{ 1,1,1 },
{ 1,1,1 },
{ 0,1,0 }
};
void PowerUpType::draw(N5110 &lcd, PowerUp &pUp) {
//printf("%f, %f; %d,%d - %d\n", pUp.getPos().x,pUp.getPos().y,pUp.getH(),pUp.getW(), (int)((int*)sprite));
lcd.drawSprite(pUp.getPos().x,pUp.getPos().y,pUp.getH(),pUp.getW(), (int*)sprite);
}
PowerUpType* PowerUpTypes[3] = {
new PaddleSizePUpType(0, *powerUpPaddleSizeSprite),
new PaddleSpeedPUpType(1, *powerUpPaddleSpeedSprite),
new BallSpeedPUpType(2, *powerUpBallSpeedSprite)
};
PowerUp::PowerUp(float x, float y, PowerUpType& pUpType) : _pUpType(&pUpType)
{
pos.x = x;
pos.y = y;
velocity.x = 0;
velocity.y = 0.5f;
w = PowerUpW;
h = PowerUpH;
}
void PowerUp::draw(N5110 &lcd) {
//printf("powerup %.02f , %.02f, %d\n", pos.x, pos.y, powerUpSprite[0][2]);
_pUpType->draw(lcd, *this);
}
void PaddleSizePUpType::giveBonus(Paddle &paddle, Ball &ball) {
int add = 2;
paddle.setW(paddle.getW()+add);
}
void PaddleSpeedPUpType::giveBonus(Paddle &paddle, Ball &ball) {
float add = 0.2f;
paddle.setSpeed(paddle.getSpeed() + add);
}
void BallSpeedPUpType::giveBonus(Paddle &paddle, Ball &ball) {
float multiply = 0.9f;
Vector2D& v = ball.getVelocity();
// 1. create variable speed = magnitude (length) of v
// 2. change speed by ...
// 3. Then normalize v and multiply by speed
float oldSpeed = sqrt(v.x*v.x + v.y*v.y);
float speed = oldSpeed * multiply;
v.x = (v.x / oldSpeed) * speed;
v.y = (v.y / oldSpeed) * speed;
}
// Map
/** 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);
}
for (int i = 0; i < powerUps.size(); i++) {
powerUps[i].draw(lcd);
}
}
//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;
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(Ball &ball, Paddle &paddle)
{
// check bricks
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,
ball.getPos().x, ball.getPos().y, ball.getW(), ball.getH())) {
// brick collision event!
// bounce the ball
resolveCollision(b, ball);
// (maybe) spawn power-up
onBrickHit(b);
// remove brick
bricks.erase(bricks.begin() + i);
break;
}
}
/** check power ups */
for (int i = 0; i < powerUps.size(); i++)
{
PowerUp& p = powerUps[i];
/** use rectIntersect to check for collisions between power-up and pad */
if (rectIntersect(p.getPos().x, p.getPos().y, p.getW(), p.getH(),
paddle.getPos().x, paddle.getPos().y, paddle.getW(), paddle.getH())) {
p.giveBonus(paddle, ball);
powerUps.erase(&p);
break;
}
}
}
void Map::onBrickHit(const Brick& brick) {
if ((rand() % 100) < PowerUpDropChancePct) {
// spawn power up
int type = rand() % 3; // each power up has the same rarity
//printf("Power up - t=%d", type);
PowerUpType& pUpType = *PowerUpTypes[type];
//printf(", pUpType=%d\n", pUpType.type);
powerUps.push_back(
PowerUp(brick.x+(brick.w/2)-PowerUpW/2, brick.y, pUpType)
);
}
}
void Map::update() {
for (int i = 0; i < powerUps.size(); i++) {
powerUps[i].move();
}
}
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();
powerUps.clear();
}