Newer
Older
Import / applications / HighwayDash / GameSim / GameSim.cpp
#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()
{
    const int lanes = 50;

    ObjectType laneFlags[lanes];
    for (int y = 0; y < lanes; 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 >= lanes)
        {
          break;
        }
      }
      y--;
    }

    laneFlags[0] = Ground;
    laneFlags[1] = Ground;

    for (int x = 0; x < 100; x++)
    {
       for (int y = (lanes-1); 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 = (lanes-1); 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 = (lanes-1); 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 > lanes*10)
    {
      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();
}