<repo_name>Variapolis/OpenGL-CW1-CarGame<file_sep>/3DExample1/src/EndGate.h
#pragma once
#include "Rect.h"
#include "PlayerCar.h"
class EndGate :
    public Rect //Endgate class used to regenerate a new level when player passes through.
{
public:
	EndGate(GLfloat x, GLfloat y, GLfloat width, GLfloat height);
	bool CheckCollision(PlayerCar* player, int score, GLfloat startX, GLfloat startY);
};

<file_sep>/3DExample1/src/EndGate.cpp
#include "EndGate.h"


EndGate::EndGate(GLfloat x, GLfloat y, GLfloat width, GLfloat height) :Rect(x, y, width, height)
{
}


bool EndGate::CheckCollision(PlayerCar* player, int score,GLfloat startX, GLfloat startY)
// Checks collision by comparing the aMin x/y and bMin x/y against each other in a AABB format.
{
	bool isColliding = false;
	GLfloat xMinCar = _posX - (_width);
	GLfloat yMinCar = _posY - (_height);
	GLfloat xMinObs = player->getPosX() - player->getWidth();
	GLfloat yMinObs = player->getPosY() - player->getHeight();
	GLfloat widthObs = player->getWidth();
	GLfloat heightObs = player->getHeight();


	if ((xMinCar + _width * 2) > xMinObs && xMinCar < xMinObs + (widthObs * 2))
	{
		if (yMinCar + _height * 2 > yMinObs && yMinCar < yMinObs + (heightObs * 2)) 
			//Essentially checks if the gate is inside the range of the player on TWO axes. If it is not within range on both axes, it is not colliding.
		{
			player->MoveTo(startX,startY);
			Log("Player reached End Gate.");
			player->AddScore(score);
			LogIntValue("Player won and gained: ", score, " points!");
			LogIntValue("Current score: ", player->GetScore(), " Points");
			return true;
		}
	}
	return false;
}<file_sep>/3DExample1/src/Boundary.h
#pragma once
#include "GameObject.h"
class Boundary :
    public GameObject
{
public:

	Boundary(GLfloat x, GLfloat y, GLfloat width, GLfloat height);
	void Draw(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
};

<file_sep>/3DExample1/src/Obstacle.cpp
#include "Obstacle.h"

Obstacle::Obstacle(GLfloat x, GLfloat y, GLfloat width, GLfloat height):Rect(x,y,width,height)
{
}

Obstacle::Obstacle(GLfloat x, GLfloat y) : Rect(x, y)
{
}

Obstacle::Obstacle():Rect()
{
}
<file_sep>/3DExample1/src/Obstacle.h
#pragma once
#include "Rect.h"
class Obstacle :  public Rect //Essentially a copy of Rect, open ended class to allow for more functionality to be given to obstacles at a later date.
{
public:
	Obstacle(GLfloat x, GLfloat y, GLfloat width, GLfloat height);
	Obstacle(GLfloat x, GLfloat y);
	Obstacle();
	
};

<file_sep>/3DExample1/src/Spawner.cpp
#include "Spawner.h"

Spawner::Spawner(GLfloat x, GLfloat y, GLfloat width, GLfloat height):GameObject(x,y,width,height)
{
}

Spawner::Spawner():GameObject()
{
}

void Spawner::DebugDraw(GLfloat r, GLfloat g, GLfloat b, GLfloat a) // Draw function inside the rectangle class creates a triangle strip with 4 vertices based on the position and size variables.
{
	glPushAttrib(GL_CURRENT_BIT);
	glBegin(GL_LINE_LOOP);
	glColor4f(r, g, b, a);
	glVertex2f((_posX - _width), (_posY - _height));
	glVertex2f((_posX + _width), (_posY - _height));
	glVertex2f((_posX + _width), (_posY + _height));
	glVertex2f((_posX - _width), (_posY + _height));
	glEnd();
	glPopAttrib();
	glFlush();
}

void Spawner::Draw() // Draws all of the spawned obstacles.
{
	for(int i = 0; i < obstacles.size(); i++)
	{
		glPushAttrib(GL_CURRENT_BIT);
		glPushMatrix();
		obstacles[i]->Draw();
		glPopMatrix();
		glPopAttrib();
		glColor3f(1, 1, 1);
	}
}

int Spawner::GetRandBounds(int upper) // Generates a number within the range of the bounds of the spawner.
{
	int bound = (rand() % (upper*2)) - upper;
	return bound;
}

void Spawner::Spawn(int amount, GLfloat width, GLfloat height)
{
	int count = 0;
	while(count != amount){
	bool isBlocked = false;
	GLfloat spawnX = GetRandBounds(_width);
	GLfloat spawnY = GetRandBounds(_height);
		for (int i = 0; i < amount; i++) // Loop spawns the specified amount of Obstacle class instances at specified size.
		{
			if (!(obstacles.empty()))
			{
				for (auto i : obstacles)
				{
					if (CheckSpawn(i, spawnX, spawnY, width, height)) { isBlocked = true; break; }
				}
			}
			if (!isBlocked) { obstacles.push_back(new Obstacle(spawnX, spawnY, width, height)); count++; }
			obstacles.back()->SetColor((GLfloat)rand() * (1.0) / (GLfloat)RAND_MAX, (GLfloat)rand() * (1.0 - 0.5) / (GLfloat)RAND_MAX, (GLfloat)rand() * (1.0 - 0.5) / (GLfloat)RAND_MAX);
		}	
	}
}

void Spawner::Spawn(GLfloat width, GLfloat height) // Spawns a single obstacle at the specified size.
{
	bool isBlocked = true;
	bool hasSpawned = false;
	GLfloat spawnX = GetRandBounds(_width);
	GLfloat spawnY = GetRandBounds(_height);
	while (!hasSpawned)
	{
		if (!(obstacles.empty()))
		{
			for (int i = 0; i < obstacles.size(); i++)
			{
				isBlocked = CheckSpawn(obstacles[i], spawnX, spawnY, width, height);
				if (isBlocked) { break; }
			}
		}
		if (!isBlocked) { obstacles.push_back(new Obstacle(spawnX, spawnY, width, height)); hasSpawned = true; }
		obstacles.back()->SetColor((GLfloat)rand() * (1.0) / (GLfloat)RAND_MAX + 0.1, (GLfloat)rand() * (1.0 - 0.5) / (GLfloat)RAND_MAX, (GLfloat)rand() * (1.0 - 0.5) / (GLfloat)RAND_MAX);

	}
}

bool Spawner::CheckSpawn(GameObject* obstacle, GLfloat posX, GLfloat posY, GLfloat width, GLfloat height) //Checks collision on spawn to see if the area is occupied already.
{
	bool isColliding = false;
	GLfloat xMinNew = posX - (width);
	GLfloat yMinNew = posY - (height);
	GLfloat xMinObs = obstacle->getPosX() - obstacle->getWidth();
	GLfloat yMinObs = obstacle->getPosY() - obstacle->getHeight();
	GLfloat widthObs = obstacle->getWidth();
	GLfloat heightObs = obstacle->getHeight();


	if (((xMinNew + width * 2) > xMinObs && xMinNew < xMinObs + (widthObs * 2)))
	{
		if ((yMinNew + height * 2 > yMinObs && yMinNew < yMinObs + (heightObs * 2)))
		{
			return true; // true means area is taken
		}
	}
	return false;
}
<file_sep>/3DExample1/src/Rect.h
#pragma once
#include "GameObject.h"
class Rect :
    public GameObject //Rect class object used as a base and as an individual object for drawing rectangle polygons.
{
	GLfloat _red, _green, _blue;
public:
	Rect(GLfloat x, GLfloat y, GLfloat width, GLfloat height);
	Rect(GLfloat x, GLfloat y);
	Rect();
	void Draw();
	void SetColor(GLfloat red, GLfloat green, GLfloat blue);
};

<file_sep>/3DExample1/src/Spawner.h
#pragma once
#include "GameObject.h"
#include "Obstacle.h"
#include <vector>

class Spawner : public GameObject //Spawner class used to hold and handle a vector of obstacles.
{
public:
	std::vector<Obstacle*> obstacles; // Container for all of the obstacles.
	Spawner(GLfloat x, GLfloat y, GLfloat width, GLfloat height);
	Spawner();
	void DebugDraw(GLfloat r, GLfloat g, GLfloat b, GLfloat a);
	void Draw();
	int GetRandBounds(int upper);
	void Spawn(int amount, GLfloat width, GLfloat height);
	void Spawn(GLfloat width, GLfloat height);
	bool CheckSpawn(GameObject* obstacle, GLfloat posX, GLfloat posY, GLfloat width, GLfloat height);
};

<file_sep>/3DExample1/src/PlayerCar.cpp
#include "PlayerCar.h"

#include <iostream>

PlayerCar::PlayerCar(GLfloat speed, int startScore, GLfloat x, GLfloat y, GLfloat width, GLfloat height)
: Rect(x, y, width, height), _speed(speed), _score(startScore)
{
	_hasWon = false;
}

PlayerCar::PlayerCar(GLfloat speed, int startScore) : Rect(), _speed(speed), _score(startScore)
{
	_hasWon = false;
}

void PlayerCar::CheckCollision(GameObject* obstacle, int score)
// Checks collision by comparing the aMin x/y and bMin x/y against each other in a AABB format.
{
	bool isColliding = false;
	GLfloat xMinCar = _posX - (_width);
	GLfloat yMinCar = _posY - (_height);
	GLfloat xMinObs = obstacle->getPosX() - obstacle->getWidth();
	GLfloat yMinObs = obstacle->getPosY() - obstacle->getHeight();
	GLfloat widthObs= obstacle->getWidth();
	GLfloat heightObs = obstacle->getHeight();
	//Essentially checks if the player is inside the range of the obstacle on TWO axes. If it is not within range on both axes, it is not colliding.
	if ((xMinCar + _width * 2) > xMinObs && xMinCar < xMinObs + (widthObs * 2))
	{
		if (yMinCar + _height * 2 > yMinObs && yMinCar < yMinObs + (heightObs * 2))
		{
			HandleCollision(obstacle);
			AddScore(-score);
			LogIntValue("Player crashed and lost: ", score, " points!");
			LogIntValue("Current score: ", GetScore(), " Points");
		}
	}
}

void PlayerCar::CheckBoundsCollision(GameObject* obstacle, GLfloat startX, GLfloat startY)
// Checks collision by comparing the aMin x/y and bMin x/y against each other in a REVERSED AABB format.
{
	bool isColliding = false;
	GLfloat xMinCar = _posX - (_width);
	GLfloat yMinCar = _posY - (_height);
	GLfloat xMinObs = obstacle->getPosX() - obstacle->getWidth();
	GLfloat yMinObs = obstacle->getPosY() - obstacle->getHeight();
	GLfloat widthObs = obstacle->getWidth();
	GLfloat heightObs = obstacle->getHeight();
	if (xMinCar < xMinObs || xMinCar + _width * 2 > xMinObs + widthObs*2 || yMinCar < yMinObs || yMinCar + _height * 2 > yMinObs + (heightObs * 2))
		//Essentially checks if the player is outside the range of the border on ANY axis. If it is not within range on atleast one axis, it is colliding.
	{
		LogIntValue("xMinCar", xMinCar);
		LogIntValue("xMinObs", xMinObs);
		MoveTo(startX, startY);
		Log("Player has been returned within bounds.");
	}
}

void PlayerCar::HandleCollision(GameObject* obstacle) // Handles the collision, essentially determines whether the object is above or below, then left or right.
{
	bool vertical = (_width < _height); // Top/Side determinant is not flawless and some slipping can be seen.
	if (abs((_posX)-obstacle->getPosX()) > abs((_posY)-obstacle->getPosY()))
	{
		if (_posX > obstacle->getPosX()) { _posX += 6; }
		else { _posX -= 6; }
	}
	else
	{
		if (_posY > obstacle->getPosY()) { _posY += 6; }
		else { _posY -= 6; }
	}
	
	Log("Collided with obstacle.");
	
}


void PlayerCar::Rotate() //Swaps the width and height values to "rotate" by 90 degrees.
{
	GLfloat temp = _width;
	_width = _height;
	_height = temp;
}

void PlayerCar::AddScore(int score) // Adds an amount to the private _score variable.
{
	_score += score;
}

int PlayerCar::GetScore(){	return _score; } // Gets player's score
<file_sep>/3DExample1/src/Rect.cpp
#include "Rect.h"

Rect::Rect(GLfloat x, GLfloat y, GLfloat width, GLfloat height) :GameObject(x, y, width, height) // Constructor with all variables.
{
	GLfloat red = 1, green = 1, blue = 1;
}

Rect::Rect(GLfloat x, GLfloat y) : GameObject(x, y) // Default constructor for position only.
{
	GLfloat _red = 1, _green = 1, _blue = 1;
}

Rect::Rect():GameObject() // Default constructor at position 1.
{
	GLfloat _red = 1, _green = 1, _blue = 1;
}

void Rect::Draw() // Draw function inside the rectangle class creates a triangle strip with 4 vertices based on the position and size variables.
{
	glPushMatrix();
	glBegin(GL_POLYGON); // Creates a polygon with the following vertices specified below.
	glColor3f(_red, _green, _blue);
	glVertex2f((_posX - _width), (_posY - _height));
	glVertex2f((_posX + _width), (_posY - _height));
	glVertex2f((_posX + _width), (_posY + _height));
	glVertex2f((_posX - _width), (_posY + _height));
	glEnd();
	glFlush();
	glPopMatrix();
}

void Rect::SetColor(GLfloat red, GLfloat green, GLfloat blue) // Sets the colour of the object for draw calls.
{
	_red = red;
	_green = green;
	_blue = blue;
}<file_sep>/3DExample1/src/Boundary.cpp
#include "Boundary.h"

#include "EndGate.h"

Boundary::Boundary(GLfloat x, GLfloat y, GLfloat width, GLfloat height) :GameObject(x, y, width, height)
{
	
}

void Boundary::Draw(GLfloat r, GLfloat g, GLfloat b, GLfloat a) // Draw function inside the rectangle class creates a triangle strip with 4 vertices based on the position and size variables.
{
	glPushAttrib(GL_CURRENT_BIT);
	glBegin(GL_LINE_LOOP);
	glColor4f(r, g, b, a);
	glVertex2f((_posX - _width), (_posY - _height));
	glVertex2f((_posX + _width), (_posY - _height));
	glVertex2f((_posX + _width), (_posY + _height));
	glVertex2f((_posX - _width), (_posY + _height));
	glEnd();
	glPopAttrib();
	glFlush();
}
<file_sep>/3DExample1/src/GameObject.h
#pragma once
#include "freeglut.h"
#include "ConsoleDebug.h"
class GameObject //Base class for every object, used to store position and size information.
{
protected:
	GLfloat _posX, _posY, _width, _height;
public:
	GameObject(GLfloat x, GLfloat y, GLfloat width, GLfloat height);
	GameObject(GLfloat x, GLfloat y);
	GameObject();
	GLfloat getPosX(); 	GLfloat getPosY();	GLfloat getWidth();	GLfloat getHeight();
	void Move(GLfloat x, GLfloat y);
	void MoveTo(GLfloat x, GLfloat y);
	void Resize(GLfloat width, GLfloat height);
	void ResizeWidth(GLfloat width);
	void ResizeHeight(GLfloat height);
};

<file_sep>/3DExample1/src/ConsoleDebug.cpp
#include "ConsoleDebug.h"

// File used  to contain Debug functions neatly.

void Log(std::string message){
std::cout<< "Debug Log: " << message << std::endl;
}

void LogIntValue(std::string message, int value, std::string message2)
{
	std::cout << "DebugValue Log: "<< message << value << message2 << std::endl;
}

void LogIntValue(std::string message, int value) // Log overload
{
	std::cout << "DebugValue Log: " << message << value << std::endl;
}

void LogIntro()
{
	std::cout << "Welcome to my Car Game! By <NAME>"<< std::endl;
	std::cout << "W - Move Up" << std::endl;
	std::cout << "S - Move Down" << std::endl;
	std::cout << "A - Move Left" << std::endl;
	std::cout << "D - Move Right" << std::endl;
	std::cout << "R - Rotate 90" << std::endl;
	std::cout << "Reach the red gate and avoid the obstacles!" << std::endl;
}
<file_sep>/3DExample1/src/PlayerCar.h
#pragma once
#include "Rect.h" //Player car used to represent the player, check collisions with the border and obstacles and contain score.
class PlayerCar :
    public Rect
{
	int _score;
	bool _hasWon;
public:
	GLfloat _speed;
	PlayerCar(GLfloat speed, int startScore, GLfloat x, GLfloat y, GLfloat width, GLfloat height);
	PlayerCar(GLfloat speed, int startScore);
	void CheckCollision(GameObject* obstacle, int score);
	void CheckBoundsCollision(GameObject* obstacle, GLfloat startX, GLfloat startY);
	void HandleCollision(GameObject* obstacle);
	void Rotate();
	void AddScore(int score);
	int GetScore();
};

<file_sep>/3DExample1/src/GameObject.cpp
#include "GameObject.h"

GameObject::GameObject(GLfloat x, GLfloat y, GLfloat width, GLfloat height):_posX(x), _posY(y), _width(width), _height(height) // constructor for 
{
	
}

GameObject::GameObject(GLfloat x, GLfloat y): _posX(x), _posY(y), _width(1), _height(1) // constructor for only x and y
{
	
}

GameObject::GameObject(): _posX(0), _posY(0), _width(1),_height(1) // default constructor
{
}

GLfloat GameObject::getPosX()	{ return _posX; } // Getters for pos and size
GLfloat GameObject::getPosY()	{ return _posY; }
GLfloat GameObject::getWidth()	{ return _width; }
GLfloat GameObject::getHeight() { return _height; }


void GameObject::Move(GLfloat x, GLfloat y) { _posX += x; _posY += y; } // Moves the object by a certain amount

void GameObject::MoveTo(GLfloat x, GLfloat y){ _posX = x; _posY = y; } // Moves the object to a specified coordinate

void GameObject::Resize(GLfloat width, GLfloat height) { _width = width; _height = height; } // Resizes the object
void GameObject::ResizeWidth(GLfloat width) { _width = width; }
void GameObject::ResizeHeight(GLfloat height) {_height = height; }<file_sep>/3DExample1/src/Main.cpp
#include <cstdlib>
#include <fstream>
#include <iostream>
#include <string>
#include <vector>
#include <ctime>
#include "freeglut.h"	// OpenGL toolkit - in the local shared folder
#include "Spawner.h"
#include "PlayerCar.h"
#include "ConsoleDebug.h"
#include "EndGate.h"
#include "Boundary.h"

//Constants
#define X_CENTRE 0.0      // Centre
#define Y_CENTRE 0.0
#define START_X -50.0	// Spawn
#define START_Y -36.0
#define END_X 50.0	// EndGate
#define END_Y 38.0

#define PLAYER_WIDTH 4.0 // Player
#define PLAYER_HEIGHT 2.0
#define PLAYER_SPEED 2

#define DEFAULT_SIZE 4.0 // Obstacle
#define DEFAULT_AMOUNT 6

#define BOUNDARY_WIDTH 60 //Bounds
#define BOUNDARY_HEIGHT 40

#define START_SCORE 50 // Scores
#define WIN_SCORE 30
#define LOSE_SCORE 10

#define GRID_SIZE 4

//Globals
GLfloat rainbowRed = 0, rainbowGreen = 0.8, rainbowBlue = 0;
Spawner* spawner = new Spawner(X_CENTRE, Y_CENTRE, 50, 20); // Creates a spawner instance
EndGate* exitGate = new EndGate(END_X+2, END_Y-2, DEFAULT_SIZE*2, DEFAULT_SIZE);  // Creates an End Gate instance
Rect* startGate = new  Rect(START_X-2, START_Y, DEFAULT_SIZE*2, DEFAULT_SIZE); // Creates a start gate instance
PlayerCar* player = new PlayerCar(PLAYER_SPEED, START_SCORE, START_X+2, START_Y+2, PLAYER_WIDTH, PLAYER_HEIGHT); // Creates a player class instance
Boundary* border = new Boundary(X_CENTRE, Y_CENTRE, BOUNDARY_WIDTH, BOUNDARY_HEIGHT);
bool rainbowMode = false, grid = false;  // Rainbow more global vars
bool redCountUp = false;
bool greenCountUp = false;
std::string scoreStr = "Score: "; // score text var
void* font = GLUT_BITMAP_9_BY_15; // font

// Callback function when the window size is changed.
void reshape(int w, int h)
{
	GLfloat aspect = (GLfloat)w / (GLfloat)h;
	glViewport(0, 0, w, h);
	glMatrixMode(GL_PROJECTION);
	glLoadIdentity();
	if (w <= h) // aspect <= 1
		glOrtho(-50.0, 50.0, -50.0 / aspect, 50.0 / aspect, -50.0, 50.0);
	else // aspect > 1
		glOrtho(-50.0*aspect, 50.0*aspect, -50.0, 50.0, -50.0, 50.0);
	glMatrixMode(GL_MODELVIEW);
	glLoadIdentity();
}

void DrawGrid()
{
	/*LogIntValue("Width", GLUT_WINDOW_WIDTH);
	LogIntValue("Height", GLUT_WINDOW_HEIGHT);*/
	glPushMatrix();
	for(GLfloat i = START_X*2; i <= END_X*2; i+= GRID_SIZE) // Vertical lines
	{
		
		glBegin(GL_LINES);
		glColor3f(0.0, 0.2, 0.2);
		glVertex2f((i), (START_Y*2));
		glVertex2f((i), (END_Y*2));
		glEnd();
	}
	for (GLfloat i = START_Y * 2; i < END_Y * 2; i += GRID_SIZE) // Horizontal lines
	{
		glBegin(GL_LINES);
		glColor3f(0.0, 0.2, 0.2);
		glVertex2f((START_X*2), (i));
		glVertex2f((END_X*2), (i));
		glEnd();
	}
	glFlush();
	glPopMatrix();
	
}

void DisplayScore(GLfloat x, GLfloat y)
{
	std::string scr = std::to_string(player->GetScore()); // Score converted to string
	glPushMatrix();
	if (player->GetScore() < 0) { glColor3f(1.0, 0.0, 0.0); } // Red
	else{ glColor3f(0.0, 1.0, 0.0); } // Green
	glRasterPos2i(x, y); // changes the raster position for the text to a specified point.
	for (std::string::iterator i = scoreStr.begin(); i != scoreStr.end(); ++i) // Iterates through the string and draws each character. 
	{
		char c = *i;
		glutBitmapCharacter(font, c);
	}
	
	for(std::string::iterator i = scr.begin(); i != scr.end(); ++i) // Iterator for score.
	{
		char c = *i;
		glutBitmapCharacter(font, c);
	}
	glPopMatrix();
}

void RateChange(bool &isUp, GLfloat &number, GLfloat rate) //Simple function to make changing the timer value smoothly go up and down
{
	if (number > 100) { isUp = true; }
	if (number < 0) { isUp = false; }
	number += rate + (isUp * (-rate * 2));
}


//Timer callback function
void TimerFunction(int value)
{
	glClear(GL_COLOR_BUFFER_BIT);
	RateChange(redCountUp, rainbowRed, 0.2); // Rate change for rainbow "GAMER MODE" colours.
	RateChange(greenCountUp, rainbowGreen, 0.3);
	glutPostRedisplay();
	glutTimerFunc(5, TimerFunction, 0); //calls TimerFunction on tick - callback
}

void rightMenu(GLint id) // Right click menu entries
{
	switch(id)
	{
	case 1:
		rainbowMode = true;
		Log("Rainbow Mode On.");
		break;
	case 2:
		rainbowMode = false;
		Log("Rainbow Mode Off.");
		break;
	case 3:
		if (grid) { grid = false; }
		else { grid = true; }
		LogIntValue("grid toggled: ", grid);
		break;
	default: 
		break;
	}
	glutPostRedisplay();
}

void keyboard(unsigned char key, int x, int y) // Keyboard actions
{
	switch (key)
	{
	case 'w':
		player->Move(0, player->_speed);
		break;
	case 's':
		player->Move(0, -player->_speed);
		break;
	case 'd':
		player->Move(player->_speed, 0);
		break;
	case 'a':
		player->Move(-player->_speed, 0);
		break;
	case 'r':
		player->Rotate();
		break;		
	}
	glutPostRedisplay();
	for(Obstacle* i : spawner->obstacles)
	{
		player->CheckCollision(i, LOSE_SCORE);
	}
}

// Graphics initialization function
void init(void)
{
	LogIntro();
    glClearColor (0.0, 0.0, 0.0, 0.0);     // window will be cleared to black
	srand(time(NULL));
    spawner->Spawn(DEFAULT_AMOUNT,DEFAULT_SIZE, DEFAULT_SIZE);
	player->SetColor(1, 1, 1);
	startGate->SetColor(0, 1, 0);
	glutCreateMenu(rightMenu);
	glutAddMenuEntry("Gamer Mode on", 1);
	glutAddMenuEntry("Gamer Mode off", 2);
	glutAddMenuEntry("Grid toggle", 3);
	glutAttachMenu(GLUT_RIGHT_BUTTON);
	
}



// display callback function called whenever contents of window need to be re-displayed
   //this is the all important drawing method - all drawing code goes in here
void display()
{
	glClear(GL_COLOR_BUFFER_BIT);     /* clear window */
	glLoadIdentity();
	if (grid) { DrawGrid(); }
	border->Draw(1, 1, 1, 1);
	player->CheckBoundsCollision(border, START_X, START_Y);
	spawner->Draw();
	//spawner->DebugDraw(1,0,0,1);
	if (rainbowMode) {	player->SetColor(rainbowRed/100, rainbowGreen/100, 0.5); }
	else {	player->SetColor(1, 1, 1);	}
	exitGate->Draw();
	startGate->Draw();
	player->Draw();
	DisplayScore(START_X, END_Y);
	glPushMatrix();
	exitGate->SetColor(1.0, 0.0, 0.0);
	glPopMatrix();
	if(exitGate->CheckCollision(player,WIN_SCORE,START_X,START_Y))
	{
		spawner->obstacles.clear();
		spawner->Spawn(DEFAULT_AMOUNT, DEFAULT_SIZE, DEFAULT_SIZE);
	}
	glutSwapBuffers();
}


//rename this to main(...) and change example 2 to run this main function
int main(int argc, char** argv)
{
	       /* window management code ... */
   
   glutInit(&argc, argv); // initialises GLUT and processes any command line arguments   
   glutInitDisplayMode (GLUT_DOUBLE | GLUT_RGB);	// Double Buffered, RGB colour-space  
   glutInitWindowSize (1024, 720);	// window width = 1024 pixels, height = 576 pixels for a 16:9 ascpect ratio    
   glutInitWindowPosition (600, 100);	// Window upper left corner at (100, 100) in Windows space.
   glutCreateWindow ("Car Game");	// creates an OpenGL window with command argument in its title bar 
   init();
   glutDisplayFunc(display);
   glutReshapeFunc(reshape);
   glutKeyboardFunc(keyboard);
   //needed for animation
   glutTimerFunc(5, TimerFunction, 0);
   glutMainLoop();
   return 0;
}

