diff --git a/assets b/assets index 8ffd0a99..dfa0fc61 160000 --- a/assets +++ b/assets @@ -1 +1 @@ -Subproject commit 8ffd0a99b9a2e5c140307d382a25c4a470cc8f33 +Subproject commit dfa0fc61ab88456f3461779bd7c6ac97d15f6493 diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index c3759393..5b4150d8 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -20,6 +20,9 @@ class World; struct ComponentWrapper; +template +class Octree; + namespace Collision { //Return true if the ray hits the box. @@ -44,21 +47,24 @@ bool RayVsTriangle(const Ray& ray, float& outVCoord, bool trueOnNegativeDistance = false); //Return true if the ray hits any of the triangles in the model. Stops checking when a hit is detected. -bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, - const std::vector& modelIndices); +bool RayVsModel(const Ray& ray, + const RawModel::Vertex* modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix); //Return true if the ray hits any of the triangles in the model. //Also returns the position of the intersection point. Will loop through all the whole model indices. bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, + const glm::mat4& modelMatrix, glm::vec3& outHitPosition); //Return true if the ray hits any of the triangles in the model. //Also returns the distance from the ray origin to the closest //intersection point, and the barycentric u,v-coordinates. Will loop through all the whole model indices. bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, + const glm::mat4& modelMatrix, float& outDistance, float& outUCoord, float& outVCoord); @@ -81,6 +87,13 @@ bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); // Calculates an absolute AABB from an entity AABB component boost::optional EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox = false); boost::optional AbsoluteAABBExplosionEffect(EntityWrapper& entity); +//Returns the first entity hit by the input ray. entitiesPotentiallyHitSorted needs to be sorted +//by their distance to the ray, e.g. result from Octree::ObjectsPossiblyHitByRay. +//Returns boost::none if none was hit. outDistance will be the distance to the intersection point if the ray intersects. +boost::optional EntityFirstHitByRay(const Ray& ray, std::vector entitiesPotentiallyHitSorted, float outDistance, glm::vec3& outIntersectPos); +//Returns the first entity hit by the input ray that exists in the octree. +//outDistance will be the distance to the intersection point if the ray intersects. +boost::optional EntityFirstHitByRay(const Ray& ray, Octree* octree, float outDistance, glm::vec3& outIntersectPos); } diff --git a/include/Engine/Core/EPlayerDamage.h b/include/Engine/Core/EPlayerDamage.h index 8ba3907e..c11b121f 100644 --- a/include/Engine/Core/EPlayerDamage.h +++ b/include/Engine/Core/EPlayerDamage.h @@ -11,6 +11,7 @@ struct PlayerDamage : Event { //NOTE: this struct is missing information on what the damageSource is EntityWrapper Player; + EntityWrapper PlayerShooter; double Damage; }; diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index b011a518..3f03a77c 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -41,6 +41,8 @@ public: void ObjectsInSameRegion(const Box& box, std::vector& outObjects); //Get the objects that are inside the frustum, the objects are put in outObjects. void ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects); + //Get objects, which AABB the input ray intersects, the objects are put in outObjects. + void ObjectsPossiblyHitByRay(const Ray& ray, std::vector& outObjects); //Empty the tree of all objects, static and dynamic. void ClearObjects(); //Empty the tree of all dynamic objects. Static objects remain in the tree. @@ -100,6 +102,8 @@ struct Child void ObjectsInSameRegion(const Box& box, std::vector& outObjects) const; template void ObjectsInFrustum(const Frustum& frustum, std::vector& outObjects, bool takeAllDontTest) const; + template + void ObjectsPossiblyHitByRay(const Ray& ray, std::vector& outObjects) const; void ClearObjects(); void ClearDynamicObjects(); bool RayCollides(const Ray& ray, Output& data) const; @@ -119,6 +123,15 @@ struct Child std::vector childIndicesContainingBox(const AABB& box) const; }; +//To be able to sort child nodes and contained objects based on distance to ray origin. +struct RaySorterInfo +{ + int Index; + float Distance; +}; + +bool isFirstLower(const RaySorterInfo& first, const RaySorterInfo& second); + } template @@ -164,6 +177,13 @@ void Octree::ObjectsInFrustum(const Frustum& frustum, std::vector& outObje m_Root->ObjectsInFrustum(frustum, outObjects, false); } +template +void Octree::ObjectsPossiblyHitByRay(const Ray& ray, std::vector& outObjects) +{ + falsifyObjectChecks(); + m_Root->ObjectsPossiblyHitByRay(ray, outObjects); +} + template void Octree::ClearObjects() { @@ -282,4 +302,59 @@ void OctSpace::Child::ObjectsInFrustum(const Frustum& frustum, std::vector& o } } +template +void OctSpace::Child::ObjectsPossiblyHitByRay(const Ray& ray, std::vector& outObjects) const +{ + //If the node AABB is missed, everything it contains is missed. + if (Collision::RayAABBIntr(ray, m_Box)) { + //If the ray shoots the tree, and it is a parent. + if (hasChildren()) { + //Sort children according to their distance from the ray origin. + std::vector childInfos; + childInfos.resize(8); + for (int i = 0; i < 8; ++i) { + childInfos[i] = { i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) }; + } + std::sort(childInfos.begin(), childInfos.end(), isFirstLower); + //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. + for (const RaySorterInfo& info : childInfos) { + m_Children[info.Index]->ObjectsPossiblyHitByRay(ray, outObjects); + } + } else { + //Check against boxes in the node. + bool intersected = false; + float dist; + //Sort all contained objects according to the distance from the ray origin to + //the intersection, if they are intersecting. + std::vector objectHitInfos; + objectHitInfos.reserve(m_StaticObjIndices.size() + m_DynamicObjIndices.size()); + for (int i : m_StaticObjIndices) { + //If we haven't tested against this object before, and the ray hits. + if (!m_StaticObjectsRef[i].Checked && + Collision::RayVsAABB(ray, *m_StaticObjectsRef[i].Box, dist)) { + objectHitInfos.push_back({ i, dist }); + } + m_StaticObjectsRef[i].Checked = true; + } + for (int i : m_DynamicObjIndices) { + //If we haven't tested against this object before, and the ray hits. + if (!m_DynamicObjectsRef[i].Checked && + Collision::RayVsAABB(ray, *m_DynamicObjectsRef[i].Box, dist)) { + objectHitInfos.push_back({ i + (int)m_StaticObjIndices.size(), dist }); + } + m_DynamicObjectsRef[i].Checked = true; + } + std::sort(objectHitInfos.begin(), objectHitInfos.end(), isFirstLower); + int startSize = (int)outObjects.size(); + outObjects.resize(startSize + objectHitInfos.size()); + for (int i = 0; i < objectHitInfos.size(); ++i) { + outObjects[startSize + i] = (objectHitInfos[i].Index < m_StaticObjIndices.size()) ? + *static_cast(m_StaticObjectsRef[objectHitInfos[i].Index].Box.get()) : + *static_cast(m_DynamicObjectsRef[objectHitInfos[i].Index - m_StaticObjIndices.size()].Box.get()); + } + } + } +} + + #endif \ No newline at end of file diff --git a/include/Engine/Input/FirstPersonInputController.h b/include/Engine/Input/FirstPersonInputController.h index f3b0a17a..5529185a 100644 --- a/include/Engine/Input/FirstPersonInputController.h +++ b/include/Engine/Input/FirstPersonInputController.h @@ -55,6 +55,7 @@ protected: //specialabilitys bool m_MovementKeyDown = false; bool m_SpecialAbilityKeyDown = false; + int m_NumberOfMovementKeysDown = 0; EventRelay m_ELockMouse; bool OnLockMouse(const Events::LockMouse& e); @@ -132,6 +133,7 @@ bool FirstPersonInputController::OnCommand(const Events::InputComm } //if value = 0 then you have just released this key if (e.Value != 0) { + m_NumberOfMovementKeysDown++; m_MovementKeyDown = true; //if you pressed the same key within m_AssaultDashDoubleTapSensitivityTimer then you have doubletapped it if (m_AssaultDashDoubleTapDeltaTime < m_AssaultDashDoubleTapSensitivityTimer && m_AssaultDashTapDirection == m_CurrentDirectionVector) { @@ -139,10 +141,14 @@ bool FirstPersonInputController::OnCommand(const Events::InputComm } } else { //== 0 - m_MovementKeyDown = false; - //you have just released the key, store what key it was and reset the doubletap-sensitivity-timer - m_AssaultDashTapDirection = m_CurrentDirectionVector; - m_AssaultDashDoubleTapDeltaTime = 0.f; + m_NumberOfMovementKeysDown--; + if (m_NumberOfMovementKeysDown == 0) { + m_MovementKeyDown = false; + } + //you have just released the key, store what key it was and reset the doubletap-sensitivity-timer + m_AssaultDashTapDirection = m_CurrentDirectionVector; + m_AssaultDashDoubleTapDeltaTime = 0.f; + } } @@ -202,12 +208,6 @@ void FirstPersonInputController::AssaultDashCheck(double dt, bool m_AssaultDashCoolDownTimer = assaultDashCoolDownMaxTimer; m_AssaultDashDoubleTapped = true; m_AssaultDashDoubleTapDeltaTime = 0.f; - //moving to the side has priority - return; - } - - //dashing with doubletap - check if doubletap to dash enabled - if (ResourceManager::Load("Input.ini")->Get("Keyboard.DoubleTapToDash", false)) { return; } @@ -216,6 +216,11 @@ void FirstPersonInputController::AssaultDashCheck(double dt, bool m_AssaultDashDoubleTapped = false; } + //dashing with doubletap - check if doubletap to dash enabled + if (!ResourceManager::Load("Input.ini")->Get("Keyboard.DoubleTapToDash", false)) { + return; + } + //check if we have received a valid doubletap if (!m_ValidDoubleTap) { return; diff --git a/include/Game/Systems/CapturePointSystem.h b/include/Game/Systems/CapturePointSystem.h index 22e7e3d5..34a23e14 100644 --- a/include/Game/Systems/CapturePointSystem.h +++ b/include/Game/Systems/CapturePointSystem.h @@ -44,7 +44,6 @@ private: //std::vector - const double m_CaptureTimeToTakeOver = 15.0; bool m_ResetTimers = false; //vectors which will keep track of enter/leave changes diff --git a/include/Game/Systems/DamageIndicatorSystem.h b/include/Game/Systems/DamageIndicatorSystem.h new file mode 100644 index 00000000..e70a69a9 --- /dev/null +++ b/include/Game/Systems/DamageIndicatorSystem.h @@ -0,0 +1,33 @@ +#ifndef DamageIndicatorSystem_h__ +#define DamageIndicatorSystem_h__ + +#include "Core/System.h" +#include "Core/Transform.h" +#include "Core/ResourceManager.h" +#include "Core/EntityFileParser.h" +#include "Core/EPlayerDamage.h" +#include "Common.h" +#include + +#include "Rendering/ESetCamera.h" +#include +#include + +#include "Rendering/Util/CommonFunctions.h" + +class DamageIndicatorSystem : public System +{ +public: + DamageIndicatorSystem(SystemParams params); + +private: + EventRelay m_DamageTakenFromPlayer; + bool OnPlayerDamageTaken(Events::PlayerDamage& e); + + EventRelay m_ESetCamera; + bool OnSetCamera(const Events::SetCamera& e); + + EntityID m_CurrentCamera = -1; + +}; +#endif diff --git a/include/Game/Systems/PlayerMovementSystem.h b/include/Game/Systems/PlayerMovementSystem.h index 63dea966..2bcae866 100644 --- a/include/Game/Systems/PlayerMovementSystem.h +++ b/include/Game/Systems/PlayerMovementSystem.h @@ -7,6 +7,9 @@ #include "Events/EDoubleJump.h" #include "../Engine/Sound/EPlaySoundOnEntity.h" +#include "Core/EntityFile.h" +#include "Core/EntityFileParser.h" + class PlayerMovementSystem : public ImpureSystem { public: diff --git a/resources/DefaultInput.ini b/resources/DefaultInput.ini index 16948f29..683d48e2 100644 --- a/resources/DefaultInput.ini +++ b/resources/DefaultInput.ini @@ -2,6 +2,9 @@ Sensitivity=0.5 InvertPitch=false +[Keyboard] +DoubleTapToDash=false + [Bindings] MouseLeft=PrimaryFire MouseX=Yaw diff --git a/resources/Schema/Components/CapturePoint.xml b/resources/Schema/Components/CapturePoint.xml index ba164fd9..638b16c3 100644 --- a/resources/Schema/Components/CapturePoint.xml +++ b/resources/Schema/Components/CapturePoint.xml @@ -2,5 +2,6 @@ 0 0 + 15 \ No newline at end of file diff --git a/resources/Schema/Components/CapturePoint.xsd b/resources/Schema/Components/CapturePoint.xsd index fbdb3568..3c91dfdd 100644 --- a/resources/Schema/Components/CapturePoint.xsd +++ b/resources/Schema/Components/CapturePoint.xsd @@ -20,7 +20,11 @@ CapturePointNumber specify an int number for this - + + + The time needed to take over a Capture Point + + Specify if this is a HomePoint for either team diff --git a/resources/Schema/Entities/CaptureTestState5.xml b/resources/Schema/Entities/CaptureTestState5.xml index 8fe85068..c733706c 100644 --- a/resources/Schema/Entities/CaptureTestState5.xml +++ b/resources/Schema/Entities/CaptureTestState5.xml @@ -2,12 +2,246 @@ - - - + + + + + + + + + Models/LevelBase/MapVersion1.mesh + + + + + + + + + 2 + + + Models/Widgets/Lights/DirectionalLightWidget.mesh + false + + + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -15,10 +249,12 @@ + 15 Models/Core/UnitSphere.mesh - + + true @@ -26,7 +262,7 @@ - + @@ -40,11 +276,12 @@ Models/Core/UnitSphere.mesh - + + true - + @@ -58,15 +295,12 @@ Models/Core/UnitSphere.mesh - + + true - - - - - + - + @@ -76,11 +310,13 @@ + -15 3 Models/Core/UnitSphere.mesh - + + true @@ -88,7 +324,7 @@ - + @@ -101,11 +337,13 @@ + -15 4 Models/Core/UnitSphere.mesh - + + true @@ -113,61 +351,12 @@ - + - - - - - - Models/Core/UnitCube.mesh - - - - - - - - - - - - - - - - - - - Models/Core/UnitCube.mesh - - - - - - - - - - - - - - - - - Models/Test/DummyScene.mesh - - - - - - - diff --git a/resources/Schema/Entities/DamageIndicator.xml b/resources/Schema/Entities/DamageIndicator.xml new file mode 100644 index 00000000..3e9e4fef --- /dev/null +++ b/resources/Schema/Entities/DamageIndicator.xml @@ -0,0 +1,22 @@ + + + + + + Textures/DamageIndicator.png + + false + + + + + + + + 1.5 + + + + + + diff --git a/resources/Schema/Entities/DamageIndicatorTest.xml b/resources/Schema/Entities/DamageIndicatorTest.xml new file mode 100644 index 00000000..1155ddd5 --- /dev/null +++ b/resources/Schema/Entities/DamageIndicatorTest.xml @@ -0,0 +1,426 @@ + + + + + + + + + + + + + + + Models\MapVersion1.mesh + + + + + + + + + 2 + + + Models/DirectionalLightWidget.mesh + false + + + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + 8 + 2.7999999523162842 + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Models/Core/UnitCube.mesh + false + + + Schema/Entities/Player.xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 99 + + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + + Fonts/DroidSans.ttf,100 + + + + + + + + + + + + + + Models/Camera.mesh + false + + + + + + + + + + + + + + + + + + + 0.99000000953674316 + + + + + Models/Core/UnitHexagon.mesh + + + + + + + + + + + + + + Models/CrosshairQuad.mesh + + + + + + + + + + + + + Models/AssaultWeaponRed.mesh + + + + + + + + + + + + + + + + + + + + + + + + + Models/Camera.mesh + false + + + + + + + + + + + + + + Models/Characters/Assault/AssaultAnimations.mesh + + + + + + + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + + + + + Models/Core/UnitCube.mesh + + false + + + + + + + + + + + + diff --git a/resources/Schema/Entities/DoubleJumpHexagon.xml b/resources/Schema/Entities/DoubleJumpHexagon.xml new file mode 100644 index 00000000..c1aaec34 --- /dev/null +++ b/resources/Schema/Entities/DoubleJumpHexagon.xml @@ -0,0 +1,30 @@ + + + + + + Models/Effects/JumpEffectHexagon.mesh + + true + + + + + + + 0.5 + + + true + + + true + 0.5 + + true + + + + + + diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index b7b21969..7b182de1 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -6,6 +6,7 @@ #include "Core/World.h" #include "Rendering/Model.h" #include "imgui/imgui.h" +#include "Core/Octree.h" namespace Collision { @@ -145,13 +146,14 @@ bool RayVsTriangle(const Ray& ray, } bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, - const std::vector& modelIndices) + const RawModel::Vertex* modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix) { - for (int i = 0; i < modelIndices.size(); ++i) { - glm::vec3 v0 = modelVertices[modelIndices[i]].Position; - glm::vec3 v1 = modelVertices[modelIndices[++i]].Position; - glm::vec3 v2 = modelVertices[modelIndices[++i]].Position; + for (int i = 0; i < modelIndices.size();) { + glm::vec3 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); + glm::vec3 v1 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); + glm::vec3 v2 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); if (RayVsTriangle(ray, v0, v1, v2)) { return true; } @@ -192,19 +194,20 @@ bool RayVsTriangle(const Ray& ray, } bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, + const glm::mat4& modelMatrix, float& outDistance, float& outUCoord, float& outVCoord) { outDistance = INFINITY; bool hit = false; - for (int i = 0; i < modelIndices.size(); ++i) { - glm::vec3 v0 = modelVertices[modelIndices[i]].Position; - glm::vec3 v1 = modelVertices[modelIndices[++i]].Position; - glm::vec3 v2 = modelVertices[modelIndices[++i]].Position; - float dist; + for (int i = 0; i < modelIndices.size();) { + glm::vec3 v0 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); + glm::vec3 v1 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); + glm::vec3 v2 = Transform::TransformPoint(modelVertices[modelIndices[i++]].Position, modelMatrix); + float dist = INFINITY; float u; float v; if (RayVsTriangle(ray, v0, v1, v2, dist, u, v)) { @@ -218,14 +221,15 @@ bool RayVsModel(const Ray& ray, } bool RayVsModel(const Ray& ray, - const std::vector& modelVertices, + const RawModel::Vertex* modelVertices, const std::vector& modelIndices, + const glm::mat4& modelMatrix, glm::vec3& outHitPosition) { float u; float v; float dist; - bool hit = RayVsModel(ray, modelVertices, modelIndices, dist, u, v); + bool hit = RayVsModel(ray, modelVertices, modelIndices, modelMatrix, dist, u, v); outHitPosition = ray.Origin() + dist * ray.Direction(); return hit; } @@ -572,11 +576,11 @@ boost::optional EntityAbsoluteAABB(EntityWrapper& entity, bool takeM ComponentWrapper& cAABB = entity["AABB"]; modelSpaceBox = EntityAABB::FromOriginSize((glm::vec3)cAABB["Origin"], (glm::vec3)cAABB["Size"]); } else if (entity.HasComponent("Model")) { - Model* model; std::string res = entity["Model"]["Resource"]; if (res.empty()) { return boost::none; } + Model* model; try { model = ResourceManager::Load<::Model, true>(res); } catch (const Resource::StillLoadingException&) { @@ -638,4 +642,36 @@ boost::optional AbsoluteAABBExplosionEffect(EntityWrapper& entity) return aabb; } +boost::optional EntityFirstHitByRay(const Ray& ray, std::vector entitiesPotentiallyHitSorted, float outDistance, glm::vec3& outIntersectPos) +{ + for (EntityAABB& entityBox : entitiesPotentiallyHitSorted) { + if (!entityBox.Entity.HasComponent("Model")) { + continue; + } + std::string res = entityBox.Entity["Model"]["Resource"]; + if (res.empty()) { + continue; + } + Model* model; + try { + model = ResourceManager::Load<::Model, true>(res); + } catch (const std::exception&) { + continue; + } + float u, v; + if (RayVsModel(ray, model->Vertices(), model->m_RawModel->m_Indices, Transform::ModelMatrix(entityBox.Entity), outDistance, u, v)) { + outIntersectPos = ray.Origin() + outDistance * ray.Direction(); + return entityBox; + } + } + return boost::none; +} + +boost::optional EntityFirstHitByRay(const Ray& ray, Octree* octree, float outDistance, glm::vec3& outIntersectPos) +{ + std::vector outObjects; + octree->ObjectsPossiblyHitByRay(ray, outObjects); + return Collision::EntityFirstHitByRay(ray, outObjects, outDistance, outIntersectPos); +} + } \ No newline at end of file diff --git a/src/Engine/Core/Octree.cpp b/src/Engine/Core/Octree.cpp index 7eee1f81..dca06c6f 100644 --- a/src/Engine/Core/Octree.cpp +++ b/src/Engine/Core/Octree.cpp @@ -5,22 +5,6 @@ #include "Core/Octree.h" #include "Collision/Collision.h" -namespace -{ -//To be able to sort nodes based on distance to ray origin. -struct ChildInfo -{ - int Index; - float Distance; -}; - -bool isFirstLower(const ChildInfo& first, const ChildInfo& second) -{ - return first.Distance < second.Distance; -} - -} - namespace OctSpace { @@ -123,14 +107,14 @@ bool Child::RayCollides(const Ray& ray, OctSpace::Output& data) const //If the ray shoots the tree, and it is a parent to 8 children :o if (hasChildren()) { //Sort children according to their distance from the ray origin. - std::vector childInfos; + std::vector childInfos; childInfos.reserve(8); for (int i = 0; i < 8; ++i) { childInfos.push_back({ i, glm::distance(ray.Origin(), m_Children[i]->m_Box.Origin()) }); } std::sort(childInfos.begin(), childInfos.end(), isFirstLower); //Loop through the children, starting with the one closest to the ray origin. I.e the first to be hit. - for (const ChildInfo& info : childInfos) { + for (const RaySorterInfo& info : childInfos) { if (m_Children[info.Index]->RayCollides(ray, data)) { return true; } @@ -275,4 +259,9 @@ std::vector Child::childIndicesContainingBox(const AABB& box) const } } +bool isFirstLower(const RaySorterInfo& first, const RaySorterInfo& second) +{ + return first.Distance < second.Distance; +} + } \ No newline at end of file diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 689f1df0..8ee6dbed 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -14,6 +14,7 @@ #include "Game/Systems/CapturePointSystem.h" #include "Game/Systems/CapturePointHUDSystem.h" #include "Game/Systems/PickupSpawnSystem.h" +#include "Game/Systems/DamageIndicatorSystem.h" #include "Game/Systems/WeaponSystem.h" #include "Rendering/AnimationSystem.h" #include "Game/Systems/PlayerHUDSystem.h" @@ -123,6 +124,7 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); + m_SystemPipeline->AddSystem(updateOrderLevel); // Populate Octree with collidables ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision, "Collidable"); diff --git a/src/Game/Systems/CapturePointHUDSystem.cpp b/src/Game/Systems/CapturePointHUDSystem.cpp index 5369b830..d6c7389c 100644 --- a/src/Game/Systems/CapturePointHUDSystem.cpp +++ b/src/Game/Systems/CapturePointHUDSystem.cpp @@ -16,6 +16,9 @@ void CapturePointHUDSystem::Update(double dt) auto CapturePointHUDElements = m_World->GetComponents("CapturePointHUD"); auto CapturePoints = m_World->GetComponents("CapturePoint"); + if (CapturePointHUDElements == nullptr) { + return; + } if(!CapturePointHUDElements) { return; diff --git a/src/Game/Systems/CapturePointSystem.cpp b/src/Game/Systems/CapturePointSystem.cpp index 9a108ff9..f938ecd0 100644 --- a/src/Game/Systems/CapturePointSystem.cpp +++ b/src/Game/Systems/CapturePointSystem.cpp @@ -32,6 +32,7 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp const int redTeam = (int)teamComponent["Team"].Enum("Red"); const int blueTeam = (int)teamComponent["Team"].Enum("Blue"); const int spectatorTeam = (int)teamComponent["Team"].Enum("Spectator"); + const double captureTimeToTakeOver = (double)cCapturePoint["CapturePointMaxTimer"]; int homePointForTeam = (int)cCapturePoint["HomePointForTeam"]; if (m_NumberOfCapturePoints == 0 && capturePointNumber != 0 && (homePointForTeam == redTeam || homePointForTeam == blueTeam)) { @@ -57,7 +58,7 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp int blueTeamPlayersStandingInside = 0; if (capturePointEntity.HasComponent("Model")) { //Now sets team color to the capturepoint, or white if it is uncaptured. - capturePointEntity["Model"]["Color"] = ownedBy == blueTeam ? glm::vec4(0, 0.2f, 1, 0.3) : ownedBy == redTeam ? glm::vec4(1, 0.2f, 0, 0.3) : glm::vec4(1, 1, 1, 0.3); + capturePointEntity["Model"]["Color"] = ownedBy == blueTeam ? glm::vec4(0, 0.0f, 1, 0.3) : ownedBy == redTeam ? glm::vec4(1, 0.0f, 0, 0.3) : glm::vec4(1, 1, 1, 0.3); } //calculate next possible capturePoint for both teams @@ -98,20 +99,16 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp ComponentWrapper& capturePoint = m_CapturePointNumberToEntityMap[i]["CapturePoint"]; if ((int)capturePoint["CapturePointNumber"] != nextPossibleCapturePoint["Red"] && (int)capturePoint["CapturePointNumber"] != nextPossibleCapturePoint["Blue"]) { - capturePoint["CaptureTimer"] = 0.0; + //RED = +, BLUE = -, NONE + auto teamOwners = (int)m_CapturePointNumberToEntityMap[i]["Team"]["Team"]; + if (teamOwners == redTeam || teamOwners == blueTeam) { + capturePoint["CaptureTimer"] = teamOwners == blueTeam ? -captureTimeToTakeOver : captureTimeToTakeOver; + } } } m_ResetTimers = false; } - //colorize next possible capturepoint - if (nextPossibleCapturePoint["Red"] == capturePointNumber) { - capturePointEntity["Model"]["Color"] = glm::vec4(1, 1, 0, 0.3); - } - if (nextPossibleCapturePoint["Blue"] == capturePointNumber) { - capturePointEntity["Model"]["Color"] = glm::vec4(0, 1, 1, 0.3); - } - //check how many players are standing inside and are healthy for (size_t i = m_ETriggerTouchVector.size(); i > 0; i--) { @@ -170,9 +167,6 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp //B. at most one of the teams have players inside //if capturePoint is not owned by the take-over team, just modify the CaptureTimer accordingly if (ownedBy != currentTeam && canCapture) { - if (abs((double)cCapturePoint["CaptureTimer"]) < 0.001f) { - LOG_DEBUG("Point is being captured by team %i", currentTeam); //Remove when we tested sufficiently. - } cCapturePoint["CaptureTimer"] = (double)cCapturePoint["CaptureTimer"] + timerDeltaChange; } //if capturePoint is owned by the team, and the other team has been trying to take it, then increase/decrease the timer towards 0.0 @@ -180,12 +174,11 @@ void CapturePointSystem::UpdateComponent(EntityWrapper& capturePointEntity, Comp (ownedBy == currentTeam && currentTeam == blueTeam && (double)cCapturePoint["CaptureTimer"] > 0.0)) { cCapturePoint["CaptureTimer"] = (double)cCapturePoint["CaptureTimer"] + timerDeltaChange; } - //check if captureTimer > m_CaptureTimeToTakeOver and if so change owner and publish the eCaptured event - if (abs((double)cCapturePoint["CaptureTimer"]) > abs(m_CaptureTimeToTakeOver) && canCapture) { + //check if captureTimer > captureTimeToTakeOver and if so change owner and publish the eCaptured event + if (abs((double)cCapturePoint["CaptureTimer"]) > captureTimeToTakeOver && canCapture) { teamComponent["Team"] = currentTeam; - cCapturePoint["CaptureTimer"] = 0.0; + cCapturePoint["CaptureTimer"] = glm::sign((double)cCapturePoint["CaptureTimer"])*captureTimeToTakeOver; //publish Captured event - LOG_DEBUG("Point is captured by team %i!", currentTeam); //Remove when we tested sufficiently. Events::Captured e; e.CapturePointID = cCapturePoint.EntityID; e.TeamNumberThatCapturedCapturePoint = currentTeam; diff --git a/src/Game/Systems/DamageIndicatorSystem.cpp b/src/Game/Systems/DamageIndicatorSystem.cpp new file mode 100644 index 00000000..93385e48 --- /dev/null +++ b/src/Game/Systems/DamageIndicatorSystem.cpp @@ -0,0 +1,65 @@ +#include "Systems/DamageIndicatorSystem.h" + +DamageIndicatorSystem::DamageIndicatorSystem(SystemParams params) + : System(params) +{ + EVENT_SUBSCRIBE_MEMBER(m_DamageTakenFromPlayer, &DamageIndicatorSystem::OnPlayerDamageTaken); + //current camera + EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &DamageIndicatorSystem::OnSetCamera); + + //load texture to cache + auto texture = CommonFunctions::LoadTexture("Textures/DamageIndicator.png", false); + auto entityFile = ResourceManager::Load("Schema/Entities/DamageIndicator.xml"); +} + +bool DamageIndicatorSystem::OnPlayerDamageTaken(Events::PlayerDamage& e) +{ + if (m_CurrentCamera == -1) { + return false; + } + + //grab players direction + auto playerOrientation = glm::quat((glm::vec3)e.Player["Transform"]["Orientation"]); + + //get the position vectors, but ignore the y-height + auto enemyPosition = (glm::vec3) e.PlayerShooter["Transform"]["Position"]; + auto playerPosition = (glm::vec3) e.Player["Transform"]["Position"]; + enemyPosition.y = 0.0f; + playerPosition.y = 0.0f; + + //calculate the enemy to player vector + auto enemyPlayerVector = glm::normalize((glm::vec3) playerPosition - enemyPosition); + + //get angle from players current rotation, this angle is how much you rotate around the y-axis + auto playerAngle = glm::angle(playerOrientation); + auto playerRotationVector = glm::normalize(glm::rotateY(glm::vec3(0, 0, 1), playerAngle)); + + //dot product of players direction-vector and enemys-to-playervector will give the cos of the angle between the vectors + auto playerRotationDot = glm::dot(playerRotationVector, enemyPlayerVector); + //to get the angle between the vectors just do cos-inverse + auto angleBetweenVectors = glm::acos(playerRotationDot); + + //rotate the direction-vector 90 degrees to get the players side-vector + auto playerSideVector = glm::normalize(glm::rotateY(glm::vec3(0, 0, 1), playerAngle + 1.57f)); + //dot of sidevector positive = enemy is on the right side, dot sidevector negative = left side + auto playerSideVectorDot = glm::dot(playerSideVector, enemyPlayerVector); + if (playerSideVectorDot < 0) { + angleBetweenVectors = -angleBetweenVectors; + } + + //load & set the "2d" sprite + auto entityFile = ResourceManager::Load("Schema/Entities/DamageIndicator.xml"); + EntityFileParser parser(entityFile); + EntityID spriteID = parser.MergeEntities(m_World); + m_World->SetParent(spriteID, m_CurrentCamera); + auto spriteWrapper = EntityWrapper(m_World, spriteID); + //simply set the rotation z-wise to the angleBetweenVectors + spriteWrapper["Transform"]["Orientation"] = glm::vec3(0, 0, angleBetweenVectors); + + return true; +} + +bool DamageIndicatorSystem::OnSetCamera(const Events::SetCamera& e) { + m_CurrentCamera = e.CameraEntity.ID; + return true; +} diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp index 7c69f0ce..93f0cd3d 100644 --- a/src/Game/Systems/PlayerMovementSystem.cpp +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -109,9 +109,15 @@ void PlayerMovementSystem::updateMovementControllers(double dt) //you cant jump and dash at the same time - since there is no friction in the air and we would thus dash much further in the air if (!controller->PlayerIsDashing() && controller->Jumping() && !controller->Crouching() && (isOnGround || !controller->DoubleJumping())) { (bool)cPhysics["IsOnGround"] = false; - if (velocity.y == 0.f) { + if (isOnGround) { controller->SetDoubleJumping(false); } else { + //put a hexagon at the players feet + auto hexagonEffect = ResourceManager::Load("Schema/Entities/DoubleJumpHexagon.xml"); + EntityFileParser parser(hexagonEffect); + EntityID hexagonEffectID = parser.MergeEntities(m_World); + EntityWrapper hexagonEW = EntityWrapper(m_World, hexagonEffectID); + hexagonEW["Transform"]["Position"] = (glm::vec3)player["Transform"]["Position"]; controller->SetDoubleJumping(true); Events::DoubleJump e; m_EventBroker->Publish(e); diff --git a/src/Game/Systems/WeaponSystem.cpp b/src/Game/Systems/WeaponSystem.cpp index eeb7dd00..8b6ba85b 100644 --- a/src/Game/Systems/WeaponSystem.cpp +++ b/src/Game/Systems/WeaponSystem.cpp @@ -130,6 +130,7 @@ bool WeaponSystem::OnShoot(Events::Shoot& eShoot) // TODO: Weapon damage calculations etc Events::PlayerDamage ePlayerDamage; ePlayerDamage.Player = player; + ePlayerDamage.PlayerShooter = eShoot.Player; ePlayerDamage.Damage = 100; m_EventBroker->Publish(ePlayerDamage);