#include "RacecourseSingleGame.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; RacecourseSingleGame::RacecourseSingleGame() { world = new GameWorld(); renderer = new GameTechRenderer(*world); physics = new PhysicsSystem(*world); forceMagnitude = 100.0f; useGravity = true; inSelectionMode = false; Debug::SetRenderer(renderer); InitialiseAssets(); } void RacecourseSingleGame::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(); } RacecourseSingleGame::~RacecourseSingleGame() { delete cubeMesh; delete sphereMesh; delete charMeshA; delete charMeshB; delete enemyMesh; delete bonusMesh; delete basicTex; delete basicShader; delete physics; delete renderer; delete world; } void RacecourseSingleGame::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); playerCharacter->UpdatePlayerAbility(dt); //for (std::vector<GameObject*>::iterator i = movablePlatforms.begin(); i != movablePlatforms.end(); i++) { // if ((*i)->GetTransform().GetPosition().x >= 13) { // (*i)->GetTransform().SetPosition(Vector3( // (*i)->GetTransform().GetPosition().x - dt, // (*i)->GetTransform().GetPosition().y, // (*i)->GetTransform().GetPosition().z)); // } // if ((*i)->GetTransform().GetPosition().x <= -13) { // (*i)->GetTransform().SetPosition(Vector3( // (*i)->GetTransform().GetPosition().x + dt, // (*i)->GetTransform().GetPosition().y, // (*i)->GetTransform().GetPosition().z)); // } //} //for (GameObject*& object : movablePlatforms) { // if (object->GetTransform().GetPosition().x >= 15) { // object->GetTransform().SetPosition(Vector3( // object->GetTransform().GetPosition().x - dt, // object->GetTransform().GetPosition().y, // object->GetTransform().GetPosition().z)); // } // if (object->GetTransform().GetPosition().x <= -15) { // object->GetTransform().SetPosition(Vector3( // object->GetTransform().GetPosition().x + dt, // object->GetTransform().GetPosition().y, // object->GetTransform().GetPosition().z)); // } //} if (snowObject) { snowObject->Update(dt); } SelectObject(); //MoveSelectedObject(); } physics->Update(dt); world->UpdateWorld(dt); renderer->Update(dt); renderer->Render(); DrawDisplay(dt); } void RacecourseSingleGame::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 (lockedObject) { // LockedObjectMovement(); //} //else { // DebugObjectMovement(); //} } void RacecourseSingleGame::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 RacecourseSingleGame::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; // } } if (Window::GetKeyboard()->KeyPressed(NCL::KeyboardKeys::F)) { if (playerCharacter->GetPlayerAttackCD() <= 0) { playerCharacter->GetPlayerAttackCD() = 5.0f; PlayerAbillity(); } } } void RacecourseSingleGame::PlayerAbillity() { for (GameObject*& object : movables) { Vector3 direction = object->GetTransform().GetPosition() - playerCharacter->GetTransform().GetPosition(); if (direction.Length() < playerCharacter->GetPlayerkRange()) { direction.Normalise(); Ray* ray = new Ray(playerCharacter->GetTransform().GetPosition(), direction); RayCollision collision; if (world->Raycast(*ray, collision, true)) { object->GetPhysicsObject()->AddForceAtPosition(direction * playerCharacter->GetPlayerForce(), collision.collidedAt); } delete ray; } } } void RacecourseSingleGame::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 RacecourseSingleGame::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(30, 2, 37.5); Vector3 wallSize(2, 50, 500); Vector4 floorColour(1, 1, 1, 1); Vector4 terrainColour(0, 0, 1, 1); //Player Starting Position playerCharacter = AddPlayerToWorld(Vector3(0,1,30)); //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 = AddPlayerToWorld(Vector3(0, 9, -630)); playerCharacter->AddScore(1000); //Wall Right obstacles.push_back(AddWallToWorld(Vector3(floorSize.x + 1, floorSize.y + 12, (-wallSize.z/2 - 110)), Vector3(1,14,400), Vector4(0.5,0.5,0.5, 1))); // Wall Left obstacles.push_back(AddWallToWorld(Vector3(-floorSize.x - 1, floorSize.y + 12, (-wallSize.z / 2 - 110)), Vector3(1, 14, 400), Vector4(0.5, 0.5, 0.5, 1))); //Add starting location AddFloorToWorld(floorPosition, floorSize , floorColour, CollisionResolution::Impulse); //OBB with Sphere collision movables.push_back(AddSphereToWorld(Vector3(0, 2, 20), 1, 0.5f)); AddRampToWorld(Vector3(-15, 3, -37.5), Vector3(8,0.5,2), Vector3(15, 50, 0), 0); movables.push_back(AddSphereToWorld(Vector3(-12, 5, -38), 1, 0.5f)); AddRampToWorld(Vector3(0, 3, -37.5), Vector3(15, 0.5, 2), Vector3(0, 90, 5), 0); movables.push_back(AddSphereToWorld(Vector3(0, 6, -38), 1, 0.5f)); //Add starting Constraint obstacle AddGateToWorld(Vector3(-8, 2, 10), Vector3(0, 0, 0)); //Add Stairs AddFloorToWorld(Vector3(0,0,-47.5), Vector3(30,2,10), floorColour, CollisionResolution::Impulse); AddFloorToWorld(Vector3(0,2,-67), Vector3(30,2,10), floorColour, CollisionResolution::Impulse); AddFloorToWorld(Vector3(0,4,-87), Vector3(30,2,10), floorColour, CollisionResolution::Impulse); AddFloorToWorld(Vector3(0,6,-132), Vector3(30,2,35), floorColour, CollisionResolution::Impulse); //Add Sphere Obstacles on Stairs movables.push_back(AddSphereToWorld(Vector3(14, 15, -93), 1, 0.5f)); movables.push_back(AddSphereToWorld(Vector3(0, 15, -93), 1, 0.5f)); movables.push_back(AddSphereToWorld(Vector3(-14, 15, -93), 1, 0.5f)); //Add Jelly AddJellyToWorld(Vector3(0, 7, -155.5)); AddCubeToWorld(Vector3(0, 10, -155.5), Vector3(2, 2, 2), 0.5f); //Water (with OBB platforms) Vector3 waterPosition(0, 6, -220); Vector3 waterSize(30, 2, 35); AddFloorToWorld(waterPosition, waterSize, terrainColour, CollisionResolution::Spring); AddFloorToWorld(waterPosition, waterSize - Vector3(0, 2, 0), terrainColour, CollisionResolution::Impulse); AddRampToWorld(waterPosition + Vector3(0, 5, 20), waterSize / 4, Vector3(15, 50, 0), 0); AddRampToWorld(waterPosition + Vector3(0, 5, -20), waterSize / 4, Vector3(-15, -50, 0), 0); //Add Floor with Doors (movable and non movable cubes) //Middle door AddFloorToWorld(Vector3(0, 6, -290), Vector3(30, 2, 35), floorColour, CollisionResolution::Impulse); movableDoors.push_back(AddCubeToWorld(Vector3(0, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(0, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(0, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-4, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-4, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-4, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(4, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(4, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(4, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(-8, 14, -290), Vector3(2, 6, 2), 0.0f, Vector4(0, 1, 1, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(0, 21, -290), Vector3(10, 1, 2), 0.0f, Vector4(0, 1, 1, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(8, 14, -290), Vector3(2, 6, 2), 0.0f, Vector4(0, 1, 1, 1))); //Left door movableDoors.push_back(AddCubeToWorld(Vector3(-24, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-24, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-24, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-20, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-20, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-20, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-16, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-16, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(-16, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(-28, 14, -290), Vector3(2, 6, 2), 0.0f, Vector4(0, 0.2, 0.6, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(-20, 21, -290), Vector3(10, 1, 2), 0.0f, Vector4(0, 0.2, 0.6, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(-12, 14, -290), Vector3(2, 6, 2), 0.0f, Vector4(0, 0.2, 0.6, 1))); //Right door movableDoors.push_back(AddCubeToWorld(Vector3(24, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(24, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(24, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(20, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(20, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(20, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(16, 7, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(16, 11, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); movableDoors.push_back(AddCubeToWorld(Vector3(16, 15, -290), Vector3(2, 2, 2), 0.5f, Vector4(0.7, 0, 0.7, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(28, 14, -290), Vector3(2, 6, 2), 0.0f, Vector4(0, 0.2, 0.6, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(20, 21, -290), Vector3(10, 1, 2), 0.0f, Vector4(0, 0.2, 0.6, 1))); obstacleDoors.push_back(AddCubeToWorld(Vector3(12, 14, -290), Vector3(2, 6, 2), 0.0f, Vector4(0, 0.2, 0.6, 1))); //Add Floor with non-movable obstacles (Maze) AddFloorToWorld(Vector3(0, 6, -395), Vector3(30, 2, 70), floorColour, CollisionResolution::Impulse); obstacleMaze.push_back(AddCubeToWorld(Vector3(-17.5, 14, -360), Vector3(12.5, 6, 2), 0.0f)); obstacleMaze.push_back(AddCubeToWorld(Vector3(17.5, 14, -360), Vector3(12.5, 6, 2), 0.0f)); //Right Maze Wall obstacleMaze.push_back(AddCubeToWorld(Vector3(7, 14, -387), Vector3(2, 6, 25), 0.0f, Vector4(1, 1, 1, 0.5))); //Left Maze Wall obstacleMaze.push_back(AddCubeToWorld(Vector3(-7, 14, -387), Vector3(2, 6, 25), 0.0f, Vector4(1, 1, 1, 0.5))); //obstacleMaze.push_back(AddCubeToWorld(Vector3(-7, 14, -382), Vector3(2, 6, 20), 0.0f, Vector4(1, 1, 1, 0.5))); // obstacleMaze.push_back(AddCubeToWorld(Vector3(17.5, 14, -414), Vector3(12.5, 6, 2), 0.0f, Vector4(1, 1, 1, 0.5))); obstacleMaze.push_back(AddCubeToWorld(Vector3(-17.5, 14, -414), Vector3(12.5, 6, 2), 0.0f, Vector4(1, 1, 1, 0.5))); //Add Snow Floor snowObject = AddSnowFloorToWorld(Vector3(0, 6, -540), Vector3(30, 1.5, 80), Vector4(0, 1, 1, 1), CollisionResolution::Snow); movables.push_back(AddSphereToWorld(Vector3(-25, 8.5, -500), 1, 0.5f)); movables.push_back(AddCubeToWorld(Vector3(0, 8.5, -540), Vector3(2, 2, 2), 0.5f, Vector4(1, 1, 1, 1))); movables.push_back(AddSphereToWorld(Vector3(25, 8.5, -580), 1, 0.5f)); //Platoforms move between in x-axis -20 to 20 movablePlatforms.push_back(AddFloorToWorld(Vector3(15, 12, -470), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); movablePlatforms.push_back(AddFloorToWorld(Vector3(5, 14, -490), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); movablePlatforms.push_back(AddFloorToWorld(Vector3(-5, 16, -510), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); movablePlatforms.push_back(AddFloorToWorld(Vector3(-15, 18, -530), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); movablePlatforms.push_back(AddFloorToWorld(Vector3(-15, 18, -550), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); movablePlatforms.push_back(AddFloorToWorld(Vector3(5, 18, -550), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); movablePlatforms.push_back(AddFloorToWorld(Vector3(-5, 16, -570), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); movablePlatforms.push_back(AddFloorToWorld(Vector3(5, 14, -590), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); movablePlatforms.push_back(AddFloorToWorld(Vector3(15, 12, -610), Vector3(5, 0.5, 5), floorColour, CollisionResolution::Impulse)); //Add Finish Floor (Finish is at z-axis -690) AddFloorToWorld(Vector3(0, 6, -690), Vector3(30, 2, 70), floorColour, CollisionResolution::Impulse); //Non passable object with Contraints (Position, Hinge and Height) AddFinishGateToWorld(Vector3(-10, 17, -688), Vector3(0, 0, 0)); //Bonuses bonus.push_back(AddBonusToWorld(Vector3(0, 10, -105))); bonus.push_back(AddBonusToWorld(Vector3(0, 12, -165))); bonus.push_back(AddBonusToWorld(Vector3(0, 10, -265))); bonus.push_back(AddBonusToWorld(Vector3(0, 10, -440))); bonus.push_back(AddBonusToWorld(Vector3(0, 10, -630))); bonus.push_back(AddBonusToWorld(Vector3(5, 20, -550), Vector4(1.0f, 1.0f, 0.0f, 1.0f))); } void RacecourseSingleGame::EndGame(float dt) { if (playerCharacter->GetScore() <= 0) { 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; } } if (playerCharacter->GetTransform().GetPosition().z <= -690) { 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; } } } GameObject* RacecourseSingleGame::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* RacecourseSingleGame::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* RacecourseSingleGame::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* RacecourseSingleGame::AddSphereToWorld(const Vector3& position, float radius, float inverseMass, const Vector4& colour) { string sphereName = std::to_string(sphereNr); GameObject* sphere = new GameObject(); //++cubeNumber; 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* RacecourseSingleGame::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 RacecourseSingleGame::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 RacecourseSingleGame::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* RacecourseSingleGame::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 RacecourseSingleGame::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 } void RacecourseSingleGame::AddSnowToWorld(const Vector3& position) { AddFloorToWorld(position, Vector3(30, 1.5, 80), Vector4(0, 1, 1, 1), CollisionResolution::Snow); } SnowObject* RacecourseSingleGame::AddSnowFloorToWorld(const Vector3& position, const Vector3& scale, const Vector4& colour, const int collisionResolution) { SnowObject* snowFloor = new SnowObject(); AABBVolume* volume = new AABBVolume(scale); snowFloor->SetBoundingVolume((CollisionVolume*)volume); snowFloor->GetTransform() .SetScale(scale * 2) .SetPosition(position); snowFloor->SetRenderObject(new RenderObject(&snowFloor->GetTransform(), cubeMesh, basicTex, basicShader)); snowFloor->SetPhysicsObject(new PhysicsObject(&snowFloor->GetTransform(), snowFloor->GetBoundingVolume())); snowFloor->GetPhysicsObject()->SetElasticity(0.0f); snowFloor->GetPhysicsObject()->SetBuoyancy(0.0f); snowFloor->GetPhysicsObject()->SetGravityAffinity(false); snowFloor->GetPhysicsObject()->SetCollisionResolution(collisionResolution); snowFloor->GetPhysicsObject()->SetInverseMass(0); snowFloor->GetPhysicsObject()->InitCubeInertia(); snowFloor->GetRenderObject()->SetColour(colour); snowFloor->SetPlayer(playerCharacter); snowFloor->SetOriginalPlayerColour(playerCharacter->GetRenderObject()->GetColour()); world->AddGameObject(snowFloor); return snowFloor; } GameObject* RacecourseSingleGame::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; } bool RacecourseSingleGame::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; } void RacecourseSingleGame::MoveSelectedObject() { renderer->DrawString("Click Force:" + std::to_string(forceMagnitude), Vector2(5, 90)); forceMagnitude += Window::GetMouse()->GetWheelMovement() * 10.0f; if (!selectionObject) { return; //we haven't selected anything! } //Push the selected object! if (Window::GetMouse()->ButtonPressed(NCL::MouseButtons::RIGHT)) { if (selectionObject != playerCharacter) { Ray ray = CollisionDetection::BuildRayFromMouse( *world->GetMainCamera()); RayCollision closestCollision; if (world->Raycast(ray, closestCollision, true)) { if (closestCollision.node == selectionObject) { selectionObject->GetPhysicsObject()-> //AddForce(ray.GetDirection() * forceMagnitude); AddForceAtPosition(ray.GetDirection() * forceMagnitude, closestCollision.collidedAt); } } } } } void RacecourseSingleGame::DrawDisplay(float dt) { renderer->DrawString("Time taken: " + std::to_string(levelTimer), Vector2(5, 10), Vector4(0, 0, 0, 1)); renderer->DrawString("Score: " + std::to_string(playerCharacter->GetScore()), Vector2(5, 15), Vector4(0, 0, 0, 1)); renderer->DrawString("Points collected: " + std::to_string(playerCharacter->GetPointsCollected()), Vector2(5, 20), Vector4(0, 0, 0, 1)); renderer->DrawString("Total items: " + std::to_string(bonus.size()), Vector2(5, 25), Vector4(0, 0, 0, 1)); renderer->DrawString("Collected items: " + std::to_string(playerCharacter->GetItems()), Vector2(5, 30), Vector4(0, 0, 0, 1)); renderer->DrawString("Remaining items: " + std::to_string(bonus.size() - playerCharacter->GetItems()), Vector2(5, 35), Vector4(0,0,0,1)); if (playerCharacter->GetPlayerAttackCD() > 0.0f && (levelCompleted == false)) { renderer->DrawString("Attack Cooldown: " + std::to_string(playerCharacter->GetPlayerAttackCD()), Vector2(5, 90)); } }