CSC8503_Advanced_Game_Technologies / CSC8503 / GameTech / MultiGame.cpp
MultiGame.cpp
Raw
#include "MultiGame.h"
#include "../CSC8503Common/GameWorld.h"
#include "../../Plugins/OpenGLRendering/OGLMesh.h"
#include "../../Plugins/OpenGLRendering/OGLShader.h"
#include "../../Plugins/OpenGLRendering/OGLTexture.h"
#include "../../Common/TextureLoader.h"

#include "../CSC8503Common/PositionConstraint.h"
#include "../CSC8503Common/HingeConstraint.h"
#include "../CSC8503Common/FixedHeightConstraint.h"

#include <string>

using namespace NCL;
using namespace CSC8503;

MultiGame::MultiGame(int enemies) {
	world = new GameWorld();
	renderer = new GameTechRenderer(*world);
	physics = new PhysicsSystem(*world);

	forceMagnitude = 100.0f;
	useGravity = true;
	inSelectionMode = false;

	numberOfEnemies = enemies;

	Debug::SetRenderer(renderer);

	InitialiseAssets();
}

void MultiGame::InitialiseAssets() {
	auto loadFunc = [](const string& name, OGLMesh** into) {
		*into = new OGLMesh(name);
		(*into)->SetPrimitiveType(GeometryPrimitive::Triangles);
		(*into)->UploadToGPU();
	};

	loadFunc("cube.msh", &cubeMesh);
	loadFunc("sphere.msh", &sphereMesh);
	loadFunc("Male1.msh", &charMeshA);
	loadFunc("courier.msh", &charMeshB);
	loadFunc("security.msh", &enemyMesh);
	loadFunc("coin.msh", &bonusMesh);
	loadFunc("capsule.msh", &capsuleMesh);

	basicTex = (OGLTexture*)TextureLoader::LoadAPITexture("checkerboard.png");
	basicShader = new OGLShader("GameTechVert.glsl", "GameTechFrag.glsl");

	InitCamera();
	InitWorld();
}

MultiGame::~MultiGame() {
	delete cubeMesh;
	delete sphereMesh;
	delete charMeshA;
	delete charMeshB;
	delete enemyMesh;
	delete bonusMesh;

	delete basicTex;
	delete basicShader;

	delete physics;
	delete renderer;
	delete world;
}

void MultiGame::DisplayGrid()
{
	NavigationGrid grid("LevelMulti1.txt");

	for (int i = 0; i < grid.GetNodeCount(); i++)
	{
		for (int j = 0; j < 4; j++)
		{
			if (grid.GetNodes()[i].connected[j])
			{
				renderer->DrawLine(grid.GetNodes()[i].position + Vector3(0, 1, 0), grid.GetNodes()[i].connected[j]->position + Vector3(0, 1, 0), Vector4(0, 0.0, 1.0, 1));
			}
		}
	}
}

void MultiGame::UpdateGame(float dt) {
	EndGame(dt);

	if (levelCompleted == false) {
		endGameTimer += dt;
		if (endGameTimer >= 1.0f) {
			endGameTimer = 0.0f;
			playerCharacter->SetScore(playerCharacter->GetScore() - 10);
		}

		levelTimer += dt;

		//Restart position of a falling player
		if (playerCharacter->GetTransform().GetPosition().y <= -10) {
			playerCharacter->GetTransform().SetPosition(Vector3(0, 1, 30));
		}


		if (!inSelectionMode) {
			world->GetMainCamera()->UpdateCamera(dt);
		}

		CameraMovement();

		UpdateKeys(dt);

		MovePlayerCharacter(dt);

		MoveEnemies(dt); // 

		SelectObject();
	}

	physics->Update(dt);

	world->UpdateWorld(dt);
	renderer->Update(dt);

	renderer->Render();

	//Display AI pathfinding grid
	if (toggleGrid)
	{
		DisplayGrid();
	}

	DrawDisplay(dt);
}

void MultiGame::UpdateKeys(float dt) {
	//if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::F1)) {
	//	InitWorld(); //We can reset the simulation at any time with F1
	//	//selectionObject = nullptr;
	//	lockedObject = nullptr;
	//	levelTimer = 0.0f;
	//}

	if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::F2)) {
		InitCamera(); //F2 will reset the camera to a specific default place
	}

	if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::G)) {
		useGravity = !useGravity; //Toggle gravity!
		physics->UseGravity(useGravity);
	}
	//Running certain physics updates in a consistent order might cause some
	//bias in the calculations - the same objects might keep 'winning' the constraint
	//allowing the other one to stretch too much etc. Shuffling the order so that it
	//is random every frame can help reduce such bias.
	if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::F9)) {
		world->ShuffleConstraints(true);
	}
	if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::F10)) {
		world->ShuffleConstraints(false);
	}

	if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::F7)) {
		world->ShuffleObjects(true);
	}
	if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::F8)) {
		world->ShuffleObjects(false);
	}
	if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::L))
	{
		toggleGrid = !toggleGrid;
	}
}

void  MultiGame::CameraMovement() {
	Vector3 objPos = playerCharacter->GetTransform().GetPosition();
	Vector3 camPos = objPos + playerCharacter->GetTransform().GetOrientation() * lockedOffset;

	Matrix4 temp = Matrix4::BuildViewMatrix(camPos, objPos + Vector3(0, 5, 0), Vector3(0, 1, 0));

	Matrix4 modelMat = temp.Inverse();

	Quaternion q(modelMat);
	Vector3 angles = q.ToEuler();

	world->GetMainCamera()->SetPosition(camPos);
	world->GetMainCamera()->SetPitch(angles.x);
	world->GetMainCamera()->SetYaw(angles.y);
}

void MultiGame::MovePlayerCharacter(float dt)
{
	float rotationSpeed = 60.0f;
	Vector3 pyr = playerCharacter->GetTransform().GetOrientation().ToEuler();

	if (Window::GetKeyboard()->KeyDown(KeyboardKeys::W)) {
		playerCharacter->SetSleep(false);
		playerCharacter->GetPhysicsObject()->AddForce(playerCharacter->GetTransform().GetOrientation() * Vector3(0, 0, -1) * forceMagnitude * playerCharacter->GetSpeedMultiplier());
	}
	if (Window::GetKeyboard()->KeyDown(KeyboardKeys::A)) {
		playerCharacter->SetSleep(false);
		pyr.y += rotationSpeed * dt;
		pyr.y = pyr.y >= 0.0f ? pyr.y <= 360.0f ? pyr.y : pyr.y - 360.0f : pyr.y + 360.0f;
		playerCharacter->GetTransform().SetOrientation(Quaternion::EulerAnglesToQuaternion(pyr.x, pyr.y, pyr.z));
	}
	if (Window::GetKeyboard()->KeyDown(KeyboardKeys::S)) {
		playerCharacter->SetSleep(false);
		playerCharacter->GetPhysicsObject()->AddForce(playerCharacter->GetTransform().GetOrientation() * Vector3(0, 0, 1) * forceMagnitude * playerCharacter->GetSpeedMultiplier());
	}
	if (Window::GetKeyboard()->KeyDown(KeyboardKeys::D)) {
		playerCharacter->SetSleep(false);
		pyr.y -= rotationSpeed * dt;
		pyr.y = pyr.y >= 0.0f ? pyr.y <= 360.0f ? pyr.y : pyr.y - 360.0f : pyr.y + 360.0f;
		playerCharacter->GetTransform().SetOrientation(Quaternion::EulerAnglesToQuaternion(pyr.x, pyr.y, pyr.z));
	}
	if (Window::GetKeyboard()->KeyDown(KeyboardKeys::SPACE)) {
		playerCharacter->SetSleep(false);
		//if (jumpTimer <= 0.0) {
		playerCharacter->GetPhysicsObject()->AddForce(Vector3(0, 2, 0) * forceMagnitude);
		jumpTimer += 2.0f;
		//	}

	}
}

void MultiGame::MoveEnemies(float dt)
{
	for (int i = 0; i < enemies.size(); i++)
	{
		enemies[i]->UpdatePosition(dt);
	}
}


void MultiGame::InitCamera()
{
	world->GetMainCamera()->SetNearPlane(0.5f);
	world->GetMainCamera()->SetFarPlane(2000.0f);
	world->GetMainCamera()->SetPitch(-15.0f);
	world->GetMainCamera()->SetYaw(315.0f);
	world->GetMainCamera()->SetPosition(Vector3(-60, 40, 60));
	lockedObject = nullptr;
}

void MultiGame::InitWorld() {
	world->ClearAndErase();
	physics->Clear();
	forceMagnitude = 50.0f;
	obstacles.clear();
	//movables.clear();
	//movableDoors.clear();
	//obstacleDoors.clear();
	//obstacleMaze.clear();
	bonus.clear();

	//Setup
	Vector3 floorPosition(0, -2, 0);
	Vector3 floorSize(125, 2, 125);
	Vector3 wallSize(2, 50, 500);
	Vector4 floorColour(1, 1, 1, 1);
	Vector4 terrainColour(0, 0, 1, 1);

	
	
	//Player Starting Position
playerCharacter = AddPlayerToWorld(Vector3(20,1,30));

//	playerCharacter = AddPlayerToWorld(Vector3(0, 1, -65));		  

//Player First save point
//playerCharacter = AddPlayerToWorld(Vector3(0, 9, -257));
//Player Second save point
//playerCharacter = AddPlayerToWorld(Vector3(0, 9, -315));

	//playerCharacter = AddPlayerToWorld(Vector3(0, 9, -430));
	//playerCharacter->AddScore(1000);
	playerCharacter->AddScore(1000);

	for (int i = 0; i < numberOfEnemies; ++i) {
		AddAIOpponentToWorld(Vector3((10 * i) - 100, 1, -30));

		//Enemies - //x115 - 10 / z100	//player x115 z110
	}

	//Wall Right
	obstacles.push_back(AddCubeToWorld(Vector3(125,2,0), Vector3(1, floorSize.y, floorSize.z), 0.0f));
	// Wall Left
	obstacles.push_back(AddCubeToWorld(Vector3(-125, 2, 0), Vector3(1, floorSize.y, floorSize.z), 0.0f));
	//Wall Bottom
	obstacles.push_back(AddCubeToWorld(Vector3(0, 2, 125), Vector3(floorSize.z, floorSize.y, 1), 0.0f));
	//Wall Up
	obstacles.push_back(AddCubeToWorld(Vector3(0, 2, -125), Vector3(floorSize.z, floorSize.y, 1), 0.0f));



	//Add starting location
	AddFloorToWorld(floorPosition, floorSize, floorColour, CollisionResolution::Impulse);
	//Add starting Constraint obstacle


	//Left
	obstacles.push_back(AddCubeToWorld(Vector3(-50, 3, -80), Vector3(70, 3, 1), 0.0f));
	//Right
	obstacles.push_back(AddCubeToWorld(Vector3(75, 3, -80), Vector3(50, 3, 1), 0.0f));
	obstacles.push_back(AddCubeToWorld(Vector3(85, 3, -70), Vector3(40, 3, 3), 0.0f));
	obstacles.push_back(AddCubeToWorld(Vector3(95, 3, -60), Vector3(30, 3, 3), 0.0f));
	obstacles.push_back(AddCubeToWorld(Vector3(65, 3, -40), Vector3(60, 3, 3), 0.0f));
	obstacles.push_back(AddCubeToWorld(Vector3(65, 3, -50), Vector3(60, 3, 3), 0.0f));
	obstacles.push_back(AddCubeToWorld(Vector3(45, 3, -30), Vector3(80, 3, 3), 0.0f));
	obstacles.push_back(AddCubeToWorld(Vector3(85, 3, -20), Vector3(40, 3, 3), 0.0f));

	//Non passable object with Contraints (Position, Hinge and Height) 
	AddFinishGateToWorld(Vector3(-12, 8, -100), Vector3(0, 0, 0));


	//Enemies
	//AddAIOpponentToWorld(Vector3(100, 1, -30));
	//AddAIOpponentToWorld(Vector3(95, 1, -30));
	//AddAIOpponentToWorld(Vector3(90, 1, -30));


	////bonus.push_back(AddBonusToWorld(Vector3(100, 1, -30)));
	//bonus.push_back(AddBonusToWorld(Vector3(1, 2, -23)));
	//bonus.push_back(AddBonusToWorld(Vector3(0, 2, -60)));
	//bonus.push_back(AddBonusToWorld(Vector3(0, 2, -80)));
	//bonus.push_back(AddBonusToWorld(Vector3(0, 2, -100)));
}





void MultiGame::EndGame(float dt) {
	if (playerCharacter->GetTransform().GetPosition().z <= -100) {
		DrawDisplay(dt);

		renderer->DrawString("You have won", Vector2(45, 50));

		renderer->DrawString("Press Enter/Return to go back to menu", Vector2(20, 60));

		levelCompleted = true;

		playerCharacter->MakeInactive();

		if (Window::GetKeyboard()->KeyDown(KeyboardKeys::RETURN)) {

			gameFinished = true;
		}
	}

	for (int i = 0; i < enemies.size(); ++i) {
		if (enemies[i]->GetTransform().GetPosition().z <= -100) {
			DrawDisplay(dt);

			renderer->DrawString("You have lost", Vector2(45, 50));

			renderer->DrawString("Press Enter/Return to go back to main menu", Vector2(20, 60));

			levelCompleted = true;

			playerCharacter->MakeInactive();

			if (Window::GetKeyboard()->KeyDown(KeyboardKeys::RETURN)) {

				gameFinished = true;
			}
		}


	}
	

}

GameObject* MultiGame::AddFloorToWorld(const Vector3& position, const Vector3& scale, const Vector4& colour, const int collisionResolution) {
	GameObject* floor = new GameObject();

	AABBVolume* volume = new AABBVolume(scale);
	floor->SetBoundingVolume((CollisionVolume*)volume);

	floor->GetTransform()
		.SetScale(scale * 2)
		.SetPosition(position);

	floor->SetRenderObject(new RenderObject(&floor->GetTransform(), cubeMesh, basicTex, basicShader));
	floor->SetPhysicsObject(new PhysicsObject(&floor->GetTransform(), floor->GetBoundingVolume()));
	floor->GetPhysicsObject()->SetElasticity(0.0f);
	floor->GetPhysicsObject()->SetBuoyancy(0.0f);
	floor->GetPhysicsObject()->SetGravityAffinity(false);
	floor->GetPhysicsObject()->SetCollisionResolution(collisionResolution);

	floor->GetPhysicsObject()->SetInverseMass(0);
	floor->GetPhysicsObject()->InitCubeInertia();

	floor->GetRenderObject()->SetColour(colour);

	world->AddGameObject(floor);

	return floor;
}

PlayerObject* MultiGame::AddPlayerToWorld(const Vector3& position) {
	float radius = 1.0f;
	float inverseMass = 0.25f;

	PlayerObject* player = new PlayerObject("Player1");

	Vector3 sphereSize = Vector3(radius, radius, radius);
	SphereVolume* volume = new SphereVolume(radius);
	player->SetBoundingVolume((CollisionVolume*)volume);

	player->GetTransform()
		.SetScale(sphereSize)
		.SetPosition(position);
	//player->GetTransform().SetOrientation(Quaternion::EulerAnglesToQuaternion(0,180,0));

	player->SetRenderObject(new RenderObject(&player->GetTransform(), charMeshB, basicTex, basicShader));
	player->SetPhysicsObject(new PhysicsObject(&player->GetTransform(), player->GetBoundingVolume()));

	player->GetPhysicsObject()->SetInverseMass(inverseMass);
	player->GetPhysicsObject()->InitSphereInertia();
	player->GetPhysicsObject()->SetBuoyancy(140);
	player->GetPhysicsObject()->SetElasticity(0.7f);
	player->GetPhysicsObject()->SetCollisionResolution(CollisionResolution::Impulse | CollisionResolution::Spring | CollisionResolution::Jelly | CollisionResolution::Snow | CollisionResolution::Collect);

	player->GetRenderObject()->SetColour(Vector4(255, 255, 0, 1));
	playerOriginalColour = Vector4(255, 255, 0, 1);

	world->AddGameObject(player);

	return player;
}

GameObject* MultiGame::AddAIOpponentToWorld(const Vector3& position) {
	//float meshSize = 4.0f;
	//float inverseMass = 0.5f;

	float radius = 1.0f;
	float inverseMass = 0.25f;

	AIOpponentObject* aiOpponent = new AIOpponentObject("LevelMulti1.txt");

	Vector3 sphereSize = Vector3(radius, radius, radius);
	SphereVolume* volume = new SphereVolume(radius);

	//keeper->SetOrigin(position);
	aiOpponent->AddObstacles(obstacles);

	//AABBVolume* volume = new AABBVolume(Vector3(0.3, 0.9f, 0.3) * meshSize);
	aiOpponent->SetBoundingVolume((CollisionVolume*)volume);

	//aiOpponent->GetTransform().SetScale(Vector3(meshSize, meshSize, meshSize));
	//aiOpponent->GetTransform().SetPosition(position);

	aiOpponent->GetTransform()
		.SetScale(sphereSize)
		.SetPosition(position);

	aiOpponent->SetRenderObject(new RenderObject(&aiOpponent->GetTransform(), charMeshA, nullptr, basicShader));
	aiOpponent->SetPhysicsObject(new PhysicsObject(&aiOpponent->GetTransform(), aiOpponent->GetBoundingVolume()));

	aiOpponent->GetPhysicsObject()->SetInverseMass(inverseMass);
	aiOpponent->GetPhysicsObject()->InitCubeInertia();
	aiOpponent->GetPhysicsObject()->SetBuoyancy(70);
	aiOpponent->GetPhysicsObject()->SetElasticity(0.7f);
	aiOpponent->GetPhysicsObject()->SetCollisionResolution(CollisionResolution::Impulse | CollisionResolution::Spring | CollisionResolution::Jelly | CollisionResolution::Snow | CollisionResolution::Collect);

	aiOpponent->SetAIOpponent(aiOpponent);
	aiOpponent->SetPlayer(playerCharacter);

	world->AddGameObject(aiOpponent);
	enemies.push_back(aiOpponent);

	return aiOpponent;
}

GameObject* MultiGame::AddCubeToWorld(const Vector3& position, Vector3 dimensions, float inverseMass, const Vector4& colour) {
	GameObject* cube = new GameObject();

	AABBVolume* volume = new AABBVolume(dimensions);

	cube->SetBoundingVolume((CollisionVolume*)volume);

	cube->GetTransform()
		.SetScale(dimensions * 2)
		.SetPosition(position);

	cube->SetRenderObject(new RenderObject(&cube->GetTransform(), cubeMesh, basicTex, basicShader));
	cube->SetPhysicsObject(new PhysicsObject(&cube->GetTransform(), cube->GetBoundingVolume()));
	cube->GetPhysicsObject()->SetElasticity((rand() % 100 + 1) / 100.f);
	cube->GetPhysicsObject()->SetBuoyancy(rand() % 351 + 50);
	cube->GetPhysicsObject()->SetCollisionResolution(CollisionResolution::Impulse | CollisionResolution::Spring | CollisionResolution::Jelly | CollisionResolution::Snow);

	cube->GetPhysicsObject()->SetInverseMass(inverseMass);
	cube->GetPhysicsObject()->InitCubeInertia();

	//cube->SetSleep(true); // 

	cube->GetRenderObject()->SetColour(colour);

	world->AddGameObject(cube);

	return cube;
}

GameObject* MultiGame::AddSphereToWorld(const Vector3& position, float radius, float inverseMass, const Vector4& colour) {
	GameObject* sphere = new GameObject();

	Vector3 sphereSize = Vector3(radius, radius, radius);
	SphereVolume* volume = new SphereVolume(radius);
	sphere->SetBoundingVolume((CollisionVolume*)volume);

	sphere->GetTransform()
		.SetScale(sphereSize)
		.SetPosition(position);

	sphere->SetRenderObject(new RenderObject(&sphere->GetTransform(), sphereMesh, basicTex, basicShader));
	sphere->SetPhysicsObject(new PhysicsObject(&sphere->GetTransform(), sphere->GetBoundingVolume()));

	sphere->GetPhysicsObject()->SetElasticity((rand() % 100 + 1) / 100.f);
	sphere->GetPhysicsObject()->SetBuoyancy(rand() % 351 + 50);
	//sphere->GetPhysicsObject()->SetElasticity(0.9f);
	//sphere->GetPhysicsObject()->SetBuoyancy(100.0f);
	//sphere->GetPhysicsObject()->SetGravityAffinity(false);
	sphere->GetPhysicsObject()->SetCollisionResolution(CollisionResolution::Impulse | CollisionResolution::Spring | CollisionResolution::Jelly | CollisionResolution::Snow);

	sphere->GetPhysicsObject()->SetInverseMass(inverseMass);
	sphere->GetPhysicsObject()->InitSphereInertia();

	//sphere->GetPhysicsObject()->SetGravityAffinity(true);
	//sphere->GetPhysicsObject()->AddForce(Vector3(100,30,35) * forceMagnitude );

	sphere->GetPhysicsObject()->AddForce(Vector3(0, 0, 1));

	sphere->GetRenderObject()->SetColour(colour);

	world->AddGameObject(sphere);

	return sphere;
}

GameObject* MultiGame::AddWallToWorld(const Vector3& position, const Vector3& scale, const Vector4& colour)
{
	GameObject* wall = new GameObject();

	AABBVolume* volume = new AABBVolume(scale);
	wall->SetBoundingVolume((CollisionVolume*)volume);

	wall->GetTransform()
		.SetScale(scale * 2)
		.SetPosition(position);

	wall->SetRenderObject(new RenderObject(&wall->GetTransform(), cubeMesh, basicTex, basicShader));
	wall->SetPhysicsObject(new PhysicsObject(&wall->GetTransform(), wall->GetBoundingVolume()));
	wall->GetPhysicsObject()->SetElasticity(0.0f);
	wall->GetPhysicsObject()->SetBuoyancy(0.0f);
	wall->GetPhysicsObject()->SetGravityAffinity(false);
	wall->GetPhysicsObject()->SetCollisionResolution(CollisionResolution::Impulse);

	wall->GetPhysicsObject()->SetInverseMass(0);
	wall->GetPhysicsObject()->InitCubeInertia();

	wall->GetRenderObject()->SetColour(colour);

	world->AddGameObject(wall);

	return wall;
}

void MultiGame::AddGateToWorld(const Vector3& position, const Vector3& rotation)
{
	GameObject* fencePillar1 = AddRampToWorld(position, Vector3(0.2, 2, 0.3), rotation, 0);
	GameObject* gate = AddRampToWorld(position + Quaternion::EulerAnglesToQuaternion(rotation.x, rotation.y, rotation.z) * Vector3(12, 0, 0), Vector3(11.5, 1.8, 0.2), rotation, 0.5);
	GameObject* fencePillar2 = AddRampToWorld(position + Quaternion::EulerAnglesToQuaternion(rotation.x, rotation.y, rotation.z) * Vector3(24, 0, 0), Vector3(0.2, 2, 0.3), rotation, 0);

	PositionConstraint* constraint = new PositionConstraint(fencePillar1, gate, 12);
	HingeConstraint* hinge = new HingeConstraint(fencePillar1, gate);
	FixedHeightConstraint* height = new FixedHeightConstraint(gate, gate->GetTransform().GetPosition().y);

	fencePillar1->SetSleep(true);
	gate->SetSleep(true);
	fencePillar2->SetSleep(true);

	world->AddConstraint(constraint);
	world->AddConstraint(hinge);
	world->AddConstraint(height);
}


void MultiGame::AddFinishGateToWorld(const Vector3& position, const Vector3& rotation)
{
	GameObject* fencePillar1 = AddRampToWorld(position, Vector3(0.4, 8, 0.6), rotation, 0);
	GameObject* gate = AddRampToWorld(position + Quaternion::EulerAnglesToQuaternion(rotation.x, rotation.y, rotation.z) * Vector3(12, 2, 0), Vector3(23, 1.8, 0.2), rotation, 0.0);
	GameObject* fencePillar2 = AddRampToWorld(position + Quaternion::EulerAnglesToQuaternion(rotation.x, rotation.y, rotation.z) * Vector3(24, 0, 0), Vector3(0.4, 8, 0.6), rotation, 0);

	PositionConstraint* constraint = new PositionConstraint(fencePillar1, gate, 12);
	HingeConstraint* hinge = new HingeConstraint(fencePillar1, gate);
	HingeConstraint* hinge2 = new HingeConstraint(fencePillar2, gate);
	FixedHeightConstraint* height = new FixedHeightConstraint(gate, gate->GetTransform().GetPosition().y);

	fencePillar1->SetSleep(true);
	gate->SetSleep(true);
	fencePillar2->SetSleep(true);

	world->AddConstraint(constraint);
	world->AddConstraint(hinge);
	world->AddConstraint(hinge2);
	world->AddConstraint(height);
}

GameObject* MultiGame::AddRampToWorld(const Vector3& position, const Vector3& scale, const Vector3& rotation, const float inverseMass)
{
	GameObject* ramp = new GameObject();

	OBBVolume* volume = new OBBVolume(scale);
	ramp->SetBoundingVolume((CollisionVolume*)volume);

	ramp->GetTransform()
		.SetScale(scale * 2)
		.SetPosition(position);

	ramp->GetTransform().SetOrientation(Quaternion::EulerAnglesToQuaternion(rotation.x, rotation.y, rotation.z));

	ramp->SetRenderObject(new RenderObject(&ramp->GetTransform(), cubeMesh, basicTex, basicShader));
	ramp->SetPhysicsObject(new PhysicsObject(&ramp->GetTransform(), ramp->GetBoundingVolume()));
	ramp->GetPhysicsObject()->SetElasticity(0.0f);
	ramp->GetPhysicsObject()->SetBuoyancy(0.0f);
	ramp->GetPhysicsObject()->SetGravityAffinity(false);
	ramp->GetPhysicsObject()->SetCollisionResolution(CollisionResolution::Impulse);

	ramp->GetPhysicsObject()->SetInverseMass(inverseMass);
	ramp->GetPhysicsObject()->InitCubeInertia();

	ramp->GetRenderObject()->SetColour(Vector4(1, 1, 1, 1));

	world->AddGameObject(ramp);

	return ramp;
}

void MultiGame::AddJellyToWorld(const Vector3& position)
{
	AddFloorToWorld(position, Vector3(25, 1.5, 25), Vector4(1, 0, 0, 1), CollisionResolution::Jelly);
	obstacles.push_back(AddWallToWorld(position + Vector3(27.5, 1, 0), Vector3(4.7, 2.5, 22.5))); //Right
	obstacles.push_back(AddWallToWorld(position - Vector3(27.5, -1, 0), Vector3(4.7, 2.5, 22.5))); //Left
	obstacles.push_back(AddWallToWorld(position + Vector3(0, 1, 27.5), Vector3(30, 2.5, 4.7))); //Bottom
	obstacles.push_back(AddWallToWorld(position - Vector3(0, -1, 27.5), Vector3(30, 2.5, 4.7))); //Up
}

GameObject* MultiGame::AddBonusToWorld(const Vector3& position, const Vector4& colour) {
	BonusObject* bonus = new BonusObject(25);

	SphereVolume* volume = new SphereVolume(0.25f);
	bonus->SetBoundingVolume((CollisionVolume*)volume);
	bonus->GetTransform()
		.SetScale(Vector3(0.25, 0.25, 0.25))
		.SetPosition(position);

	bonus->SetRenderObject(new RenderObject(&bonus->GetTransform(), bonusMesh, nullptr, basicShader));
	bonus->SetPhysicsObject(new PhysicsObject(&bonus->GetTransform(), bonus->GetBoundingVolume()));

	bonus->GetPhysicsObject()->SetInverseMass(1.0f);
	bonus->GetPhysicsObject()->InitSphereInertia();

	bonus->GetRenderObject()->SetColour(colour);

	world->AddGameObject(bonus);

	return bonus;
}


void MultiGame::DrawDisplay(float dt) {
	renderer->DrawString("Time taken: " + std::to_string(levelTimer), Vector2(5, 10));
	renderer->DrawString("Score: " + std::to_string(playerCharacter->GetScore()), Vector2(5, 15));
	renderer->DrawString("Points collected: " + std::to_string(playerCharacter->GetPointsCollected()), Vector2(5, 20));
	renderer->DrawString("Total items: " + std::to_string(bonus.size()), Vector2(5, 25));
	renderer->DrawString("Collected items: " + std::to_string(playerCharacter->GetItems()), Vector2(5, 30));
	renderer->DrawString("Remaining items: " + std::to_string(bonus.size() - playerCharacter->GetItems()), Vector2(5, 35));


	renderer->DrawString("Enemy score: " + std::to_string(enemies[0]->GetScore()), Vector2(5, 40));

}

bool MultiGame::SelectObject() {
	if (Window::GetKeyboard()->KeyPressed(KeyboardKeys::Q)) {
		inSelectionMode = !inSelectionMode;
		if (inSelectionMode) {
			Window::GetWindow()->ShowOSPointer(true);
			Window::GetWindow()->LockMouseToWindow(false);
		}
		else {
			Window::GetWindow()->ShowOSPointer(false);
			Window::GetWindow()->LockMouseToWindow(true);
		}
	}
	if (inSelectionMode) {
		renderer->DrawString("Press Q to change to camera mode!", Vector2(5, 95));

		if (Window::GetMouse()->ButtonDown(NCL::MouseButtons::LEFT)) {
			if (selectionObject) {	//set colour to deselected;
				selectionObject->GetRenderObject()->SetColour(Vector4(1, 1, 1, 1));
				selectionObject = nullptr;
				lockedObject = nullptr;

			}

			Ray ray = CollisionDetection::BuildRayFromMouse(*world->GetMainCamera());

			RayCollision closestCollision;
			if (world->Raycast(ray, closestCollision, true)) {
				selectionObject = (GameObject*)closestCollision.node;
				selectionObject->GetRenderObject()->SetColour(Vector4(0, 1, 0, 1));

				renderer->DrawString("Pos x: " + std::to_string(selectionObject->GetRenderObject()->GetTransform()->GetPosition().x), Vector2(55, 5));
				renderer->DrawString("Pos y: " + std::to_string(selectionObject->GetRenderObject()->GetTransform()->GetPosition().y), Vector2(55, 10));
				renderer->DrawString("Pos z: " + std::to_string(selectionObject->GetRenderObject()->GetTransform()->GetPosition().z), Vector2(55, 15));
				renderer->DrawString("Object name: " + selectionObject->GetName(), Vector2(55, 20));
				return true;
			}
			else {
				return false;
			}
		}

	}
	else {
		renderer->DrawString("Press Q to change to select mode!", Vector2(5, 95));
	}
	return false;
}