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.
Dependencies: mbed N5110 ShiftReg PinDetect
Game.cpp
- Committer:
- Siriagus
- Date:
- 2015-05-10
- Revision:
- 15:d5eb13c4c1c6
- Parent:
- 14:b4fed570abaf
- Child:
- 16:caf613d5b85e
File content as of revision 15:d5eb13c4c1c6:
#include "Game.h"
Serial pc(USBTX, USBRX); // TO DELETE - DEBUGGING ONLY
void Game::init()
{
paused = false;
// Set initial values for the player
player.x = 40; // start x
player.y = 5; // start y
player.width = player.height = 5; // important that this is correct, see size of Image::Player in Resources.h
player.onGround = false;
enemy = new Enemy(75, 3, 6, 5);
enemy->vx = -2;
enemy->facingLeft = true;
}
// Functions
void Game::update(float dt)
{
// Pause button input
if (input->read(Input::ButtonC))
{
if (releasedBtnC)
{
paused = !paused;
releasedBtnC = false;
}
}
else
releasedBtnC = true;
// Skip the rest if paused
if (paused) return;
// Handle input, should be its own function
switch(input->joystick->getDirection())
{
case LEFT:
case UP_LEFT:
case DOWN_LEFT:
player.vx = -2;
player.facingLeft = true;
break;
case RIGHT:
case UP_RIGHT:
case DOWN_RIGHT:
player.vx = 2;
player.facingLeft = false;
break;
case CENTER:
player.vx = 0;
break;
}
// Random movement for enemies
if (enemy->onGround && (rand() % 100) > 97) // 3 % chance
{
// jump
enemy->vy = -3;
enemy->onGround = false;
}
else if ((rand() % 100) > 98) // 2% chance
{
// switch direction
enemy->vx *= -1;
enemy->facingLeft = (enemy->vx < 0);
}
// Gravity
player.vy += 1;
enemy->vy += 1;
// Check if player is trying to jump. Player can only jump if it's on the ground
if (input->read(Input::ButtonA) && player.onGround)
{
player.vy = -4;
player.onGround = false;
}
// Terminal velocity 3 px/update
if (player.vy > TERMINAL_VELOCITY) player.vy = TERMINAL_VELOCITY;
moveWithCollisionTest(&player, map);
if (!enemy->dead)
moveWithCollisionTest(enemy, map);
else
{
enemy->y += enemy->vy;
enemy->x += enemy->vx;
}
// else if (enemy->y >= HEIGHT) ; // TODO : delete enemy
// Enemy AI
if (!enemy->dead)
{
int nextRight = enemy->getRight() + 1; // Next position of right edge if enemy moves to the right
for (int i = 0; i < enemy->height; ++i) // Check for all heighs
{
// Check if crashing if moving right or left. Bounds should already be limited by moveWithCollisionTest!
// will also try to climb a slope if it can find one
if ((map[enemy->y + i][nextRight] && map[enemy->y+i-1][nextRight]) || (map[enemy->y + i][enemy->x - 1] && map[enemy->y + i-1][enemy->x - 1]))
{
enemy->vx *= -1; // move in opposite direction
enemy->facingLeft = !enemy->facingLeft; // toggle direction
break; // no further testing required
}
}
}
// Check if bullet should be fired
if (input->read(Input::ButtonB) && releasedBtnB)
{
// Create a new bullet and give it initial values
Point* bullet = new Point;
bullet->x = (int)(player.x + (player.width / 2)); //(player.facingLeft) ? (player.x-1) : (player.x + player.width);
bullet->y = player.y + 2;
bullet->vx = (player.facingLeft) ? -4 : 4;
bullet->vy = 0;
bullets.push_back(bullet);
releasedBtnB = false;
}
else if (!input->read(Input::ButtonB))
releasedBtnB = true;
// Loop through bullets and move them + collision test
for (std::vector<Point*>::iterator it = bullets.begin(); it != bullets.end();)
{
Point* bullet = *it;
int x0; // left border of collision rect
int x1; // right border of collision rect
int oldX = bullet->x;
int newX = bullet->x + bullet->vx;
x0 = min(oldX, newX);
x1 = max(oldX, newX);
// Collision rect for bullet in this time step
Rectangle bulletColRect(x0, bullet->y, (x1-x0)+1, 1);
bool col = false;
// Delete if outside screen
if (newX < 0 || newX > WIDTH || bulletHitMap(bulletColRect, map)) // if outside screen
{
col = true;
}
else
{
// loop through all enemies
//bullet // point
//enemy // entity
if (!enemy->dead && bullet->x >= enemy->x && bullet->x <= enemy->getRight() && bullet->y >= enemy->y && bullet->y <= enemy->getBottom())
{
col = true;
// break; // todo: make for loop - iterate through all enemies
enemy->vx = bullet->vx / 2; // sends the dead enemy in the same direction as the incoming bullet
enemy->vy = -3; // sends the dead enemy upwards in the air, because of impact
enemy->dead = true;
// remove enemy - todo: make vector
}
}
if (!col)
{
++it; // go to next element
bullet->x += bullet->vx; // update position
}
else
{
delete bullet;
it = bullets.erase(it); // go to next element
}
// TODO: Check for collisions
// TODO: Go both ways
}
}
void Game::render()
{
// Draw map
drawImage(map);
// Draw player
drawImage(Image::Player, player.x, player.y, false, !player.facingLeft);
// Draw enemies
drawImage(Image::Enemy3, enemy->x, enemy->y, false, !enemy->facingLeft, enemy->dead);
/*
// Draw player - TODO: Make this a part of sprite class (so they can draw themselves)
int x0, x1, y0, y1;
x0 = (player.x < 0) ? 0 : player.x; // x0 = max(0,x);
y0 = (player.y < 0) ? 0 : player.y; // y0 = max(0,y);
x1 = (player.width + player.x > WIDTH) ? WIDTH : player.width + player.x; //x1 = min(WIDTH, width);
y1 = (player.height + player.y > HEIGHT) ? HEIGHT : player.height + player.y; //y1 = min(HEIGHT, height);
for (int i = y0; i < y1; ++i)
{
for (int j = x0; j < x1; ++j)
{
// If player is going right, obtain data from sprite in reverse order => render in reverse
int xIndex = (player.facingLeft) ? (j-x0) : (player.width - 1 - (j-x0));
if (Image::Player[i-y0][xIndex])
lcd->setPixel(j,i);
}
}*/
// Render bullets
for (std::vector<Point*>::iterator it = bullets.begin(); it != bullets.end(); ++it)
{
int x, y;
x = (*it)->x;
y = (*it)->y;
if (x >= 0 && x < WIDTH && y >= 0 && y < HEIGHT) // Boundary check
lcd->setPixel(x,y);
}
// Draw pause
if (paused)
{
lcd->drawRect(24, 13, 40, 13, 0); // outline
lcd->drawRect(25, 14, 38, 11, 2); // white fill
lcd->printString("Paused", 27, 2); // text
}
}
// Collision test between entites and map
void Game::moveWithCollisionTest(Entity* entity, const int map[HEIGHT][WIDTH])
{
int x = entity->x;
int y = entity->y;
int steps = abs(entity->vx); // how many units (pixels) the entity should move in said direction
bool collision; // true if colliding
// Check x-axis
if (entity->vx > 0) // moving right
{
int entityRight = x + entity->width - 1; // Need to check right border of entity, since it is moving right
while(steps--) // While it still have more movement left
{
collision = false;
for (int i = 0; i < entity->height; ++i) // Loop through all vertical points on the right hand side of the entity (y+i)
{
if (map[y+i][entityRight+1]) // If moving to the right leads to collision for given y+i
{
// Slope + allows player to climb to top of platform by going right if it hits close to top of wall.
if (!map[y+i-1][entityRight+1] && entity->onGround)
{
entity->vy = -1;
}
else
{
collision = true; // Then collision is true
break; // Skip the for loop, no need for further testing
}
}
}
if (collision) // If collision
break; // skip the while loop, entity can not move further, even though its velocity is higher
else
++entityRight; // Move entity one px to the right
}
entity->x = entityRight - (entity->width - 1); // Update entity's position. Need to set upper-left pixel.
}
else // moving left
{
while(steps--) // While still movement left
{
collision = false;
for (int i = 0; i < entity->height; ++i) // Check for all y-positions
{
if (map[y+i][x-1]) // If solid block
{
if (!map[y+i-1][x-1] && entity->onGround) // If slope or close to top of wall (=> can climb by going left).
{
entity->vy = -1;
}
else
{
collision = true;
break; // Collision detected, no further testing required
}
}
}
if (collision)
break;
else
--x; // Move to the left if no collision is detected
}
entity->x = x;
}
// Check collision with map in y-direction - works the same way as the x-axis, except for other axis
x = entity->x;
y = entity->y;
steps = abs(entity->vy);
if (entity->vy > 0) // downwards
{
int entityBottom = y + entity->height - 1; // Need to check if bottom part collides
while(steps--) // Still movement left
{
collision = false;
for (int i = 0; i < entity->width; ++i) // Loop through all x-position on lower part of entity
{
if (map[entityBottom+1][x+i]) // If moving the entity one step down for a given (x+i)-position gives a collision
{
collision = true;
break; // No further testing required
}
}
if (collision) // If collision
{
entity->vy = 0; // Set vertical velocity to 0 (playe
entity->onGround = true; // entity has hit ground
break; // Skip the while loop as the entity can not move further downwards
}
else // Can safely move entity without collision
{
++entityBottom; // Move entity one step down
entity->onGround = false;
}
}
entity->y = entityBottom - (entity->height - 1); // Update position when done moving, remember that entity.y refers to upper part of the entity
}
else // moving up, check collision from top
{
while(steps--) // Still movement left
{
collision = false;
for (int i = 0; i < entity->width; ++i) // Check for all x-positions
{
if (map[y-1][x+i]) // If moving upwards gives collision for a given x+i
{
collision = true; // Then we have a collision
break; // No further testing needed, skip for loop
}
}
if (collision) // If collision was detected
{
entity->vy = 0; // Set vertical velocity to zero
break; // Skip while loop as entity can not move further up
}
else // If safe to move for all x-values
--y; // Move entity one step up
}
entity->y = y; // Update vertical position of entity
}
}
bool Game::hitTestRect(Rectangle r1, Rectangle r2)
{
return ((r1.x + r1.width > r2.x) // r1's right edge to the right of r2's left edge
&& (r1.x < r2.x + r2.width) // r1's left edge to the left of r2's right edge
&& (r1.y + r2.height > r2.y) // r1's bottom lower than r2's top
&& (r1.y < r2.y + r2.height)); // r1's top higher than r2's bottom
// Note: Right border: r1.x + r1.width - 1, but we don't need to subtract 1 as we use > instead of >=
}
bool Game::bulletHitMap(Rectangle &bulletColRect, const int map[HEIGHT][WIDTH])
{
for (int j = 0; j < bulletColRect.width; ++j)
{
if (map[bulletColRect.y][bulletColRect.x + j])
return true;
}
return false;
}