From d931660c56cc994df1b0cac66eecb53db59c9a55 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Wed, 10 Feb 2016 01:16:38 +0100 Subject: [PATCH] WIP --- include/Engine/Core/EntityWrapper.h | 2 +- include/Engine/Core/EventBroker.h | 3 +- include/Engine/Core/Octree.h | 4 +- include/Engine/Core/System.h | 2 +- include/Game/Systems/WeaponSystem.h | 129 ++++++++++++++++-- resources/Schema/Components/AssaultWeapon.xml | 3 +- resources/Schema/Components/AssaultWeapon.xsd | 1 + resources/Schema/Entities/Player.xml | 7 +- src/Engine/Core/EntityWrapper.cpp | 3 +- src/Engine/Core/EventBroker.cpp | 14 +- src/Game/Game.cpp | 2 +- src/Game/Systems/PlayerSpawnSystem.cpp | 3 + src/Game/Systems/WeaponSystem.cpp | 108 ++++++--------- 13 files changed, 181 insertions(+), 100 deletions(-) diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index bf34b9be..0ffb190e 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -29,7 +29,7 @@ struct EntityWrapper EntityWrapper FirstChildByName(const std::string& name); EntityWrapper FirstParentWithComponent(const std::string& componentType); bool IsChildOf(EntityWrapper potentialParent); - bool Valid(); + bool Valid() const; ComponentWrapper operator[](const char* componentName); bool operator==(const EntityWrapper& e) const; diff --git a/include/Engine/Core/EventBroker.h b/include/Engine/Core/EventBroker.h index dc1babc0..20d3b60c 100644 --- a/include/Engine/Core/EventBroker.h +++ b/include/Engine/Core/EventBroker.h @@ -5,6 +5,7 @@ #include #include #include +#include #include "../Common.h" #include "Event.h" @@ -107,7 +108,7 @@ private: typedef std::unordered_map ContextRelays_t; ContextRelays_t m_ContextRelays; std::vector m_RelaysToSubscribe; - std::vector> m_RelaysToUnsubscribe; + std::unordered_map> m_RelaysToUnsubscribe; typedef std::list>> EventQueue_t; std::shared_ptr m_EventQueueRead; diff --git a/include/Engine/Core/Octree.h b/include/Engine/Core/Octree.h index 8bac5503..8fce7744 100644 --- a/include/Engine/Core/Octree.h +++ b/include/Engine/Core/Octree.h @@ -5,9 +5,7 @@ #include "../Common.h" #include "AABB.h" - -//Fwd declarations. -class Ray; +#include "Ray.h" namespace OctSpace { diff --git a/include/Engine/Core/System.h b/include/Engine/Core/System.h index e21d8c7e..43438fd5 100644 --- a/include/Engine/Core/System.h +++ b/include/Engine/Core/System.h @@ -68,7 +68,7 @@ protected: const std::string m_ComponentType; - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) = 0; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) = 0; }; class ImpureSystem : public virtual System diff --git a/include/Game/Systems/WeaponSystem.h b/include/Game/Systems/WeaponSystem.h index fccb1b0b..489048b8 100644 --- a/include/Game/Systems/WeaponSystem.h +++ b/include/Game/Systems/WeaponSystem.h @@ -13,17 +13,23 @@ #include "Input/EInputCommand.h" #include "Core/EntityFile.h" #include "Core/EntityFileParser.h" +#include "Core/Octree.h" +#include "Collision/EntityAABB.h" + +class WeaponBehaviour; class WeaponSystem : public PureSystem, ImpureSystem { public: - WeaponSystem(SystemParams params, IRenderer* renderer); + WeaponSystem(SystemParams params, IRenderer* renderer, Octree* collisionOctree); virtual void Update(double dt) override; - virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) override; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) override; private: + SystemParams m_SystemParams; IRenderer* m_Renderer; + Octree* m_CollisionOctree; std::unordered_map> m_ActiveWeapons; @@ -38,12 +44,18 @@ private: void selectWeapon(EntityWrapper player, ComponentInfo::EnumType slot); }; -class WeaponBehaviour +class WeaponBehaviour : protected System { public: - WeaponBehaviour(EntityWrapper weaponEntity) - : m_Entity(weaponEntity) + WeaponBehaviour(SystemParams systemParams, Octree* collisionOctree, EntityWrapper weaponEntity) + : System(systemParams) + , m_CollisionOctree(collisionOctree) + , m_Entity(weaponEntity) { } + virtual ~WeaponBehaviour() = default; + + WeaponBehaviour(const WeaponBehaviour&) = delete; + WeaponBehaviour& operator=(const WeaponBehaviour &) = delete; virtual void Fire() = 0; virtual void CeaseFire() { } @@ -51,15 +63,19 @@ public: virtual void Update(double dt) { } protected: + Octree* m_CollisionOctree; EntityWrapper m_Entity; }; class AssaultWeaponBehaviour : public WeaponBehaviour { public: - AssaultWeaponBehaviour(EntityWrapper weaponEntity) - : WeaponBehaviour(weaponEntity) - { } + AssaultWeaponBehaviour(SystemParams systemParams, Octree* collisionOctree, EntityWrapper weaponEntity) + : WeaponBehaviour(systemParams, collisionOctree, weaponEntity) + { + m_RayRed = ResourceManager::Load("Schema/Entities/RayRed.xml"); + m_RayBlue = ResourceManager::Load("Schema/Entities/RayBlue.xml"); + } virtual void Fire() override { @@ -73,6 +89,25 @@ public: m_Firing = false; } + virtual void Reload() override + { + ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"]; + + int& magAmmo = cAssaultWeapon["MagazineAmmo"]; + int magSize = cAssaultWeapon["MagazineSize"]; + int& ammo = cAssaultWeapon["Ammo"]; + + // Don't reload if we're already fully loaded + if (magAmmo == magSize) { + return; + } + + // Throw away rounds in magazine to incentivise ammo sharing + int toLoad = glm::min(magSize, ammo); + magAmmo = toLoad; + ammo -= toLoad; + } + virtual void Update(double dt) override { if (!m_Firing) { @@ -82,7 +117,7 @@ public: m_TimeSinceLastFire += dt; ComponentWrapper& cAssaultWeapon = m_Entity["AssaultWeapon"]; - if (m_TimeSinceLastFire > (double)cAssaultWeapon["RPM"] / 60.0) { + if (m_TimeSinceLastFire >= 1.0 / ((double)cAssaultWeapon["RPM"] / 60.0)) { fireRound(); } } @@ -90,7 +125,8 @@ public: private: bool m_Firing = false; double m_TimeSinceLastFire = 0.0; - ComponentWrapper m_Component; + EntityFile* m_RayRed = nullptr; + EntityFile* m_RayBlue = nullptr; void fireRound() { @@ -99,18 +135,85 @@ private: int& magAmmo = cAssaultWeapon["MagazineAmmo"]; int ammo = cAssaultWeapon["Ammo"]; - // Reload if our magazine is empty and we have ammo to fill it with - if (magAmmo <= 0 && ammo > 0) { - CeaseFire(); + // Reload if our magazine is empty + if (magAmmo <= 0) { Reload(); return; } // Fire magAmmo -= 1; + spawnTracer(); m_TimeSinceLastFire = 0.0; } + + void spawnTracer() + { + ComponentWrapper cTeam = m_Entity["Team"]; + ComponentInfo::EnumType team = cTeam["Team"]; + + // Select the right color of effect + EntityFile* rayFile = nullptr; + if (team == cTeam["Team"].Enum("Red")) { + rayFile = m_RayRed; + } + if (team == cTeam["Team"].Enum("Blue")) { + rayFile = m_RayBlue; + } + if (rayFile == nullptr) { + return; + } + + // Create the entity + EntityFileParser parser(rayFile); + EntityID rayID = parser.MergeEntities(m_World); + EntityWrapper ray(m_World, rayID); + + // Figure out where to put it + EntityWrapper attachment; + if (m_Entity == LocalPlayer || true) { + // Spawn the effect from the weapon view model for the local player + attachment = m_Entity.FirstChildByName("WeaponMuzzle"); + } + // TODO: Spawn the effect from the weapon world model once it exists + + glm::mat4 transformation = Transform::AbsoluteTransformation(attachment); + glm::vec3 _scale; + glm::vec3 translation; + glm::quat _orientation; + glm::vec3 _skew; + glm::vec4 _perspective; + glm::decompose(transformation, _scale, _orientation, translation, _skew, _perspective); + + // Matrix to euler angles + glm::vec3 euler; + euler.y = glm::asin(-transformation[0][2]); + if (cos(euler.y) != 0) { + euler.x = atan2(transformation[1][2], transformation[2][2]); + euler.z = atan2(transformation[0][1], transformation[0][0]); + } else { + euler.x = atan2(-transformation[2][0], transformation[1][1]); + euler.z = 0; + } + + // TODO: Spread? + + (glm::vec3&)ray["Transform"]["Position"] = translation; + (glm::vec3&)ray["Transform"]["Orientation"] = euler; + glm::vec3& scale = ray["Transform"]["Scale"]; + scale.z = traceRayDistance(translation, glm::quat(euler) * glm::vec3(0.f, 0.f, -1.f)); + } + + float traceRayDistance(glm::vec3 origin, glm::vec3 direction) + { + OctSpace::Output result; + if (m_CollisionOctree->RayCollides(Ray(origin, direction), result)) { + return result.CollideDistance; + } else { + return 0.f; + } + } }; #endif \ No newline at end of file diff --git a/resources/Schema/Components/AssaultWeapon.xml b/resources/Schema/Components/AssaultWeapon.xml index 8dc2a50a..902795c1 100755 --- a/resources/Schema/Components/AssaultWeapon.xml +++ b/resources/Schema/Components/AssaultWeapon.xml @@ -4,5 +4,6 @@ 32 360 360 - 40 + 5 + 120 \ No newline at end of file diff --git a/resources/Schema/Components/AssaultWeapon.xsd b/resources/Schema/Components/AssaultWeapon.xsd index 167fee18..1b2704ea 100755 --- a/resources/Schema/Components/AssaultWeapon.xsd +++ b/resources/Schema/Components/AssaultWeapon.xsd @@ -18,6 +18,7 @@ Maximum ammo able to be carried + Rate of fire in rounds per minute diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index e9fa0be3..b13082e7 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -6,6 +6,9 @@ + + 600 + 2 @@ -118,7 +121,7 @@ - + @@ -145,7 +148,7 @@ Hold Pos - + 1 diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index 071329a3..be7b96a8 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -54,7 +54,7 @@ bool EntityWrapper::IsChildOf(EntityWrapper potentialParent) return false; } -bool EntityWrapper::Valid() +bool EntityWrapper::Valid() const { if (this->World == nullptr) { return false; @@ -65,7 +65,6 @@ bool EntityWrapper::Valid() } if (!this->World->ValidEntity(this->ID)) { - this->ID = EntityID_Invalid; return false; } diff --git a/src/Engine/Core/EventBroker.cpp b/src/Engine/Core/EventBroker.cpp index d847e1a2..ef4d138d 100644 --- a/src/Engine/Core/EventBroker.cpp +++ b/src/Engine/Core/EventBroker.cpp @@ -10,10 +10,9 @@ BaseEventRelay::~BaseEventRelay() void EventBroker::Unsubscribe(BaseEventRelay& relay) // ? { auto identifier = std::make_tuple(relay.m_EventID, relay.m_ContextTypeName, relay.m_EventTypeName); - relay.m_Broker = nullptr; if (m_IsProcessing) { - m_RelaysToUnsubscribe.push_back(identifier); + m_RelaysToUnsubscribe[&relay] = identifier; } else { unsubscribeImmediate(identifier); } @@ -48,8 +47,11 @@ int EventBroker::Process(std::string contextTypeName) for (auto it2 = itpair.first; it2 != itpair.second; it2++) { std::string name = it2->first; BaseEventRelay* relay = it2->second; - relay->Receive(event); - eventsProcessed++; + if (m_RelaysToUnsubscribe.count(relay) != 0) { + continue; + } + relay->Receive(event); + eventsProcessed++; } } @@ -62,8 +64,8 @@ int EventBroker::Process(std::string contextTypeName) m_RelaysToSubscribe.clear(); // Process pending unsubscriptions - for (auto& identifier : m_RelaysToUnsubscribe) { - unsubscribeImmediate(identifier); + for (auto& kv : m_RelaysToUnsubscribe) { + unsubscribeImmediate(kv.second); } m_RelaysToUnsubscribe.clear(); diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index ce782ece..47170764 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -103,7 +103,7 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); - m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer); + m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); // Populate Octree with collidables diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp index fa713675..b7a3d91b 100644 --- a/src/Game/Systems/PlayerSpawnSystem.cpp +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -71,6 +71,9 @@ bool PlayerSpawnSystem::OnInputCommand(const Events::InputCommand& e) bool PlayerSpawnSystem::OnPlayerSpawned(Events::PlayerSpawned& e) { // When a player is actually spawned (since the actual spawning is handled on the server) + if (!IsClient) { + return false; + } // Check if a player already exists if (m_PlayerEntities.count(e.PlayerID) != 0) { diff --git a/src/Game/Systems/WeaponSystem.cpp b/src/Game/Systems/WeaponSystem.cpp index fe0f066f..dfb84581 100644 --- a/src/Game/Systems/WeaponSystem.cpp +++ b/src/Game/Systems/WeaponSystem.cpp @@ -1,13 +1,15 @@ #include "Systems/WeaponSystem.h" -WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer) +WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer, Octree* collisionOctree) : System(params) , PureSystem("Player") - , ImpureSystem() + , m_SystemParams(params) , m_Renderer(renderer) + , m_CollisionOctree(collisionOctree) { EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &WeaponSystem::OnInputCommand); EVENT_SUBSCRIBE_MEMBER(m_EShoot, &WeaponSystem::OnShoot); + EVENT_SUBSCRIBE_MEMBER(m_EPlayerSpawned, &WeaponSystem::OnPlayerSpawned); } void WeaponSystem::Update(double dt) @@ -15,41 +17,48 @@ void WeaponSystem::Update(double dt) } -void WeaponSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cComponent, double dt) +void WeaponSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cPlayer, double dt) { - + // Update potential weapon behaviour for player + //auto it = m_ActiveWeapons.find(entity); + //if (it != m_ActiveWeapons.end()) { + // //if (it->first.Valid()) { + // it->second->Update(dt); + // //} else { + // // m_ActiveWeapons.erase(it); + // //} + //} } bool WeaponSystem::OnInputCommand(Events::InputCommand& e) { + EntityWrapper player = e.Player; + if (e.PlayerID == -1) { + player = LocalPlayer; + } + // Make sure player is alive - if (!e.Player.Valid()) { + if (!player.Valid()) { return false; } // Weapon selection if (e.Command == "SelectWeapon") { - selectWeapon(e.Player, static_cast(e.Value)); - } - - // Only shoot client-side! - if (!IsClient) { - return false; - } - - // Only shoot if the player is alive - if (!e.Player.Valid()) { - return false; - } - - if (e.Command == "PrimaryFire" && e.Value > 0) { - Events::Shoot eShoot; - if (e.PlayerID == -1) { - eShoot.Player = LocalPlayer; - } else { - eShoot.Player = e.Player; + if (e.Value != 0) { + selectWeapon(player, static_cast(e.Value)); + } + } + + // Fire + if (e.Command == "PrimaryFire") { + if (m_ActiveWeapons.find(player) != m_ActiveWeapons.end()) { + auto weapon = m_ActiveWeapons.at(player); + if (e.Value > 0) { + weapon->Fire(); + } else { + weapon->CeaseFire(); + } } - m_EventBroker->Publish(eShoot); } return true; @@ -60,7 +69,11 @@ void WeaponSystem::selectWeapon(EntityWrapper player, ComponentInfo::EnumType sl // Primary if (slot == 1) { // TODO: if class... - m_ActiveWeapons[player] = std::make_shared(); + if (m_ActiveWeapons.count(player) == 0) { + m_ActiveWeapons.insert(std::make_pair(player, std::make_shared(m_SystemParams, m_CollisionOctree, player))); + } else { + m_ActiveWeapons.erase(player); + } } // Secondary @@ -83,49 +96,6 @@ bool WeaponSystem::OnShoot(Events::Shoot& eShoot) return false; } - // TODO: Weapon firing effects here - - auto rayRed = ResourceManager::Load("Schema/Entities/RayRed.xml"); - auto rayBlue = ResourceManager::Load("Schema/Entities/RayBlue.xml"); - - EntityWrapper weapon = eShoot.Player.FirstChildByName("WeaponMuzzle"); - if (weapon.Valid()) { - EntityWrapper ray; - if ((ComponentInfo::EnumType)eShoot.Player["Team"]["Team"] == eShoot.Player["Team"]["Team"].Enum("Red")) { - EntityFileParser parser(rayRed); - EntityID rayID = parser.MergeEntities(m_World); - ray = EntityWrapper(m_World, rayID); - } else { - EntityFileParser parser(rayBlue); - EntityID rayID = parser.MergeEntities(m_World); - ray = EntityWrapper(m_World, rayID); - } - - glm::mat4 transformation = Transform::AbsoluteTransformation(weapon); - glm::vec3 scale; - glm::vec3 translation; - glm::quat orientation; - glm::vec3 skew; - glm::vec4 perspective; - glm::decompose(transformation, scale, orientation, translation, skew, perspective); - - // Matrix to euler angles - glm::vec3 euler; - euler.y = glm::asin(-transformation[0][2]); - if (cos(euler.y) != 0) { - euler.x = atan2(transformation[1][2], transformation[2][2]); - euler.z = atan2(transformation[0][1], transformation[0][0]); - } else { - euler.x = atan2(-transformation[2][0], transformation[1][1]); - euler.z = 0; - } - - //LOG_DEBUG("rotation: %f %f %f", euler.x, euler.y, euler.z); - (glm::vec3&)ray["Transform"]["Position"] = translation; - (glm::vec3&)ray["Transform"]["Orientation"] = euler; - //(glm::vec3&)ray["Transform"]["Orientation"] = Transform::AbsoluteOrientationEuler(weapon); - } - // Only run further picking code for the local player! if (eShoot.Player != LocalPlayer) { return false;