From 2d5f71e442270b416a9ec08f758a4135bea91e97 Mon Sep 17 00:00:00 2001 From: verysecrethero Date: Wed, 10 Feb 2016 16:25:47 +0100 Subject: [PATCH 01/12] Added 3 PickupSpawnSystem tests. --- src/Tests/PickupSpawnTest.cpp | 205 ++++++++++++++++++++++++++++++++++ src/Tests/PickupSpawnTest.h | 73 ++++++++++++ 2 files changed, 278 insertions(+) create mode 100644 src/Tests/PickupSpawnTest.cpp create mode 100644 src/Tests/PickupSpawnTest.h diff --git a/src/Tests/PickupSpawnTest.cpp b/src/Tests/PickupSpawnTest.cpp new file mode 100644 index 00000000..ebddb71f --- /dev/null +++ b/src/Tests/PickupSpawnTest.cpp @@ -0,0 +1,205 @@ +#include +using boost::unit_test_framework::test_suite; +using boost::unit_test_framework::test_case; + +#include "PickupSpawnTest.h" + + +BOOST_AUTO_TEST_SUITE(PickupSpawnTestSuite) + +//dont use the same name as the classname in test cases... +BOOST_AUTO_TEST_CASE(PickupSpawnTest_HealthPickupRespawns_PlayerHealthPickupEventTriggers) +{ + PickupSpawnTest game(1); + bool success = game.Game_Loop_OneHundredTimes(); + BOOST_TEST(success); +} +BOOST_AUTO_TEST_CASE(PickupSpawnTest_APlayerAtMaxHealth_CantTakeHealthPickup) +{ + PickupSpawnTest game(2); + bool success = game.Game_Loop_OneHundredTimes(); + BOOST_TEST(success); +} +BOOST_AUTO_TEST_CASE(PickupSpawnTest_APickupCanRespawnSlowly) +{ + PickupSpawnTest game(3); + bool success = game.Game_Loop_OneHundredTimes(); + BOOST_TEST(success); +} +BOOST_AUTO_TEST_SUITE_END() + +PickupSpawnTest::PickupSpawnTest(int runTestNumber) +{ + ResourceManager::RegisterType("ConfigFile"); + ResourceManager::RegisterType("EntityFile"); + + m_Config = ResourceManager::Load("Config.ini"); + LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get("Debug.LogLevel", 1)); + + m_EventBroker = new EventBroker(); + m_World = new World(); + + // Create system pipeline + m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker); + m_SystemPipeline->AddSystem(0); + m_SystemPipeline->AddSystem(1); + + //must register components (Components.xsd), else you cant create entities. Easiest done by loading a test xsd file + auto file = ResourceManager::Load("Schema/Entities/HealthPickup.xml"); + EntityFilePreprocessor fpp(file); + fpp.RegisterComponents(m_World); + EntityFileParser fp(file); + //connect the healthpickup to the world + m_HealthPickupID = fp.MergeEntities(m_World); + + //create a player + m_PlayerID = m_World->CreateEntity(); + auto& player = m_World->AttachComponent(m_PlayerID, "Player"); + + m_RunTestNumber = runTestNumber; + + //further testsetups + TestSetup(m_RunTestNumber); + + //init glfw so dt works + glfwInit(); + + //listen to the 2 events that are related to PickupSpawn + EVENT_SUBSCRIBE_MEMBER(m_HP, &PickupSpawnTest::OnHealthPickup); + EVENT_SUBSCRIBE_MEMBER(m_PS, &PickupSpawnTest::OnPickupSpawned); +} + +bool PickupSpawnTest::OnHealthPickup(Events::PlayerHealthPickup& e) { + //very that the event has the correct healthgain number and playerid + if (m_RunTestNumber == 1) { + if (e.HealthAmount == 22.0 && e.Player.ID == m_PlayerID) { + testStage1Success = true; + } + } + if (m_RunTestNumber == 2) { + testStage1Success = false; + } + if (m_RunTestNumber == 3) { + if (e.HealthAmount == 50.0 && e.Player.ID == m_PlayerID) { + testStage1Success = true; + } + } + return true; +} +bool PickupSpawnTest::OnPickupSpawned(Events::PickupSpawned& e) { + //verify that the newly spawned pickup has the same variable values as the original one + if (m_RunTestNumber == 1) { + if ((double)e.Pickup["HealthPickup"]["HealthGain"] == 22.0 && (double)e.Pickup["HealthPickup"]["RespawnTimer"] == 2.0) { + testStage2Success = true; + } + } + if (m_RunTestNumber == 2) { + testStage2Success = false; + } + if (m_RunTestNumber == 3) { + testStage2Success = false; + } + return true; +} + +void PickupSpawnTest::TestSetup(int testNumber) +{ + //cant use switch here, since each case might initialize different variables + if (m_RunTestNumber == 1) { + //PickupSpawnTest_HealthPickupRespawns_PlayerHealthPickupEventTriggers + auto& healthPickupEW = EntityWrapper(m_World, m_HealthPickupID); + healthPickupEW["HealthPickup"]["RespawnTimer"] = 2.0; + healthPickupEW["HealthPickup"]["HealthGain"] = 22.0; + + //create a player + auto& health = m_World->AttachComponent(m_PlayerID, "Health"); + health["Health"] = 20.0; + health["MaxHealth"] = 100.0; + + Events::TriggerTouch eTriggerTouch; + DoTouchEvent(m_PlayerID, m_HealthPickupID); + } + if (m_RunTestNumber == 2) { + //PickupSpawnTest_APlayerAtMaxHealth_CantTakeHealthPickup + auto& healthPickupEW = EntityWrapper(m_World, m_HealthPickupID); + healthPickupEW["HealthPickup"]["RespawnTimer"] = 1.0; + healthPickupEW["HealthPickup"]["HealthGain"] = 50.0; + + //create a player at max health + auto& health = m_World->AttachComponent(m_PlayerID, "Health"); + health["Health"] = 100.0; + health["MaxHealth"] = 100.0; + + Events::TriggerTouch eTriggerTouch; + DoTouchEvent(m_PlayerID, m_HealthPickupID); + } + if (m_RunTestNumber == 3) { + //PickupSpawnTest_APickupCanRespawnSlowly + auto& healthPickupEW = EntityWrapper(m_World, m_HealthPickupID); + healthPickupEW["HealthPickup"]["RespawnTimer"] = 100.0; + healthPickupEW["HealthPickup"]["HealthGain"] = 50.0; + + //create a player + auto& health = m_World->AttachComponent(m_PlayerID, "Health"); + health["Health"] = 1.0; + health["MaxHealth"] = 100.0; + + Events::TriggerTouch eTriggerTouch; + DoTouchEvent(m_PlayerID, m_HealthPickupID); + } +} + +//generic stuff +void PickupSpawnTest::Tick() +{ + glfwPollEvents(); + + //just set dt to 1.0 since we want fast testing + double dt = 1.0; + + // Iterate through systems and update world! + m_SystemPipeline->Update(dt); + + m_EventBroker->Swap(); + m_EventBroker->Clear(); + + //verify that healthgain event has been published and pickup has respawned + if (m_RunTestNumber == 1 && testStage1Success && testStage2Success) { + m_TestSucceeded = true; + } + //verify that no healthgain event has been published and that no pickup has respawned + if (m_NumLoops > 90 && m_RunTestNumber == 2 && !testStage1Success && !testStage2Success) { + m_TestSucceeded = true; + } + //3: verify that the pickup hasnt spawned + if (m_NumLoops > 90 && m_RunTestNumber == 3 && testStage1Success && !testStage2Success) { + m_TestSucceeded = true; + } +} +bool PickupSpawnTest::Game_Loop_OneHundredTimes() { + //100 loops will be more than enough to do the test + int loops = 100; + bool success = false; + while (loops > 0) { + Tick(); + m_NumLoops++; + if (m_TestSucceeded) { + success = true; + break; + } + loops--; + } + return success; +} +PickupSpawnTest::~PickupSpawnTest() +{ + delete m_SystemPipeline; + delete m_World; + //delete m_EventBroker; +} +void PickupSpawnTest::DoTouchEvent(EntityID whoDidSomething, EntityID onWhatObject) { + Events::TriggerTouch touchEvent; + touchEvent.Entity = EntityWrapper(m_World, whoDidSomething); + touchEvent.Trigger = EntityWrapper(m_World, onWhatObject); + m_EventBroker->Publish(touchEvent); +} diff --git a/src/Tests/PickupSpawnTest.h b/src/Tests/PickupSpawnTest.h new file mode 100644 index 00000000..2869c119 --- /dev/null +++ b/src/Tests/PickupSpawnTest.h @@ -0,0 +1,73 @@ +#ifndef PickupSpawnTest_h__ +#define PickupSpawnTest_h__ + +#include "Core/ResourceManager.h" +#include "Core/ConfigFile.h" +#include "Core/EventBroker.h" +#include "Core/World.h" +#include "Input/InputProxy.h" +#include "Input/KeyboardInputHandler.h" +#include "Input/MouseInputHandler.h" +#include "Core/EKeyDown.h" +#include "Core/EntityFile.h" +#include "Core/SystemPipeline.h" + +#include "Core/EntityFilePreprocessor.h" +#include "Core/EntityFileParser.h" +#include "Core/EntityFileWriter.h" + +#include "Engine/Collision/ETrigger.h" + +//#include "Core/System.h" +//#include "Core/Transform.h" +//#include "Core/ResourceManager.h" +//#include "Core/EntityFileParser.h" +//#include "Core/EPickupSpawned.h" +//#include "Core/EPlayerHealthPickup.h" +#include "Engine/Collision/ETrigger.h" +//#include "Common.h" +//#include +#include "Collision/TriggerSystem.h" +#include "Collision/CollisionSystem.h" +#include "Core/EntityFileWriter.h" +#include "Game/Systems/HealthSystem.h" +#include "Game/Systems/PickupSpawnSystem.h" + +#include "Core/ResourceManager.h" + +class PickupSpawnTest +{ +public: + PickupSpawnTest(int runTestNumber); + ~PickupSpawnTest(); + + void Tick(); + bool m_TestSucceeded = false; + int m_NumLoops = 0; + + bool Game_Loop_OneHundredTimes(); + + void TestSetup(int testNumber); + void DoTouchEvent(EntityID whoDidSomething, EntityID onWhatObject); + +private: + double m_LastTime; + ConfigFile* m_Config = nullptr; + EventBroker* m_EventBroker; + World* m_World; + SystemPipeline* m_SystemPipeline; + EntityID m_PlayerID, m_HealthPickupID; + int m_RunTestNumber; + + EventRelay m_HP; + bool OnHealthPickup(Events::PlayerHealthPickup& e); + EventRelay m_PS; + bool OnPickupSpawned(Events::PickupSpawned& e); + + bool testStage1Success = false; + bool testStage2Success = false; + + +}; + +#endif From f7756ff60fc850c44ab93d156a14dd9763fd57d3 Mon Sep 17 00:00:00 2001 From: verysecrethero Date: Wed, 10 Feb 2016 16:51:00 +0100 Subject: [PATCH 02/12] Tiny refactoring of PickupSpawnTest. Updated and fixed HealthSystemTest. --- src/Tests/HealthSystemTest.cpp | 28 +++++++++------- src/Tests/HealthSystemTest.h | 4 ++- src/Tests/PickupSpawnTest.cpp | 59 ++++++++++++++++++---------------- src/Tests/PickupSpawnTest.h | 8 ++--- 4 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/Tests/HealthSystemTest.cpp b/src/Tests/HealthSystemTest.cpp index 36608f8f..7d06bba3 100644 --- a/src/Tests/HealthSystemTest.cpp +++ b/src/Tests/HealthSystemTest.cpp @@ -55,19 +55,14 @@ GameHealthSystemTest::GameHealthSystemTest() //create entity which has transform,player,model,health in it. i.e. is a player EntityID playerID = m_World->CreateEntity(); ComponentWrapper player = m_World->AttachComponent(playerID, "Player"); - ComponentWrapper health = m_World->AttachComponent(playerID, "Health"); - healthsID = playerID; + ComponentWrapper& health = m_World->AttachComponent(playerID, "Health"); + health["Health"] = 100.0; + m_PlayersID = playerID; EntityID playerID2 = m_World->CreateEntity(); ComponentWrapper player2 = m_World->AttachComponent(playerID2, "Player"); ComponentWrapper health2 = m_World->AttachComponent(playerID2, "Health"); - //heal player with 40 - Events::PlayerHealthPickup e3; - e3.HealthAmount = 40.0f; - e3.Player = EntityWrapper(m_World, player.EntityID); - m_EventBroker->Publish(e3); - //damage player with 50 Events::PlayerDamage e; e.Damage = 50.0f; @@ -103,9 +98,18 @@ void GameHealthSystemTest::Tick() m_EventBroker->Swap(); m_EventBroker->Clear(); - - //if health reaches 90 then we know the test has succeeded (start with 100hp, remove 50hp, add 40hp) - double currentHealth = (double)m_World->GetComponent(healthsID, "Health")["Health"]; - if (currentHealth == 90) + + double currentHealth = (double)m_World->GetComponent(m_PlayersID, "Health")["Health"]; + //if players health reach 50 means he got damaged by 50 + if (currentHealth == 50) { + m_TestStage1Success = true; + //heal player with 40 + Events::PlayerHealthPickup e3; + e3.HealthAmount = 40.0f; + e3.Player = EntityWrapper(m_World, m_PlayersID); + m_EventBroker->Publish(e3); + } + if (m_TestStage1Success && currentHealth == 90.0f) { TestSucceeded = true; + } } diff --git a/src/Tests/HealthSystemTest.h b/src/Tests/HealthSystemTest.h index 62c5f55b..685a06dd 100644 --- a/src/Tests/HealthSystemTest.h +++ b/src/Tests/HealthSystemTest.h @@ -31,7 +31,9 @@ private: EventBroker* m_EventBroker; World* m_World; SystemPipeline* m_SystemPipeline; - int healthsID; + int m_PlayersID; + bool m_TestStage1Success = false; + }; #endif diff --git a/src/Tests/PickupSpawnTest.cpp b/src/Tests/PickupSpawnTest.cpp index ebddb71f..2de9e459 100644 --- a/src/Tests/PickupSpawnTest.cpp +++ b/src/Tests/PickupSpawnTest.cpp @@ -4,7 +4,6 @@ using boost::unit_test_framework::test_case; #include "PickupSpawnTest.h" - BOOST_AUTO_TEST_SUITE(PickupSpawnTestSuite) //dont use the same name as the classname in test cases... @@ -73,15 +72,15 @@ bool PickupSpawnTest::OnHealthPickup(Events::PlayerHealthPickup& e) { //very that the event has the correct healthgain number and playerid if (m_RunTestNumber == 1) { if (e.HealthAmount == 22.0 && e.Player.ID == m_PlayerID) { - testStage1Success = true; + m_TestStage1Success = true; } } if (m_RunTestNumber == 2) { - testStage1Success = false; + m_TestStage1Success = false; } if (m_RunTestNumber == 3) { if (e.HealthAmount == 50.0 && e.Player.ID == m_PlayerID) { - testStage1Success = true; + m_TestStage1Success = true; } } return true; @@ -90,22 +89,24 @@ bool PickupSpawnTest::OnPickupSpawned(Events::PickupSpawned& e) { //verify that the newly spawned pickup has the same variable values as the original one if (m_RunTestNumber == 1) { if ((double)e.Pickup["HealthPickup"]["HealthGain"] == 22.0 && (double)e.Pickup["HealthPickup"]["RespawnTimer"] == 2.0) { - testStage2Success = true; + m_TestStage2Success = true; } } if (m_RunTestNumber == 2) { - testStage2Success = false; + m_TestStage2Success = false; } if (m_RunTestNumber == 3) { - testStage2Success = false; + m_TestStage2Success = false; } return true; } void PickupSpawnTest::TestSetup(int testNumber) { - //cant use switch here, since each case might initialize different variables - if (m_RunTestNumber == 1) { + switch (m_RunTestNumber) + { + case 1: + { //PickupSpawnTest_HealthPickupRespawns_PlayerHealthPickupEventTriggers auto& healthPickupEW = EntityWrapper(m_World, m_HealthPickupID); healthPickupEW["HealthPickup"]["RespawnTimer"] = 2.0; @@ -115,11 +116,10 @@ void PickupSpawnTest::TestSetup(int testNumber) auto& health = m_World->AttachComponent(m_PlayerID, "Health"); health["Health"] = 20.0; health["MaxHealth"] = 100.0; - - Events::TriggerTouch eTriggerTouch; - DoTouchEvent(m_PlayerID, m_HealthPickupID); } - if (m_RunTestNumber == 2) { + break; + case 2: + { //PickupSpawnTest_APlayerAtMaxHealth_CantTakeHealthPickup auto& healthPickupEW = EntityWrapper(m_World, m_HealthPickupID); healthPickupEW["HealthPickup"]["RespawnTimer"] = 1.0; @@ -129,11 +129,10 @@ void PickupSpawnTest::TestSetup(int testNumber) auto& health = m_World->AttachComponent(m_PlayerID, "Health"); health["Health"] = 100.0; health["MaxHealth"] = 100.0; - - Events::TriggerTouch eTriggerTouch; - DoTouchEvent(m_PlayerID, m_HealthPickupID); } - if (m_RunTestNumber == 3) { + break; + case 3: + { //PickupSpawnTest_APickupCanRespawnSlowly auto& healthPickupEW = EntityWrapper(m_World, m_HealthPickupID); healthPickupEW["HealthPickup"]["RespawnTimer"] = 100.0; @@ -143,10 +142,14 @@ void PickupSpawnTest::TestSetup(int testNumber) auto& health = m_World->AttachComponent(m_PlayerID, "Health"); health["Health"] = 1.0; health["MaxHealth"] = 100.0; - - Events::TriggerTouch eTriggerTouch; - DoTouchEvent(m_PlayerID, m_HealthPickupID); } + break; + default: + break; + } + //do the triggerTouch event to get the pickupSpawnTest started + Events::TriggerTouch eTriggerTouch; + DoTouchEvent(m_PlayerID, m_HealthPickupID); } //generic stuff @@ -164,16 +167,16 @@ void PickupSpawnTest::Tick() m_EventBroker->Clear(); //verify that healthgain event has been published and pickup has respawned - if (m_RunTestNumber == 1 && testStage1Success && testStage2Success) { - m_TestSucceeded = true; + if (m_RunTestNumber == 1 && m_TestStage1Success && m_TestStage2Success) { + TestSucceeded = true; } //verify that no healthgain event has been published and that no pickup has respawned - if (m_NumLoops > 90 && m_RunTestNumber == 2 && !testStage1Success && !testStage2Success) { - m_TestSucceeded = true; + if (NumLoops > 90 && m_RunTestNumber == 2 && !m_TestStage1Success && !m_TestStage2Success) { + TestSucceeded = true; } //3: verify that the pickup hasnt spawned - if (m_NumLoops > 90 && m_RunTestNumber == 3 && testStage1Success && !testStage2Success) { - m_TestSucceeded = true; + if (NumLoops > 90 && m_RunTestNumber == 3 && m_TestStage1Success && !m_TestStage2Success) { + TestSucceeded = true; } } bool PickupSpawnTest::Game_Loop_OneHundredTimes() { @@ -182,8 +185,8 @@ bool PickupSpawnTest::Game_Loop_OneHundredTimes() { bool success = false; while (loops > 0) { Tick(); - m_NumLoops++; - if (m_TestSucceeded) { + NumLoops++; + if (TestSucceeded) { success = true; break; } diff --git a/src/Tests/PickupSpawnTest.h b/src/Tests/PickupSpawnTest.h index 2869c119..fdb18b12 100644 --- a/src/Tests/PickupSpawnTest.h +++ b/src/Tests/PickupSpawnTest.h @@ -42,8 +42,8 @@ public: ~PickupSpawnTest(); void Tick(); - bool m_TestSucceeded = false; - int m_NumLoops = 0; + bool TestSucceeded = false; + int NumLoops = 0; bool Game_Loop_OneHundredTimes(); @@ -64,8 +64,8 @@ private: EventRelay m_PS; bool OnPickupSpawned(Events::PickupSpawned& e); - bool testStage1Success = false; - bool testStage2Success = false; + bool m_TestStage1Success = false; + bool m_TestStage2Success = false; }; From 02cd822cf198295c01835ef7a1a445c469272e00 Mon Sep 17 00:00:00 2001 From: verysecrethero Date: Wed, 10 Feb 2016 17:04:05 +0100 Subject: [PATCH 03/12] Tiny test refactoring --- src/Tests/HealthSystemTest.cpp | 2 +- src/Tests/PickupSpawnTest.cpp | 46 +++++++++++++++++++--------------- src/Tests/PickupSpawnTest.h | 5 ++-- 3 files changed, 29 insertions(+), 24 deletions(-) diff --git a/src/Tests/HealthSystemTest.cpp b/src/Tests/HealthSystemTest.cpp index 7d06bba3..fa88d815 100644 --- a/src/Tests/HealthSystemTest.cpp +++ b/src/Tests/HealthSystemTest.cpp @@ -101,7 +101,7 @@ void GameHealthSystemTest::Tick() double currentHealth = (double)m_World->GetComponent(m_PlayersID, "Health")["Health"]; //if players health reach 50 means he got damaged by 50 - if (currentHealth == 50) { + if (currentHealth == 50.0) { m_TestStage1Success = true; //heal player with 40 Events::PlayerHealthPickup e3; diff --git a/src/Tests/PickupSpawnTest.cpp b/src/Tests/PickupSpawnTest.cpp index 2de9e459..7cbed85f 100644 --- a/src/Tests/PickupSpawnTest.cpp +++ b/src/Tests/PickupSpawnTest.cpp @@ -69,34 +69,41 @@ PickupSpawnTest::PickupSpawnTest(int runTestNumber) } bool PickupSpawnTest::OnHealthPickup(Events::PlayerHealthPickup& e) { - //very that the event has the correct healthgain number and playerid - if (m_RunTestNumber == 1) { + switch (m_RunTestNumber) + { + case 1: + //verify that the event has the correct healthgain number and playerid if (e.HealthAmount == 22.0 && e.Player.ID == m_PlayerID) { m_TestStage1Success = true; } - } - if (m_RunTestNumber == 2) { + break; + case 2: m_TestStage1Success = false; - } - if (m_RunTestNumber == 3) { + break; + case 3: + //verify that the event has the correct healthgain number and playerid if (e.HealthAmount == 50.0 && e.Player.ID == m_PlayerID) { m_TestStage1Success = true; } + break; } return true; } bool PickupSpawnTest::OnPickupSpawned(Events::PickupSpawned& e) { - //verify that the newly spawned pickup has the same variable values as the original one - if (m_RunTestNumber == 1) { + switch (m_RunTestNumber) + { + case 1: + //verify that the newly spawned pickup has the same variable values as the original one if ((double)e.Pickup["HealthPickup"]["HealthGain"] == 22.0 && (double)e.Pickup["HealthPickup"]["RespawnTimer"] == 2.0) { m_TestStage2Success = true; } - } - if (m_RunTestNumber == 2) { + break; + case 2: m_TestStage2Success = false; - } - if (m_RunTestNumber == 3) { + break; + case 3: m_TestStage2Success = false; + break; } return true; } @@ -168,15 +175,15 @@ void PickupSpawnTest::Tick() //verify that healthgain event has been published and pickup has respawned if (m_RunTestNumber == 1 && m_TestStage1Success && m_TestStage2Success) { - TestSucceeded = true; + m_TestSucceeded = true; } //verify that no healthgain event has been published and that no pickup has respawned - if (NumLoops > 90 && m_RunTestNumber == 2 && !m_TestStage1Success && !m_TestStage2Success) { - TestSucceeded = true; + if (m_NumLoops > 90 && m_RunTestNumber == 2 && !m_TestStage1Success && !m_TestStage2Success) { + m_TestSucceeded = true; } //3: verify that the pickup hasnt spawned - if (NumLoops > 90 && m_RunTestNumber == 3 && m_TestStage1Success && !m_TestStage2Success) { - TestSucceeded = true; + if (m_NumLoops > 90 && m_RunTestNumber == 3 && m_TestStage1Success && !m_TestStage2Success) { + m_TestSucceeded = true; } } bool PickupSpawnTest::Game_Loop_OneHundredTimes() { @@ -185,8 +192,8 @@ bool PickupSpawnTest::Game_Loop_OneHundredTimes() { bool success = false; while (loops > 0) { Tick(); - NumLoops++; - if (TestSucceeded) { + m_NumLoops++; + if (m_TestSucceeded) { success = true; break; } @@ -198,7 +205,6 @@ PickupSpawnTest::~PickupSpawnTest() { delete m_SystemPipeline; delete m_World; - //delete m_EventBroker; } void PickupSpawnTest::DoTouchEvent(EntityID whoDidSomething, EntityID onWhatObject) { Events::TriggerTouch touchEvent; diff --git a/src/Tests/PickupSpawnTest.h b/src/Tests/PickupSpawnTest.h index fdb18b12..b9d5483a 100644 --- a/src/Tests/PickupSpawnTest.h +++ b/src/Tests/PickupSpawnTest.h @@ -42,11 +42,8 @@ public: ~PickupSpawnTest(); void Tick(); - bool TestSucceeded = false; - int NumLoops = 0; bool Game_Loop_OneHundredTimes(); - void TestSetup(int testNumber); void DoTouchEvent(EntityID whoDidSomething, EntityID onWhatObject); @@ -67,6 +64,8 @@ private: bool m_TestStage1Success = false; bool m_TestStage2Success = false; + bool m_TestSucceeded = false; + int m_NumLoops = 0; }; From 4b8f1d95a355d54c570e70153d8c341542062c4b Mon Sep 17 00:00:00 2001 From: verysecrethero Date: Tue, 16 Feb 2016 16:57:46 +0100 Subject: [PATCH 04/12] Added static class PerformanceTimer. Changed CMakeLists for engine to include boost timer. Added F2,F3 functions in editor. Added some timing, more to be added --- include/Engine/Core/PerformanceTimer.h | 36 +++++++++++ include/Engine/Core/SystemPipeline.h | 13 +++- include/Game/Game.h | 3 + resources/DefaultInput.ini | 4 +- src/Engine/CMakeLists.txt | 2 +- src/Engine/Core/PerformanceTimer.cpp | 87 ++++++++++++++++++++++++++ src/Engine/Editor/EditorSystem.cpp | 6 ++ src/Game/Game.cpp | 8 +++ 8 files changed, 154 insertions(+), 5 deletions(-) create mode 100644 include/Engine/Core/PerformanceTimer.h create mode 100644 src/Engine/Core/PerformanceTimer.cpp diff --git a/include/Engine/Core/PerformanceTimer.h b/include/Engine/Core/PerformanceTimer.h new file mode 100644 index 00000000..6fb5c4a5 --- /dev/null +++ b/include/Engine/Core/PerformanceTimer.h @@ -0,0 +1,36 @@ +#ifndef PerformanceTimer_h__ +#define PerformanceTimer_h__ + +#include +#include +#include "../Common.h" + +#include +using boost::timer::cpu_timer; + +class PerformanceTimer +{ +public: + static void StartTimer(std::string nameOfTimer); + static void StartTimerAndStopPrevious(std::string nameOfTimer); + static void StopTimer(std::string nameOfTimer); + static void SetFrameNumber(int frameNumber); + + static void ResetAllTimers(); + static void CreateExcelData(); + + //set timer/start + //get performance excel nånting + +private: + static std::map timers; + static double m_TimeElapsed; + static cpu_timer m_Timer; + static std::string currentTimerRunning; + static bool active; + //static map + + +}; + +#endif diff --git a/include/Engine/Core/SystemPipeline.h b/include/Engine/Core/SystemPipeline.h index 5f7aee0b..c4801fde 100644 --- a/include/Engine/Core/SystemPipeline.h +++ b/include/Engine/Core/SystemPipeline.h @@ -6,6 +6,7 @@ #include "System.h" #include "World.h" #include "EPause.h" +#include "PerformanceTimer.h" class SystemPipeline { @@ -72,7 +73,10 @@ public: // Update for (auto& system : group.ImpureSystems) { + auto className = (std::string)typeid(*system).name(); + PerformanceTimer::StartTimer(className); system->Update(dt); + PerformanceTimer::StopTimer(className); } for (auto& pair : group.PureSystems) { const std::string& componentName = pair.first; @@ -83,7 +87,10 @@ public: } for (auto& component : *pool) { for (auto& system : systems) { + auto className = (std::string)typeid(*system).name(); + PerformanceTimer::StartTimer(className); system->UpdateComponent(EntityWrapper(m_World, component.EntityID), component, dt); + PerformanceTimer::StopTimer(className); } } } @@ -106,9 +113,9 @@ private: std::vector m_OrderedSystemGroups; EventRelay m_EPause; - bool OnPause(const Events::Pause& e) { - if (e.World == m_World) { - m_Paused = true; + bool OnPause(const Events::Pause& e) { + if (e.World == m_World) { + m_Paused = true; } return true; } diff --git a/include/Game/Game.h b/include/Game/Game.h index baf15656..5a53c15c 100644 --- a/include/Game/Game.h +++ b/include/Game/Game.h @@ -35,6 +35,9 @@ #include "Sound/SoundManager.h" #include "Systems/SoundSystem.h" +//Performance +#include "Core/PerformanceTimer.h" + class Game { public: diff --git a/resources/DefaultInput.ini b/resources/DefaultInput.ini index d5489c3a..776cbecd 100644 --- a/resources/DefaultInput.ini +++ b/resources/DefaultInput.ini @@ -25,4 +25,6 @@ C=ConnectToServer N=SwitchToServer M=SwitchToClient P=SwitchToPlayer -K=TakeDamage,1500 \ No newline at end of file +K=TakeDamage,1500 +F2=PerformanceTimingResetAllTimers +F3=PerformanceTimingCreateExcelData \ No newline at end of file diff --git a/src/Engine/CMakeLists.txt b/src/Engine/CMakeLists.txt index 19763310..e74214cf 100644 --- a/src/Engine/CMakeLists.txt +++ b/src/Engine/CMakeLists.txt @@ -3,7 +3,7 @@ project(TacticalZ-Engine) find_package(OpenGL REQUIRED) find_package(GLEW REQUIRED) find_package(GLFW REQUIRED) -find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono program_options) +find_package(Boost REQUIRED COMPONENTS system filesystem thread chrono timer program_options) find_package(assimp REQUIRED) find_package(ZLIB REQUIRED) find_package(PNG REQUIRED) diff --git a/src/Engine/Core/PerformanceTimer.cpp b/src/Engine/Core/PerformanceTimer.cpp new file mode 100644 index 00000000..a7a437c2 --- /dev/null +++ b/src/Engine/Core/PerformanceTimer.cpp @@ -0,0 +1,87 @@ +#include "Core/PerformanceTimer.h" +#include +#include +#include +#include + +cpu_timer PerformanceTimer::m_Timer; +double PerformanceTimer::m_TimeElapsed; +std::map PerformanceTimer::timers; +std::string PerformanceTimer::currentTimerRunning = ""; + +void PerformanceTimer::StartTimer(std::string nameOfTimer) +{ + timers[nameOfTimer].stop(); + timers[nameOfTimer].start(); + currentTimerRunning = nameOfTimer; +} + +void PerformanceTimer::StartTimerAndStopPrevious(std::string nameOfTimer) +{ + //stop the current timer and start some other - useful to not have to stop timers all the time + if (currentTimerRunning != "") { + timers[currentTimerRunning].stop(); + } + timers[nameOfTimer].stop(); + timers[nameOfTimer].start(); + currentTimerRunning = nameOfTimer; +} + + + +void PerformanceTimer::StopTimer(std::string nameOfTimer) +{ + timers[nameOfTimer].stop(); + currentTimerRunning = nameOfTimer; +} + + + +void PerformanceTimer::SetFrameNumber(int frameNumber) +{ +} + +void PerformanceTimer::ResetAllTimers() +{ + //stop all timers + for (auto aTimer : timers) + { + aTimer.second.stop(); + } + currentTimerRunning = ""; + timers.clear(); +} + +void PerformanceTimer::CreateExcelData() +{ + //wall = http://theboostcpplibraries.com/boost.timer + //http://www.boost.org/doc/libs/1_48_0/libs/timer/doc/cpu_timers.html + + //get path,time + char Dump_Path[MAX_PATH]; + GetModuleFileName(NULL, Dump_Path, sizeof(Dump_Path)); //path of current process + std::time_t t = std::time(NULL); + char tStr[16]; + std::strftime(tStr, 32, " %a %H-%M-%S", std::localtime(&t)); + std::string time(tStr); + std::string path(Dump_Path); + path = path.substr(0, path.length() - 4); + path += time + ".xls"; + std::ofstream someFileStream; + someFileStream.open(path, std::ofstream::out); + someFileStream << "classname" << ',' << "walltime" << ',' << "userTime" << ',' << "systemTime" << '\n'; + for (auto aTimer : timers) + { + //remove the "class" name in front of the string + auto className = aTimer.first; + if (className.find("class ") != std::string::npos) { + className.replace(0, 6, ""); + } + auto wallTime = (double)aTimer.second.elapsed().wall*1e-3; + auto userTime = (double)aTimer.second.elapsed().user*1e-3; + auto systemTime = (double)aTimer.second.elapsed().system*1e-3; + + someFileStream << className << "," << wallTime << ',' << userTime << ',' << systemTime << '\n'; + } + someFileStream.close(); +} diff --git a/src/Engine/Editor/EditorSystem.cpp b/src/Engine/Editor/EditorSystem.cpp index 4899519d..eedc7c22 100644 --- a/src/Engine/Editor/EditorSystem.cpp +++ b/src/Engine/Editor/EditorSystem.cpp @@ -223,6 +223,12 @@ bool EditorSystem::OnInputCommand(const Events::InputCommand& e) Enable(); } } + if (e.Command == "PerformanceTimingResetAllTimers" && e.Value > 0) { + PerformanceTimer::ResetAllTimers(); + } + if (e.Command == "PerformanceTimingCreateExcelData" && e.Value > 0) { + PerformanceTimer::CreateExcelData(); + } return true; } diff --git a/src/Game/Game.cpp b/src/Game/Game.cpp index 49b1a963..d2535518 100644 --- a/src/Game/Game.cpp +++ b/src/Game/Game.cpp @@ -187,16 +187,20 @@ void Game::Tick() // Handle input in a weird looking but responsive way m_EventBroker->Process(); m_EventBroker->Swap(); + PerformanceTimer::StartTimer("InputManager"); m_InputManager->Update(dt); m_EventBroker->Swap(); + PerformanceTimer::StartTimerAndStopPrevious("InputProxy"); m_InputProxy->Update(dt); m_EventBroker->Swap(); m_InputProxy->Process(); m_EventBroker->Swap(); + PerformanceTimer::StartTimerAndStopPrevious("SoundManager"); m_SoundManager->Update(dt); // Update network + PerformanceTimer::StartTimerAndStopPrevious("Network"); m_EventBroker->Process(); if (m_NetworkClient != nullptr) { m_NetworkClient->Update(); @@ -207,10 +211,14 @@ void Game::Tick() //m_SoundManager->Update(dt); // Iterate through systems and update world! + PerformanceTimer::StartTimerAndStopPrevious("SystemPipeline"); m_EventBroker->Process(); m_SystemPipeline->Update(dt); + PerformanceTimer::StartTimerAndStopPrevious("RendererUpdate"); m_Renderer->Update(dt); + PerformanceTimer::StartTimerAndStopPrevious("RendererDraw"); m_Renderer->Draw(*m_RenderFrame); + PerformanceTimer::StopTimer("RendererDraw"); m_RenderFrame->Clear(); m_EventBroker->Swap(); m_EventBroker->Clear(); From 42b49f9dba92e054a246c7c3d56814d82f4129d5 Mon Sep 17 00:00:00 2001 From: verysecrethero Date: Tue, 16 Feb 2016 17:51:39 +0100 Subject: [PATCH 05/12] Added more timers to Rendering. --- include/Engine/Rendering/Renderer.h | 1 + resources/Schema/Entities/GameMap.xml | 8 +++++--- src/Engine/Rendering/Renderer.cpp | 19 ++++++++++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/include/Engine/Rendering/Renderer.h b/include/Engine/Rendering/Renderer.h index 04754514..936b0359 100644 --- a/include/Engine/Rendering/Renderer.h +++ b/include/Engine/Rendering/Renderer.h @@ -23,6 +23,7 @@ #include "imgui/imgui.h" #include "TextPass.h" #include "Util/CommonFunctions.h" +#include "Core/PerformanceTimer.h" class Renderer : public IRenderer { diff --git a/resources/Schema/Entities/GameMap.xml b/resources/Schema/Entities/GameMap.xml index 84a1e363..c3a16361 100644 --- a/resources/Schema/Entities/GameMap.xml +++ b/resources/Schema/Entities/GameMap.xml @@ -144,7 +144,7 @@ - + @@ -206,14 +206,16 @@ - + - + + + diff --git a/src/Engine/Rendering/Renderer.cpp b/src/Engine/Rendering/Renderer.cpp index be84160c..85687bf5 100644 --- a/src/Engine/Rendering/Renderer.cpp +++ b/src/Engine/Rendering/Renderer.cpp @@ -99,34 +99,48 @@ void Renderer::Draw(RenderFrame& frame) glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); //Clear other buffers + PerformanceTimer::StartTimer("Renderer-ClearBuffers"); m_PickingPass->ClearPicking(); m_DrawFinalPass->ClearBuffer(); m_DrawBloomPass->ClearBuffer(); + PerformanceTimer::StopTimer("Renderer-ClearBuffers"); for (auto scene : frame.RenderScenes){ + PerformanceTimer::StartTimer("Renderer-Depth"); SortRenderJobsByDepth(*scene); GLERROR("SortByDepth"); + PerformanceTimer::StartTimerAndStopPrevious("Renderer-Drawing PickingPass"); m_PickingPass->Draw(*scene); GLERROR("Drawing pickingpass"); + PerformanceTimer::StartTimerAndStopPrevious("Renderer-Generate Frustrums"); m_LightCullingPass->GenerateNewFrustum(*scene); GLERROR("Generate frustums"); + PerformanceTimer::StartTimerAndStopPrevious("Renderer-Filling Light List"); m_LightCullingPass->FillLightList(*scene); GLERROR("Filling light list"); + PerformanceTimer::StartTimerAndStopPrevious("Renderer-Light Culling"); m_LightCullingPass->CullLights(*scene); GLERROR("LightCulling"); + PerformanceTimer::StartTimerAndStopPrevious("Renderer-Draw Geometry+Light"); m_DrawFinalPass->Draw(*scene); GLERROR("Draw Geometry+Light"); //m_DrawScenePass->Draw(*scene); + PerformanceTimer::StartTimerAndStopPrevious("Renderer-Draw Text"); m_TextPass->Draw(*scene, *m_DrawFinalPass->FinalPassFrameBuffer()); GLERROR("Draw Text"); - + PerformanceTimer::StopTimer("Renderer-Draw Text"); } + PerformanceTimer::StartTimer("Renderer-Draw Bloom"); m_DrawBloomPass->Draw(m_DrawFinalPass->BloomTexture()); + PerformanceTimer::StopTimer("Renderer-Draw Bloom"); if (m_DebugTextureToDraw == 0) { + PerformanceTimer::StartTimer("Renderer-Color Correction Pass"); m_DrawColorCorrectionPass->Draw(m_DrawFinalPass->SceneTexture(), m_DrawBloomPass->GaussianTexture(), m_DrawFinalPass->SceneTextureLowRes(), m_DrawFinalPass->BloomTextureLowRes(), frame.Gamma, frame.Exposure); + PerformanceTimer::StopTimer("Renderer-Color Correction Pass"); } + PerformanceTimer::StartTimer("Renderer-Misc Debug Draws"); if (m_DebugTextureToDraw == 1) { m_DrawScreenQuadPass->Draw(m_DrawFinalPass->SceneTexture()); } @@ -145,10 +159,13 @@ void Renderer::Draw(RenderFrame& frame) if (m_DebugTextureToDraw == 6) { m_DrawScreenQuadPass->Draw(m_PickingPass->PickingTexture()); } + PerformanceTimer::StopTimer("Renderer-Misc Debug Draws"); + PerformanceTimer::StartTimer("Renderer-ImGuiRenderPass"); m_ImGuiRenderPass->Draw(); GLERROR("Imgui draw"); glfwSwapBuffers(m_Window); + PerformanceTimer::StopTimer("Renderer-ImGuiRenderPass"); } PickData Renderer::Pick(glm::vec2 screenCoord) From b2a437731ec8e5a85029b8f3132717bd0162f110 Mon Sep 17 00:00:00 2001 From: verysecrethero Date: Tue, 16 Feb 2016 17:58:27 +0100 Subject: [PATCH 06/12] Small cleanup in the code --- include/Engine/Core/PerformanceTimer.h | 7 ------- src/Engine/Core/PerformanceTimer.cpp | 9 ++------- 2 files changed, 2 insertions(+), 14 deletions(-) diff --git a/include/Engine/Core/PerformanceTimer.h b/include/Engine/Core/PerformanceTimer.h index 6fb5c4a5..9f2c3d66 100644 --- a/include/Engine/Core/PerformanceTimer.h +++ b/include/Engine/Core/PerformanceTimer.h @@ -19,18 +19,11 @@ public: static void ResetAllTimers(); static void CreateExcelData(); - //set timer/start - //get performance excel nånting - private: static std::map timers; static double m_TimeElapsed; static cpu_timer m_Timer; static std::string currentTimerRunning; - static bool active; - //static map - - }; #endif diff --git a/src/Engine/Core/PerformanceTimer.cpp b/src/Engine/Core/PerformanceTimer.cpp index a7a437c2..05ac221a 100644 --- a/src/Engine/Core/PerformanceTimer.cpp +++ b/src/Engine/Core/PerformanceTimer.cpp @@ -27,16 +27,12 @@ void PerformanceTimer::StartTimerAndStopPrevious(std::string nameOfTimer) currentTimerRunning = nameOfTimer; } - - void PerformanceTimer::StopTimer(std::string nameOfTimer) { timers[nameOfTimer].stop(); currentTimerRunning = nameOfTimer; } - - void PerformanceTimer::SetFrameNumber(int frameNumber) { } @@ -54,9 +50,6 @@ void PerformanceTimer::ResetAllTimers() void PerformanceTimer::CreateExcelData() { - //wall = http://theboostcpplibraries.com/boost.timer - //http://www.boost.org/doc/libs/1_48_0/libs/timer/doc/cpu_timers.html - //get path,time char Dump_Path[MAX_PATH]; GetModuleFileName(NULL, Dump_Path, sizeof(Dump_Path)); //path of current process @@ -70,6 +63,8 @@ void PerformanceTimer::CreateExcelData() std::ofstream someFileStream; someFileStream.open(path, std::ofstream::out); someFileStream << "classname" << ',' << "walltime" << ',' << "userTime" << ',' << "systemTime" << '\n'; + + //write all timers to file for (auto aTimer : timers) { //remove the "class" name in front of the string From 833015f45e97ae173130abe67595c24f86bfa333 Mon Sep 17 00:00:00 2001 From: verysecrethero Date: Wed, 17 Feb 2016 13:44:41 +0100 Subject: [PATCH 07/12] Small code cleanup for PerformanceTimer --- include/Engine/Core/PerformanceTimer.h | 4 ---- resources/Schema/Entities/NewMap.xml | 20 ++++++++++---------- src/Engine/Core/PerformanceTimer.cpp | 12 +++--------- 3 files changed, 13 insertions(+), 23 deletions(-) diff --git a/include/Engine/Core/PerformanceTimer.h b/include/Engine/Core/PerformanceTimer.h index 9f2c3d66..a3cdfa92 100644 --- a/include/Engine/Core/PerformanceTimer.h +++ b/include/Engine/Core/PerformanceTimer.h @@ -1,10 +1,7 @@ #ifndef PerformanceTimer_h__ #define PerformanceTimer_h__ -#include -#include #include "../Common.h" - #include using boost::timer::cpu_timer; @@ -21,7 +18,6 @@ public: private: static std::map timers; - static double m_TimeElapsed; static cpu_timer m_Timer; static std::string currentTimerRunning; }; diff --git a/resources/Schema/Entities/NewMap.xml b/resources/Schema/Entities/NewMap.xml index dcdb7bec..f5b975b8 100644 --- a/resources/Schema/Entities/NewMap.xml +++ b/resources/Schema/Entities/NewMap.xml @@ -5019,7 +5019,7 @@ - + @@ -5089,7 +5089,7 @@ - + @@ -5165,7 +5165,7 @@ - + @@ -5184,7 +5184,7 @@ - + @@ -5203,7 +5203,7 @@ - + @@ -5222,7 +5222,7 @@ - + @@ -5241,7 +5241,7 @@ - + @@ -5260,7 +5260,7 @@ - + @@ -5279,7 +5279,7 @@ - + @@ -5298,7 +5298,7 @@ - + diff --git a/src/Engine/Core/PerformanceTimer.cpp b/src/Engine/Core/PerformanceTimer.cpp index 05ac221a..50983e79 100644 --- a/src/Engine/Core/PerformanceTimer.cpp +++ b/src/Engine/Core/PerformanceTimer.cpp @@ -1,11 +1,8 @@ #include "Core/PerformanceTimer.h" -#include #include #include -#include cpu_timer PerformanceTimer::m_Timer; -double PerformanceTimer::m_TimeElapsed; std::map PerformanceTimer::timers; std::string PerformanceTimer::currentTimerRunning = ""; @@ -50,16 +47,13 @@ void PerformanceTimer::ResetAllTimers() void PerformanceTimer::CreateExcelData() { - //get path,time - char Dump_Path[MAX_PATH]; - GetModuleFileName(NULL, Dump_Path, sizeof(Dump_Path)); //path of current process + //get time std::time_t t = std::time(NULL); char tStr[16]; std::strftime(tStr, 32, " %a %H-%M-%S", std::localtime(&t)); std::string time(tStr); - std::string path(Dump_Path); - path = path.substr(0, path.length() - 4); - path += time + ".xls"; + std::string path("TacticalZ"); + path += time + ".csv"; std::ofstream someFileStream; someFileStream.open(path, std::ofstream::out); someFileStream << "classname" << ',' << "walltime" << ',' << "userTime" << ',' << "systemTime" << '\n'; From 23bb1a64057fc3f5f9c21b0206b2daf3e384217b Mon Sep 17 00:00:00 2001 From: William Moberg Date: Wed, 17 Feb 2016 14:54:59 +0100 Subject: [PATCH 08/12] Cannot respawn inside other players, unless all are blocked. --- include/Engine/Collision/Collision.h | 10 ++- include/Game/Systems/SpawnerSystem.h | 7 +- src/Engine/Collision/Collision.cpp | 53 +++++++++++++-- src/Game/Systems/PlayerSpawnSystem.cpp | 4 +- src/Game/Systems/SpawnerSystem.cpp | 93 +++++++++++++++++++++----- 5 files changed, 143 insertions(+), 24 deletions(-) diff --git a/include/Engine/Collision/Collision.h b/include/Engine/Collision/Collision.h index 546d03f5..9e1a81db 100644 --- a/include/Engine/Collision/Collision.h +++ b/include/Engine/Collision/Collision.h @@ -78,13 +78,21 @@ bool AABBvsTriangles(const AABB& box, bool& isOnGround, glm::vec3& outResolutionVector); +//Detects collision, but does not resolve. +bool AABBvsTriangles(const AABB& box, + const RawModel::Vertex* modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix); + //Return true if the boxes are intersecting. bool AABBVsAABB(const AABB& a, const AABB& b); //Return true if the boxes are intersecting. //Also outputs the minimum translation that box [a] would need in order to resolve collision. bool AABBVsAABB(const AABB& a, const AABB& b, glm::vec3& minimumTranslation); -// Calculates an absolute AABB from an entity AABB component +// Calculates an absolute AABB from an entity AABB component or Model component. +// if takeModelBox is true, the AABB component will be ignored and box is calculated from Model. +// if takeModelBox is false, the AABB component will be prefered, if it exists. 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 diff --git a/include/Game/Systems/SpawnerSystem.h b/include/Game/Systems/SpawnerSystem.h index 9cb4bd06..e4a44738 100644 --- a/include/Game/Systems/SpawnerSystem.h +++ b/include/Game/Systems/SpawnerSystem.h @@ -15,11 +15,16 @@ class SpawnerSystem : public System public: SpawnerSystem(SystemParams params); - static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid); + // If dontCollideComponent is set, to e.g. "Player", then all the spawner + // will try to pick a spawn location so that the spawned entity doesn't + // collide with anything that has that component and is collidable. + static EntityWrapper Spawn(EntityWrapper spawner, EntityWrapper parent = EntityWrapper::Invalid, const std::string& dontCollideComponent = ""); private: EventRelay m_OnSpawnerSpawn; bool OnSpawnerSpawn(Events::SpawnerSpawn& e); + static void transformEntityToSpawnPoint(EntityWrapper spawnedEntity, EntityWrapper spawnPoint); + static bool spawnedEntityIsColliding(EntityWrapper spawnedEntity, EntityWrapper spawnPoint, const std::string& dontCollideComponent); }; #endif \ No newline at end of file diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index ab2098b7..87d8bf26 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -366,7 +366,8 @@ bool AABBvsTriangle(const AABB& box, float verticalStepHeight, bool& isOnGround, glm::vec3& boxVelocity, - glm::vec3& outResolution) + glm::vec3& outResolution, + bool resolveCollision) { //Check so we don't have a zero area triangle when calculating the normal. //Also, don't check a triangle facing away from the player. @@ -426,7 +427,7 @@ bool AABBvsTriangle(const AABB& box, //if projections don't overlap, return false. if (!rectangleVsTriangle(boxMin, boxMax, t2D, resolutionVector, resolutionDist, pushedFromTriangleLine)) { return false; - } else { + } else if (resolveCollision) { //Overwrite the smallest resolution if this is smaller. if (resolutionDist < resolveShortest.DistanceSq) { resolveShortest.Vector = glm::vec3(0.f); @@ -463,6 +464,11 @@ bool AABBvsTriangle(const AABB& box, if (glm::abs(t) > 1) { return false; } + + if (!resolveCollision) { + return true; + } + glm::vec3 cornerResolution = (1+t) * diagonal; //Overwrite the smallest resolution if cornerResolution is smaller. float lenSq = glm::length2(cornerResolution); @@ -537,7 +543,8 @@ bool AABBvsTriangles(const AABB& box, glm::vec3& boxVelocity, float verticalStepHeight, bool& isOnGround, - glm::vec3& outResolutionVector) + glm::vec3& outResolutionVector, + bool resolveCollision) { bool hit = false; @@ -553,7 +560,7 @@ bool AABBvsTriangles(const AABB& box, }; glm::vec3 outVec; bool collideWithGround = isOnGround; - if (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec)) { + if (AABBvsTriangle(newBox, triVertices, originalBoxVelocity, verticalStepHeight, collideWithGround, boxVelocity, outVec, resolveCollision)) { hit = true; outResolutionVector += outVec; newBox = AABB::FromOriginSize(newBox.Origin() + outVec, newBox.Size()); @@ -569,6 +576,44 @@ bool AABBvsTriangles(const AABB& box, return hit; } +bool AABBvsTriangles(const AABB& box, + const RawModel::Vertex* modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix, + glm::vec3& boxVelocity, + float verticalStepHeight, + bool& isOnGround, + glm::vec3& outResolutionVector) +{ + return AABBvsTriangles(box, + modelVertices, + modelIndices, + modelMatrix, + boxVelocity, + verticalStepHeight, + isOnGround, + outResolutionVector, + true); +} + +bool AABBvsTriangles(const AABB& box, + const RawModel::Vertex* modelVertices, + const std::vector& modelIndices, + const glm::mat4& modelMatrix) +{ + glm::vec3 vel, outres; + bool g; + return AABBvsTriangles(box, + modelVertices, + modelIndices, + modelMatrix, + vel, + 0.f, + g, + outres, + false); +} + boost::optional EntityAbsoluteAABB(EntityWrapper& entity, bool takeModelBox) { AABB modelSpaceBox; diff --git a/src/Game/Systems/PlayerSpawnSystem.cpp b/src/Game/Systems/PlayerSpawnSystem.cpp index 5f53a1fc..6254c674 100644 --- a/src/Game/Systems/PlayerSpawnSystem.cpp +++ b/src/Game/Systems/PlayerSpawnSystem.cpp @@ -3,7 +3,7 @@ //This should be set by the config anyway. float PlayerSpawnSystem::m_RespawnTime = 15.0f; -PlayerSpawnSystem::PlayerSpawnSystem(SystemParams params) +PlayerSpawnSystem::PlayerSpawnSystem(SystemParams params) : System(params) , m_Timer(0.f) { @@ -49,7 +49,7 @@ void PlayerSpawnSystem::Update(double dt) } // Spawn the player! - EntityWrapper player = SpawnerSystem::Spawn(spawner); + EntityWrapper player = SpawnerSystem::Spawn(spawner, EntityWrapper::Invalid, "Player"); // Set the player team affiliation player["Team"]["Team"] = req.Team; diff --git a/src/Game/Systems/SpawnerSystem.cpp b/src/Game/Systems/SpawnerSystem.cpp index b3c556f1..90f677fe 100644 --- a/src/Game/Systems/SpawnerSystem.cpp +++ b/src/Game/Systems/SpawnerSystem.cpp @@ -1,12 +1,13 @@ #include "Systems/SpawnerSystem.h" +#include "Collision/Collision.h" -SpawnerSystem::SpawnerSystem(SystemParams params) +SpawnerSystem::SpawnerSystem(SystemParams params) : System(params) { EVENT_SUBSCRIBE_MEMBER(m_OnSpawnerSpawn, &SpawnerSystem::OnSpawnerSpawn); } -EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /*= EntityWrapper::Invalid*/) +EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent /*= EntityWrapper::Invalid*/, const std::string& dontCollideComponent) { // Spawn the entity in the parent's world if it exists, otherwise in the spawner's world World* world = parent.World; @@ -14,17 +15,41 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent / world = spawner.World; } + // Load the entity file and parse it + const std::string& entityFilePath = spawner["Spawner"]["EntityFile"]; + auto entityFile = ResourceManager::Load(entityFilePath); + if (entityFile == nullptr) { + return EntityWrapper::Invalid; + } + EntityFileParser parser(entityFile); + EntityWrapper spawnedEntity(world, parser.MergeEntities(world, parent.ID)); + + //If the spawned entity is collideable, then we must not spawn it where it collides with something that + //has a dontCollideComponent attached. + bool spawnOnCollidable = dontCollideComponent.empty() || !spawnedEntity.HasComponent("Collidable"); + if (!spawnOnCollidable) { + boost::optional optBox = Collision::EntityAbsoluteAABB(spawnedEntity); + //If we can't calculate the box for some reason, then just spawn somewhere anyway. + if (!optBox) { + spawnOnCollidable = true; + } + } + // Find any SpawnPoints existing as children of spawner auto children = spawner.World->GetChildren(spawner.ID); std::vector spawnPoints; for (auto kv = children.first; kv != children.second; ++kv) { const EntityID& child = kv->second; if (spawner.World->HasComponent(child, "SpawnPoint")) { - spawnPoints.push_back(EntityWrapper(spawner.World, child)); + EntityWrapper spawnPoint = EntityWrapper(spawner.World, child); + if (spawnOnCollidable || !spawnedEntityIsColliding(spawnedEntity, spawnPoint, dontCollideComponent)) { + spawnPoints.push_back(spawnPoint); + } } } // Choose a random SpawnPoint + // If there are no children, or if they are all blocked, then the entity will be spawned at the spawner itself. EntityWrapper spawnPoint = spawner; if (!spawnPoints.empty()) { if (spawnPoints.size() > 1) { @@ -39,25 +64,61 @@ EntityWrapper SpawnerSystem::Spawn(EntityWrapper spawner, EntityWrapper parent / } } - // Load the entity file and parse it - const std::string& entityFilePath = spawner["Spawner"]["EntityFile"]; - auto entityFile = ResourceManager::Load(entityFilePath); - if (entityFile == nullptr) { - return EntityWrapper::Invalid; - } - EntityFileParser parser(entityFile); - EntityWrapper spawnedEntity(world, parser.MergeEntities(world, parent.ID)); - if (spawnPoint != parent) { - // Set its position and orientation to that of the SpawnPoint - spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID); - // TODO: Quaternions, bitch - spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint)); + transformEntityToSpawnPoint(spawnedEntity, spawnPoint); } return spawnedEntity; } +void SpawnerSystem::transformEntityToSpawnPoint(EntityWrapper spawnedEntity, EntityWrapper spawnPoint) +{ + // Set its position and orientation to that of the SpawnPoint + spawnedEntity["Transform"]["Position"] = Transform::AbsolutePosition(spawnPoint.World, spawnPoint.ID); + // TODO: Quaternions, bitch + spawnedEntity["Transform"]["Orientation"] = glm::eulerAngles(Transform::AbsoluteOrientation(spawnPoint)); +} + +bool SpawnerSystem::spawnedEntityIsColliding(EntityWrapper spawnedEntity, EntityWrapper spawnPoint, const std::string& dontCollideComponent) +{ + transformEntityToSpawnPoint(spawnedEntity, spawnPoint); + //Check if the spawned entity collides with anything, and if so, continue to the next spawnpoint. + EntityAABB spawnedBox = *Collision::EntityAbsoluteAABB(spawnedEntity); + const ComponentPool* otherSpawnedEntities = spawnPoint.World->GetComponents(dontCollideComponent); + for (const auto& obj : *otherSpawnedEntities) { + if (spawnedEntity.ID == obj.EntityID) { + continue; + } + EntityWrapper otherEntity = EntityWrapper(spawnPoint.World, obj.EntityID); + if (!otherEntity.HasComponent("Collidable")) { + continue; + } + auto otherBox = Collision::EntityAbsoluteAABB(otherEntity); + if (!otherBox) { + continue; + } + if (Collision::AABBVsAABB(spawnedBox, *otherBox)) { + if (!spawnedBox.Entity.HasComponent("Model")) { + return true; + } + RawModel* model = nullptr; + try { + model = ResourceManager::Load(otherEntity["Model"]["Resource"]); + } catch (const std::exception&) { + } + + if (model != nullptr && Collision::AABBvsTriangles( + spawnedBox, + model->Vertices(), + model->m_Indices, + Transform::ModelMatrix(otherEntity))) { + return true; + } + } + } + return false; +} + bool SpawnerSystem::OnSpawnerSpawn(Events::SpawnerSpawn& e) { EntityWrapper spawnedEntity = Spawn(e.Spawner, e.Parent); From 72db672dbf55bf207df7aef8a7ccf3a41d2f50dd Mon Sep 17 00:00:00 2001 From: William Moberg Date: Wed, 17 Feb 2016 16:06:35 +0100 Subject: [PATCH 09/12] Ray will not hit objects in octree if they are transparent or invisible. --- src/Engine/Collision/Collision.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Engine/Collision/Collision.cpp b/src/Engine/Collision/Collision.cpp index 87d8bf26..99566404 100644 --- a/src/Engine/Collision/Collision.cpp +++ b/src/Engine/Collision/Collision.cpp @@ -693,8 +693,9 @@ boost::optional EntityFirstHitByRay(const Ray& ray, std::vector Date: Thu, 18 Feb 2016 11:27:07 +0100 Subject: [PATCH 10/12] Fixed so some of the tests are working again. Also removed the test errors --- src/Tests/CapturePointTest.cpp | 2 +- src/Tests/CollisionTest.cpp | 18 +++++++++--------- src/Tests/HealthSystemTest.cpp | 2 +- src/Tests/PickupSpawnTest.cpp | 2 +- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/Tests/CapturePointTest.cpp b/src/Tests/CapturePointTest.cpp index 2c7bf430..8a9baf40 100644 --- a/src/Tests/CapturePointTest.cpp +++ b/src/Tests/CapturePointTest.cpp @@ -94,7 +94,7 @@ CapturePointTest::CapturePointTest(int runTestNumber) m_World = new World(); // Create system pipeline - m_SystemPipeline = new SystemPipeline(m_World,m_EventBroker); + m_SystemPipeline = new SystemPipeline(m_World,m_EventBroker, true, false); m_SystemPipeline->AddSystem(0); m_SystemPipeline->AddSystem(1); diff --git a/src/Tests/CollisionTest.cpp b/src/Tests/CollisionTest.cpp index 6cb6c88b..b5ba8245 100644 --- a/src/Tests/CollisionTest.cpp +++ b/src/Tests/CollisionTest.cpp @@ -33,10 +33,10 @@ void RayTest(std::string fileName) { ResourceManager::RegisterType("RawModel"); auto unitBox = ResourceManager::Load(fileName); BOOST_REQUIRE(unitBox != nullptr); - bool hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices); + bool hit = Collision::RayVsModel(ray, unitBox->Vertices(), unitBox->m_Indices, glm::mat4(1)); BOOST_CHECK(hit); ray.SetDirection(glm::vec3(-1, 0, 0)); - hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices); + hit = Collision::RayVsModel(ray, unitBox->Vertices(), unitBox->m_Indices, glm::mat4(1)); BOOST_CHECK(!hit); } @@ -146,12 +146,12 @@ BOOST_AUTO_TEST_CASE(rayVsModelTest2) z = Collision::RayVsAABB(ray, someAABB); if (z) { //hit - bool hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices); + bool hit = Collision::RayVsModel(ray, unitBox->Vertices(), unitBox->m_Indices,glm::mat4(1)); if (!hit) { //if rayvsaabb hit but rayvvmodel didnt hit, we get to here - glm::vec3 outtttttttt; - hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices, outtttttttt); - hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices); + glm::mat4 outtttttttt; + hit = Collision::RayVsModel(ray, unitBox->Vertices(), unitBox->m_Indices, glm::mat4(1)); + hit = Collision::RayVsModel(ray, unitBox->Vertices(), unitBox->m_Indices, glm::mat4(1)); } else { hit = hit; @@ -163,7 +163,7 @@ BOOST_AUTO_TEST_CASE(rayVsModelTest2) // z = z; //} // - bool hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices); + bool hit = Collision::RayVsModel(ray, unitBox->Vertices(), unitBox->m_Indices, glm::mat4(1)); ////breakpoint test //if (!hit) { // hit = hit; @@ -175,8 +175,8 @@ BOOST_AUTO_TEST_CASE(rayVsModelTest2) //if rayvsmodel hit but rayvsaabb didnt hit then we get to here z = Collision::RayVsAABB(ray, someAABB); glm::vec3 outtttttttt; - hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices, outtttttttt); - hit = Collision::RayVsModel(ray, unitBox->m_Vertices, unitBox->m_Indices); + hit = Collision::RayVsModel(ray, unitBox->Vertices(), unitBox->m_Indices, glm::mat4(1)); + hit = Collision::RayVsModel(ray, unitBox->Vertices(), unitBox->m_Indices, glm::mat4(1)); } else { z = z; diff --git a/src/Tests/HealthSystemTest.cpp b/src/Tests/HealthSystemTest.cpp index 8c084070..bf2650a3 100644 --- a/src/Tests/HealthSystemTest.cpp +++ b/src/Tests/HealthSystemTest.cpp @@ -48,7 +48,7 @@ GameHealthSystemTest::GameHealthSystemTest() fp.MergeEntities(m_World); // Create system pipeline - m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker); + m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker, false, false); m_SystemPipeline->AddSystem(0); //The Test diff --git a/src/Tests/PickupSpawnTest.cpp b/src/Tests/PickupSpawnTest.cpp index 7cbed85f..4acd897e 100644 --- a/src/Tests/PickupSpawnTest.cpp +++ b/src/Tests/PickupSpawnTest.cpp @@ -39,7 +39,7 @@ PickupSpawnTest::PickupSpawnTest(int runTestNumber) m_World = new World(); // Create system pipeline - m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker); + m_SystemPipeline = new SystemPipeline(m_World, m_EventBroker, false, false); m_SystemPipeline->AddSystem(0); m_SystemPipeline->AddSystem(1); From fc5d054cb2bc9a7a6a5f08fca25f2f50eca9a4ba Mon Sep 17 00:00:00 2001 From: Tleety Date: Fri, 19 Feb 2016 12:49:07 +0100 Subject: [PATCH 11/12] Entity is now sent with the click events. Fixed small things --- include/Engine/GUI/EButtonClicked.h | 3 ++- include/Engine/GUI/EButtonPressed.h | 3 ++- include/Engine/GUI/EButtonReleased.h | 4 +++- include/Engine/Rendering/ModelJob.h | 4 ++-- src/Engine/GUI/ButtonSystem.cpp | 11 ++++++++--- src/Engine/Rendering/DrawFinalPass.cpp | 4 ++-- 6 files changed, 19 insertions(+), 10 deletions(-) diff --git a/include/Engine/GUI/EButtonClicked.h b/include/Engine/GUI/EButtonClicked.h index f34d6b3d..e4fe7abe 100644 --- a/include/Engine/GUI/EButtonClicked.h +++ b/include/Engine/GUI/EButtonClicked.h @@ -7,7 +7,8 @@ namespace Events { struct ButtonClicked : public Event { - std::string EntityName = "DEFAULT STRING USED"; + std::string EntityName; + EntityWrapper Entity; }; } diff --git a/include/Engine/GUI/EButtonPressed.h b/include/Engine/GUI/EButtonPressed.h index 04d50978..3615ac8a 100644 --- a/include/Engine/GUI/EButtonPressed.h +++ b/include/Engine/GUI/EButtonPressed.h @@ -7,7 +7,8 @@ namespace Events { struct ButtonPressed : public Event { - std::string EntityName = "DEFAULT STRING USED"; + std::string EntityName; + EntityWrapper Entity; }; } diff --git a/include/Engine/GUI/EButtonReleased.h b/include/Engine/GUI/EButtonReleased.h index 14736ca0..90170518 100644 --- a/include/Engine/GUI/EButtonReleased.h +++ b/include/Engine/GUI/EButtonReleased.h @@ -6,7 +6,9 @@ namespace Events { -struct ButtonReleased : public Event { }; +struct ButtonReleased : public Event { + EntityWrapper Entity; +}; } diff --git a/include/Engine/Rendering/ModelJob.h b/include/Engine/Rendering/ModelJob.h index ccd0e093..8801d2eb 100644 --- a/include/Engine/Rendering/ModelJob.h +++ b/include/Engine/Rendering/ModelJob.h @@ -108,7 +108,7 @@ struct ModelJob : RenderJob EndIndex = matGroup->EndIndex; Matrix = matrix; Color = modelComponent["Color"]; - GlowIntencity = ((double)modelComponent["GlowIntensity"]); + GlowIntensity = ((double)modelComponent["GlowIntensity"]); Entity = modelComponent.EntityID; glm::vec3 abspos = Transform::AbsolutePosition(world, modelComponent.EntityID); glm::vec3 worldpos = glm::vec3(camera->ViewMatrix() * glm::vec4(abspos, 1)); @@ -171,7 +171,7 @@ struct ModelJob : RenderJob ::Skeleton::AnimationOffset AnimationOffset; - float GlowIntencity = 8.0; + float GlowIntensity = 8.0; glm::vec4 DiffuseColor; glm::vec4 SpecularColor; glm::vec4 IncandescenceColor; diff --git a/src/Engine/GUI/ButtonSystem.cpp b/src/Engine/GUI/ButtonSystem.cpp index dbdc0e18..7c66e456 100644 --- a/src/Engine/GUI/ButtonSystem.cpp +++ b/src/Engine/GUI/ButtonSystem.cpp @@ -38,6 +38,7 @@ bool ButtonSystem::OnMousePress(const Events::MousePress& e) //You have clicked on a button entity, send pressed event. Events::ButtonPressed ePressed; + ePressed.Entity = m_PickEntity; ePressed.EntityName = m_PickEntity.Name(); m_EventBroker->Publish(ePressed); } @@ -50,15 +51,19 @@ bool ButtonSystem::OnMouseRelease(const Events::MouseRelease& e) { if(!m_MouseIsLocked) { //Mouse is not locked, send release event. - Events::ButtonReleased eReleased; - m_EventBroker->Publish(eReleased); m_PickData = m_Renderer->Pick(glm::vec2(e.X, e.Y)); if(m_PickData.Entity != EntityID_Invalid && m_PickData.World == m_World) { + EntityWrapper ent = EntityWrapper(m_World, m_PickData.Entity); + + Events::ButtonReleased eReleased; + eReleased.Entity = ent; + m_EventBroker->Publish(eReleased); + if(m_World->HasComponent(m_PickData.Entity, "Button")) { - EntityWrapper ent = EntityWrapper(m_World, m_PickData.Entity); if (ent == m_PickEntity) { //The entity you released the mouse button on is the same as you pressed it on. "Clicked" Events::ButtonClicked eClicked; + eClicked.Entity = m_PickEntity; eClicked.EntityName = m_PickEntity.Name(); m_EventBroker->Publish(eClicked); } diff --git a/src/Engine/Rendering/DrawFinalPass.cpp b/src/Engine/Rendering/DrawFinalPass.cpp index fd95ecee..54a523be 100644 --- a/src/Engine/Rendering/DrawFinalPass.cpp +++ b/src/Engine/Rendering/DrawFinalPass.cpp @@ -736,7 +736,7 @@ void DrawFinalPass::BindExplosionUniforms(GLuint shaderHandle, std::shared_ptrGlowIntencity); + glUniform1f(glGetUniformLocation(shaderHandle, "GlowIntensity"), job->GlowIntensity); GLERROR("END"); } @@ -775,7 +775,7 @@ void DrawFinalPass::BindModelUniforms(GLuint shaderHandle, std::shared_ptrGlowIntencity); + glUniform1f(Location_GlowIntensity, job->GlowIntensity); GLERROR("END"); } From 6e5335a266afa82a4a2a64e8d2b8244b93dae200 Mon Sep 17 00:00:00 2001 From: Tleety Date: Fri, 19 Feb 2016 13:16:26 +0100 Subject: [PATCH 12/12] Release now return name and entity of the entity that was previously klicked. --- include/Engine/GUI/EButtonReleased.h | 1 + src/Engine/GUI/ButtonSystem.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/include/Engine/GUI/EButtonReleased.h b/include/Engine/GUI/EButtonReleased.h index 90170518..ecd8dde2 100644 --- a/include/Engine/GUI/EButtonReleased.h +++ b/include/Engine/GUI/EButtonReleased.h @@ -7,6 +7,7 @@ namespace Events { struct ButtonReleased : public Event { + std::string EntityName; EntityWrapper Entity; }; diff --git a/src/Engine/GUI/ButtonSystem.cpp b/src/Engine/GUI/ButtonSystem.cpp index 7c66e456..93ae1811 100644 --- a/src/Engine/GUI/ButtonSystem.cpp +++ b/src/Engine/GUI/ButtonSystem.cpp @@ -56,7 +56,8 @@ bool ButtonSystem::OnMouseRelease(const Events::MouseRelease& e) EntityWrapper ent = EntityWrapper(m_World, m_PickData.Entity); Events::ButtonReleased eReleased; - eReleased.Entity = ent; + eReleased.EntityName = m_PickEntity.Name(); + eReleased.Entity = m_PickEntity; m_EventBroker->Publish(eReleased); if(m_World->HasComponent(m_PickData.Entity, "Button")) {