From cd315bbaa05bb022d36ae80bdacffd0eadd6b71d Mon Sep 17 00:00:00 2001 From: William Moberg Date: Thu, 25 Feb 2016 12:12:44 +0100 Subject: [PATCH 1/6] Added DoubleJump component and JumpSpeed in Player component so jumpheight can be adjusted for regular jump and double jump. --- resources/Schema/Components.xsd | 1 + resources/Schema/Components/DoubleJump.xml | 4 ++++ resources/Schema/Components/DoubleJump.xsd | 16 ++++++++++++++++ resources/Schema/Components/Player.xml | 1 + resources/Schema/Components/Player.xsd | 3 +++ resources/Schema/Entities/Player.xml | 1 + resources/Schema/Entities/PlayerRed.xml | 1 + src/Game/Systems/PlayerMovementSystem.cpp | 17 +++++++++++------ 8 files changed, 38 insertions(+), 6 deletions(-) create mode 100644 resources/Schema/Components/DoubleJump.xml create mode 100644 resources/Schema/Components/DoubleJump.xsd diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 42abed82..e2d07374 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -46,4 +46,5 @@ + \ No newline at end of file diff --git a/resources/Schema/Components/DoubleJump.xml b/resources/Schema/Components/DoubleJump.xml new file mode 100644 index 00000000..bb0d3bc7 --- /dev/null +++ b/resources/Schema/Components/DoubleJump.xml @@ -0,0 +1,4 @@ + + + 4.0 + \ No newline at end of file diff --git a/resources/Schema/Components/DoubleJump.xsd b/resources/Schema/Components/DoubleJump.xsd new file mode 100644 index 00000000..65ff0419 --- /dev/null +++ b/resources/Schema/Components/DoubleJump.xsd @@ -0,0 +1,16 @@ + + + + + + + Enables a Player to double jump. + + + + Vertical velocity set on double jump. + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/Player.xml b/resources/Schema/Components/Player.xml index 00cff257..429aa5fb 100644 --- a/resources/Schema/Components/Player.xml +++ b/resources/Schema/Components/Player.xml @@ -2,5 +2,6 @@ 3 1.5 + 4.0 \ No newline at end of file diff --git a/resources/Schema/Components/Player.xsd b/resources/Schema/Components/Player.xsd index 1b33d222..b121fd06 100644 --- a/resources/Schema/Components/Player.xsd +++ b/resources/Schema/Components/Player.xsd @@ -11,6 +11,9 @@ + + Vertical velocity set when jumping. + diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index 7a5d2eb4..569dbc77 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -11,6 +11,7 @@ + diff --git a/resources/Schema/Entities/PlayerRed.xml b/resources/Schema/Entities/PlayerRed.xml index cd01632e..3285a91f 100644 --- a/resources/Schema/Entities/PlayerRed.xml +++ b/resources/Schema/Entities/PlayerRed.xml @@ -11,6 +11,7 @@ + diff --git a/src/Game/Systems/PlayerMovementSystem.cpp b/src/Game/Systems/PlayerMovementSystem.cpp index a144dd18..916573a4 100644 --- a/src/Game/Systems/PlayerMovementSystem.cpp +++ b/src/Game/Systems/PlayerMovementSystem.cpp @@ -116,12 +116,18 @@ void PlayerMovementSystem::updateMovementControllers(double dt) ImGui::Text("velocity: (%f, %f, %f) |%f|", velocity.x, velocity.y, velocity.z, glm::length(velocity)); } - //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 (isOnGround) { + controller->SetDoubleJumping(false); + } + //If player presses Jump and is not crouching. + if (controller->Jumping() && !controller->Crouching()) { if (isOnGround) { - controller->SetDoubleJumping(false); - } else { + (bool)cPhysics["IsOnGround"] = false; + velocity.y = player["Player"]["JumpSpeed"]; + } else if (player.HasComponent("DoubleJump") && !controller->DoubleJumping()) { + //Enter here if player can double jump and is doing so. + (bool)cPhysics["IsOnGround"] = false; + velocity.y = player["DoubleJump"]["DoubleJumpSpeed"]; if (IsClient) { //put a hexagon at the players feet auto hexagonEffect = ResourceManager::Load("Schema/Entities/DoubleJumpHexagon.xml"); @@ -134,7 +140,6 @@ void PlayerMovementSystem::updateMovementControllers(double dt) m_EventBroker->Publish(e); } } - velocity.y = 4.f; } if (player.HasComponent("AABB")) { From bb76c9d248bb94d503e5331c25bcf55d567f2a01 Mon Sep 17 00:00:00 2001 From: sippeangelo Date: Thu, 25 Feb 2016 16:24:38 +0100 Subject: [PATCH 2/6] WIP multi-weapon behaviours --- include/Engine/Core/EntityWrapper.h | 4 + include/Engine/Core/System.h | 2 +- .../Systems/Weapon/AssaultWeaponBehaviour.h | 30 +-- .../Systems/Weapon/DefenderWeaponBehaviour.h | 38 +++ include/Game/Systems/Weapon/WeaponBehaviour.h | 173 +++++++++++- resources/Schema/Components.xsd | 2 + resources/Schema/Components/AssaultWeapon.xml | 1 + resources/Schema/Components/AssaultWeapon.xsd | 2 + .../Schema/Components/DefenderWeapon.xml | 16 ++ .../Schema/Components/DefenderWeapon.xsd | 44 +++ resources/Schema/Components/Player.xml | 1 + resources/Schema/Components/Player.xsd | 1 + resources/Schema/Components/Weapon.xml | 3 - resources/Schema/Components/Weapon.xsd | 17 -- .../Schema/Components/WeaponAttachment.xml | 5 + .../Schema/Components/WeaponAttachment.xsd | 28 ++ .../Schema/Entities/AssaultWeaponView.xml | 99 +++++++ .../Schema/Entities/AssaultWeaponWorld.xml | 40 +++ resources/Schema/Entities/DefenderShield.xml | 40 +++ .../Schema/Entities/DefenderWeaponView.xml | 99 +++++++ .../Schema/Entities/DefenderWeaponViewRed.xml | 99 +++++++ .../Schema/Entities/DefenderWeaponWorld.xml | 41 +++ .../Entities/DefenderWeaponWorldRed.xml | 41 +++ resources/Schema/Entities/MovementTest.xml | 253 +----------------- resources/Schema/Entities/Player.xml | 204 +++++--------- resources/Schema/Entities/PlayerRed.xml | 209 ++++++--------- resources/Schema/Types/Entity.xsd | 2 + resources/Schema/Types/WeaponSlotEnum.xsd | 16 ++ src/Engine/Core/EntityWrapper.cpp | 43 +++ src/Engine/Core/Util/Logging.cpp | 4 +- src/Game/Game.cpp | 8 +- .../Network/MultiplayerSnapshotFilter.cpp | 1 + src/Game/Systems/DamageIndicatorSystem.cpp | 2 +- ...aviour.cpp => AssaultWeaponBehaviour.cpp_} | 52 ++-- .../Weapon/DefenderWeaponBehaviour.cpp | 188 +++++++++++++ .../{WeaponSystem.cpp => WeaponSystem.cpp_} | 56 +++- 36 files changed, 1251 insertions(+), 613 deletions(-) create mode 100644 include/Game/Systems/Weapon/DefenderWeaponBehaviour.h create mode 100755 resources/Schema/Components/DefenderWeapon.xml create mode 100755 resources/Schema/Components/DefenderWeapon.xsd delete mode 100644 resources/Schema/Components/Weapon.xml delete mode 100644 resources/Schema/Components/Weapon.xsd create mode 100644 resources/Schema/Components/WeaponAttachment.xml create mode 100644 resources/Schema/Components/WeaponAttachment.xsd create mode 100755 resources/Schema/Entities/AssaultWeaponView.xml create mode 100755 resources/Schema/Entities/AssaultWeaponWorld.xml create mode 100755 resources/Schema/Entities/DefenderShield.xml create mode 100755 resources/Schema/Entities/DefenderWeaponView.xml create mode 100755 resources/Schema/Entities/DefenderWeaponViewRed.xml create mode 100755 resources/Schema/Entities/DefenderWeaponWorld.xml create mode 100755 resources/Schema/Entities/DefenderWeaponWorldRed.xml mode change 100644 => 100755 resources/Schema/Entities/PlayerRed.xml create mode 100644 resources/Schema/Types/WeaponSlotEnum.xsd rename src/Game/Systems/Weapon/{AssaultWeaponBehaviour.cpp => AssaultWeaponBehaviour.cpp_} (87%) create mode 100644 src/Game/Systems/Weapon/DefenderWeaponBehaviour.cpp rename src/Game/Systems/Weapon/{WeaponSystem.cpp => WeaponSystem.cpp_} (56%) diff --git a/include/Engine/Core/EntityWrapper.h b/include/Engine/Core/EntityWrapper.h index 4643e28b..8ece8e59 100644 --- a/include/Engine/Core/EntityWrapper.h +++ b/include/Engine/Core/EntityWrapper.h @@ -30,10 +30,13 @@ struct EntityWrapper EntityWrapper FirstChildByName(const std::string& name); EntityWrapper FirstParentWithComponent(const std::string& componentType); EntityWrapper Clone(EntityWrapper parent = EntityWrapper::Invalid); + std::vector ChildrenWithComponent(const std::string& componentType); + void DeleteChildren(); bool IsChildOf(EntityWrapper potentialParent); bool Valid() const; ComponentWrapper operator[](const char* componentName); + ComponentWrapper operator[](const std::string& componentName); bool operator==(const EntityWrapper& e) const; bool operator!=(const EntityWrapper& e) const; explicit operator EntityID() const; @@ -41,6 +44,7 @@ struct EntityWrapper private: EntityWrapper firstChildByNameRecursive(const std::string& name, EntityID parent); EntityWrapper cloneRecursive(EntityWrapper entity, EntityWrapper parent); + void childrenWithComponentRecursive(const std::string& componentType, EntityWrapper& entity, std::vector& childrenWithComponent); }; namespace std diff --git a/include/Engine/Core/System.h b/include/Engine/Core/System.h index 1a387855..23d5f9a5 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& cPlayer, double dt) = 0; + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) = 0; }; class ImpureSystem : public virtual System diff --git a/include/Game/Systems/Weapon/AssaultWeaponBehaviour.h b/include/Game/Systems/Weapon/AssaultWeaponBehaviour.h index 7bd9c175..993dd060 100644 --- a/include/Game/Systems/Weapon/AssaultWeaponBehaviour.h +++ b/include/Game/Systems/Weapon/AssaultWeaponBehaviour.h @@ -1,37 +1,33 @@ +#ifndef AssaultWeaponBehaviour_h__ +#define AssaultWeaponBehaviour_h__ + #include "Sound/EPlaySoundOnEntity.h" #include "Collision/Collision.h" -#include "Rendering/AnimationSystem.h" #include "Core/ConfigFile.h" #include "WeaponBehaviour.h" #include "../SpawnerSystem.h" #include "Core/EPlayerDamage.h" #include "Core/EShoot.h" - -class AssaultWeaponBehaviour : public WeaponBehaviour +class AssaultWeaponBehaviour : public WeaponBehaviour { public: - AssaultWeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree, EntityWrapper weaponEntity); - - virtual void Fire() override; - virtual void CeaseFire() override; - virtual void Reload() override; + AssaultWeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree) + : WeaponBehaviour(systemParams, "AssaultWeapon", renderer, collisionOctree) + { } - virtual void Update(double dt) override; +protected: + virtual void OnPrimaryFire(WeaponInfo& wi) override; + virtual void OnCeasePrimaryFire(WeaponInfo& wi) override; + virtual void OnReload(WeaponInfo& wi) override; private: - EntityWrapper m_FirstPersonModel; - EntityWrapper m_ThirdPersonModel; // State bool m_Firing = false; bool m_Reloading = false; double m_ReloadTimer = 0.0; - EntityWrapper m_FirstPersonReloadImpersonator; - EntityWrapper m_ThirdPersonReloadImpersonator; double m_TimeSinceLastFire = 0.0; - - EventRelay m_EAnimationComplete; - bool OnAnimationComplete(Events::AnimationComplete& e); + EntityWrapper m_FirstPersonReloadImpostor; bool hasAmmo(); void fireRound(); @@ -47,3 +43,5 @@ private: bool shoot(double damage); void showHitMarker(); }; + +#endif \ No newline at end of file diff --git a/include/Game/Systems/Weapon/DefenderWeaponBehaviour.h b/include/Game/Systems/Weapon/DefenderWeaponBehaviour.h new file mode 100644 index 00000000..5ca13d3e --- /dev/null +++ b/include/Game/Systems/Weapon/DefenderWeaponBehaviour.h @@ -0,0 +1,38 @@ +#include "WeaponBehaviour.h" +#include "Collision/Collision.h" +#include "Core/EPlayerDamage.h" +#include "Rendering/ESetCamera.h" + +class DefenderWeaponBehaviour : public WeaponBehaviour +{ +public: + DefenderWeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree) + : System(systemParams) + , WeaponBehaviour(systemParams, "DefenderWeapon", renderer, collisionOctree) + , m_RandomEngine(m_RandomDevice()) + { + EVENT_SUBSCRIBE_MEMBER(m_ESetCamera, &DefenderWeaponBehaviour::OnSetCamera); + } + + void UpdateComponent(EntityWrapper& entity, ComponentWrapper& cWeapon, double dt) override; + void UpdateWeapon(WeaponInfo& wi, double dt) override; + void OnPrimaryFire(WeaponInfo& wi) override; + void OnCeasePrimaryFire(WeaponInfo& wi) override; + bool OnInputCommand(WeaponInfo& wi, const Events::InputCommand& e) override; + +private: + std::random_device m_RandomDevice; + std::mt19937 m_RandomEngine; + EntityWrapper m_CurrentCamera; + + EventRelay m_ESetCamera; + bool OnSetCamera(const Events::SetCamera& e); + + // Weapon functions + void fireShell(WeaponInfo& wi); + void dealDamage(WeaponInfo& wi, glm::vec3 direction, double damage); + + // Utility + float traceRayDistance(glm::vec3 origin, glm::vec3 direction); + Camera cameraFromEntity(EntityWrapper camera); +}; \ No newline at end of file diff --git a/include/Game/Systems/Weapon/WeaponBehaviour.h b/include/Game/Systems/Weapon/WeaponBehaviour.h index 7a0b4626..f23269df 100644 --- a/include/Game/Systems/Weapon/WeaponBehaviour.h +++ b/include/Game/Systems/Weapon/WeaponBehaviour.h @@ -5,30 +5,177 @@ #include "Rendering/IRenderer.h" #include "Core/Octree.h" #include "Collision/EntityAABB.h" +#include "Input/EInputCommand.h" +#include "Systems/SpawnerSystem.h" -class WeaponBehaviour : public System +template +class WeaponBehaviour : public PureSystem { + friend class WeaponSystem; + public: - WeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree, EntityWrapper player) - : System(systemParams) + WeaponBehaviour(SystemParams params, std::string componentType, IRenderer* renderer, Octree* collisionOctree) + : System(params) + , PureSystem(componentType) , m_Renderer(renderer) , m_CollisionOctree(collisionOctree) - , m_Player(player) - { } + { + EVENT_SUBSCRIBE_MEMBER(m_EInputCommand, &WeaponBehaviour::_OnInputCommand) + } virtual ~WeaponBehaviour() = default; - WeaponBehaviour(const WeaponBehaviour&) = delete; - WeaponBehaviour& operator=(const WeaponBehaviour &) = delete; - - virtual void Fire() = 0; - virtual void CeaseFire() { } - virtual void Reload() { } - virtual void Update(double dt) { } + virtual void UpdateComponent(EntityWrapper& entity, ComponentWrapper& component, double dt) override + { + auto weapon = getActiveWeapon(entity); + if (!weapon) { + return; + } else { + UpdateWeapon(*weapon, dt); + } + } protected: + struct WeaponInfo + { + std::string WeaponComponent; + EntityWrapper Player; + EntityWrapper WeaponEntity; + EntityWrapper FirstPersonEntity; + EntityWrapper ThirdPersonEntity; + ComponentWrapper GetComponent() { return WeaponEntity[WeaponComponent]; } + }; + IRenderer* m_Renderer; Octree* m_CollisionOctree; - EntityWrapper m_Player; + std::unordered_map m_ActiveWeapons; + + virtual void UpdateWeapon(WeaponInfo& wi, double dt) { } + virtual void OnPrimaryFire(WeaponInfo& wi) { } + virtual void OnCeasePrimaryFire(WeaponInfo& wi) { } + virtual void OnReload(WeaponInfo& wi) { } + virtual bool OnInputCommand(WeaponInfo& wi, const Events::InputCommand& e) { return false; } + +private: + EventRelay m_EInputCommand; + bool _OnInputCommand(const Events::InputCommand& e) + { + EntityWrapper player = e.Player; + if (e.PlayerID == -1) { + player = LocalPlayer; + } + + // Make sure the player is alive + if (!player.Valid()) { + return false; + } + + // Make sure the player has this weapon + auto weapon = getWeaponComponent(player); + if (!weapon) { + return false; + } + + // Weapon selection + if (e.Command == "SelectWeapon") { + if (static_cast(e.Value) == static_cast((*weapon)["Slot"])) { + selectWeapon(player); + } + } + + // Only handle weapon actions if the weapon is active + auto activeWeapon = getActiveWeapon(player); + if (!activeWeapon) { + return false; + } + + // Fire + if (e.Command == "PrimaryFire") { + if (e.Value > 0) { + OnPrimaryFire(*activeWeapon); + } else { + OnCeasePrimaryFire(*activeWeapon); + } + } + + // Reload + if (e.Command == "Reload" && e.Value != 0) { + OnReload(*activeWeapon); + } + + return OnInputCommand(*activeWeapon, e); + } + + boost::optional getWeaponComponent(EntityWrapper player) + { + if (!player.HasComponent(m_ComponentType)) { + return boost::none; + } + + return player[m_ComponentType]; + } + + boost::optional getActiveWeapon(EntityWrapper player) + { + auto it = m_ActiveWeapons.find(player); + if (it == m_ActiveWeapons.end()) { + return boost::none; + } + WeaponInfo& activeWeapon = it->second; + + if (!activeWeapon.FirstPersonEntity.Valid() && !activeWeapon.ThirdPersonEntity.Valid()) { + return boost::none; + } + + return activeWeapon; + } + + void selectWeapon(EntityWrapper player) + { + // Find the weapon attachments matching the weapon type + std::vector weaponAttachments = player.ChildrenWithComponent("WeaponAttachment"); + EntityWrapper firstPersonAttachment; + EntityWrapper thirdPersonAttachment; + for (auto& attachment : weaponAttachments) { + ComponentWrapper cWeaponAttachment = attachment["WeaponAttachment"]; + if ((std::string&)cWeaponAttachment["Weapon"] == m_ComponentType) { + ComponentWrapper::SubscriptProxy person = cWeaponAttachment["Person"]; + if ((ComponentInfo::EnumType)person == person.Enum("FirstPerson")) { + firstPersonAttachment = attachment; + } else if ((ComponentInfo::EnumType)person == person.Enum("ThirdPerson")) { + thirdPersonAttachment = attachment; + } + } + } + + if (!firstPersonAttachment.Valid() && !thirdPersonAttachment.Valid()) { + LOG_WARNING("No weapon attachment found for %s of player #%i", m_ComponentType.c_str(), player.ID); + return; + } + + // Purge other weapon entities + for (auto& attachment : weaponAttachments) { + //if (attachment == firstPersonAttachment || attachment == thirdPersonAttachment) { + // continue; + //} + attachment.DeleteChildren(); + } + + // Spawn the weapon(s) + EntityWrapper firstPersonWeapon; + EntityWrapper thirdPersonWeapon; + if (firstPersonAttachment.Valid()) { + firstPersonWeapon = SpawnerSystem::Spawn(firstPersonAttachment, firstPersonAttachment); + } + if (thirdPersonAttachment.Valid()) { + thirdPersonWeapon = SpawnerSystem::Spawn(thirdPersonAttachment, thirdPersonAttachment); + } + + m_ActiveWeapons[player].WeaponComponent = m_ComponentType; + m_ActiveWeapons[player].Player = player; + m_ActiveWeapons[player].WeaponEntity = player; + m_ActiveWeapons[player].FirstPersonEntity = firstPersonWeapon; + m_ActiveWeapons[player].ThirdPersonEntity = thirdPersonWeapon; + } }; #endif diff --git a/resources/Schema/Components.xsd b/resources/Schema/Components.xsd index 42abed82..cad50c7e 100644 --- a/resources/Schema/Components.xsd +++ b/resources/Schema/Components.xsd @@ -46,4 +46,6 @@ + + \ No newline at end of file diff --git a/resources/Schema/Components/AssaultWeapon.xml b/resources/Schema/Components/AssaultWeapon.xml index 6c645624..c835217b 100755 --- a/resources/Schema/Components/AssaultWeapon.xml +++ b/resources/Schema/Components/AssaultWeapon.xml @@ -8,4 +8,5 @@ 120 0.01 2 + \ No newline at end of file diff --git a/resources/Schema/Components/AssaultWeapon.xsd b/resources/Schema/Components/AssaultWeapon.xsd index 95df64b7..7e9854a2 100755 --- a/resources/Schema/Components/AssaultWeapon.xsd +++ b/resources/Schema/Components/AssaultWeapon.xsd @@ -2,6 +2,7 @@ + @@ -28,6 +29,7 @@ Time it takes to reload the weapon in seconds + diff --git a/resources/Schema/Components/DefenderWeapon.xml b/resources/Schema/Components/DefenderWeapon.xml new file mode 100755 index 00000000..998f3bde --- /dev/null +++ b/resources/Schema/Components/DefenderWeapon.xml @@ -0,0 +1,16 @@ + + + 8 + 8 + 64 + 64 + 90 + 0.174533 + 10 + 120 + 0.01 + 0.5 + + false + 0 + \ No newline at end of file diff --git a/resources/Schema/Components/DefenderWeapon.xsd b/resources/Schema/Components/DefenderWeapon.xsd new file mode 100755 index 00000000..3fe5a64a --- /dev/null +++ b/resources/Schema/Components/DefenderWeapon.xsd @@ -0,0 +1,44 @@ + + + + + + + + + + + Ammo currently loaded into the magazine + + + Max number of rounds in a magazine + + + Current ammo carried + + + Maximum ammo able to be carried + + + Damage dealt if all shotgun pellets hit + + + Spread angle in radians + + + + Rate of fire in rounds per minute + + + View punch in radians for each shell fired + + + Time it takes to load ONE SHELL into the weapon in seconds + + + + + + + + diff --git a/resources/Schema/Components/Player.xml b/resources/Schema/Components/Player.xml index 00cff257..1aaeff25 100644 --- a/resources/Schema/Components/Player.xml +++ b/resources/Schema/Components/Player.xml @@ -3,4 +3,5 @@ 3 1.5 + \ No newline at end of file diff --git a/resources/Schema/Components/Player.xsd b/resources/Schema/Components/Player.xsd index 1b33d222..ebaed462 100644 --- a/resources/Schema/Components/Player.xsd +++ b/resources/Schema/Components/Player.xsd @@ -12,6 +12,7 @@ + diff --git a/resources/Schema/Components/Weapon.xml b/resources/Schema/Components/Weapon.xml deleted file mode 100644 index 38c6fce9..00000000 --- a/resources/Schema/Components/Weapon.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/resources/Schema/Components/Weapon.xsd b/resources/Schema/Components/Weapon.xsd deleted file mode 100644 index 8bddd8a9..00000000 --- a/resources/Schema/Components/Weapon.xsd +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/resources/Schema/Components/WeaponAttachment.xml b/resources/Schema/Components/WeaponAttachment.xml new file mode 100644 index 00000000..8867b2b7 --- /dev/null +++ b/resources/Schema/Components/WeaponAttachment.xml @@ -0,0 +1,5 @@ + + + + + \ No newline at end of file diff --git a/resources/Schema/Components/WeaponAttachment.xsd b/resources/Schema/Components/WeaponAttachment.xsd new file mode 100644 index 00000000..3b1291ae --- /dev/null +++ b/resources/Schema/Components/WeaponAttachment.xsd @@ -0,0 +1,28 @@ + + + + + + + + + + + + + + + + + + Combine with a spawner to define a weapon attachment point + + + + The weapon component type this attachment refers to + + + + + + \ No newline at end of file diff --git a/resources/Schema/Entities/AssaultWeaponView.xml b/resources/Schema/Entities/AssaultWeaponView.xml new file mode 100755 index 00000000..4b985fbb --- /dev/null +++ b/resources/Schema/Entities/AssaultWeaponView.xml @@ -0,0 +1,99 @@ + + + + + + R_Arm_Weapon_Joint + + + Models/Weapons/Blue/AssaultWeaponBlue.mesh + + + + + + + + + + + + Schema/Entities/RayBlue.xml + + + + + + + + + + + Schema/Entities/ReloadEffectView.xml + + + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + + + + + + + + 32 + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + 360 + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/AssaultWeaponWorld.xml b/resources/Schema/Entities/AssaultWeaponWorld.xml new file mode 100755 index 00000000..6fcb97b3 --- /dev/null +++ b/resources/Schema/Entities/AssaultWeaponWorld.xml @@ -0,0 +1,40 @@ + + + + + + R_Arm_Weapon_Joint + + + Models/Weapons/Blue/AssaultWeaponBlue.mesh + + + + + + + + + + + + Schema/Entities/RayBlue.xml + + + + + + + + + + + Schema/Entities/ReloadEffectWorld.xml + + + + + + + + diff --git a/resources/Schema/Entities/DefenderShield.xml b/resources/Schema/Entities/DefenderShield.xml new file mode 100755 index 00000000..da760e72 --- /dev/null +++ b/resources/Schema/Entities/DefenderShield.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + Models/Core/UnitPlane.mesh + + + + + + + + + + + + + + Models/Core/UnitHexagon.mesh + + true + + + + + + + + + + + + diff --git a/resources/Schema/Entities/DefenderWeaponView.xml b/resources/Schema/Entities/DefenderWeaponView.xml new file mode 100755 index 00000000..f6b6e89d --- /dev/null +++ b/resources/Schema/Entities/DefenderWeaponView.xml @@ -0,0 +1,99 @@ + + + + + + R_Arm_Weapon_Joint + + + + Models/Weapons/Blue/DefenderGunBlue.mesh + + + + + + + + + + + Schema/Entities/RayBlue.xml + + + + + + + + + + + Schema/Entities/ReloadEffectView.xml + + + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + + + + + + + + 32 + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + 360 + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/DefenderWeaponViewRed.xml b/resources/Schema/Entities/DefenderWeaponViewRed.xml new file mode 100755 index 00000000..b5b1c322 --- /dev/null +++ b/resources/Schema/Entities/DefenderWeaponViewRed.xml @@ -0,0 +1,99 @@ + + + + + + R_Arm_Weapon_Joint + + + + Models/Weapons/Red/DefenderGunRed.mesh + + + + + + + + + + + Schema/Entities/RayRed.xml + + + + + + + + + + + Schema/Entities/ReloadEffectView.xml + + + + + + + + + + + + + + + + + + Textures/Core/UnitHexagon.png + + + + + + + + + + + + + + + + + + + 32 + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + 360 + Fonts/DroidSans.ttf,64 + + + + + + + + + + + + + + + + diff --git a/resources/Schema/Entities/DefenderWeaponWorld.xml b/resources/Schema/Entities/DefenderWeaponWorld.xml new file mode 100755 index 00000000..826301b4 --- /dev/null +++ b/resources/Schema/Entities/DefenderWeaponWorld.xml @@ -0,0 +1,41 @@ + + + + + + R_Arm_Weapon_Joint + + + + Models/Weapons/Blue/DefenderGunBlue.mesh + + + + + + + + + + + + Schema/Entities/RayBlue.xml + + + + + + + + + + + Schema/Entities/ReloadEffectWorld.xml + + + + + + + + diff --git a/resources/Schema/Entities/DefenderWeaponWorldRed.xml b/resources/Schema/Entities/DefenderWeaponWorldRed.xml new file mode 100755 index 00000000..7f697304 --- /dev/null +++ b/resources/Schema/Entities/DefenderWeaponWorldRed.xml @@ -0,0 +1,41 @@ + + + + + + R_Arm_Weapon_Joint + + + + Models/Weapons/Red/DefenderGunRed.mesh + + + + + + + + + + + + Schema/Entities/RayRed.xml + + + + + + + + + + + Schema/Entities/ReloadEffectWorld.xml + + + + + + + + diff --git a/resources/Schema/Entities/MovementTest.xml b/resources/Schema/Entities/MovementTest.xml index 84aaa03a..41474568 100644 --- a/resources/Schema/Entities/MovementTest.xml +++ b/resources/Schema/Entities/MovementTest.xml @@ -10,7 +10,7 @@ - Schema/Entities/Player.xml + Schema/Entities/PlayerRed.xml @@ -118,257 +118,6 @@ - - - - - - - - 600 - - - - - - - - - 5 - - - - - - - - - - - - - - - - - - - - - - - Fonts/DroidSans.ttf,100 - - - - - - - - - - - - - - Models/Widgets/Camera.mesh - false - - - - - - - - - - - - - - - - - - - 1 - - - - - Models/Core/UnitHexagon.mesh - - - - - - - - - - - - - - Textures/Weapons/Crosshair/SmallThickHoleDot.png - false - - - - - - - - - - - - - - Idle - 1.9569972344146196 - 1 - - - Models/Characters/Assault/FirstPerson.mesh - true - - - - - - - - R_Arm_Weapon_Joint - - - Models/Weapons/Blue/AssaultWeaponBlue.mesh - true - - - - - - - - - - - Schema/Entities/RayBlue.xml - - - - - - - - - - - - - Schema/Entities/WeaponReloadEffect.xml - - - - - - - - - - - - - - Models/Widgets/Camera.mesh - false - - - - - - - - - - - - Idle - 1.8055945618467364 - 1 - - - AimRifle - - - - - Models/Characters/Assault/AssaultAnimations.mesh - - - - - - - - - R_Arm_Weapon_Joint - - - Models/Weapons/Blue/AssaultWeaponBlue.mesh - false - - - - - - - - - - - Schema/Entities/RayBlue.xml - - - - - - - - - - - - - - - Models/Core/UnitCube.mesh - - false - - - - - - - - - - - - Models/Core/UnitCube.mesh - - false - - - - - - - - - diff --git a/resources/Schema/Entities/Player.xml b/resources/Schema/Entities/Player.xml index 4f012955..7976fe2b 100644 --- a/resources/Schema/Entities/Player.xml +++ b/resources/Schema/Entities/Player.xml @@ -7,23 +7,30 @@ - 600 + + + - + + 1.6944730461160304 + 5 + - + + + @@ -303,7 +310,8 @@ - + + @@ -363,7 +371,7 @@ Idle - 0.97725610639912475 + 0.67172915251515519 1 @@ -375,100 +383,29 @@ - + - - R_Arm_Weapon_Joint - - - Models/Weapons/Blue/AssaultWeaponBlue.mesh - - - - - + + Schema/Entities/DefenderWeaponView.xml + + + + DefenderWeapon + - - - - - Schema/Entities/RayBlue.xml - - - - - - - - - - - Schema/Entities/ReloadEffectView.xml - - - - - - - - - - - - - - - - - - Textures/Core/UnitHexagon.png - - - - - - - - - - - - - - - - - - - 32 - Fonts/DroidSans.ttf,64 - - - - - - - - - - - - 360 - Fonts/DroidSans.ttf,64 - - - - - - - - - - - - - - + + + + + + Schema/Entities/AssaultWeaponView.xml + + + + AssaultWeapon + + + @@ -492,7 +429,6 @@ Idle - 0.87583812735846323 1 @@ -501,6 +437,7 @@ AimRifle + Models/Characters/Assault/AssaultAnimations.mesh @@ -509,41 +446,35 @@ - + - - R_Arm_Weapon_Joint - - - Models/Weapons/Blue/AssaultWeaponBlue.mesh - - - - - + + Schema/Entities/DefenderWeaponWorld.xml + + + + DefenderWeapon + + + + - - - - - Schema/Entities/RayBlue.xml - - - - - - - - - - - Schema/Entities/ReloadEffectWorld.xml - - - - - - + + + + + + Schema/Entities/AssaultWeaponWorld.xml + + + + AssaultWeapon + + + + + + @@ -609,6 +540,17 @@ + + + + Schema/Entities/DefenderShield.xml + + + + + + + diff --git a/resources/Schema/Entities/PlayerRed.xml b/resources/Schema/Entities/PlayerRed.xml old mode 100644 new mode 100755 index d56fa3c1..69116f21 --- a/resources/Schema/Entities/PlayerRed.xml +++ b/resources/Schema/Entities/PlayerRed.xml @@ -7,23 +7,30 @@ - 600 + + + - + + 1.6944730461160304 + 5 + - + + + @@ -364,7 +371,7 @@ Idle - 1.2667383999985162 + 0.67172915251515519 1 @@ -376,100 +383,29 @@ - + - - R_Arm_Weapon_Joint - - - Models/Weapons/Red/AssaultWeaponRed.mesh - - - - - + + Schema/Entities/DefenderWeaponViewRed.xml + + + + DefenderWeapon + - - - - - Schema/Entities/RayRed.xml - - - - - - - - - - - Schema/Entities/ReloadEffectViewRed.xml - - - - - - - - - - - - - - - - - - Textures/Core/UnitHexagon.png - - - - - - - - - - - - - - - - - - - 32 - Fonts/DroidSans.ttf,64 - - - - - - - - - - - - 360 - Fonts/DroidSans.ttf,64 - - - - - - - - - - - - - - + + + + + + Schema/Entities/AssaultWeaponView.xml + + + + AssaultWeapon + + + @@ -493,7 +429,6 @@ Idle - 0.26532318661337229 1 @@ -502,6 +437,7 @@ AimRifle + Models/Characters/Assault/AssaultAnimations.mesh @@ -510,41 +446,35 @@ - + - - R_Arm_Weapon_Joint - - - Models/Weapons/Red/AssaultWeaponRed.mesh - - - - - + + Schema/Entities/DefenderWeaponWorldRed.xml + + + + DefenderWeapon + + + + - - - - - Schema/Entities/RayRed.xml - - - - - - - - - - - Schema/Entities/ReloadEffectWorldRed.xml - - - - - - + + + + + + Schema/Entities/AssaultWeaponWorld.xml + + + + AssaultWeapon + + + + + + @@ -583,20 +513,20 @@ - + - + Textures/Icons/Arrow.png false - + @@ -604,12 +534,23 @@ true - + + + + + Schema/Entities/DefenderShield.xml + + + + + + + diff --git a/resources/Schema/Types/Entity.xsd b/resources/Schema/Types/Entity.xsd index a9c5f641..0965ef89 100644 --- a/resources/Schema/Types/Entity.xsd +++ b/resources/Schema/Types/Entity.xsd @@ -50,6 +50,8 @@ + + diff --git a/resources/Schema/Types/WeaponSlotEnum.xsd b/resources/Schema/Types/WeaponSlotEnum.xsd new file mode 100644 index 00000000..6713ca9d --- /dev/null +++ b/resources/Schema/Types/WeaponSlotEnum.xsd @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Engine/Core/EntityWrapper.cpp b/src/Engine/Core/EntityWrapper.cpp index ace1f4a7..b3bef55a 100644 --- a/src/Engine/Core/EntityWrapper.cpp +++ b/src/Engine/Core/EntityWrapper.cpp @@ -62,6 +62,29 @@ EntityWrapper EntityWrapper::Clone(EntityWrapper parent /*= Invalid*/) return clone; } +std::vector EntityWrapper::ChildrenWithComponent(const std::string& componentType) +{ + std::vector childrenWithComponent; + childrenWithComponentRecursive(componentType, *this, childrenWithComponent); + return childrenWithComponent; +} + +void EntityWrapper::DeleteChildren() +{ + auto itPair = this->World->GetDirectChildren(this->ID); + if (itPair.first == itPair.second) { + return; + } + + std::vector entitiesToDelete; + for (auto it = itPair.first; it != itPair.second; it++) { + entitiesToDelete.push_back(it->second); + } + for (auto& e : entitiesToDelete) { + this->World->DeleteEntity(e); + } +} + bool EntityWrapper::IsChildOf(EntityWrapper potentialParent) { EntityWrapper entity = *this; @@ -101,6 +124,11 @@ ComponentWrapper EntityWrapper::operator[](const char* componentName) } } +ComponentWrapper EntityWrapper::operator[](const std::string& componentName) +{ + return this->operator[](componentName.c_str()); +} + bool EntityWrapper::operator==(const EntityWrapper& e) const { return (this->ID == e.ID) && (this->World == e.World); @@ -166,3 +194,18 @@ EntityWrapper EntityWrapper::cloneRecursive(EntityWrapper entity, EntityWrapper return clone; } +void EntityWrapper::childrenWithComponentRecursive(const std::string& componentType, EntityWrapper& entity, std::vector& childrenWithComponent) +{ + auto itPair = this->World->GetDirectChildren(entity.ID); + if (itPair.first == itPair.second) { + return; + } + + for (auto it = itPair.first; it != itPair.second; ++it) { + EntityWrapper child = EntityWrapper(entity.World, it->second); + if (child.HasComponent(componentType)) { + childrenWithComponent.push_back(child); + } + childrenWithComponentRecursive(componentType, child, childrenWithComponent); + } +} diff --git a/src/Engine/Core/Util/Logging.cpp b/src/Engine/Core/Util/Logging.cpp index 63a6f380..c7612fd8 100644 --- a/src/Engine/Core/Util/Logging.cpp +++ b/src/Engine/Core/Util/Logging.cpp @@ -33,8 +33,8 @@ void _LOG(_LOG_LEVEL logLevel, const char* file, const char* func, unsigned int va_end(args); if (logLevel == LOG_LEVEL_ERROR) { - std::cerr << file << ":" << line << " " << func << std::endl; - std::cerr << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl; + //std::cerr << file << ":" << line << " " << func << std::endl; + //std::cerr << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl; } else { std::cout << _LOG_LEVEL_PREFIX[logLevel] << message << std::endl; } diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 24b7cd1e..5388fd04 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -16,7 +16,7 @@ #include "Game/Systems/PickupSpawnSystem.h" #include "Game/Systems/AmmoPickupSystem.h" #include "Game/Systems/DamageIndicatorSystem.h" -#include "Game/Systems/Weapon/WeaponSystem.h" +#include "Game/Systems/Weapon/DefenderWeaponBehaviour.h" #include "Rendering/AnimationSystem.h" #include "Game/Systems/HealthHUDSystem.h" #include "Rendering/BoneAttachmentSystem.h" @@ -98,6 +98,10 @@ Game::Game(int argc, char* argv[]) m_NetworkClient->Connect(m_NetworkAddress, m_NetworkPort); m_Renderer->SetWindowTitle(m_Renderer->WindowTitle() + " CLIENT"); } + } else { + // If network is disabled, pretend we're a server + m_IsClient = true; + m_IsServer = true; } // Create Octrees @@ -120,7 +124,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_OctreeCollision); + m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); diff --git a/src/Game/Network/MultiplayerSnapshotFilter.cpp b/src/Game/Network/MultiplayerSnapshotFilter.cpp index 69b7f282..295cdd7a 100644 --- a/src/Game/Network/MultiplayerSnapshotFilter.cpp +++ b/src/Game/Network/MultiplayerSnapshotFilter.cpp @@ -13,6 +13,7 @@ bool MultiplayerSnapshotFilter::FilterComponent(EntityWrapper entity, SharedComp component.Info.Name == "Transform" || component.Info.Name == "Physics" || component.Info.Name == "AssaultWeapon" + || component.Info.Name == "DefenderWeapon" || component.Info.Name == "Animation" || component.Info.Name == "AnimationOffset" || entity.Name() == "PlayerName" diff --git a/src/Game/Systems/DamageIndicatorSystem.cpp b/src/Game/Systems/DamageIndicatorSystem.cpp index 92fbe607..ca26052d 100644 --- a/src/Game/Systems/DamageIndicatorSystem.cpp +++ b/src/Game/Systems/DamageIndicatorSystem.cpp @@ -13,7 +13,7 @@ DamageIndicatorSystem::DamageIndicatorSystem(SystemParams params) } void DamageIndicatorSystem::Update(double dt) { - if (!IsServer) { + if (!IsServer && LocalPlayer.Valid()) { for (auto& iter = updateDamageIndicatorVector.begin(); iter != updateDamageIndicatorVector.end(); iter++) { if (!iter->spriteEntity.Valid()) { updateDamageIndicatorVector.erase(iter); diff --git a/src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp b/src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp_ similarity index 87% rename from src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp rename to src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp_ index 84d3ccd4..c3b3385f 100644 --- a/src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp +++ b/src/Game/Systems/Weapon/AssaultWeaponBehaviour.cpp_ @@ -1,13 +1,5 @@ #include "Systems/Weapon/AssaultWeaponBehaviour.h" -AssaultWeaponBehaviour::AssaultWeaponBehaviour(SystemParams systemParams, IRenderer* renderer, Octree* collisionOctree, EntityWrapper player) - : WeaponBehaviour(systemParams, renderer, collisionOctree, player) -{ - m_FirstPersonModel = m_Player.FirstChildByName("Hands"); - m_ThirdPersonModel = m_Player.FirstChildByName("PlayerModel"); - EVENT_SUBSCRIBE_MEMBER(m_EAnimationComplete, &AssaultWeaponBehaviour::OnAnimationComplete); -} - void AssaultWeaponBehaviour::Fire() { m_TimeSinceLastFire = 0.0; @@ -36,7 +28,7 @@ void AssaultWeaponBehaviour::Reload() return; } - // Don't reload if we're completly out of ammo + // Don't reload if we're completely out of ammo if (ammo == 0) { playEmptySound(); m_TimeSinceLastFire = -0.0f; // HACK: To make empty sound play with interval @@ -56,14 +48,14 @@ void AssaultWeaponBehaviour::Update(double dt) { if (m_Reloading) { m_ReloadTimer -= dt; - // Re-enable glow on reload impersonator half-way through the animation + // Re-enable glow on reload impostor half-way through the animation if (IsClient) { if (m_ReloadTimer <= (double)m_Player["AssaultWeapon"]["ReloadTime"] / 2.0) { - if (m_FirstPersonReloadImpersonator.Valid()) { - m_FirstPersonReloadImpersonator["Model"]["GlowMap"] = true; + if (m_FirstPersonReloadImpostor.Valid()) { + m_FirstPersonReloadImpostor["Model"]["GlowMap"] = true; } - if (m_ThirdPersonReloadImpersonator.Valid()) { - m_ThirdPersonReloadImpersonator["Model"]["GlowMap"] = true; + if (m_ThirdPersonReloadImpostor.Valid()) { + m_ThirdPersonReloadImpostor["Model"]["GlowMap"] = true; } } } @@ -96,21 +88,6 @@ void AssaultWeaponBehaviour::Update(double dt) } } -bool AssaultWeaponBehaviour::OnAnimationComplete(Events::AnimationComplete& e) -{ - if (e.Entity != m_FirstPersonModel) { - return false; - } - - //if (e.Name == "ShootRifle") { - // if (!m_Firing) { - // playIdleAnimation(); - // } - //} - - return true; -} - bool AssaultWeaponBehaviour::hasAmmo() { ComponentWrapper& cAssaultWeapon = m_Player["AssaultWeapon"]; @@ -177,7 +154,6 @@ void AssaultWeaponBehaviour::spawnTracer() float AssaultWeaponBehaviour::traceRayDistance(glm::vec3 origin, glm::vec3 direction) { - // TODO: Cast a ray and size tracer appropriately float distance; glm::vec3 pos; auto entity = Collision::EntityFirstHitByRay(Ray(origin, direction), m_CollisionOctree, distance, pos); @@ -215,6 +191,12 @@ void AssaultWeaponBehaviour::playEmptySound() void AssaultWeaponBehaviour::viewPunch() { + // Since we send absolute client orientations to server, running this server side would + // cause aim desync. + if (!IsClient) { + return; + } + EntityWrapper playerCamera = m_Player.FirstChildByName("Camera"); if (!playerCamera.Valid()) { return; @@ -323,8 +305,8 @@ void AssaultWeaponBehaviour::playReloadAnimation() EntityWrapper firstPersonWeaponModel = m_Player.FirstChildByName("WeaponModel"); EntityWrapper reloadSpawner = m_Player.FirstChildByName("FirstPersonReloadSpawner"); if (IsClient) { - m_FirstPersonReloadImpersonator = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner); - firstPersonWeaponModel["Model"].Copy(m_FirstPersonReloadImpersonator["Model"]); + m_FirstPersonReloadImpostor = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner); + firstPersonWeaponModel["Model"].Copy(m_FirstPersonReloadImpostor["Model"]); } firstPersonWeaponModel["Model"]["Visible"] = false; } @@ -332,8 +314,8 @@ void AssaultWeaponBehaviour::playReloadAnimation() EntityWrapper thirdPersonWeaponModel = m_Player.FirstChildByName("ThirdPersonWeaponModel"); EntityWrapper reloadSpawner = m_Player.FirstChildByName("ThirdPersonReloadSpawner"); if (IsClient) { - m_ThirdPersonReloadImpersonator = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner); - thirdPersonWeaponModel["Model"].Copy(m_ThirdPersonReloadImpersonator["Model"]); + m_ThirdPersonReloadImpostor = SpawnerSystem::Spawn(reloadSpawner, reloadSpawner); + thirdPersonWeaponModel["Model"].Copy(m_ThirdPersonReloadImpostor["Model"]); } thirdPersonWeaponModel["Model"]["Visible"] = false; } @@ -371,7 +353,7 @@ bool AssaultWeaponBehaviour::shoot(double damage) return false; } - // Don't let us shoot ourselves in the foot + // Don't let us shoot ourselves in the foot somehow if (victim == LocalPlayer) { return false; } diff --git a/src/Game/Systems/Weapon/DefenderWeaponBehaviour.cpp b/src/Game/Systems/Weapon/DefenderWeaponBehaviour.cpp new file mode 100644 index 00000000..028bd10c --- /dev/null +++ b/src/Game/Systems/Weapon/DefenderWeaponBehaviour.cpp @@ -0,0 +1,188 @@ +#include "Systems/Weapon/DefenderWeaponBehaviour.h" + +void DefenderWeaponBehaviour::UpdateComponent(EntityWrapper& entity, ComponentWrapper& cWeapon, double dt) +{ + (double&)cWeapon["TimeSinceLastFire"] += dt; + WeaponBehaviour::UpdateComponent(entity, cWeapon, dt); +} + +void DefenderWeaponBehaviour::UpdateWeapon(WeaponInfo& wi, double dt) +{ + ComponentWrapper cWeapon = wi.GetComponent(); + + bool isFiring = cWeapon["IsFiring"]; + bool cooldownPassed = (double)cWeapon["TimeSinceLastFire"] >= (60.0 / (double)cWeapon["RPM"]); + bool isNotShielding = wi.Player.ChildrenWithComponent("Shield").size() == 0; + if (isFiring && cooldownPassed && isNotShielding) { + fireShell(wi); + } +} + +void DefenderWeaponBehaviour::OnPrimaryFire(WeaponInfo& wi) +{ + ComponentWrapper cWeapon = wi.GetComponent(); + cWeapon["IsFiring"] = true; + bool cooldownPassed = (double)cWeapon["TimeSinceLastFire"] >= (60.0 / (double)cWeapon["RPM"]); + bool isNotShielding = wi.Player.ChildrenWithComponent("Shield").size() == 0; + if (cooldownPassed && isNotShielding) { + fireShell(wi); + } +} + +void DefenderWeaponBehaviour::OnCeasePrimaryFire(WeaponInfo& wi) +{ + ComponentWrapper cWeapon = wi.GetComponent(); + cWeapon["IsFiring"] = false; +} + +bool DefenderWeaponBehaviour::OnInputCommand(WeaponInfo& wi, const Events::InputCommand& e) +{ + if (e.Command == "SpecialAbility" && IsServer) { + EntityWrapper attachment = wi.Player.FirstChildByName("ShieldAttachment"); + if (attachment.Valid()) { + if (e.Value > 0) { + SpawnerSystem::Spawn(attachment, attachment); + } else { + attachment.DeleteChildren(); + } + } + } + + return false; +} + +bool DefenderWeaponBehaviour::OnSetCamera(const Events::SetCamera& e) +{ + m_CurrentCamera = e.CameraEntity; + return true; +} + +void DefenderWeaponBehaviour::fireShell(WeaponInfo& wi) +{ + ComponentWrapper cWeapon = wi.GetComponent(); + + cWeapon["TimeSinceLastFire"] = 0.0; + int numPellets = cWeapon["NumPellets"]; + float spreadAngle = cWeapon["SpreadAngle"]; + std::uniform_real_distribution randomSpreadAngle(-spreadAngle, spreadAngle); + + // Calculate pellet angles + // HACK: Random for now? + // TODO: Make distribution even for each quadrant + std::vector pelletAngles; + for (int i = 0; i < numPellets; i++) { + pelletAngles.push_back(glm::vec2(randomSpreadAngle(m_RandomEngine), randomSpreadAngle(m_RandomEngine))); + LOG_DEBUG("%f %f", pelletAngles[i].x, pelletAngles[i].y); + } + + double pelletDamage = (double)cWeapon["BaseDamage"] / numPellets; + + // Tracers + EntityWrapper weaponModelEntity; + if (wi.Player == LocalPlayer) { + weaponModelEntity = wi.FirstPersonEntity; + } else { + weaponModelEntity = wi.ThirdPersonEntity; + } + if (weaponModelEntity.Valid()) { + EntityWrapper spawner = weaponModelEntity.FirstChildByName("WeaponMuzzle"); + for (auto& angles : pelletAngles) { + glm::vec3 direction = Transform::AbsoluteOrientation(spawner) * glm::quat(glm::vec3(angles, 0.f)) * glm::vec3(0, 0, -1); + float distance = traceRayDistance(Transform::AbsolutePosition(spawner), direction); + EntityWrapper ray = SpawnerSystem::Spawn(spawner); + ((glm::vec3&)ray["Transform"]["Scale"]).z = (distance / 100.f); + glm::vec3& orientation = ray["Transform"]["Orientation"]; + orientation.x += angles.x; + orientation.y += angles.y; + glm::vec3 trajectory = direction * distance; + dealDamage(wi, direction, pelletDamage); + } + } + +} + +void DefenderWeaponBehaviour::dealDamage(WeaponInfo& wi, glm::vec3 direction, double damage) +{ + // Only deal damage client side + if (!IsClient) { + return; + } + + // Only handle shooting for the local player + if (wi.Player != LocalPlayer) { + return; + } + + // Make sure the player isn't shooting from the grave + if (!wi.Player.Valid()) { + return; + } + + glm::vec3 maxRange = direction * 2.f; + EntityWrapper camera = wi.Player.FirstChildByName("Camera"); + glm::vec3 cameraPosition = Transform::AbsolutePosition(camera); + if (!camera.Valid()) { + return; + } + Rectangle screenResolution = m_Renderer->GetViewportSize(); + glm::vec2 centerScreen = glm::vec2(screenResolution.Width / 2, screenResolution.Height / 2); + glm::vec2 screenCoords = cameraFromEntity(m_CurrentCamera).WorldToScreen(cameraPosition + maxRange, m_Renderer->GetViewportSize()); + PickData pickData = m_Renderer->Pick(centerScreen + screenCoords); + EntityWrapper victim(m_World, pickData.Entity); + if (!victim.Valid()) { + return; + } + + // Don't let us shoot ourselves in the foot somehow + if (victim == LocalPlayer) { + return; + } + + // Only care about players being hit + if (!victim.HasComponent("Player")) { + victim = victim.FirstParentWithComponent("Player"); + } + if (!victim.Valid()) { + return; + } + + // Check for friendly fire + if ((ComponentInfo::EnumType)victim["Team"]["Team"] == (ComponentInfo::EnumType)wi.Player["Team"]["Team"]) { + return; + } + + // Deal damage! + Events::PlayerDamage ePlayerDamage; + ePlayerDamage.Inflictor = wi.Player; + ePlayerDamage.Victim = victim; + ePlayerDamage.Damage = damage; + m_EventBroker->Publish(ePlayerDamage); + LOG_DEBUG("Damage: %f", damage); +} + +float DefenderWeaponBehaviour::traceRayDistance(glm::vec3 origin, glm::vec3 direction) +{ + float distance; + glm::vec3 pos; + auto entity = Collision::EntityFirstHitByRay(Ray(origin, direction), m_CollisionOctree, distance, pos); + if (entity) { + return distance; + } else { + return 100.f; + } +} + +Camera DefenderWeaponBehaviour::cameraFromEntity(EntityWrapper camera) +{ + ComponentWrapper cTransform = camera["Transform"]; + ComponentWrapper cCamera = camera["Camera"]; + Camera cam( + (float)m_Renderer->Resolution().Width / m_Renderer->Resolution().Height, + (double)cCamera["FOV"], + (double)cCamera["NearClip"], + (double)cCamera["FarClip"] + ); + cam.SetPosition(cTransform["Position"]); + cam.SetOrientation(glm::quat((const glm::vec3&)cTransform["Orientation"])); + return cam; +} diff --git a/src/Game/Systems/Weapon/WeaponSystem.cpp b/src/Game/Systems/Weapon/WeaponSystem.cpp_ similarity index 56% rename from src/Game/Systems/Weapon/WeaponSystem.cpp rename to src/Game/Systems/Weapon/WeaponSystem.cpp_ index 3a49ae90..d33c5098 100644 --- a/src/Game/Systems/Weapon/WeaponSystem.cpp +++ b/src/Game/Systems/Weapon/WeaponSystem.cpp_ @@ -13,7 +13,7 @@ WeaponSystem::WeaponSystem(SystemParams params, IRenderer* renderer, Octree weaponAttachments = player.ChildrenWithComponent("WeaponAttachment"); + + // Find the weapon attachments matching the slot selected + EntityWrapper firstPersonAttachment; + EntityWrapper thirdPersonAttachment; + for (auto& attachment : weaponAttachments) { + ComponentWrapper cWeaponAttachment = attachment["WeaponAttachment"]; + if ((ComponentInfo::EnumType)cWeaponAttachment["Slot"] == slot) { + ComponentWrapper::SubscriptProxy person = cWeaponAttachment["Person"]; + if (person == person.Enum("FirstPerson")) { + firstPersonAttachment = attachment; + } else if (person == person.Enum("ThirdPerson")) { + thirdPersonAttachment = attachment; + } + } + } + + if (firstPersonAttachment.Valid() && thirdPersonAttachment.Valid()) { + LOG_WARNING("No weapon attachment found for slot %i of player #%i", slot, player.ID); + return; + } + + // TODO: Delete old weapons + + // Spawn the weapon(s) + EntityWrapper firstPersonWeapon; + EntityWrapper thirdPersonWeapon; + if (firstPersonAttachment.Valid()) { + firstPersonWeapon = SpawnerSystem::Spawn(firstPersonAttachment, firstPersonAttachment); + } + if (thirdPersonAttachment.Valid()) { + firstPersonWeapon = SpawnerSystem::Spawn(thirdPersonAttachment, thirdPersonAttachment); + } + + // Create the correct behaviour + if (firstPersonWeapon.Valid()) { + if (firstPersonWeapon.HasComponent("AssaultWeapon") { + + } + } + // Primary if (slot == 1) { // TODO: if class... - if (m_ActiveWeapons.count(player) == 0) { - m_ActiveWeapons.insert(std::make_pair(player, std::make_shared(m_SystemParams, m_Renderer, m_CollisionOctree, player))); - } else { - //m_ActiveWeapons.erase(player); - } + nextBehaviour = std::make_shared(m_SystemParams, m_Renderer, m_CollisionOctree, player); } // Secondary if (slot == 2) { //m_ActiveWeapons[player] = std::make_shared(); } + + if (nextBehaviour != nullptr) { + // TODO: Destroy previous behaviour and make new + if (m_ActiveWeapons.count(player) == 0) { + m_ActiveWeapons[player] = nextBehaviour; + } + } } bool WeaponSystem::OnPlayerSpawned(Events::PlayerSpawned& e) From db5170c6993baf18f0bb5be8a49fa36f44b76093 Mon Sep 17 00:00:00 2001 From: William Moberg Date: Mon, 29 Feb 2016 09:37:51 +0100 Subject: [PATCH 3/6] WIP, should take shortest resolution even if forced upwards because of slopes, not solving the jittering problem though. + debug code. --- src/Engine/Collision/Collision.cpp | 156 ++++++++++++++++------- src/Engine/Collision/CollisionSystem.cpp | 2 + 2 files changed, 113 insertions(+), 45 deletions(-) diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 68d99d92..166518c5 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -380,11 +380,11 @@ bool AABBvsTriangle(const AABB& box, enum BoxTriResolveCase { - ResolveDimX, - ResolveDimY, - ResolveDimZ, - Line, //Box edge colliding with triangle line. - Corner //Box corner colliding with the triangle face. + EResolveDimX, + EResolveDimY, + EResolveDimZ, + ELine, //Box edge colliding with triangle line. + ECorner //Box corner colliding with the triangle face. }; struct Resolution { @@ -396,10 +396,55 @@ bool AABBvsTriangle(const AABB& box, float DistanceSq; glm::vec3 Vector; }; + struct CaseResolutions + { + Resolution Vertex; + Resolution Line; + Resolution Corner; + Resolution* Shortest = &Vertex; + + void AddResolution(BoxTriResolveCase resCase, float distanceSq, const glm::vec3& resVec) + { + switch (resCase) { + case EResolveDimY: + case EResolveDimX: + case EResolveDimZ: + if (distanceSq < Vertex.DistanceSq) { + Vertex.Vector = resVec; + Vertex.DistanceSq = distanceSq; + Vertex.Case = resCase; + if (distanceSq < Line.DistanceSq) { + Shortest = &Vertex; + } + } + break; + case ELine: + if (distanceSq < Vertex.DistanceSq && distanceSq < Line.DistanceSq) { + Line.Vector = resVec; + Line.DistanceSq = distanceSq; + Line.Case = resCase; + Shortest = &Line; + } + break; + case ECorner: + //NOTE: It is assumed that the Corner is less than the + //added resolution, since only one corner should be added per triangle. + if (distanceSq < Vertex.DistanceSq && distanceSq < Line.DistanceSq) { + Corner.Vector = resVec; + Corner.DistanceSq = distanceSq; + Corner.Case = resCase; + Shortest = &Corner; + } + break; + default: + break; + } + } + }; //The smallest resolution that solves the collision. - Resolution resolveShortest; + CaseResolutions resolveShortest; //The smallest resolution that solves the collision, that resolves upwards. - Resolution resolveUpwards; + CaseResolutions resolveUpwards; //If player stands on the ground and collides with a ground triangle, //we might step up onto it if the step is small enough. bool canStairStepUp = isOnGround && FaceIsGround(triNormal.y); @@ -421,34 +466,27 @@ bool AABBvsTriangle(const AABB& box, //Project box. glm::vec2 boxMin(min[dim.first], min[dim.second]); glm::vec2 boxMax(max[dim.first], max[dim.second]); - glm::vec2 resolutionVector; - float resolutionDist; + glm::vec2 resolutionVector2D; + float resolutionDistSq; bool pushedFromTriangleLine; //if projections don't overlap, return false. - if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) { + if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector2D, resolutionDistSq, pushedFromTriangleLine)) { return false; } else if (resolveCollision) { + glm::vec3 resolve3D = glm::vec3(0.f); + resolve3D[dim.first] = resolutionVector2D.x; + resolve3D[dim.second] = resolutionVector2D.y; + //If we pushed away from triangle line (edge), or if we + //move the player along one coordinate axis (pick the dimension that isn't zero). + BoxTriResolveCase resCase = pushedFromTriangleLine ? ELine : static_cast((abs(resolve3D[dim.first]) < 0.0001f) ? dim.second : dim.first); //Overwrite the smallest resolution if this is smaller. - if (resolutionDist < resolveShortest.DistanceSq) { - resolveShortest.Vector = glm::vec3(0.f); - resolveShortest.Vector[dim.first] = resolutionVector.x; - resolveShortest.Vector[dim.second] = resolutionVector.y; - resolveShortest.DistanceSq = resolutionDist; - //If we pushed away from triangle line (edge), or if we - //move the player along one coordinate axis (pick the dimension that isn't zero). - resolveShortest.Case = pushedFromTriangleLine ? Line : static_cast((abs(resolveShortest.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first); - } + resolveShortest.AddResolution(resCase, resolutionDistSq, resolve3D); + //Overwrite the smallest upward resolution if this is smaller, and resolves upwards. constexpr int yAxis = 1; - bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector.x > 0 || dim.second == yAxis && resolutionVector.y > 0; - if (canStairStepUp && resIsUpwardsIn3D && resolutionDist < resolveUpwards.DistanceSq) { - resolveUpwards.Vector = glm::vec3(0.f); - resolveUpwards.Vector[dim.first] = resolutionVector.x; - resolveUpwards.Vector[dim.second] = resolutionVector.y; - resolveUpwards.DistanceSq = resolutionDist; - //If we pushed away from triangle line (edge), or if we - //move the player along one coordinate axis (pick the dimension that isn't zero). - resolveUpwards.Case = pushedFromTriangleLine ? Line : static_cast((abs(resolveUpwards.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first); + bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector2D.x > 0 || dim.second == yAxis && resolutionVector2D.y > 0; + if (canStairStepUp && resIsUpwardsIn3D) { + resolveUpwards.AddResolution(resCase, resolutionDistSq, resolve3D); } } } @@ -472,37 +510,40 @@ bool AABBvsTriangle(const AABB& box, glm::vec3 cornerResolution = (1+t) * diagonal; //Overwrite the smallest resolution if cornerResolution is smaller. float lenSq = glm::length2(cornerResolution); - if (lenSq < resolveShortest.DistanceSq) { - resolveShortest.Vector = cornerResolution; - resolveShortest.Case = Corner; - } - if (canStairStepUp && cornerResolution.y > 0 && lenSq < resolveUpwards.DistanceSq) { - resolveUpwards.Vector = cornerResolution; - resolveUpwards.Case = Corner; - resolveUpwards.DistanceSq = lenSq; + resolveShortest.AddResolution(ECorner, lenSq, cornerResolution); + if (canStairStepUp && cornerResolution.y > 0) { + resolveUpwards.AddResolution(ECorner, lenSq, cornerResolution); } //Force the resolution upwards if it is smaller than the threshold verticalStepHeight. //Else take the shortest resolution. - bool takeUp = resolveUpwards.Vector.y > 0 && resolveUpwards.Vector.y < verticalStepHeight; - Resolution& bestResolve = takeUp ? resolveUpwards : resolveShortest; - outResolution = bestResolve.Vector; + bool takeUp = resolveUpwards.Shortest->Vector.y > 0 && resolveUpwards.Shortest->Vector.y < verticalStepHeight; + CaseResolutions& bestResolve = takeUp ? resolveUpwards : resolveShortest; + outResolution = bestResolve.Shortest->Vector; + std::string dbgString = ""; glm::vec3 projNorm; - switch (bestResolve.Case) { - case ResolveDimY: + switch (bestResolve.Shortest->Case) { + case EResolveDimY: boxVelocity.y = 0.f; if (outResolution.y > 0) isOnGround = true; - case ResolveDimX: - case ResolveDimZ: + case EResolveDimX: + case EResolveDimZ: //If we get here, the resolution is along one coordinate axis. //set velocity to 0 in y if it is along y-axis. + dbgString = "Vertex Collision"; + dbgString += isOnGround ? " Ground" : " Air"; + dbgString += takeUp ? " Force up" : " Normal"; + std::cout << (dbgString.c_str()) << std::endl; + ImGui::Text(dbgString.c_str()); return true; - case Line: + case ELine: + dbgString = "Line Collision"; projNorm = glm::normalize(outResolution); break; - case Corner: + case ECorner: + dbgString = "Corner Collision"; projNorm = triNormal; break; default: @@ -519,6 +560,23 @@ bool AABBvsTriangle(const AABB& box, outResolution.y = len / glm::sin(ang); outResolution.z = 0; } + float y; + if (bestResolve.Shortest->Case == ECorner) { + len = glm::length(bestResolve.Line.Vector); + ang = glm::half_pi() - glm::acos(bestResolve.Line.Vector.y / len); + if (len > 0.0000001f && ang > 0.0000001f) { + y = len / glm::sin(ang); + if (y < outResolution.y) { + outResolution.x = 0; + outResolution.y = y; + outResolution.z = 0; + } + } + } + y = bestResolve.Vertex.Vector.y; + if (bestResolve.Vertex.Case == EResolveDimY && y < outResolution.y) { + outResolution.y = y; + } //Also zero the vertical velocity, if it is positive, else project it onto the normal. //Project the velocity onto the normal of the hit line/face. //w = v - *n, |n|==1. @@ -533,6 +591,10 @@ bool AABBvsTriangle(const AABB& box, boxVelocity = boxVelocity - glm::dot(boxVelocity, projNorm) * projNorm; } } + dbgString += isOnGround ? " Ground" : " Air"; + dbgString += takeUp ? " Force up" : " Normal"; + std::cout << (dbgString.c_str()) << std::endl; + ImGui::Text(dbgString.c_str()); return true; } @@ -546,6 +608,7 @@ bool AABBvsTriangles(const AABB& box, glm::vec3& outResolutionVector, bool resolveCollision) { + std::cout << ("---->>>--AABBvsTriangles--------") << std::endl; bool hit = false; bool everHitTheGround = false; @@ -573,6 +636,9 @@ bool AABBvsTriangles(const AABB& box, if (!everHitTheGround) { isOnGround = false; } + std::cout << (isOnGround ? "Hit Ground" : "In Air") << std::endl; + ImGui::Text(isOnGround ? "Hit Ground" : "In Air"); + std::cout << ("--------AABBvsTriangles---->>>--") << std::endl; return hit; } diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 9689bf13..30b60df9 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -12,6 +12,7 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c if (!boundingBox) { return; } + std::cout << "---->>>--Start Update--------" << std::endl; ComponentWrapper& cTransform = entity["Transform"]; EntityAABB& boxA = *boundingBox; bool everHitTheGround = false; @@ -115,4 +116,5 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c } m_PrevPositions[entity] = boxA.Origin(); + std::cout << "--------End Update---->>>--" << std::endl; } From 8e21c5a5e42b2fafcff7b20348146881d143823c Mon Sep 17 00:00:00 2001 From: William Moberg Date: Mon, 29 Feb 2016 15:38:36 +0100 Subject: [PATCH 4/6] Reverts last WIP since it probably added code without improving anything. Revert "WIP, should take shortest resolution even if forced upwards because of slopes, not solving the jittering problem though. + debug code." This reverts commit db5170c6993baf18f0bb5be8a49fa36f44b76093. --- src/Engine/Collision/Collision.cpp | 156 +++++++---------------- src/Engine/Collision/CollisionSystem.cpp | 2 - 2 files changed, 45 insertions(+), 113 deletions(-) diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 166518c5..68d99d92 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -380,11 +380,11 @@ bool AABBvsTriangle(const AABB& box, enum BoxTriResolveCase { - EResolveDimX, - EResolveDimY, - EResolveDimZ, - ELine, //Box edge colliding with triangle line. - ECorner //Box corner colliding with the triangle face. + ResolveDimX, + ResolveDimY, + ResolveDimZ, + Line, //Box edge colliding with triangle line. + Corner //Box corner colliding with the triangle face. }; struct Resolution { @@ -396,55 +396,10 @@ bool AABBvsTriangle(const AABB& box, float DistanceSq; glm::vec3 Vector; }; - struct CaseResolutions - { - Resolution Vertex; - Resolution Line; - Resolution Corner; - Resolution* Shortest = &Vertex; - - void AddResolution(BoxTriResolveCase resCase, float distanceSq, const glm::vec3& resVec) - { - switch (resCase) { - case EResolveDimY: - case EResolveDimX: - case EResolveDimZ: - if (distanceSq < Vertex.DistanceSq) { - Vertex.Vector = resVec; - Vertex.DistanceSq = distanceSq; - Vertex.Case = resCase; - if (distanceSq < Line.DistanceSq) { - Shortest = &Vertex; - } - } - break; - case ELine: - if (distanceSq < Vertex.DistanceSq && distanceSq < Line.DistanceSq) { - Line.Vector = resVec; - Line.DistanceSq = distanceSq; - Line.Case = resCase; - Shortest = &Line; - } - break; - case ECorner: - //NOTE: It is assumed that the Corner is less than the - //added resolution, since only one corner should be added per triangle. - if (distanceSq < Vertex.DistanceSq && distanceSq < Line.DistanceSq) { - Corner.Vector = resVec; - Corner.DistanceSq = distanceSq; - Corner.Case = resCase; - Shortest = &Corner; - } - break; - default: - break; - } - } - }; //The smallest resolution that solves the collision. - CaseResolutions resolveShortest; + Resolution resolveShortest; //The smallest resolution that solves the collision, that resolves upwards. - CaseResolutions resolveUpwards; + Resolution resolveUpwards; //If player stands on the ground and collides with a ground triangle, //we might step up onto it if the step is small enough. bool canStairStepUp = isOnGround && FaceIsGround(triNormal.y); @@ -466,27 +421,34 @@ bool AABBvsTriangle(const AABB& box, //Project box. glm::vec2 boxMin(min[dim.first], min[dim.second]); glm::vec2 boxMax(max[dim.first], max[dim.second]); - glm::vec2 resolutionVector2D; - float resolutionDistSq; + glm::vec2 resolutionVector; + float resolutionDist; bool pushedFromTriangleLine; //if projections don't overlap, return false. - if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector2D, resolutionDistSq, pushedFromTriangleLine)) { + if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) { return false; } else if (resolveCollision) { - glm::vec3 resolve3D = glm::vec3(0.f); - resolve3D[dim.first] = resolutionVector2D.x; - resolve3D[dim.second] = resolutionVector2D.y; - //If we pushed away from triangle line (edge), or if we - //move the player along one coordinate axis (pick the dimension that isn't zero). - BoxTriResolveCase resCase = pushedFromTriangleLine ? ELine : static_cast((abs(resolve3D[dim.first]) < 0.0001f) ? dim.second : dim.first); //Overwrite the smallest resolution if this is smaller. - resolveShortest.AddResolution(resCase, resolutionDistSq, resolve3D); - + if (resolutionDist < resolveShortest.DistanceSq) { + resolveShortest.Vector = glm::vec3(0.f); + resolveShortest.Vector[dim.first] = resolutionVector.x; + resolveShortest.Vector[dim.second] = resolutionVector.y; + resolveShortest.DistanceSq = resolutionDist; + //If we pushed away from triangle line (edge), or if we + //move the player along one coordinate axis (pick the dimension that isn't zero). + resolveShortest.Case = pushedFromTriangleLine ? Line : static_cast((abs(resolveShortest.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first); + } //Overwrite the smallest upward resolution if this is smaller, and resolves upwards. constexpr int yAxis = 1; - bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector2D.x > 0 || dim.second == yAxis && resolutionVector2D.y > 0; - if (canStairStepUp && resIsUpwardsIn3D) { - resolveUpwards.AddResolution(resCase, resolutionDistSq, resolve3D); + bool resIsUpwardsIn3D = dim.first == yAxis && resolutionVector.x > 0 || dim.second == yAxis && resolutionVector.y > 0; + if (canStairStepUp && resIsUpwardsIn3D && resolutionDist < resolveUpwards.DistanceSq) { + resolveUpwards.Vector = glm::vec3(0.f); + resolveUpwards.Vector[dim.first] = resolutionVector.x; + resolveUpwards.Vector[dim.second] = resolutionVector.y; + resolveUpwards.DistanceSq = resolutionDist; + //If we pushed away from triangle line (edge), or if we + //move the player along one coordinate axis (pick the dimension that isn't zero). + resolveUpwards.Case = pushedFromTriangleLine ? Line : static_cast((abs(resolveUpwards.Vector[dim.first]) < 0.0001f) ? dim.second : dim.first); } } } @@ -510,40 +472,37 @@ bool AABBvsTriangle(const AABB& box, glm::vec3 cornerResolution = (1+t) * diagonal; //Overwrite the smallest resolution if cornerResolution is smaller. float lenSq = glm::length2(cornerResolution); - resolveShortest.AddResolution(ECorner, lenSq, cornerResolution); - if (canStairStepUp && cornerResolution.y > 0) { - resolveUpwards.AddResolution(ECorner, lenSq, cornerResolution); + if (lenSq < resolveShortest.DistanceSq) { + resolveShortest.Vector = cornerResolution; + resolveShortest.Case = Corner; + } + if (canStairStepUp && cornerResolution.y > 0 && lenSq < resolveUpwards.DistanceSq) { + resolveUpwards.Vector = cornerResolution; + resolveUpwards.Case = Corner; + resolveUpwards.DistanceSq = lenSq; } //Force the resolution upwards if it is smaller than the threshold verticalStepHeight. //Else take the shortest resolution. - bool takeUp = resolveUpwards.Shortest->Vector.y > 0 && resolveUpwards.Shortest->Vector.y < verticalStepHeight; - CaseResolutions& bestResolve = takeUp ? resolveUpwards : resolveShortest; - outResolution = bestResolve.Shortest->Vector; + bool takeUp = resolveUpwards.Vector.y > 0 && resolveUpwards.Vector.y < verticalStepHeight; + Resolution& bestResolve = takeUp ? resolveUpwards : resolveShortest; + outResolution = bestResolve.Vector; - std::string dbgString = ""; glm::vec3 projNorm; - switch (bestResolve.Shortest->Case) { - case EResolveDimY: + switch (bestResolve.Case) { + case ResolveDimY: boxVelocity.y = 0.f; if (outResolution.y > 0) isOnGround = true; - case EResolveDimX: - case EResolveDimZ: + case ResolveDimX: + case ResolveDimZ: //If we get here, the resolution is along one coordinate axis. //set velocity to 0 in y if it is along y-axis. - dbgString = "Vertex Collision"; - dbgString += isOnGround ? " Ground" : " Air"; - dbgString += takeUp ? " Force up" : " Normal"; - std::cout << (dbgString.c_str()) << std::endl; - ImGui::Text(dbgString.c_str()); return true; - case ELine: - dbgString = "Line Collision"; + case Line: projNorm = glm::normalize(outResolution); break; - case ECorner: - dbgString = "Corner Collision"; + case Corner: projNorm = triNormal; break; default: @@ -560,23 +519,6 @@ bool AABBvsTriangle(const AABB& box, outResolution.y = len / glm::sin(ang); outResolution.z = 0; } - float y; - if (bestResolve.Shortest->Case == ECorner) { - len = glm::length(bestResolve.Line.Vector); - ang = glm::half_pi() - glm::acos(bestResolve.Line.Vector.y / len); - if (len > 0.0000001f && ang > 0.0000001f) { - y = len / glm::sin(ang); - if (y < outResolution.y) { - outResolution.x = 0; - outResolution.y = y; - outResolution.z = 0; - } - } - } - y = bestResolve.Vertex.Vector.y; - if (bestResolve.Vertex.Case == EResolveDimY && y < outResolution.y) { - outResolution.y = y; - } //Also zero the vertical velocity, if it is positive, else project it onto the normal. //Project the velocity onto the normal of the hit line/face. //w = v - *n, |n|==1. @@ -591,10 +533,6 @@ bool AABBvsTriangle(const AABB& box, boxVelocity = boxVelocity - glm::dot(boxVelocity, projNorm) * projNorm; } } - dbgString += isOnGround ? " Ground" : " Air"; - dbgString += takeUp ? " Force up" : " Normal"; - std::cout << (dbgString.c_str()) << std::endl; - ImGui::Text(dbgString.c_str()); return true; } @@ -608,7 +546,6 @@ bool AABBvsTriangles(const AABB& box, glm::vec3& outResolutionVector, bool resolveCollision) { - std::cout << ("---->>>--AABBvsTriangles--------") << std::endl; bool hit = false; bool everHitTheGround = false; @@ -636,9 +573,6 @@ bool AABBvsTriangles(const AABB& box, if (!everHitTheGround) { isOnGround = false; } - std::cout << (isOnGround ? "Hit Ground" : "In Air") << std::endl; - ImGui::Text(isOnGround ? "Hit Ground" : "In Air"); - std::cout << ("--------AABBvsTriangles---->>>--") << std::endl; return hit; } diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 30b60df9..9689bf13 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -12,7 +12,6 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c if (!boundingBox) { return; } - std::cout << "---->>>--Start Update--------" << std::endl; ComponentWrapper& cTransform = entity["Transform"]; EntityAABB& boxA = *boundingBox; bool everHitTheGround = false; @@ -116,5 +115,4 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c } m_PrevPositions[entity] = boxA.Origin(); - std::cout << "--------End Update---->>>--" << std::endl; } From d47a806c64e8d1711ad448af169f98463feb1c4d Mon Sep 17 00:00:00 2001 From: William Moberg Date: Mon, 29 Feb 2016 15:49:23 +0100 Subject: [PATCH 5/6] Made a easy hack to solve jittering when standing still. Jittering should still be present when moving, but at least it is less prominent when moving. --- src/Engine/Collision/CollisionSystem.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Engine/Collision/CollisionSystem.cpp b/src/Engine/Collision/CollisionSystem.cpp index 9689bf13..95609ea6 100644 --- a/src/Engine/Collision/CollisionSystem.cpp +++ b/src/Engine/Collision/CollisionSystem.cpp @@ -12,6 +12,7 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c if (!boundingBox) { return; } + ComponentWrapper& cTransform = entity["Transform"]; EntityAABB& boxA = *boundingBox; bool everHitTheGround = false; @@ -86,10 +87,12 @@ void CollisionSystem::UpdateComponent(EntityWrapper& entity, ComponentWrapper& c glm::mat4 modelMatrix = Transform::ModelMatrix(boxB.Entity); glm::vec3 inOutVelocity = (glm::vec3)cPhysics["Velocity"]; + bool notMovingxz = glm::all(glm::lessThan(glm::abs(glm::vec2(inOutVelocity.x, inOutVelocity.z)), glm::vec2(0.01f))) && prevPosIt != m_PrevPositions.end(); bool isOnGround = (bool)cPhysics["IsOnGround"]; float verticalStepHeight = (float)(double)cPhysics["VerticalStepHeight"]; if (Collision::AABBvsTriangles(boxA, model->Vertices(), model->m_Indices, modelMatrix, inOutVelocity, verticalStepHeight, isOnGround, resolutionVector)) { - (glm::vec3&)cTransform["Position"] += resolutionVector; + //Move the position to previous position if it is not moving in the xz-plane, else resolve with the resolution vector. + (glm::vec3&)cTransform["Position"] += notMovingxz ? prevPosIt->second - boxA.Origin() : resolutionVector; boxA = *Collision::EntityAbsoluteAABB(entity); cPhysics["Velocity"] = inOutVelocity; if (isOnGround) { From 3c35c0a956ce470e2abef733f99aea0dbe61221a Mon Sep 17 00:00:00 2001 From: William Moberg Date: Mon, 29 Feb 2016 15:50:26 +0100 Subject: [PATCH 6/6] Frustum culling octree updates after collisions, no more disappearing weapons. --- src/Game/Game.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 24b7cd1e..65dbf7e5 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -135,7 +135,6 @@ Game::Game(int argc, char* argv[]) ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision, "Collidable"); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger, "Player"); - m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeFrustrumCulling); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel); @@ -145,6 +144,9 @@ Game::Game(int argc, char* argv[]) m_SystemPipeline->AddSystem(updateOrderLevel); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeCollision); m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeTrigger); + // Octree for frustum culling must be updated after collisions, otherwise players frustum may be moved after tree is filled, and wrong things are culled. + ++updateOrderLevel; + m_SystemPipeline->AddSystem(updateOrderLevel, m_OctreeFrustrumCulling); ++updateOrderLevel; m_SystemPipeline->AddSystem(updateOrderLevel, m_Renderer, m_RenderFrame, m_OctreeFrustrumCulling); ++updateOrderLevel;