Merge remote-tracking branch 'origin/master' into Forward+

# Conflicts:
#	resources/Schema/Types/Entity.xsd
This commit is contained in:
Tleety
2016-01-08 14:14:43 +01:00
25 changed files with 639 additions and 67 deletions
+20
View File
@@ -0,0 +1,20 @@
#ifndef EPlayerDamage_h__
#define EPlayerDamage_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
namespace Events
{
struct PlayerDamage : Event
{
double DamageAmount;
EntityID PlayerDamagedID;
//optional TypeOfDamage
std::string TypeOfDamage;
};
}
#endif
+20
View File
@@ -0,0 +1,20 @@
#ifndef EPlayerDeath_h__
#define EPlayerDeath_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
namespace Events
{
struct PlayerDeath : Event
{
//KilledBy,KilledByWhat is optional for now. It might be used later in the playerlog-system
EntityID KilledBy;
EntityID PlayerID;
std::string KilledByWhat;
};
}
#endif
+18
View File
@@ -0,0 +1,18 @@
#ifndef EPlayerHealthPickup_h__
#define EPlayerHealthPickup_h__
#include "EventBroker.h"
#include "../Core/Entity.h"
namespace Events
{
struct PlayerHealthPickup : Event
{
double HealthAmount;
EntityID PlayerHealedID;
};
}
#endif
+6 -2
View File
@@ -13,6 +13,8 @@
relay = decltype(relay)(std::bind(handler, this, std::placeholders::_1)); \
m_EventBroker->Subscribe(relay);
typedef unsigned int EventID;
class EventBroker;
class BaseEventRelay
@@ -31,6 +33,7 @@ public:
virtual bool Receive(const std::shared_ptr<Event> event) = 0;
protected:
EventID m_EventID;
std::string m_ContextTypeName;
std::string m_EventTypeName;
EventBroker* m_Broker;
@@ -95,6 +98,7 @@ public:
private:
bool m_IsProcessing = false;
EventID m_NextEventID = 0;
typedef std::string ContextTypeName_t; // typeid(ContextType).name()
typedef std::string EventTypeName_t; // typeid(EventType).name()
@@ -103,14 +107,14 @@ private:
typedef std::unordered_map<ContextTypeName_t, EventRelays_t> ContextRelays_t;
ContextRelays_t m_ContextRelays;
std::vector<BaseEventRelay*> m_RelaysToSubscribe;
std::vector<BaseEventRelay*> m_RelaysToUnsubscribe;
std::vector<std::tuple<EventID, ContextTypeName_t, EventTypeName_t>> m_RelaysToUnsubscribe;
typedef std::list<std::pair<EventTypeName_t, std::shared_ptr<Event>>> EventQueue_t;
std::shared_ptr<EventQueue_t> m_EventQueueRead;
std::shared_ptr<EventQueue_t> m_EventQueueWrite;
void subscribeImmediate(BaseEventRelay& relay);
void unsubscribeImmediate(BaseEventRelay& relay);
void unsubscribeImmediate(std::tuple<EventID, ContextTypeName_t, EventTypeName_t> identifier);
};
template <typename EventType>
+40 -27
View File
@@ -14,21 +14,28 @@ public:
{ }
~SystemPipeline()
{
for (auto& pair : m_Systems) {
delete pair.second;
for (UnorderedSystems& group : m_OrderedSystemGroups) {
for (auto& pair : group.Systems) {
delete pair.second;
}
}
}
template <typename T, typename... Arguments>
void AddSystem(Arguments... args)
//All systems with orderlevel 0 will be updated first, then 1, 2, etc.
void AddSystem(int updateOrderLevel, Arguments... args)
{
if (updateOrderLevel + 1 > m_OrderedSystemGroups.size()) {
m_OrderedSystemGroups.resize(updateOrderLevel + 1);
}
UnorderedSystems& group = m_OrderedSystemGroups[updateOrderLevel];
System* system = new T(m_EventBroker, args...);
m_Systems[typeid(T).name()] = system;
group.Systems[typeid(T).name()] = system;
if (std::is_base_of<PureSystem, T>::value) {
PureSystem* pureSystem = static_cast<PureSystem*>(system);
if (!pureSystem->m_ComponentType.empty()) {
m_PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
group.PureSystems[pureSystem->m_ComponentType].push_back(pureSystem);
} else {
LOG_ERROR("Failed to add pure system \"%s\": Missing component type!", typeid(T).name());
}
@@ -36,41 +43,47 @@ public:
if (std::is_base_of<ImpureSystem, T>::value) {
ImpureSystem* impureSystem = static_cast<ImpureSystem*>(system);
m_ImpureSystems.push_back(impureSystem);
group.ImpureSystems.push_back(impureSystem);
}
}
void Update(World* world, double dt)
{
// Process events
for (auto& pair : m_Systems) {
m_EventBroker->Process(pair.first);
}
// Update
for (auto& pair : m_PureSystems) {
const std::string& componentName = pair.first;
auto& systems = pair.second;
const ComponentPool* pool = world->GetComponents(componentName);
if (pool == nullptr) {
continue;
for (UnorderedSystems& group : m_OrderedSystemGroups) {
// Process events
for (auto& pair : group.Systems) {
m_EventBroker->Process(pair.first);
}
for (auto& component : *pool) {
for (auto& system : systems) {
system->UpdateComponent(world, component, dt);
// Update
for (auto& pair : group.PureSystems) {
const std::string& componentName = pair.first;
auto& systems = pair.second;
const ComponentPool* pool = world->GetComponents(componentName);
if (pool == nullptr) {
continue;
}
for (auto& component : *pool) {
for (auto& system : systems) {
system->UpdateComponent(world, component, dt);
}
}
}
}
for (auto& system : m_ImpureSystems) {
system->Update(world, dt);
for (auto& system : group.ImpureSystems) {
system->Update(world, dt);
}
}
}
private:
EventBroker* m_EventBroker;
std::map<std::string, System*> m_Systems;
std::map<std::string, std::vector<PureSystem*>> m_PureSystems;
std::vector<ImpureSystem*> m_ImpureSystems;
struct UnorderedSystems
{
std::map<std::string, System*> Systems;
std::map<std::string, std::vector<PureSystem*>> PureSystems;
std::vector<ImpureSystem*> ImpureSystems;
};
std::vector<UnorderedSystems> m_OrderedSystemGroups;
};
#endif
+36
View File
@@ -0,0 +1,36 @@
#ifndef HealthSystem_h__
#define HealthSystem_h__
#include <GLFW/glfw3.h>
#include <glm/common.hpp>
#include "Common.h"
#include "Core/System.h"
#include "Core\EPlayerDamage.h";
#include "Core\EPlayerHealthPickup.h";
#include "Core\EPlayerDeath.h";
#include <tuple>
#include <vector>
class HealthSystem : public PureSystem
{
public:
HealthSystem(EventBroker* eventBroker);
//updatecomponent
virtual void UpdateComponent(World* world, ComponentWrapper& health, double dt) override;
private:
//methods which will take care of specific events
EventRelay<HealthSystem, Events::PlayerDamage> m_EPlayerDamage;
bool HealthSystem::OnPlayerDamaged(const Events::PlayerDamage& e);
EventRelay<HealthSystem, Events::PlayerHealthPickup> m_EPlayerHealthPickup;
bool HealthSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup& e);
//vector which will keep track of health changes
std::vector<std::tuple<EntityID, double>> m_DeltaHealthVector;
};
#endif
+1
View File
@@ -9,4 +9,5 @@
<xs:include schemaLocation="Components/AABB.xsd"/>
<xs:include schemaLocation="Components/PointLight.xsd"/>
<xs:include schemaLocation="Components/Trigger.xsd"/>
<xs:include schemaLocation="Components/Health.xsd"/>
</xs:schema>
+4
View File
@@ -0,0 +1,4 @@
<c:Health>
<Health>100</Health>
<MaxHealth>100</MaxHealth>
</c:Health>
+14
View File
@@ -0,0 +1,14 @@
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:t="types">
<xs:import schemaLocation="../Types.xsd" namespace="types"/>
<xs:element name="Health">
<xs:complexType>
<xs:all>
<xs:element name="Health" type="t:double" minOccurs="0"/>
<xs:element name="MaxHealth" type="t:double" minOccurs="0"/>
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
+1
View File
@@ -15,6 +15,7 @@
<xs:element ref="c:Test" minOccurs="0"/>
<xs:element ref="c:RaptorCopter" minOccurs="0"/>
<xs:element ref="c:Player" minOccurs="0"/>
<xs:element ref="c:Health" minOccurs="0"/>
<xs:element ref="c:PointLight" minOccurs="0"/>
</xs:all>
</xs:complexType>
-2
View File
@@ -4,8 +4,6 @@
void CollisionSystem::UpdateComponent(World * world, ComponentWrapper & cAABB, double dt)
{
//TODO: Update CollisionSystem system after PlayerSystem.
//Right now, cAABB is a component attached to any entity that should be collideable.
AABB thisBox;
if (!Collision::GetEntityBox(world, cAABB, thisBox)) {
+26 -19
View File
@@ -2,21 +2,24 @@
BaseEventRelay::~BaseEventRelay()
{
if (m_Broker != nullptr) {
if (m_Broker != nullptr) {
m_Broker->Unsubscribe(*this);
}
}
}
void EventBroker::Unsubscribe(BaseEventRelay &relay) // ?
void EventBroker::Unsubscribe(BaseEventRelay& relay) // ?
{
if (m_IsProcessing) {
m_RelaysToUnsubscribe.push_back(&relay);
} else {
unsubscribeImmediate(relay);
}
auto identifier = std::make_tuple(relay.m_EventID, relay.m_ContextTypeName, relay.m_EventTypeName);
relay.m_Broker = nullptr;
if (m_IsProcessing) {
m_RelaysToUnsubscribe.push_back(identifier);
} else {
unsubscribeImmediate(identifier);
}
}
void EventBroker::Subscribe(BaseEventRelay &relay)
void EventBroker::Subscribe(BaseEventRelay& relay)
{
if (m_IsProcessing) {
m_RelaysToSubscribe.push_back(&relay);
@@ -38,12 +41,11 @@ int EventBroker::Process(std::string contextTypeName)
int eventsProcessed = 0;
for (auto &pair : *m_EventQueueRead) {
std::string &eventTypeName = pair.first;
std::string& eventTypeName = pair.first;
std::shared_ptr<Event> event = pair.second;
auto itpair = relays.equal_range(eventTypeName);
for (auto it2 = itpair.first; it2 != itpair.second; it2++)
{
for (auto it2 = itpair.first; it2 != itpair.second; it2++) {
std::string name = it2->first;
BaseEventRelay* relay = it2->second;
relay->Receive(event);
@@ -60,8 +62,8 @@ int EventBroker::Process(std::string contextTypeName)
m_RelaysToSubscribe.clear();
// Process pending unsubscriptions
for (auto& r : m_RelaysToUnsubscribe) {
unsubscribeImmediate(*r);
for (auto& identifier : m_RelaysToUnsubscribe) {
unsubscribeImmediate(identifier);
}
m_RelaysToUnsubscribe.clear();
@@ -81,21 +83,26 @@ void EventBroker::Clear()
void EventBroker::subscribeImmediate(BaseEventRelay& relay)
{
relay.m_Broker = this;
relay.m_EventID = m_NextEventID++;
m_ContextRelays[relay.m_ContextTypeName].insert(std::make_pair(relay.m_EventTypeName, &relay));
}
void EventBroker::unsubscribeImmediate(BaseEventRelay& relay)
void EventBroker::unsubscribeImmediate(std::tuple<EventID, ContextTypeName_t, EventTypeName_t> identifier)
{
auto contextIt = m_ContextRelays.find(relay.m_ContextTypeName);
EventID eventID;
ContextTypeName_t contextTypeName;
EventTypeName_t eventTypeName;
std::tie(eventID, contextTypeName, eventTypeName) = identifier;
auto contextIt = m_ContextRelays.find(contextTypeName);
if (contextIt == m_ContextRelays.end()) {
return;
}
auto eventRelays = contextIt->second;
auto itpair = eventRelays.equal_range(relay.m_EventTypeName);
auto itpair = eventRelays.equal_range(eventTypeName);
for (auto it = itpair.first; it != itpair.second; ++it) {
if (it->second == &relay) {
relay.m_Broker = nullptr;
if (it->second->m_EventID == eventID) {
eventRelays.erase(it);
break;
}
+1
View File
@@ -19,6 +19,7 @@ file(GLOB SOURCE_FILES
set(SOURCE_FILES
${SOURCE_FILES}
"Game.cpp"
"HealthSystem.cpp"
"PlayerSystem.cpp"
)
+14 -6
View File
@@ -1,6 +1,7 @@
#include "Game.h"
#include "Collision/TriggerSystem.h"
#include "Collision/CollisionSystem.h"
#include "Game/HealthSystem.h"
Game::Game(int argc, char* argv[])
{
@@ -27,7 +28,7 @@ Game::Game(int argc, char* argv[])
0,
m_Config->Get<int>("Video.Width", 1280),
m_Config->Get<int>("Video.Height", 720)
));
));
m_Renderer->Initialize();
m_Renderer->Camera()->SetFOV(glm::radians(m_Config->Get<float>("Video.FOV", 90.f)));
@@ -52,11 +53,18 @@ Game::Game(int argc, char* argv[])
// Create system pipeline
m_SystemPipeline = new SystemPipeline(m_EventBroker);
m_SystemPipeline->AddSystem<RaptorCopterSystem>();
m_SystemPipeline->AddSystem<PlayerSystem>();
m_SystemPipeline->AddSystem<EditorSystem>(m_Renderer);
m_SystemPipeline->AddSystem<CollisionSystem>();
m_SystemPipeline->AddSystem<TriggerSystem>();
//All systems with orderlevel 0 will be updated first.
unsigned int updateOrderLevel = 0;
m_SystemPipeline->AddSystem<RaptorCopterSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<PlayerSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<EditorSystem>(updateOrderLevel, m_Renderer);
m_SystemPipeline->AddSystem<HealthSystem>(updateOrderLevel);
//Collision and TriggerSystem should update after player.
++updateOrderLevel;
m_SystemPipeline->AddSystem<CollisionSystem>(updateOrderLevel);
m_SystemPipeline->AddSystem<TriggerSystem>(updateOrderLevel);
// Invoke network
if (m_Config->Get<bool>("Networking.StartNetwork", false)) {
+59
View File
@@ -0,0 +1,59 @@
#include "HealthSystem.h"
#include <algorithm>
HealthSystem::HealthSystem(EventBroker* eventBroker)
: PureSystem(eventBroker, "Health")
{
//subscribe/listenTo playerdamage,healthpickup events (using the eventBroker)
EVENT_SUBSCRIBE_MEMBER(m_EPlayerDamage, &HealthSystem::OnPlayerDamaged);
EVENT_SUBSCRIBE_MEMBER(m_EPlayerHealthPickup, &HealthSystem::OnPlayerHealthPickup);
}
void HealthSystem::UpdateComponent(World *world, ComponentWrapper &health, double dt)
{
//if entityID of health is 9 then the players ID is also 9 (player,health are connected to the same entity)
ComponentWrapper player = world->GetComponent(health.EntityID, "Player");
double maxHealth = (double)health["MaxHealth"];
//process the DeltaHealthVector and change the entitys health accordingly
for (size_t i = m_DeltaHealthVector.size(); i > 0; i--)
{
auto deltaHP = m_DeltaHealthVector[i - 1];
//if we have a healthchange for the current player and health is greater than 0, then apply it
if (std::get<0>(deltaHP) == player.EntityID && (double)health["Health"] > 0.0f) {
//get the deltaHP value from the tuple and make sure you dont get more than maxHealth
double newHealth = std::min((double)health["Health"] + (double)std::get<1>(deltaHP), maxHealth);
health["Health"] = newHealth;
m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + i - 1);
//check if health is <= 0
if ((double)health["Health"] <= 0.0f) {
//publish death event
Events::PlayerDeath e;
e.PlayerID = player.EntityID;
m_EventBroker->Publish(e);
//clear the remaining hpDeltas for the dead player
for (size_t j = m_DeltaHealthVector.size(); j > 0; j--)
{
if (std::get<0>(m_DeltaHealthVector[j - 1]) == player.EntityID)
m_DeltaHealthVector.erase(m_DeltaHealthVector.begin() + j - 1);
}
//break the loop if the player is dead
break;
}
}
}
}
bool HealthSystem::OnPlayerDamaged(const Events::PlayerDamage& e)
{
//save the changed HP to a vector. it will be taken care of in UpdateComponent
m_DeltaHealthVector.push_back(std::make_tuple(e.PlayerDamagedID, -e.DamageAmount));
return true;
}
bool HealthSystem::OnPlayerHealthPickup(const Events::PlayerHealthPickup& e)
{
//save the changed HP to a vector. it will be taken care of in UpdateComponent
m_DeltaHealthVector.push_back(std::make_tuple(e.PlayerHealedID, e.HealthAmount));
return true;
}
+66
View File
@@ -0,0 +1,66 @@
#include <boost/test/unit_test.hpp>
#include <boost/test/execution_monitor.hpp>
using boost::unit_test_framework::test_suite;
using boost::unit_test_framework::test_case;
#include <stdlib.h>//srand
//#define private public
#include "Engine\Core\ConfigFile.h"
#define _CRTDBG_MAP_ALLOC
#include <crtdbg.h>
#define DEBUG_CLIENTBLOCK new( _CLIENT_BLOCK, __FILE__, __LINE__)
#define new DEBUG_CLIENTBLOCK
BOOST_AUTO_TEST_SUITE(confTest)
BOOST_AUTO_TEST_CASE(configFileTest)
{
//note: this ConfigFileclass currently has memleaks!
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
auto m_Config = ResourceManager::Load<ConfigFile>("ConfigTest.ini");
//bägge måste vara av samma typ, T typen är string
//http://www.boost.org/doc/libs/1_42_0/doc/html/boost_propertytree/tutorial.html
//"Note that we construct the path to the value by separating the individual keys with dots"
//get from tree tests
auto getSomething = m_Config->Get("Test.Test1", 0);
BOOST_CHECK(getSomething == 423);
auto getSomething2 = m_Config->Get("fsdfdsfd.T", std::string(""));
BOOST_CHECK(getSomething2 == "\"gfdjakflsdl!\"");
//set/get tests
m_Config->Set("Test.4321", 123);
auto getSomething3 = m_Config->Get("Test.4321", 0);
BOOST_CHECK(getSomething3 == 123);
m_Config->Set("3_2_1_0_5", "t454j54hj5k32");
auto getSomething4 = m_Config->Get("3_2_1_0_5", std::string(""));
BOOST_CHECK(getSomething4 == "t454j54hj5k32");
//***check so outputwindow says: EE: Failed to find "DefaultConfigTestNotExists.ini"! Relying on hardcoded default values!
auto m_Config2 = ResourceManager::Load<ConfigFile>("ConfigTestNotExists.ini");
//set value/savetodisk/load/checkvalue...
m_Config->SaveToDisk();
m_Config->Set("Test.4321", 145);
m_Config->SaveToDisk();
auto m_Config3 = ResourceManager::Load<ConfigFile>("ConfigTest.ini");
auto getSomething5 = m_Config->Get("Test.4321", 0);
BOOST_CHECK(getSomething5 == 145);
//***check so outputwindow says: EE: Failed to parse "DefaultConfigTestFailed.ini"
//***check so outputwindow says: EE: Failed to parse "ConfigTestFailed.ini":
auto m_Config4 = ResourceManager::Load<ConfigFile>("ConfigTestFailed.ini");
//reload,onchildreload unimplemented
//NOTE:still massive amount of memoryleaks from this method
_CrtDumpMemoryLeaks();
}
BOOST_AUTO_TEST_SUITE_END()
+54
View File
@@ -0,0 +1,54 @@
#ifndef EVENTFIXTURE_H
#define EVENTFIXTURE_H
#include <boost/test/unit_test.hpp>
#include "Core\EventBroker.h"
template <typename EventType>
struct EventFixture
{
EventFixture()
{
this->ventBroker = new EventBroker();
m_EEventType = decltype(m_EEventType)(std::bind(&EventFixture::OnEvent, this, std::placeholders::_1));
this->ventBroker->Subscribe(m_EEventType);
Run();
Check();
}
~EventFixture()
{
this->ventBroker->Unsubscribe(m_EEventType);
delete this->ventBroker;
}
EventBroker* ventBroker = nullptr;
EventRelay<EventFixture, EventType> m_EEventType;
bool m_EventRecieved = false;
EventType Before;
EventType After;
bool OnEvent(const EventType& event)
{
m_EventRecieved = true;
After = event;
return true;
}
void Run()
{
// Publish the event
this->ventBroker->Publish(Before);
// Clear to swap buffers
this->ventBroker->Swap();
// Process the event
this->ventBroker->template Process<EventFixture>();
}
void Check()
{
BOOST_CHECK(m_EventRecieved);
}
};
#endif
+19
View File
@@ -0,0 +1,19 @@
#include <boost/test/unit_test.hpp>
#include "EventFixture.h"
struct ETestEvent : public Event
{
int Int = 5;
float Float = 1.33333f;
double Double = 1.33333;
std::string String = "Hello World";
};
BOOST_AUTO_TEST_CASE(EventBrokerTest)
{
EventFixture<ETestEvent> f;
BOOST_CHECK(f.Before.Int == f.After.Int);
BOOST_CHECK_CLOSE(f.Before.Float, f.After.Float, 0.00001f);
BOOST_CHECK_CLOSE(f.Before.Double, f.After.Double, 0.00001f);
BOOST_CHECK(f.Before.String == f.After.String);
}
+114
View File
@@ -0,0 +1,114 @@
#include <boost/test/unit_test.hpp>
using boost::unit_test_framework::test_suite;
using boost::unit_test_framework::test_case;
#include "HealthSystemTest.h"
#include "Game/HealthSystem.h"
BOOST_AUTO_TEST_SUITE(HealthSystemSuite)
BOOST_AUTO_TEST_CASE(HealthSystemTest)
{
//this tests 2 healthevents and the healthsystem
GameHealthSystemTest game;
//100 loops will be more than enough to do the test
int loops = 100;
bool success = false;
while (loops > 0) {
game.Tick();
if (game.TestSucceeded) {
success = true;
break;
}
loops--;
}
//The system will process the events, hence it will take a while before we can read anything
BOOST_TEST(success);
}
BOOST_AUTO_TEST_SUITE_END()
GameHealthSystemTest::GameHealthSystemTest()
{
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
ResourceManager::RegisterType<EntityXMLFile>("EntityXMLFile");
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
// Create the core event broker
m_EventBroker = new EventBroker();
// Create a world
m_World = new World();
std::string mapToLoad = m_Config->Get<std::string>("Debug.LoadMap", "");
if (!mapToLoad.empty()) {
ResourceManager::Load<EntityXMLFile>(mapToLoad)->PopulateWorld(m_World);
}
// Create system pipeline
m_SystemPipeline = new SystemPipeline(m_EventBroker);
m_SystemPipeline->AddSystem<PlayerSystem>(0);
m_SystemPipeline->AddSystem<HealthSystem>(0);
//The Test
//create entity which has transorm,player,model,health in it. i.e. is a player
EntityID playerID = m_World->CreateEntity();
ComponentWrapper transform = m_World->AttachComponent(playerID, "Transform");
ComponentWrapper model = m_World->AttachComponent(playerID, "Model");
model["Resource"] = "Models/Core/UnitSphere.obj";
ComponentWrapper player = m_World->AttachComponent(playerID, "Player");
ComponentWrapper health = m_World->AttachComponent(playerID, "Health");
healthsID = playerID;
double currentHealth = (double)m_World->GetComponent(healthsID, "Health")["Health"];
//heal player with 40
Events::PlayerHealthPickup e3;
e3.HealthAmount = 40.0f;
e3.PlayerHealedID = healthsID;
m_EventBroker->Publish(e3);
//damage player with 50
Events::PlayerDamage e;
e.DamageAmount = 50.0f;
e.PlayerDamagedID = healthsID;
m_EventBroker->Publish(e);
//heal some other player with 40
Events::PlayerHealthPickup e2;
e2.HealthAmount = 40.0f;
e2.PlayerHealedID = healthsID+1;
m_EventBroker->Publish(e2);
EntityID playerID2 = m_World->CreateEntity();
ComponentWrapper transform2 = m_World->AttachComponent(playerID2, "Transform");
ComponentWrapper model2 = m_World->AttachComponent(playerID2, "Model");
model2["Resource"] = "Models/Core/UnitSphere.obj";
ComponentWrapper player2 = m_World->AttachComponent(playerID2, "Player");
ComponentWrapper health2 = m_World->AttachComponent(playerID2, "Health");
//END TEST
}
GameHealthSystemTest::~GameHealthSystemTest()
{
delete m_SystemPipeline;
delete m_World;
delete m_EventBroker;
}
void GameHealthSystemTest::Tick()
{
glfwPollEvents();
double currentTime = glfwGetTime();
double dt = currentTime - m_LastTime;
m_LastTime = currentTime;
// Iterate through systems and update world!
m_SystemPipeline->Update(m_World, dt);
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)
TestSucceeded = true;
}
+40
View File
@@ -0,0 +1,40 @@
#ifndef HealthTest_h__
#define HealthTest_h__
#include "Core/ResourceManager.h"
#include "Core/ConfigFile.h"
#include "Core/EventBroker.h"
#include "Rendering/Renderer.h"
#include "Core/InputManager.h"
#include "GUI/Frame.h"
#include "Core/World.h"
#include "Rendering/RenderQueueFactory.h"
#include "Input/InputProxy.h"
#include "Input/KeyboardInputHandler.h"
#include "Input/MouseInputHandler.h"
#include "Core/EKeyDown.h"
#include "Core/EntityXMLFile.h"
#include "Core/SystemPipeline.h"
#include "RaptorCopterSystem.h"
#include "PlayerSystem.h"
#include "Editor/EditorSystem.h"
class GameHealthSystemTest
{
public:
GameHealthSystemTest();
~GameHealthSystemTest();
void Tick();
bool TestSucceeded = false;
private:
double m_LastTime;
ConfigFile* m_Config = nullptr;
EventBroker* m_EventBroker;
World* m_World;
SystemPipeline* m_SystemPipeline;
int healthsID;
};
#endif
+12
View File
@@ -0,0 +1,12 @@
#include <boost/test/unit_test.hpp>
#include "Engine\Core\InputManager.h"
BOOST_AUTO_TEST_SUITE(inputManagerTests)
BOOST_AUTO_TEST_CASE(inputManagerTest)
{
//already tested eventbroker so inputManager is indirectly already tested
}
BOOST_AUTO_TEST_SUITE_END()
+1 -5
View File
@@ -34,16 +34,12 @@ BOOST_AUTO_TEST_CASE(octTreeTest)
BOOST_CHECK(someAABB.MaxCorner() == maxCorner);
BOOST_CHECK(someAABB.Center() == 0.5f * (minCorner + maxCorner));
//simple OctTree constructor check
//OctTree someOctTree(someAABB, 5);
//BOOST_CHECK(someOctTree.m_Children[0] != nullptr);
//simple destructor check in the end, just look for memleaks, then it didnt clear the AABB structure
}
BOOST_AUTO_TEST_CASE(octTreeTest2)
{
//octtree ritningen osv
//octtree draw etc
Game game(0, nullptr);
while (game.Running()) {
game.Tick();
+26 -5
View File
@@ -5,6 +5,8 @@ Game::Game(int argc, char* argv[]) : someOctTree(AABB(-0.5f*worldSize, 0.5f*worl
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
ResourceManager::RegisterType<Model>("Model");
ResourceManager::RegisterType<Texture>("Texture");
ResourceManager::RegisterType<EntityXMLFile>("EntityXMLFile");
ResourceManager::RegisterType<ShaderProgram>("ShaderProgram");
m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
LOG_LEVEL = static_cast<_LOG_LEVEL>(m_Config->Get<int>("Debug.LogLevel", 1));
@@ -25,9 +27,14 @@ Game::Game(int argc, char* argv[]) : someOctTree(AABB(-0.5f*worldSize, 0.5f*worl
m_Config->Get<int>("Video.Height", 720)
));
m_Renderer->Initialize();
m_Renderer->Camera()->SetFOV(glm::radians(m_Config->Get<float>("Video.FOV", 90.f)));
// Create input manager
m_InputManager = new InputManager(m_Renderer->Window(), m_EventBroker);
m_InputProxy = new InputProxy(m_EventBroker);
m_InputProxy->AddHandler<KeyboardInputHandler>();
m_InputProxy->AddHandler<MouseInputHandler>();
m_InputProxy->LoadBindings("Input.ini");
// Create the root level GUI frame
m_FrameStack = new GUI::Frame(m_EventBroker);
@@ -37,6 +44,9 @@ Game::Game(int argc, char* argv[]) : someOctTree(AABB(-0.5f*worldSize, 0.5f*worl
// Create a TEST WORLD
m_World = new HardcodedTestWorld();
m_SystemPipeline = new SystemPipeline(m_EventBroker);
m_SystemPipeline->AddSystem<PlayerSystem>(0);
m_LastTime = glfwGetTime();
}
@@ -52,9 +62,14 @@ void Game::Tick()
double dt = currentTime - m_LastTime;
m_LastTime = currentTime;
// Handle input in a weird looking but responsive way
m_EventBroker->Process<InputManager>();
m_EventBroker->Swap();
m_InputManager->Update(dt);
m_Renderer->Update(dt);
m_EventBroker->Swap();
m_InputProxy->Update(dt);
m_EventBroker->Swap();
m_InputProxy->Process();
m_EventBroker->Swap();
#define TEST1
@@ -70,7 +85,7 @@ void Game::Tick()
AABB boxi;
boxi.CreateFromCenter(pos, maxPos - minPos);
frameCounter++;
if (frameCounter > 50) {
if (frameCounter > 1) {
m_World->someOctTree.ClearDynamicObjects();
m_World->someOctTree.AddDynamicObject(boxi);
frameCounter = 0;
@@ -149,8 +164,8 @@ void Game::Tick()
if (someOctTree.BoxCollides(redBox, AABB())) {
//this checks AABB vs AABB
//if (Collision::AABBVsAABB(redBox, aabb)) {
m_Renderer->Camera()->SetPosition(m_PrevPos);
m_Renderer->Camera()->SetOrientation(m_PrevOri);
//m_Renderer->Camera()->SetPosition(m_PrevPos);
//m_Renderer->Camera()->SetOrientation(m_PrevOri);
model["Color"] = greenCol;
}
else {
@@ -163,8 +178,14 @@ void Game::Tick()
m_RenderQueueFactory->Update(m_World);
#endif
m_Renderer->Draw(m_RenderQueueFactory->RenderQueues());
// Iterate through systems and update world!
m_SystemPipeline->Update(m_World, dt);
m_Renderer->Update(dt);
m_RenderQueueFactory->Update(m_World);
GLERROR("Game::Tick m_RenderQueueFactory->Update");
m_Renderer->Draw(m_RenderQueueFactory->RenderQueues());
GLERROR("Game::Tick m_Renderer->Draw");
m_EventBroker->Swap();
m_EventBroker->Clear();
+11 -1
View File
@@ -9,11 +9,19 @@
#include "GUI/Frame.h"
#include "Core/World.h"
#include "Rendering/RenderQueueFactory.h"
#include "Input/InputProxy.h"
#include "Input/KeyboardInputHandler.h"
#include "Input/MouseInputHandler.h"
#include "Core/EKeyDown.h"
#include "Core/EntityXMLFile.h"
#include "Core/SystemPipeline.h"
#include "RaptorCopterSystem.h"
#include "PlayerSystem.h"
#include "Editor/EditorSystem.h"
#include "OctTreeTestHardCodedTestWorld.h"
#include "Collision/Collision.h"
class Game
{
public:
@@ -32,6 +40,8 @@ private:
GUI::Frame* m_FrameStack;
HardcodedTestWorld* m_World;
RenderQueueFactory* m_RenderQueueFactory;
InputProxy* m_InputProxy;
SystemPipeline* m_SystemPipeline;
//Test1
int frameCounter = 0;
+36
View File
@@ -0,0 +1,36 @@
#include <boost/test/unit_test.hpp>
#include "Core/World.h"
//private->public hack doesnt work, tons of link errors
//so there is currently no good way to test this class
//#define private public
#include "Core/ResourceManager.h"
#include "Core/ConfigFile.h"
#include "Rendering/Renderer.h"
#include "Core/EntityXMLFile.h"
#include "Engine\Rendering\Texture.h"
BOOST_AUTO_TEST_SUITE(resourceManagerTests)
BOOST_AUTO_TEST_CASE(resourceManagerTest)
{
World m_World;
//private static metoder/variabler
ResourceManager::RegisterType<ConfigFile>("ConfigFile");
BOOST_CHECK(!ResourceManager::IsResourceLoaded("ConfigFile", "Config.ini"));
auto m_Config = ResourceManager::Load<ConfigFile>("Config.ini");
BOOST_CHECK(ResourceManager::IsResourceLoaded("ConfigFile", "Config.ini"));
ResourceManager::Release("ConfigFile", "Config.ini");
BOOST_CHECK(!ResourceManager::IsResourceLoaded("ConfigFile", "Config.ini"));
//configfile without register
//check so output says "EE failed to load: type not registered..."
auto m_ScreenQuadNoRegister = ResourceManager::Load<Model>("Models/Core/ScreenQuad.obj");
BOOST_CHECK(!ResourceManager::IsResourceLoaded("Model", "Models/Core/ScreenQuad.obj"));
//there is no error feedback to check if you try to release the wrong resources - hence that cant be tested either
}
BOOST_AUTO_TEST_SUITE_END()