#include <cstdlib>
#include "GameSim.h"
GameSim::GameSim()
{
reset();
}
GameSim::~GameSim()
{
}
void GameSim::reset()
{
std::vector<GameObjectList*> lists = objectLists();
for (GameObjectList* list : lists)
list->clear();
generateLevel();
m_gameOver = false;
m_won = false;
}
static bool rectangleIntersect(int ax1, int ay1, int ax2, int ay2, int bx1, int by1, int bx2, int by2)
{
// Early out
if (ax1 > bx2 || bx1 > ax2 || ay1 > by2 || by1 > ay2)
return false;
bool overlayInX = (ax1 > bx1 && ax1 < bx2) || (ax2 > bx1 && ax2 < bx2) || (bx1 > ax1 && bx1 < ax2) || (bx2 > ax1 && bx2 < ax2);
if (!overlayInX)
return false;
bool overlayInY = (ay1 > by1 && ay1 < by2) || (ay2 > by1 && ay2 < by2) || (by1 > ay1 && by1 < ay2) || (by2 > ay1 && by2 < ay2);
if (!overlayInY)
return false;
return true; // overlaps in X and Y dimensions, therefore intersect
}
static bool objectsIntersect(const GameObject& a_objA, const GameObject& a_objB)
{
return rectangleIntersect(a_objA.m_x, a_objA.m_y, a_objA.m_x + a_objA.m_w, a_objA.m_y + a_objA.m_h,
a_objB.m_x, a_objB.m_y, a_objB.m_x + a_objB.m_w, a_objB.m_y + a_objB.m_h);
}
void GameSim::movePlayer(Movement a_movement)
{
if (m_gameOver)
return;
float origX = m_player.front().m_x;
float origY = m_player.front().m_y;
if (a_movement == Forward)
{
m_player.front().m_y += 10;
}
else if (a_movement == Backward)
{
m_player.front().m_y -= 10;
}
else if (a_movement == Left)
{
m_player.front().m_x -= 10;
}
else if (a_movement == Right)
{
m_player.front().m_x += 10;
}
bool onWater = false;
bool willHitObstacle = false;
// reset
for (GameObject& tile : m_backgroundLevel)
{
if (tile.m_type == Water || tile.m_type == WaterLane)
{
if (objectsIntersect(m_player.front(), tile))
{
onWater = true;
break;
}
}
}
for (GameObject& tile : m_populationLevel)
{
if (objectsIntersect(m_player.front(), tile))
{
if (onWater)
{
// maybe game over if we aren't on a craft
}
else
{
// rollback movement
m_player.front().m_x = origX;
m_player.front().m_y = origY;
}
}
}
}
void GameSim::generateLevel()
{
ObjectType laneFlags[50];
for (int y = 0; y < 50; y++)
{
int laneWidth = rand() % 6;
ObjectType laneFlag = ObjectType(rand() % 5);
if (y && laneFlags[y-1] == laneFlag)
{
y--;
continue;
}
if (laneFlag == Water)
laneWidth = 1;
if (laneFlag == Rail && laneWidth > 3)
laneWidth = 3;
for (int i = 0; i < laneWidth; i++)
{
laneFlags[y] = laneFlag;
y++;
if (y >= 50)
{
break;
}
}
y--;
}
laneFlags[0] = Ground;
laneFlags[1] = Ground;
for (int x = 0; x < 100; x++)
{
for (int y = 49; y >= 0; y--)
{
GameObject tile;
tile.m_type = laneFlags[y];
tile.m_x = x * 10;
tile.m_y = y * 10;
tile.m_z = 0;
tile.m_w = 10;
tile.m_h = 10;
tile.m_d = (tile.m_type == Water || tile.m_type == WaterLane) ? -3 :
((tile.m_type == Rail || tile.m_type == Ground) ? 3 : 0); // height for terrain
tile.m_dx = 0;
tile.m_dy = 0;
tile.m_color = 0x808020 + (laneFlags[y]*5);
m_backgroundLevel.push_back(tile);
}
}
for (int y = 49; y >= 0; y--)
{
if (laneFlags[y] == Ground) // if Ground, place obstacles
{
for (int x = 0; x < 100; x++)
{
if ((rand() % 20) == 0)
{
GameObject tile;
tile.m_type = ObjectType(Tree + (rand() % 4));//Obstacle;
tile.m_x = x * 10;
tile.m_y = y * 10;
tile.m_z = 0;
tile.m_w = 10;
tile.m_h = 10;
tile.m_d = 10; // height of terrain
tile.m_dx = 0;
tile.m_dy = 0;
tile.m_color = 0xf08080;
m_populationLevel.push_back(tile);
}
}
}
else if (laneFlags[y] == Water)
{
for (int x = 0; x < 100; x++)
{
if ((rand() % 20) == 0)
{
GameObject tile;
tile.m_type = ObjectType(LilyPad + (rand() % 2));//Landing
tile.m_x = x * 10;
tile.m_y = y * 10;
tile.m_z = 0;
tile.m_w = 10;
tile.m_h = 10;
tile.m_d = 2; // height of terrain
tile.m_dx = 0;
tile.m_dy = 0;
tile.m_color = 0xf08080;
m_populationLevel.push_back(tile);
}
}
}
}
for (int y = 49; y >= 0; y--)
{
if (laneFlags[y] != Ground && laneFlags[y] != Water) // if not Ground, place vehicles
{
ObjectType laneType = laneFlags[y];
int width = (rand() % 4) + 1;
int speed = (rand() % 9) + 1;
int count = rand() % 16;
int direction = rand() % 2;
int x = rand() % 10;
if (laneType == Rail)
{
width = 30;
speed = 20;
count = 1;
x = rand() % 70;
}
for (int i = 0; i < count; i++)
{
GameObject tile;
if (laneType == Road) {
tile.m_type = ObjectType(Bike + (rand()%4));
} else if (laneType == Rail) {
tile.m_type = ObjectType(Train1 + (rand()%4));
} else if (laneType == WaterLane) {
tile.m_type = ObjectType(Log + (rand()%3));
}
//tile.m_type = (laneType == Water) ? FloatingPlatform : Vehicle;
tile.m_x = x * 10;
tile.m_y = y * 10;
tile.m_z = 0;
tile.m_w = 10 * width;
tile.m_h = 10;
tile.m_d = 15; // height for terrain
tile.m_dx = (direction) ? speed : -speed;
tile.m_dy = 0;
tile.m_color = (0x80 << 16) | ((0x10*width)<<8) | (0x10*speed);
m_movingObjects.push_back(tile);
x += width + 1;
int avgWidthBetweenObjects = 100 / count;
x += avgWidthBetweenObjects / 2;
x += rand() % avgWidthBetweenObjects;
if (x > 100)
{
break;
}
}
}
}
GameObject tile;
tile.m_type = Player;
tile.m_x = 302;
tile.m_y = 12;
tile.m_z = 0;
tile.m_w = 6;
tile.m_h = 6;
tile.m_d = 20; // height for terrain
tile.m_dx = 0;
tile.m_dy = 0;//1;
tile.m_color = 0xffffff;
m_player.push_back(tile);
}
std::vector<GameObjectList*> GameSim::objectLists()
{
std::vector<GameObjectList*> objLists;
objLists.push_back(&m_backgroundLevel);
objLists.push_back(&m_populationLevel);
objLists.push_back(&m_movingObjects);
objLists.push_back(&m_player);
return objLists;
}
bool GameSim::checkGameOver()
{
if (m_player.front().m_x < 0 || m_player.front().m_x > 1000)
{
return true;
}
// reset
m_player.front().m_dx = 0;
for (GameObject& tile : m_movingObjects)
{
if (objectsIntersect(m_player.front(), tile))
{
if (tile.m_type >= Bike && tile.m_type <= Train4)
{
return true;
}
if (tile.m_type == Crocodile)
{
// TODO: more logic if near head of croc
//if (tile.m_dx > 0 && tile.m_x + )
return true;
}
if (tile.m_type == Log || tile.m_type == Boat)
{
// moves with the log or boat
m_player.front().m_dx = tile.m_dx;
return false;
}
}
}
if (m_player.front().m_y > 500)
{
m_won = true;
return true;
}
return false;
/*
// Terrain
Ground,
Road,
Rail,
WaterLane,
Water,
// Obstacle
Tree,
Shrub,
Building,
Rocks,
LilyPad,
SteppingStone,
// Pickup
Coin,
Food,
Life,
Bonus,
*/
}
void GameSim::update(float a_dt)
{
if (m_gameOver)
return;
for (GameObject& tile : m_movingObjects)
{
tile.m_x += tile.m_dx * a_dt;
tile.m_y += tile.m_dy * a_dt;
if (tile.m_dx > 0)
{
if (tile.m_x > 1000)
tile.m_x -= 1000 + tile.m_w;
}
else
{
if ((tile.m_x + tile.m_w) < 0)
tile.m_x += 1000 + tile.m_w;
}
}
for (GameObject& tile : m_player)
{
tile.m_x += tile.m_dx * a_dt;
tile.m_y += tile.m_dy * a_dt;
}
m_gameOver = checkGameOver();
}