asteroids-cs165/game.cpp

279 lines
7.1 KiB
C++
Raw Normal View History

2020-06-30 22:04:55 -04:00
/*********************************************************************
* File: game.cpp
* Description: Contains the implementaiton of the game class
* methods.
*
*********************************************************************/
#include "game.h"
#include "uiDraw.h"
#include "bullet.h"
// These are needed for the getClosestDistance function...
#include <limits>
#include <iostream>
#include <algorithm>
#define CLOSE_ENOUGH 15
using namespace std;
// Game non-default constructor
Game :: Game ( const Point &tl , const Point &br ) : topLeft ( tl ) , bottomRight ( br )
{
rocks = createRocks();
ship = new Ship ( Point() );
}
// Create rocks for the game
vector<Rock *> Game :: createRocks()
{
vector<Rock *> initRocks;
for ( int i = 0; i < random ( 5 , 8 ); i++ )
{
Point rockPoint = Point ( random( -190 , 190 ) , random ( -190 , 190 ) );
Velocity velocity;
velocity.setDx ( random ( -3.0 , 3.0 ) );
velocity.setDy ( random ( -2.0 , 2.0 ) );
// Make sure spawn is safe on start by calculating if
// The rock is on a trajectory to the ship
float m = velocity.getDy() / velocity.getDx();
if ( fabs ( rockPoint.getY() - m * rockPoint.getX() ) >= 50 )
{
switch ( random( 1 , 5 ) ) {
case 1:
case 2:
case 3:
initRocks.push_back ( new BigRock ( rockPoint , velocity ) );
break;
case 4:
initRocks.push_back ( new MediumRock ( rockPoint , velocity ) );
break;
case 5:
initRocks.push_back ( new SmallRock ( rockPoint , velocity ) );
break;
default:
break;
}
}
}
return initRocks;
}
// Get closest distance between two flying objects
float Game :: getClosestDistance(const FlyingObject &obj1, const FlyingObject &obj2) const
{
// find the maximum distance traveled
float dMax = max(abs(obj1.getVelocity().getDx()), abs(obj1.getVelocity().getDy()));
dMax = max(dMax, abs(obj2.getVelocity().getDx()));
dMax = max(dMax, abs(obj2.getVelocity().getDy()));
dMax = max(dMax, 0.1f); // when dx and dy are 0.0. Go through the loop once.
float distMin = std::numeric_limits<float>::max();
for (float i = 0.0; i <= dMax; i++)
{
Point point1(obj1.getPoint().getX() + (obj1.getVelocity().getDx() * i / dMax),
obj1.getPoint().getY() + (obj1.getVelocity().getDy() * i / dMax));
Point point2(obj2.getPoint().getX() + (obj2.getVelocity().getDx() * i / dMax),
obj2.getPoint().getY() + (obj2.getVelocity().getDy() * i / dMax));
float xDiff = point1.getX() - point2.getX();
float yDiff = point1.getY() - point2.getY();
float distSquared = (xDiff * xDiff) +(yDiff * yDiff);
distMin = min(distMin, distSquared);
}
return sqrt(distMin);
}
// Advance everything in the game
void Game :: advance()
{
cleanUpZombies();
advanceShip();
advanceBullets();
advanceAsteroids();
handleCollisions();
}
// Advance all asteroids in game
void Game :: advanceAsteroids()
{
for ( int i = 0; i < rocks.size(); i++ )
{
rocks[i]->advance();
}
}
// Advance all the bullets
void Game :: advanceBullets()
{
for ( int i = 0; i < bullets.size(); i++ )
{
bullets[i]->advance();
}
}
// Advance the ship
void Game :: advanceShip()
{
if ( ship->isAlive() && ship->getFuel() >= 0 )
{
ship->advance();
}
}
// Clean up memory
void Game :: cleanUpZombies()
{
for ( int i = 0; i < bullets.size(); i++ )
{
if ( !bullets[i]->isAlive() )
{
delete bullets[i];
bullets[i] = NULL;
bullets.erase( bullets.begin() + i );
}
}
for ( int i = 0; i < rocks.size(); i++ )
{
if ( !rocks[i]->isAlive() )
{
delete rocks[i];
rocks[i] = NULL;
rocks.erase( rocks.begin() + i );
}
}
}
// Handle all collisions
void Game :: handleCollisions()
{
// Handle bullet collisions
for ( int i = 0; i < rocks.size(); i++ )
{
Rock * rock = rocks[i];
if ( rock->isAlive() )
{
for ( int j = 0; j < bullets.size(); j++ )
{
Bullet * bullet = bullets[j];
if ( bullet->isAlive() )
{
float allowedRange = rock->getSize() + CLOSE_ENOUGH;
if ( fabs( getClosestDistance( *bullet , *rock ) ) < allowedRange
|| bullet->getPoint().inRange( rock->getPoint() , allowedRange ) )
{
vector<Rock *> newRocks = rock->destroy();
for ( int i = 0; i < newRocks.size(); i++ )
{
rocks.push_back ( newRocks[i] );
}
rock->kill();
bullet->kill();
}
}
}
}
}
// Handle ship collisions
for ( int i = 0; i < rocks.size(); i++ )
{
Rock * rock = rocks[i];
if ( rock->isAlive() && ship->isAlive() )
{
float allowedRange = rock->getSize() + CLOSE_ENOUGH;
if ( fabs( getClosestDistance( *ship , *rock ) ) < allowedRange
|| ship->getPoint().inRange( rock->getPoint() , allowedRange ) )
{
vector<Rock *> newRocks = rock->destroy();
for ( int i = 0; i < newRocks.size(); i++ )
{
rocks.push_back ( newRocks[i] );
}
rock->kill();
ship->kill();
}
}
}
cleanUpZombies();
}
// Draw everything
void Game :: draw ( const Interface &ui )
{
drawRocks();
drawShip();
drawBullets();
drawNumber ( Point ( -170 , 170 ) , (int) ship->getFuel() );
drawText ( Point ( -170 , 180 ) , "FUEL:" );
}
// Draw rocks
void Game :: drawRocks()
{
for ( int i = 0; i < rocks.size(); i++ )
{
rocks[i]->draw();
}
}
// Draw ship
void Game :: drawShip()
{
if ( ship->isAlive() )
{
ship->draw();
}
}
// Draw bullets
void Game :: drawBullets()
{
for ( int i = 0; i < bullets.size(); i++ )
{
bullets[i]->draw();
}
}
// Handle in-game input
void Game::handleInput(const Interface & ui)
{
if ( ship->isAlive() )
{
if ( ui.isUp() )
{
ship->setThrusting ( true );
ship->thrust( true );
}
if ( ui.isDown() )
{
ship->setThrusting ( true );
ship->thrust( false );
}
if ( ui.isLeft() )
{
ship->setThrusting ( true );
ship->rotate( true );
}
if ( ui.isRight() )
{
ship->setThrusting ( true );
ship->rotate( false );
}
if ( ui.isSpace() )
{
Bullet * newBullet = new Bullet( ship->getPoint() );
newBullet->fire( ship->getVelocity(), ship->getAngle() );
bullets.push_back( newBullet );
}
if ( !ui.isRight() && !ui.isUp() && !ui.isDown() && !ui.isLeft() )
{
ship->setThrusting ( false );
}
}
}