Remove Nazara SDK
This commit is contained in:
parent
8bef707de2
commit
5aa63831e8
|
|
@ -1,25 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_ALGORITHM_HPP
|
||||
#define NDK_ALGORITHM_HPP
|
||||
|
||||
#include <NazaraSDK/Prerequisites.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
template<unsigned int N> ComponentId BuildComponentId(const char (&name)[N]);
|
||||
template<typename ComponentType> ComponentIndex GetComponentIndex();
|
||||
template<typename SystemType> SystemIndex GetSystemIndex();
|
||||
template<typename ComponentType, unsigned int N> ComponentIndex InitializeComponent(const char (&name)[N]);
|
||||
template<typename SystemType> SystemIndex InitializeSystem();
|
||||
template<typename ComponentType, typename C> bool IsComponent(C& component);
|
||||
template<typename SystemType, typename S> bool IsSystem(S& system);
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Algorithm.inl>
|
||||
|
||||
#endif // NDK_ALGORITHM_HPP
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Core/Endianness.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \brief Builds a component id based on a name
|
||||
* \return Identifier for the component
|
||||
*
|
||||
* \param name Name to generate id from
|
||||
*/
|
||||
|
||||
///TODO: constexpr with the C++14
|
||||
template<unsigned int N>
|
||||
ComponentId BuildComponentId(const char (&name)[N])
|
||||
{
|
||||
static_assert(N-1 <= sizeof(ComponentId), "Name too long for this size of component id");
|
||||
|
||||
ComponentId componentId = 0;
|
||||
for (unsigned int i = 0; i < N - 1; ++i)
|
||||
componentId |= static_cast<ComponentId>(name[i]) << i*8;
|
||||
|
||||
return componentId;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \brief Gets the component id of a component
|
||||
* \return Identifier for the component
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
ComponentIndex GetComponentIndex()
|
||||
{
|
||||
return ComponentType::componentIndex;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \brief Gets the system id of a system
|
||||
* \return Identifier for the system
|
||||
*/
|
||||
|
||||
template<typename SystemType>
|
||||
SystemIndex GetSystemIndex()
|
||||
{
|
||||
return SystemType::systemIndex;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \brief Initializes the a component
|
||||
* \return Identifier for the component
|
||||
*
|
||||
* \param name Name to generate id from
|
||||
*/
|
||||
|
||||
template<typename ComponentType, unsigned int N>
|
||||
ComponentIndex InitializeComponent(const char (&name)[N])
|
||||
{
|
||||
ComponentType::componentIndex = ComponentType::RegisterComponent(name);
|
||||
return ComponentType::componentIndex;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \brief Initializes the a system
|
||||
* \return Identifier for the system
|
||||
*/
|
||||
|
||||
template<typename SystemType>
|
||||
SystemIndex InitializeSystem()
|
||||
{
|
||||
SystemType::systemIndex = SystemType::RegisterSystem();
|
||||
return SystemType::systemIndex;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the parameter is a component
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param component Component to check
|
||||
*/
|
||||
|
||||
template<typename ComponentType, typename C>
|
||||
bool IsComponent(C& component)
|
||||
{
|
||||
return component.GetIndex() == GetComponentIndex<ComponentType>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the parameter is a system
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param system System to check
|
||||
*/
|
||||
|
||||
template<typename SystemType, typename S>
|
||||
bool IsSystem(S& system)
|
||||
{
|
||||
return system.GetIndex() == GetSystemIndex<SystemType>();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,67 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_APPLICATION_HPP
|
||||
#define NDK_APPLICATION_HPP
|
||||
|
||||
#include <NazaraSDK/Prerequisites.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API Application
|
||||
{
|
||||
public:
|
||||
inline Application();
|
||||
Application(int argc, char* argv[]);
|
||||
Application(const Application&) = delete;
|
||||
Application(Application&&) = delete;
|
||||
inline ~Application();
|
||||
|
||||
template<typename... Args> World& AddWorld(Args&&... args);
|
||||
|
||||
inline const std::set<std::string>& GetOptions() const;
|
||||
inline const std::map<std::string, std::string>& GetParameters() const;
|
||||
|
||||
inline float GetUpdateTime() const;
|
||||
|
||||
inline bool HasOption(const std::string& option) const;
|
||||
inline bool HasParameter(const std::string& key, std::string* value) const;
|
||||
|
||||
bool Run();
|
||||
|
||||
inline void Quit();
|
||||
|
||||
Application& operator=(const Application&) = delete;
|
||||
Application& operator=(Application&&) = delete;
|
||||
|
||||
inline static Application* Instance();
|
||||
|
||||
protected:
|
||||
void ClearWorlds();
|
||||
void ParseCommandline(int argc, char* argv[]);
|
||||
|
||||
private:
|
||||
std::map<std::string, std::string> m_parameters;
|
||||
std::set<std::string> m_options;
|
||||
std::list<World> m_worlds;
|
||||
Nz::Clock m_updateClock;
|
||||
|
||||
bool m_shouldQuit;
|
||||
float m_updateTime;
|
||||
|
||||
static Application* s_application;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Application.inl>
|
||||
|
||||
#endif // NDK_APPLICATION_HPP
|
||||
|
|
@ -1,143 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <NazaraSDK/Sdk.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs an Application object without passing command-line arguments
|
||||
*
|
||||
* This calls Sdk::Initialize()
|
||||
*
|
||||
* \remark Only one Application instance can exist at a time
|
||||
*/
|
||||
inline Application::Application() :
|
||||
m_shouldQuit(false),
|
||||
m_updateTime(0.f)
|
||||
{
|
||||
NazaraAssert(s_application == nullptr, "You can create only one application instance per program");
|
||||
s_application = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the application object
|
||||
*
|
||||
* This destroy all worlds and windows and then calls Sdk::Uninitialize
|
||||
*/
|
||||
inline Application::~Application()
|
||||
{
|
||||
m_worlds.clear();
|
||||
|
||||
// Automatic free of modules
|
||||
s_application = nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a world to the application
|
||||
* \return A reference to the newly created world
|
||||
*
|
||||
* \param args Arguments used to create the world
|
||||
*/
|
||||
|
||||
template<typename... Args>
|
||||
World& Application::AddWorld(Args&&... args)
|
||||
{
|
||||
m_worlds.emplace_back(std::forward<Args>(args)...);
|
||||
return m_worlds.back();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the options used to start the application
|
||||
*
|
||||
* Options are defined as "-optionName" in command-line and are always lower-case
|
||||
*
|
||||
* \return Command-line options
|
||||
*/
|
||||
inline const std::set<std::string>& Application::GetOptions() const
|
||||
{
|
||||
return m_options;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the parameters used to start the application
|
||||
*
|
||||
* Parameters are defined as "-key=value" in command-line, their key is lower-case but value capitals are kept.
|
||||
*
|
||||
* \return Command-line parameters
|
||||
*/
|
||||
inline const std::map<std::string, std::string>& Application::GetParameters() const
|
||||
{
|
||||
return m_parameters;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the update time of the application
|
||||
* \return Update rate
|
||||
*/
|
||||
inline float Application::GetUpdateTime() const
|
||||
{
|
||||
return m_updateTime;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Query for a command-line option
|
||||
*
|
||||
* \param option Option name
|
||||
*
|
||||
* \remark option must be lower-case
|
||||
*
|
||||
* \return True if option is present
|
||||
*
|
||||
* \see GetOptions
|
||||
*/
|
||||
inline bool Application::HasOption(const std::string& option) const
|
||||
{
|
||||
return m_options.count(option) != 0;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Query for a command-line option
|
||||
*
|
||||
* \param key Parameter name
|
||||
* \param value Optional string to receive the parameter value
|
||||
*
|
||||
* \remark key must be lower-case
|
||||
*
|
||||
* \return True if parameter is present
|
||||
*
|
||||
* \see GetParameters
|
||||
*/
|
||||
inline bool Application::HasParameter(const std::string& key, std::string* value) const
|
||||
{
|
||||
auto it = m_parameters.find(key);
|
||||
if (it == m_parameters.end())
|
||||
return false;
|
||||
|
||||
if (value)
|
||||
*value = it->second;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Quits the application
|
||||
*/
|
||||
|
||||
inline void Application::Quit()
|
||||
{
|
||||
m_shouldQuit = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the singleton instance of the application
|
||||
* \return Singleton application
|
||||
*/
|
||||
|
||||
inline Application* Application::Instance()
|
||||
{
|
||||
return s_application;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,74 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_BASECOMPONENT_HPP
|
||||
#define NDK_BASECOMPONENT_HPP
|
||||
|
||||
#include <NazaraSDK/Entity.hpp>
|
||||
#include <functional>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API BaseComponent
|
||||
{
|
||||
friend Entity;
|
||||
friend class Sdk;
|
||||
|
||||
public:
|
||||
using Factory = std::function<BaseComponent*()>;
|
||||
|
||||
BaseComponent(ComponentIndex componentIndex);
|
||||
BaseComponent(BaseComponent&&) noexcept = default;
|
||||
virtual ~BaseComponent();
|
||||
|
||||
virtual std::unique_ptr<BaseComponent> Clone() const = 0;
|
||||
|
||||
inline const EntityHandle& GetEntity() const;
|
||||
ComponentIndex GetIndex() const;
|
||||
|
||||
inline static ComponentIndex GetMaxComponentIndex();
|
||||
|
||||
BaseComponent& operator=(const BaseComponent&) = delete;
|
||||
BaseComponent& operator=(BaseComponent&&) noexcept = default;
|
||||
|
||||
protected:
|
||||
BaseComponent(const BaseComponent&) = default;
|
||||
|
||||
ComponentIndex m_componentIndex;
|
||||
EntityHandle m_entity;
|
||||
|
||||
static ComponentIndex RegisterComponent(ComponentId id, Factory factoryFunc);
|
||||
|
||||
private:
|
||||
virtual void OnAttached();
|
||||
virtual void OnComponentAttached(BaseComponent& component);
|
||||
virtual void OnComponentDetached(BaseComponent& component);
|
||||
virtual void OnDetached();
|
||||
virtual void OnEntityDestruction();
|
||||
virtual void OnEntityDisabled();
|
||||
virtual void OnEntityEnabled();
|
||||
|
||||
void SetEntity(Entity* entity);
|
||||
|
||||
static bool Initialize();
|
||||
static void Uninitialize();
|
||||
|
||||
struct ComponentEntry
|
||||
{
|
||||
ComponentId id;
|
||||
Factory factory;
|
||||
};
|
||||
|
||||
static std::vector<ComponentEntry> s_entries;
|
||||
static std::unordered_map<ComponentId, ComponentIndex> s_idToIndex;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/BaseComponent.inl>
|
||||
|
||||
#endif // NDK_BASECOMPONENT_HPP
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a BaseComponent object with an index
|
||||
*
|
||||
* \param index Index of the component
|
||||
*/
|
||||
|
||||
inline BaseComponent::BaseComponent(ComponentIndex index) :
|
||||
m_componentIndex(index),
|
||||
m_entity(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the entity owning this component
|
||||
* \return A handle to the entity owning this component, may be invalid if no entity owns it.
|
||||
*/
|
||||
inline const EntityHandle& BaseComponent::GetEntity() const
|
||||
{
|
||||
return m_entity;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the index of the component
|
||||
* \return Index of the component
|
||||
*/
|
||||
inline ComponentIndex BaseComponent::GetIndex() const
|
||||
{
|
||||
return m_componentIndex;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the maximal index of the components
|
||||
* \return Index of the maximal component
|
||||
*/
|
||||
|
||||
inline ComponentIndex BaseComponent::GetMaxComponentIndex()
|
||||
{
|
||||
return static_cast<ComponentIndex>(s_entries.size());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Registers a component
|
||||
* \return Index of the registered component
|
||||
*
|
||||
* \param id Index of the component
|
||||
* \param factory Factory to create the component
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the identifier is already in use
|
||||
*/
|
||||
|
||||
inline ComponentIndex BaseComponent::RegisterComponent(ComponentId id, Factory factoryFunc)
|
||||
{
|
||||
// We add our component to the end
|
||||
ComponentIndex index = static_cast<ComponentIndex>(s_entries.size());
|
||||
s_entries.resize(index + 1);
|
||||
|
||||
// We retrieve it and affect it
|
||||
ComponentEntry& entry = s_entries.back();
|
||||
entry.factory = factoryFunc;
|
||||
entry.id = id;
|
||||
|
||||
// We ensure that id is not already in use
|
||||
NazaraAssert(s_idToIndex.find(id) == s_idToIndex.end(), "This id is already in use");
|
||||
|
||||
s_idToIndex[id] = index;
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the entity on which the component operates
|
||||
*/
|
||||
|
||||
inline void BaseComponent::SetEntity(Entity* entity)
|
||||
{
|
||||
if (m_entity != entity)
|
||||
{
|
||||
if (m_entity)
|
||||
OnDetached();
|
||||
|
||||
m_entity = entity;
|
||||
if (m_entity)
|
||||
OnAttached();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the BaseComponent
|
||||
* \return true
|
||||
*/
|
||||
|
||||
inline bool BaseComponent::Initialize()
|
||||
{
|
||||
// Nothing to do
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the BaseComponent
|
||||
*/
|
||||
|
||||
inline void BaseComponent::Uninitialize()
|
||||
{
|
||||
s_entries.clear();
|
||||
s_idToIndex.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_BASESYSTEM_HPP
|
||||
#define NDK_BASESYSTEM_HPP
|
||||
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <NazaraSDK/EntityList.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class World;
|
||||
|
||||
class NDK_API BaseSystem
|
||||
{
|
||||
friend class Sdk;
|
||||
friend Entity;
|
||||
friend World;
|
||||
|
||||
public:
|
||||
inline BaseSystem(SystemIndex systemId);
|
||||
BaseSystem(const BaseSystem&) = delete;
|
||||
BaseSystem(BaseSystem&&) noexcept = default;
|
||||
virtual ~BaseSystem();
|
||||
|
||||
inline void Enable(bool enable = true);
|
||||
|
||||
bool Filters(const Entity* entity) const;
|
||||
|
||||
inline const EntityList& GetEntities() const;
|
||||
inline float GetFixedUpdateRate() const;
|
||||
inline SystemIndex GetIndex() const;
|
||||
inline float GetMaximumUpdateRate() const;
|
||||
inline int GetUpdateOrder() const;
|
||||
inline World& GetWorld() const;
|
||||
|
||||
inline bool IsEnabled() const;
|
||||
|
||||
inline bool HasEntity(const Entity* entity) const;
|
||||
|
||||
inline void SetFixedUpdateRate(float updatePerSecond);
|
||||
inline void SetMaximumUpdateRate(float updatePerSecond);
|
||||
void SetUpdateOrder(int updateOrder);
|
||||
|
||||
inline void Update(float elapsedTime);
|
||||
|
||||
BaseSystem& operator=(const BaseSystem&) = delete;
|
||||
BaseSystem& operator=(BaseSystem&&) noexcept = default;
|
||||
|
||||
protected:
|
||||
template<typename ComponentType> void Excludes();
|
||||
template<typename ComponentType1, typename ComponentType2, typename... Rest> void Excludes();
|
||||
inline void ExcludesComponent(ComponentIndex index);
|
||||
|
||||
static SystemIndex GetNextIndex();
|
||||
|
||||
template<typename ComponentType> void Requires();
|
||||
template<typename ComponentType1, typename ComponentType2, typename... Rest> void Requires();
|
||||
inline void RequiresComponent(ComponentIndex index);
|
||||
|
||||
template<typename ComponentType> void RequiresAny();
|
||||
template<typename ComponentType1, typename ComponentType2, typename... Rest> void RequiresAny();
|
||||
inline void RequiresAnyComponent(ComponentIndex index);
|
||||
|
||||
virtual void OnUpdate(float elapsedTime) = 0;
|
||||
|
||||
private:
|
||||
inline void AddEntity(Entity* entity);
|
||||
|
||||
virtual void OnEntityAdded(Entity* entity);
|
||||
virtual void OnEntityRemoved(Entity* entity);
|
||||
virtual void OnEntityValidation(Entity* entity, bool justAdded);
|
||||
|
||||
inline void RemoveEntity(Entity* entity);
|
||||
|
||||
inline void SetWorld(World* world) noexcept;
|
||||
|
||||
inline void ValidateEntity(Entity* entity, bool justAdded);
|
||||
|
||||
static inline bool Initialize();
|
||||
static inline void Uninitialize();
|
||||
|
||||
Nz::Bitset<> m_excludedComponents;
|
||||
mutable Nz::Bitset<> m_filterResult;
|
||||
Nz::Bitset<> m_requiredAnyComponents;
|
||||
Nz::Bitset<> m_requiredComponents;
|
||||
EntityList m_entities;
|
||||
SystemIndex m_systemIndex;
|
||||
World* m_world;
|
||||
bool m_updateEnabled;
|
||||
float m_fixedUpdateRate;
|
||||
float m_maxUpdateRate;
|
||||
float m_updateCounter;
|
||||
int m_updateOrder;
|
||||
|
||||
static SystemIndex s_nextIndex;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/BaseSystem.inl>
|
||||
|
||||
#endif // NDK_BASESYSTEM_HPP
|
||||
|
|
@ -1,383 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a BaseSystem object with an index
|
||||
*
|
||||
* \param systemId Index of the system
|
||||
*/
|
||||
|
||||
inline BaseSystem::BaseSystem(SystemIndex systemId) :
|
||||
m_systemIndex(systemId),
|
||||
m_world(nullptr),
|
||||
m_updateEnabled(true),
|
||||
m_updateOrder(0)
|
||||
{
|
||||
SetFixedUpdateRate(0);
|
||||
SetMaximumUpdateRate(30);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables the system
|
||||
*
|
||||
* \param enable Should the system be enabled
|
||||
*/
|
||||
|
||||
inline void BaseSystem::Enable(bool enable)
|
||||
{
|
||||
m_updateEnabled = enable;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets every entities that system handle
|
||||
* \return A constant reference to the list of entities
|
||||
*/
|
||||
|
||||
inline const EntityList& BaseSystem::GetEntities() const
|
||||
{
|
||||
return m_entities;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the maximum rate of update of the system
|
||||
* \return Update rate
|
||||
*/
|
||||
inline float BaseSystem::GetFixedUpdateRate() const
|
||||
{
|
||||
return (m_fixedUpdateRate > 0.f) ? 1.f / m_fixedUpdateRate : 0.f;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the maximum rate of update of the system
|
||||
* \return Update rate
|
||||
*/
|
||||
inline float BaseSystem::GetMaximumUpdateRate() const
|
||||
{
|
||||
return (m_maxUpdateRate > 0.f) ? 1.f / m_maxUpdateRate : 0.f;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the index of the system
|
||||
* \return Index of the system
|
||||
*/
|
||||
|
||||
inline SystemIndex BaseSystem::GetIndex() const
|
||||
{
|
||||
return m_systemIndex;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the update order of the system
|
||||
* \return Update order
|
||||
*
|
||||
* \see SetUpdateOrder
|
||||
*/
|
||||
inline int BaseSystem::GetUpdateOrder() const
|
||||
{
|
||||
return m_updateOrder;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the world on which the system operate
|
||||
* \return World in which the system is
|
||||
*/
|
||||
|
||||
inline World& BaseSystem::GetWorld() const
|
||||
{
|
||||
return *m_world;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not the system is enabled
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
inline bool BaseSystem::IsEnabled() const
|
||||
{
|
||||
return m_updateEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not the system has the entity
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
*/
|
||||
|
||||
inline bool BaseSystem::HasEntity(const Entity* entity) const
|
||||
{
|
||||
return m_entities.Has(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the fixed update rate for the system
|
||||
*
|
||||
* \param updatePerSecond Update rate, 0 means update rate is not fixed
|
||||
*/
|
||||
inline void BaseSystem::SetFixedUpdateRate(float updatePerSecond)
|
||||
{
|
||||
m_updateCounter = 0.f;
|
||||
m_fixedUpdateRate = (updatePerSecond > 0.f) ? 1.f / updatePerSecond : 0.f; // 0.f means no limit
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the maximum update rate for the system
|
||||
*
|
||||
* \param updatePerSecond Update rate, 0 means as much as possible
|
||||
*/
|
||||
inline void BaseSystem::SetMaximumUpdateRate(float updatePerSecond)
|
||||
{
|
||||
m_updateCounter = 0.f;
|
||||
m_maxUpdateRate = (updatePerSecond > 0.f) ? 1.f / updatePerSecond : 0.f; // 0.f means no limit
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the system
|
||||
*
|
||||
* \param elapsedTime Delta time used for the update
|
||||
*/
|
||||
|
||||
inline void BaseSystem::Update(float elapsedTime)
|
||||
{
|
||||
if (!IsEnabled())
|
||||
return;
|
||||
|
||||
m_updateCounter += elapsedTime;
|
||||
|
||||
if (m_maxUpdateRate > 0.f)
|
||||
{
|
||||
if (m_updateCounter >= m_maxUpdateRate)
|
||||
{
|
||||
if (m_fixedUpdateRate > 0.f)
|
||||
{
|
||||
while (m_updateCounter >= m_fixedUpdateRate)
|
||||
{
|
||||
OnUpdate(m_fixedUpdateRate);
|
||||
m_updateCounter -= m_fixedUpdateRate;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
float updateRate = std::max(elapsedTime, m_maxUpdateRate);
|
||||
|
||||
OnUpdate(updateRate);
|
||||
m_updateCounter -= updateRate;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_fixedUpdateRate > 0.f)
|
||||
{
|
||||
while (m_updateCounter >= m_fixedUpdateRate)
|
||||
{
|
||||
OnUpdate(m_fixedUpdateRate);
|
||||
m_updateCounter -= m_fixedUpdateRate;
|
||||
}
|
||||
}
|
||||
else
|
||||
OnUpdate(elapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Excludes some component from the system
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
void BaseSystem::Excludes()
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>::value , "ComponentType is not a component");
|
||||
|
||||
ExcludesComponent(GetComponentIndex<ComponentType>());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Excludes some components from the system
|
||||
*/
|
||||
|
||||
template<typename ComponentType1, typename ComponentType2, typename... Rest>
|
||||
void BaseSystem::Excludes()
|
||||
{
|
||||
Excludes<ComponentType1>();
|
||||
Excludes<ComponentType2, Rest...>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Excludes some component from the system by index
|
||||
*
|
||||
* \param index Index of the component
|
||||
*/
|
||||
|
||||
inline void BaseSystem::ExcludesComponent(ComponentIndex index)
|
||||
{
|
||||
m_excludedComponents.UnboundedSet(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the next index for the system
|
||||
* \return Next unique index for the system
|
||||
*/
|
||||
|
||||
inline SystemIndex BaseSystem::GetNextIndex()
|
||||
{
|
||||
return s_nextIndex++;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Requires some component from the system
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
void BaseSystem::Requires()
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");
|
||||
|
||||
RequiresComponent(GetComponentIndex<ComponentType>());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Requires some components from the system
|
||||
*/
|
||||
|
||||
template<typename ComponentType1, typename ComponentType2, typename... Rest>
|
||||
void BaseSystem::Requires()
|
||||
{
|
||||
Requires<ComponentType1>();
|
||||
Requires<ComponentType2, Rest...>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Requires some component for the system by index
|
||||
*
|
||||
* \param index Index of the component
|
||||
*/
|
||||
|
||||
inline void BaseSystem::RequiresComponent(ComponentIndex index)
|
||||
{
|
||||
m_requiredComponents.UnboundedSet(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Requires any component from the system
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
void BaseSystem::RequiresAny()
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");
|
||||
|
||||
RequiresAnyComponent(GetComponentIndex<ComponentType>());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Requires any components from the system
|
||||
*/
|
||||
|
||||
template<typename ComponentType1, typename ComponentType2, typename... Rest>
|
||||
void BaseSystem::RequiresAny()
|
||||
{
|
||||
RequiresAny<ComponentType1>();
|
||||
RequiresAny<ComponentType2, Rest...>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Requires any component for the system by index
|
||||
*
|
||||
* \param index Index of the component
|
||||
*/
|
||||
|
||||
inline void BaseSystem::RequiresAnyComponent(ComponentIndex index)
|
||||
{
|
||||
m_requiredAnyComponents.UnboundedSet(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds an entity to a system
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
*
|
||||
* \remark Produces a NazaraAssert if entity is invalid
|
||||
*/
|
||||
|
||||
inline void BaseSystem::AddEntity(Entity* entity)
|
||||
{
|
||||
NazaraAssert(entity, "Invalid entity");
|
||||
|
||||
m_entities.Insert(entity);
|
||||
entity->RegisterSystem(m_systemIndex);
|
||||
|
||||
OnEntityAdded(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes an entity to a system
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
*
|
||||
* \remark Produces a NazaraAssert if entity is invalid
|
||||
*/
|
||||
|
||||
inline void BaseSystem::RemoveEntity(Entity* entity)
|
||||
{
|
||||
NazaraAssert(entity, "Invalid entity");
|
||||
|
||||
m_entities.Remove(entity);
|
||||
entity->UnregisterSystem(m_systemIndex);
|
||||
|
||||
OnEntityRemoved(entity); // And we alert our callback
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Validates an entity to a system
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
* \param justAdded Is the entity newly added
|
||||
*
|
||||
* \remark Produces a NazaraAssert if entity is invalid or if system does not hold this entity
|
||||
*/
|
||||
|
||||
inline void BaseSystem::ValidateEntity(Entity* entity, bool justAdded)
|
||||
{
|
||||
NazaraAssert(entity, "Invalid entity");
|
||||
NazaraAssert(HasEntity(entity), "Entity should be part of system");
|
||||
|
||||
OnEntityValidation(entity, justAdded);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the world on which the system operates
|
||||
*/
|
||||
|
||||
inline void BaseSystem::SetWorld(World* world) noexcept
|
||||
{
|
||||
m_world = world;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the BaseSystem
|
||||
* \return true
|
||||
*/
|
||||
|
||||
inline bool BaseSystem::Initialize()
|
||||
{
|
||||
s_nextIndex = 0;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitialize the BaseSystem
|
||||
*/
|
||||
|
||||
inline void BaseSystem::Uninitialize()
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_CLIENTAPPLICATION_HPP
|
||||
#define NDK_CLIENTAPPLICATION_HPP
|
||||
|
||||
#include <NazaraSDK/ClientPrerequisites.hpp>
|
||||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Platform/Window.hpp>
|
||||
#include <NazaraSDK/Application.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <set>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_CLIENT_API ClientApplication : public Application
|
||||
{
|
||||
public:
|
||||
struct ConsoleOverlay;
|
||||
struct FPSCounterOverlay;
|
||||
|
||||
inline ClientApplication();
|
||||
ClientApplication(int argc, char* argv[]);
|
||||
ClientApplication(const ClientApplication&) = delete;
|
||||
ClientApplication(ClientApplication&&) = delete;
|
||||
inline ~ClientApplication();
|
||||
|
||||
template<typename T, typename... Args> T& AddWindow(Args&&... args);
|
||||
|
||||
bool Run();
|
||||
|
||||
inline void MakeExitOnLastWindowClosed(bool exitOnClosedWindows);
|
||||
|
||||
ClientApplication& operator=(const ClientApplication&) = delete;
|
||||
ClientApplication& operator=(ClientApplication&&) = delete;
|
||||
|
||||
inline static ClientApplication* Instance();
|
||||
|
||||
private:
|
||||
enum OverlayFlags
|
||||
{
|
||||
OverlayFlags_Console = 0x1,
|
||||
OverlayFlags_FPSCounter = 0x2
|
||||
};
|
||||
|
||||
struct WindowInfo
|
||||
{
|
||||
inline WindowInfo(std::unique_ptr<Nz::Window>&& window);
|
||||
|
||||
std::unique_ptr<Nz::Window> window;
|
||||
};
|
||||
|
||||
std::vector<WindowInfo> m_windows;
|
||||
Nz::UInt32 m_overlayFlags;
|
||||
bool m_exitOnClosedWindows;
|
||||
|
||||
static ClientApplication* s_clientApplication;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/ClientApplication.inl>
|
||||
|
||||
#endif // NDK_CLIENTAPPLICATION_HPP
|
||||
|
|
@ -1,79 +0,0 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/ClientApplication.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <NazaraSDK/ClientSdk.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs an Application object without passing command-line arguments
|
||||
*
|
||||
* This calls Sdk::Initialize()
|
||||
*
|
||||
* \remark Only one Application instance can exist at a time
|
||||
*/
|
||||
inline ClientApplication::ClientApplication() :
|
||||
m_overlayFlags(0U),
|
||||
m_exitOnClosedWindows(true)
|
||||
{
|
||||
NazaraAssert(s_clientApplication == nullptr, "You can create only one application instance per program");
|
||||
s_clientApplication = this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the application object
|
||||
*
|
||||
* This destroy all worlds and windows and then calls Sdk::Uninitialize
|
||||
*/
|
||||
inline ClientApplication::~ClientApplication()
|
||||
{
|
||||
ClearWorlds();
|
||||
m_windows.clear();
|
||||
|
||||
s_clientApplication = nullptr;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a window to the application
|
||||
* \return A reference to the newly created windows
|
||||
*
|
||||
* \param args Arguments used to create the window
|
||||
*/
|
||||
template<typename T, typename... Args>
|
||||
T& ClientApplication::AddWindow(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<Nz::Window, T>::value, "Type must inherit Window");
|
||||
|
||||
m_windows.emplace_back(std::make_unique<T>(std::forward<Args>(args)...));
|
||||
WindowInfo& info = m_windows.back();
|
||||
|
||||
return static_cast<T&>(*info.window.get()); //< Warning: ugly
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Makes the application exit when there's no more open window
|
||||
*
|
||||
* \param exitOnClosedWindows Should exit be called when no more window is open
|
||||
*/
|
||||
inline void ClientApplication::MakeExitOnLastWindowClosed(bool exitOnClosedWindows)
|
||||
{
|
||||
m_exitOnClosedWindows = exitOnClosedWindows;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the singleton instance of the application
|
||||
* \return Singleton application
|
||||
*/
|
||||
inline ClientApplication* ClientApplication::Instance()
|
||||
{
|
||||
return s_clientApplication;
|
||||
}
|
||||
|
||||
inline ClientApplication::WindowInfo::WindowInfo(std::unique_ptr<Nz::Window>&& windowPtr) :
|
||||
window(std::move(windowPtr))
|
||||
{
|
||||
}
|
||||
}
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
/*
|
||||
Nazara Development Kit ("NDK"), also called Nazara Engine - SDK ("Software Development Kit")
|
||||
|
||||
Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NDK_CLIENT_PREREQUISITES_HPP
|
||||
#define NDK_CLIENT_PREREQUISITES_HPP
|
||||
|
||||
/*!
|
||||
* \defgroup NDK (NazaraSDK) Nazara Development Kit
|
||||
* A library grouping every modules of Nazara into multiple higher-level features suchs as scene management (handled by an ECS), application, lua binding, etc.
|
||||
*/
|
||||
|
||||
#include <NazaraSDK/Prerequisites.hpp>
|
||||
|
||||
// Importation/Exportation of the API
|
||||
#if defined(NAZARA_STATIC)
|
||||
#define NDK_CLIENT_API
|
||||
#else
|
||||
#ifdef NDK_CLIENT_BUILD
|
||||
#define NDK_CLIENT_API NAZARA_EXPORT
|
||||
#else
|
||||
#define NDK_CLIENT_API NAZARA_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#endif // NDK_CLIENT_PREREQUISITES_HPP
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_CLIENTSDK_HPP
|
||||
#define NDK_CLIENTSDK_HPP
|
||||
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <NazaraSDK/ClientPrerequisites.hpp>
|
||||
#include <NazaraSDK/Sdk.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_CLIENT_API ClientSdk : public Nz::ModuleBase<ClientSdk>
|
||||
{
|
||||
friend ModuleBase;
|
||||
|
||||
public:
|
||||
using Dependencies = Nz::TypeList<Ndk::Sdk, Nz::Audio, Nz::Graphics>;
|
||||
|
||||
struct Config {};
|
||||
|
||||
ClientSdk(Config /*config*/);
|
||||
~ClientSdk();
|
||||
|
||||
private:
|
||||
static ClientSdk* s_instance;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/ClientSdk.inl>
|
||||
|
||||
#endif // NDK_CLIENTSDK_HPP
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENT_HPP
|
||||
#define NDK_COMPONENT_HPP
|
||||
|
||||
#include <NazaraSDK/BaseComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
template<typename ComponentType>
|
||||
class Component : public BaseComponent, public Nz::HandledObject<ComponentType>
|
||||
{
|
||||
public:
|
||||
Component();
|
||||
virtual ~Component();
|
||||
|
||||
std::unique_ptr<BaseComponent> Clone() const override;
|
||||
|
||||
static ComponentIndex RegisterComponent(ComponentId id);
|
||||
|
||||
template<unsigned int N>
|
||||
static ComponentIndex RegisterComponent(const char (&name)[N]);
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Component.inl>
|
||||
|
||||
#endif // NDK_COMPONENT_HPP
|
||||
|
|
@ -1,76 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Algorithm.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::Component<ComponentType>
|
||||
* \brief NDK class that represents a component for an entity which interacts with a system
|
||||
*
|
||||
* \remark This class is meant to be derived as CRTP: "Component<Subtype>"
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a Component object by default
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
Component<ComponentType>::Component() :
|
||||
BaseComponent(GetComponentIndex<ComponentType>())
|
||||
{
|
||||
}
|
||||
|
||||
template<typename ComponentType>
|
||||
Component<ComponentType>::~Component() = default;
|
||||
|
||||
/*!
|
||||
* \brief Clones the component
|
||||
* \return The clone newly created
|
||||
*
|
||||
* \remark The component to clone should be trivially copy constructible
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
std::unique_ptr<BaseComponent> Component<ComponentType>::Clone() const
|
||||
{
|
||||
///FIXME: Pas encore supporté par GCC (4.9.2)
|
||||
//static_assert(std::is_trivially_copy_constructible<ComponentType>::value, "ComponentType must be copy-constructible");
|
||||
|
||||
return std::make_unique<ComponentType>(static_cast<const ComponentType&>(*this));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Registers the component by assigning it an index
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
ComponentIndex Component<ComponentType>::RegisterComponent(ComponentId id)
|
||||
{
|
||||
//We use the lambda to create a factory function
|
||||
auto factory = []() -> BaseComponent*
|
||||
{
|
||||
return nullptr; //< Temporary workaround to allow non-default-constructed components, will be updated for serialization
|
||||
//return new ComponentType;
|
||||
};
|
||||
|
||||
return BaseComponent::RegisterComponent(id, factory);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Registers the component by assigning it an index based on the name
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
template<unsigned int N>
|
||||
ComponentIndex Component<ComponentType>::RegisterComponent(const char (&name)[N])
|
||||
{
|
||||
// We convert the string to a number which will be used as unique identifier
|
||||
ComponentId id = BuildComponentId(name);
|
||||
return RegisterComponent(id);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// This file was automatically generated
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_GLOBAL_HPP
|
||||
#define NDK_COMPONENTS_GLOBAL_HPP
|
||||
|
||||
#include <NazaraSDK/Components/CameraComponent.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NazaraSDK/Components/ConstraintComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/DebugComponent.hpp>
|
||||
#include <NazaraSDK/Components/GraphicsComponent.hpp>
|
||||
#include <NazaraSDK/Components/LifetimeComponent.hpp>
|
||||
#include <NazaraSDK/Components/LightComponent.hpp>
|
||||
#include <NazaraSDK/Components/ListenerComponent.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/ParticleEmitterComponent.hpp>
|
||||
#include <NazaraSDK/Components/ParticleGroupComponent.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <NazaraSDK/Components/VelocityComponent.hpp>
|
||||
|
||||
#endif // NDK_COMPONENTS_GLOBAL_HPP
|
||||
|
|
@ -1,66 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_COLLISIONCOMPONENT2D_HPP
|
||||
#define NDK_COMPONENTS_COLLISIONCOMPONENT2D_HPP
|
||||
|
||||
#include <Nazara/Physics2D/Collider2D.hpp>
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class CollisionComponent2D;
|
||||
|
||||
using CollisionComponent2DHandle = Nz::ObjectHandle<CollisionComponent2D>;
|
||||
|
||||
class NDK_API CollisionComponent2D : public Component<CollisionComponent2D>
|
||||
{
|
||||
friend class ConstraintComponent2D;
|
||||
friend class PhysicsComponent2D;
|
||||
friend class PhysicsSystem2D;
|
||||
|
||||
public:
|
||||
CollisionComponent2D(std::shared_ptr<Nz::Collider2D> geom = std::shared_ptr<Nz::Collider2D>());
|
||||
CollisionComponent2D(const CollisionComponent2D& collision);
|
||||
~CollisionComponent2D() = default;
|
||||
|
||||
Nz::Rectf GetAABB() const;
|
||||
const std::shared_ptr<Nz::Collider2D>& GetGeom() const;
|
||||
const Nz::Vector2f& GetGeomOffset() const;
|
||||
|
||||
void Recenter(const Nz::Vector2f& origin);
|
||||
|
||||
void SetGeom(std::shared_ptr<Nz::Collider2D> geom, bool recomputeMoment = true, bool recomputeMassCenter = true);
|
||||
void SetGeomOffset(const Nz::Vector2f& geomOffset);
|
||||
|
||||
CollisionComponent2D& operator=(std::shared_ptr<Nz::Collider2D> geom);
|
||||
CollisionComponent2D& operator=(CollisionComponent2D&& collision) = delete;
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
void InitializeStaticBody();
|
||||
Nz::RigidBody2D* GetRigidBody();
|
||||
const Nz::RigidBody2D* GetRigidBody() const;
|
||||
Nz::RigidBody2D* GetStaticBody();
|
||||
const Nz::RigidBody2D* GetStaticBody() const;
|
||||
|
||||
void OnAttached() override;
|
||||
void OnComponentAttached(BaseComponent& component) override;
|
||||
void OnComponentDetached(BaseComponent& component) override;
|
||||
void OnDetached() override;
|
||||
|
||||
std::unique_ptr<Nz::RigidBody2D> m_staticBody;
|
||||
std::shared_ptr<Nz::Collider2D> m_geom;
|
||||
bool m_bodyUpdated;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/CollisionComponent2D.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_COLLISIONCOMPONENT2D_HPP
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a CollisionComponent2D object with a geometry
|
||||
*
|
||||
* \param geom Reference to a geometry symbolizing the entity
|
||||
*/
|
||||
|
||||
inline CollisionComponent2D::CollisionComponent2D(std::shared_ptr<Nz::Collider2D> geom) :
|
||||
m_geom(std::move(geom)),
|
||||
m_bodyUpdated(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a CollisionComponent2D object by copy semantic
|
||||
*
|
||||
* \param collision CollisionComponent2D to copy
|
||||
*/
|
||||
|
||||
inline CollisionComponent2D::CollisionComponent2D(const CollisionComponent2D& collision) :
|
||||
m_geom(collision.m_geom),
|
||||
m_bodyUpdated(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the geometry representing the entity
|
||||
* \return A constant reference to the physics geometry
|
||||
*/
|
||||
|
||||
inline const std::shared_ptr<Nz::Collider2D>& CollisionComponent2D::GetGeom() const
|
||||
{
|
||||
return m_geom;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the geometry to this component
|
||||
* \return A reference to this
|
||||
*
|
||||
* \param geom Reference to a geometry symbolizing the entity
|
||||
*/
|
||||
|
||||
inline CollisionComponent2D& CollisionComponent2D::operator=(std::shared_ptr<Nz::Collider2D> geom)
|
||||
{
|
||||
SetGeom(geom);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline Nz::RigidBody2D* CollisionComponent2D::GetStaticBody()
|
||||
{
|
||||
return m_staticBody.get();
|
||||
}
|
||||
|
||||
inline const Nz::RigidBody2D* CollisionComponent2D::GetStaticBody() const
|
||||
{
|
||||
return m_staticBody.get();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,58 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_COLLISIONCOMPONENT3D_HPP
|
||||
#define NDK_COMPONENTS_COLLISIONCOMPONENT3D_HPP
|
||||
|
||||
#include <Nazara/Physics3D/Collider3D.hpp>
|
||||
#include <Nazara/Physics3D/RigidBody3D.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class CollisionComponent3D;
|
||||
|
||||
using CollisionComponent3DHandle = Nz::ObjectHandle<CollisionComponent3D>;
|
||||
|
||||
class NDK_API CollisionComponent3D : public Component<CollisionComponent3D>
|
||||
{
|
||||
friend class PhysicsSystem3D;
|
||||
|
||||
public:
|
||||
CollisionComponent3D(std::shared_ptr<Nz::Collider3D> geom = std::shared_ptr<Nz::Collider3D>());
|
||||
CollisionComponent3D(const CollisionComponent3D& collision);
|
||||
~CollisionComponent3D() = default;
|
||||
|
||||
const std::shared_ptr<Nz::Collider3D>& GetGeom() const;
|
||||
|
||||
void SetGeom(std::shared_ptr<Nz::Collider3D> geom);
|
||||
|
||||
CollisionComponent3D& operator=(std::shared_ptr<Nz::Collider3D> geom);
|
||||
CollisionComponent3D& operator=(CollisionComponent3D&& collision) = delete;
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
void InitializeStaticBody();
|
||||
Nz::RigidBody3D* GetStaticBody();
|
||||
|
||||
void OnAttached() override;
|
||||
void OnComponentAttached(BaseComponent& component) override;
|
||||
void OnComponentDetached(BaseComponent& component) override;
|
||||
void OnDetached() override;
|
||||
void OnEntityDisabled() override;
|
||||
void OnEntityEnabled() override;
|
||||
|
||||
std::unique_ptr<Nz::RigidBody3D> m_staticBody;
|
||||
std::shared_ptr<Nz::Collider3D> m_geom;
|
||||
bool m_bodyUpdated;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/CollisionComponent3D.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_COLLISIONCOMPONENT3D_HPP
|
||||
|
|
@ -1,64 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a CollisionComponent3D object with a geometry
|
||||
*
|
||||
* \param geom Reference to a geometry symbolizing the entity
|
||||
*/
|
||||
|
||||
inline CollisionComponent3D::CollisionComponent3D(std::shared_ptr<Nz::Collider3D> geom) :
|
||||
m_geom(std::move(geom)),
|
||||
m_bodyUpdated(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a CollisionComponent3D object by copy semantic
|
||||
*
|
||||
* \param collision CollisionComponent3D to copy
|
||||
*/
|
||||
|
||||
inline CollisionComponent3D::CollisionComponent3D(const CollisionComponent3D& collision) :
|
||||
m_geom(collision.m_geom),
|
||||
m_bodyUpdated(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the geometry representing the entity
|
||||
* \return A constant reference to the physics geometry
|
||||
*/
|
||||
|
||||
inline const std::shared_ptr<Nz::Collider3D>& CollisionComponent3D::GetGeom() const
|
||||
{
|
||||
return m_geom;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the geometry to this component
|
||||
* \return A reference to this
|
||||
*
|
||||
* \param geom Reference to a geometry symbolizing the entity
|
||||
*/
|
||||
|
||||
inline CollisionComponent3D& CollisionComponent3D::operator=(std::shared_ptr<Nz::Collider3D> geom)
|
||||
{
|
||||
SetGeom(geom);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the static body used by the entity
|
||||
* \return A pointer to the entity
|
||||
*/
|
||||
|
||||
inline Nz::RigidBody3D* CollisionComponent3D::GetStaticBody()
|
||||
{
|
||||
return m_staticBody.get();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_CONSTRAINTCOMPONENT2D_HPP
|
||||
#define NDK_COMPONENTS_CONSTRAINTCOMPONENT2D_HPP
|
||||
|
||||
#include <Nazara/Physics2D/Constraint2D.hpp>
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
#include <NazaraSDK/Entity.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class ConstraintComponent2D;
|
||||
|
||||
using ConstraintComponent2DHandle = Nz::ObjectHandle<ConstraintComponent2D>;
|
||||
|
||||
class NDK_API ConstraintComponent2D : public Component<ConstraintComponent2D>
|
||||
{
|
||||
public:
|
||||
ConstraintComponent2D() = default;
|
||||
ConstraintComponent2D(const ConstraintComponent2D& joint);
|
||||
ConstraintComponent2D(ConstraintComponent2D&& joint) = default;
|
||||
|
||||
template<typename T, typename... Args> T* CreateConstraint(const Ndk::EntityHandle& first, const Ndk::EntityHandle& second, Args&&... args);
|
||||
bool RemoveConstraint(Nz::Constraint2D* constraint);
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
struct ConstraintData
|
||||
{
|
||||
std::unique_ptr<Nz::Constraint2D> constraint;
|
||||
|
||||
NazaraSlot(Ndk::Entity, OnEntityDestruction, onBodyADestruction);
|
||||
NazaraSlot(Ndk::Entity, OnEntityDestruction, onBodyBDestruction);
|
||||
};
|
||||
|
||||
std::vector<ConstraintData> m_constraints;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/ConstraintComponent2D.inl>
|
||||
|
||||
#endif// NDK_COMPONENTS_CONSTRAINTCOMPONENT2D_HPP
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/ConstraintComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent2D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
template<typename T, typename ...Args>
|
||||
T* ConstraintComponent2D::CreateConstraint(const Ndk::EntityHandle& first, const Ndk::EntityHandle& second, Args&& ...args)
|
||||
{
|
||||
auto FetchBody = [](const Ndk::EntityHandle& entity) -> Nz::RigidBody2D*
|
||||
{
|
||||
if (entity->HasComponent<Ndk::PhysicsComponent2D>())
|
||||
return entity->GetComponent<Ndk::PhysicsComponent2D>().GetRigidBody();
|
||||
else if (entity->HasComponent<Ndk::CollisionComponent2D>())
|
||||
return entity->GetComponent<Ndk::CollisionComponent2D>().GetStaticBody();
|
||||
|
||||
return nullptr;
|
||||
};
|
||||
|
||||
Nz::RigidBody2D* firstBody = FetchBody(first);
|
||||
NazaraAssert(firstBody, "First entity has no CollisionComponent2D nor PhysicsComponent2D component");
|
||||
|
||||
Nz::RigidBody2D* secondBody = FetchBody(second);
|
||||
NazaraAssert(secondBody, "Second entity has no CollisionComponent2D nor PhysicsComponent2D component");
|
||||
|
||||
m_constraints.emplace_back();
|
||||
auto& constraintData = m_constraints.back();
|
||||
constraintData.constraint = std::make_unique<T>(*firstBody, *secondBody, std::forward<Args>(args)...);
|
||||
|
||||
constraintData.onBodyADestruction.Connect(first->OnEntityDestruction, [this, constraint = constraintData.constraint.get()](const Ndk::Entity* /*entity*/)
|
||||
{
|
||||
RemoveConstraint(constraint);
|
||||
});
|
||||
|
||||
constraintData.onBodyBDestruction.Connect(second->OnEntityDestruction, [this, constraint = constraintData.constraint.get()](const Ndk::Entity* /*entity*/)
|
||||
{
|
||||
RemoveConstraint(constraint);
|
||||
});
|
||||
|
||||
return static_cast<T*>(constraintData.constraint.get());
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_LIFETIMECOMPONENT_HPP
|
||||
#define NDK_COMPONENTS_LIFETIMECOMPONENT_HPP
|
||||
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class LifetimeComponent;
|
||||
|
||||
using LifetimeComponentHandle = Nz::ObjectHandle<LifetimeComponent>;
|
||||
|
||||
class NDK_API LifetimeComponent : public Component<LifetimeComponent>
|
||||
{
|
||||
friend class LifetimeSystem;
|
||||
|
||||
public:
|
||||
inline LifetimeComponent(float lifetime);
|
||||
LifetimeComponent(const LifetimeComponent&) = default;
|
||||
~LifetimeComponent() = default;
|
||||
|
||||
inline float GetRemainingTime() const;
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
inline bool UpdateLifetime(float elapsedTime);
|
||||
|
||||
float m_lifetime;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/LifetimeComponent.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_LIFETIMECOMPONENT_HPP
|
||||
|
|
@ -1,24 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/LifetimeComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
inline LifetimeComponent::LifetimeComponent(float lifetime) :
|
||||
m_lifetime(lifetime)
|
||||
{
|
||||
}
|
||||
|
||||
inline float Ndk::LifetimeComponent::GetRemainingTime() const
|
||||
{
|
||||
return m_lifetime;
|
||||
}
|
||||
|
||||
inline bool LifetimeComponent::UpdateLifetime(float elapsedTime)
|
||||
{
|
||||
m_lifetime -= elapsedTime;
|
||||
return m_lifetime < 0.f;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_LISTENERCOMPONENT_HPP
|
||||
#define NDK_COMPONENTS_LISTENERCOMPONENT_HPP
|
||||
|
||||
#include <NazaraSDK/ClientPrerequisites.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class ListenerComponent;
|
||||
|
||||
using ListenerComponentHandle = Nz::ObjectHandle<ListenerComponent>;
|
||||
|
||||
class NDK_CLIENT_API ListenerComponent : public Component<ListenerComponent>
|
||||
{
|
||||
public:
|
||||
inline ListenerComponent();
|
||||
~ListenerComponent() = default;
|
||||
|
||||
inline bool IsActive() const;
|
||||
inline void SetActive(bool active = true);
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
bool m_isActive;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/ListenerComponent.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_LISTENERCOMPONENT_HPP
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs an ListenerComponent object by default
|
||||
*/
|
||||
|
||||
inline ListenerComponent::ListenerComponent() :
|
||||
m_isActive(true)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the listener is activated
|
||||
* \param true If it is the case
|
||||
*/
|
||||
|
||||
inline bool ListenerComponent::IsActive() const
|
||||
{
|
||||
return m_isActive;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables the listener
|
||||
*
|
||||
* \param active Should the listener be active
|
||||
*/
|
||||
|
||||
inline void ListenerComponent::SetActive(bool active)
|
||||
{
|
||||
m_isActive = active;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_NODECOMPONENT_HPP
|
||||
#define NDK_COMPONENTS_NODECOMPONENT_HPP
|
||||
|
||||
#include <Nazara/Utility/Node.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class Entity;
|
||||
class NodeComponent;
|
||||
|
||||
using NodeComponentHandle = Nz::ObjectHandle<NodeComponent>;
|
||||
|
||||
class NDK_API NodeComponent : public Component<NodeComponent>, public Nz::Node
|
||||
{
|
||||
public:
|
||||
NodeComponent() = default;
|
||||
~NodeComponent() = default;
|
||||
|
||||
void SetParent(Entity* entity, bool keepDerived = false);
|
||||
using Nz::Node::SetParent;
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/NodeComponent.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_NODECOMPONENT_HPP
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <NazaraSDK/Entity.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Sets the parent node of the entity
|
||||
*
|
||||
* \param entity Pointer to the entity considered as parent
|
||||
* \param keepDerived Should this component considered as a derived
|
||||
*
|
||||
* \remark Produces a NazaraAssert if entity has no component NodeComponent
|
||||
*/
|
||||
|
||||
inline void NodeComponent::SetParent(Entity* entity, bool keepDerived)
|
||||
{
|
||||
if (entity)
|
||||
{
|
||||
NazaraAssert(entity->HasComponent<NodeComponent>(), "Entity must have a NodeComponent");
|
||||
|
||||
Nz::Node::SetParent(entity->GetComponent<NodeComponent>(), keepDerived);
|
||||
}
|
||||
else
|
||||
Nz::Node::SetParent(nullptr, keepDerived);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_PHYSICSCOMPONENT2D_HPP
|
||||
#define NDK_COMPONENTS_PHYSICSCOMPONENT2D_HPP
|
||||
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class PhysicsComponent2D;
|
||||
|
||||
using PhysicsComponent2DHandle = Nz::ObjectHandle<PhysicsComponent2D>;
|
||||
|
||||
class NDK_API PhysicsComponent2D : public Component<PhysicsComponent2D>
|
||||
{
|
||||
friend class CollisionComponent2D;
|
||||
friend class PhysicsSystem2D;
|
||||
friend class ConstraintComponent2D;
|
||||
|
||||
public:
|
||||
using VelocityFunc = Nz::RigidBody2D::VelocityFunc;
|
||||
|
||||
PhysicsComponent2D();
|
||||
PhysicsComponent2D(const PhysicsComponent2D& physics);
|
||||
~PhysicsComponent2D() = default;
|
||||
|
||||
inline void AddForce(const Nz::Vector2f& force, Nz::CoordSys coordSys = Nz::CoordSys::Global);
|
||||
inline void AddForce(const Nz::Vector2f& force, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys::Global);
|
||||
inline void AddImpulse(const Nz::Vector2f& impulse, Nz::CoordSys coordSys = Nz::CoordSys::Global);
|
||||
inline void AddImpulse(const Nz::Vector2f& impulse, const Nz::Vector2f& point, Nz::CoordSys coordSys = Nz::CoordSys::Global);
|
||||
inline void AddTorque(const Nz::RadianAnglef& torque);
|
||||
|
||||
inline bool ClosestPointQuery(const Nz::Vector2f& position, Nz::Vector2f* closestPoint, float* closestDistance) const;
|
||||
|
||||
inline void EnableNodeSynchronization(bool nodeSynchronization);
|
||||
|
||||
inline void ForceSleep();
|
||||
inline void ForEachArbiter(const std::function<void(Nz::Arbiter2D&)>& callback);
|
||||
|
||||
inline Nz::Rectf GetAABB() const;
|
||||
inline float GetAngularDamping() const;
|
||||
inline Nz::RadianAnglef GetAngularVelocity() const;
|
||||
NAZARA_DEPRECATED("Name error, please use GetMassCenter")
|
||||
inline Nz::Vector2f GetCenterOfGravity(Nz::CoordSys coordSys = Nz::CoordSys::Local) const;
|
||||
inline float GetElasticity(std::size_t shapeIndex = 0) const;
|
||||
inline float GetFriction(std::size_t shapeIndex = 0) const;
|
||||
inline float GetMass() const;
|
||||
inline Nz::Vector2f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys::Local) const;
|
||||
inline float GetMomentOfInertia() const;
|
||||
inline Nz::Vector2f GetPosition() const;
|
||||
inline Nz::RadianAnglef GetRotation() const;
|
||||
inline Nz::Vector2f GetSurfaceVelocity(std::size_t shapeIndex = 0) const;
|
||||
inline std::size_t GetShapeCount() const;
|
||||
inline Nz::Vector2f GetVelocity() const;
|
||||
const VelocityFunc& GetVelocityFunction() const;
|
||||
|
||||
inline bool IsNodeSynchronizationEnabled() const;
|
||||
inline bool IsSleeping() const;
|
||||
inline bool IsValid() const;
|
||||
|
||||
inline void ResetVelocityFunction();
|
||||
|
||||
inline void SetAngularDamping(float angularDamping);
|
||||
inline void SetAngularVelocity(const Nz::RadianAnglef& angularVelocity);
|
||||
inline void SetElasticity(float elasticity);
|
||||
inline void SetElasticity(std::size_t shapeIndex, float friction);
|
||||
inline void SetFriction(float friction);
|
||||
inline void SetFriction(std::size_t shapeIndex, float friction);
|
||||
inline void SetMass(float mass, bool recomputeMoment = true);
|
||||
inline void SetMassCenter(const Nz::Vector2f& center, Nz::CoordSys coordSys = Nz::CoordSys::Local);
|
||||
inline void SetMomentOfInertia(float moment);
|
||||
inline void SetPosition(const Nz::Vector2f& position);
|
||||
inline void SetRotation(const Nz::RadianAnglef& rotation);
|
||||
inline void SetSurfaceVelocity(const Nz::Vector2f& velocity);
|
||||
inline void SetSurfaceVelocity(std::size_t shapeIndex, const Nz::Vector2f& velocity);
|
||||
inline void SetVelocity(const Nz::Vector2f& velocity);
|
||||
inline void SetVelocityFunction(VelocityFunc velocityFunc);
|
||||
|
||||
inline void UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime);
|
||||
|
||||
inline void Wakeup();
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
inline void ApplyPhysicsState(Nz::RigidBody2D& rigidBody) const;
|
||||
inline void CopyPhysicsState(const Nz::RigidBody2D& rigidBody);
|
||||
Nz::RigidBody2D* GetRigidBody();
|
||||
const Nz::RigidBody2D* GetRigidBody() const;
|
||||
|
||||
void OnAttached() override;
|
||||
void OnComponentAttached(BaseComponent& component) override;
|
||||
void OnComponentDetached(BaseComponent& component) override;
|
||||
void OnDetached() override;
|
||||
void OnEntityDestruction() override;
|
||||
void OnEntityDisabled() override;
|
||||
void OnEntityEnabled() override;
|
||||
|
||||
struct PendingPhysObjectStates
|
||||
{
|
||||
struct ShapeStates
|
||||
{
|
||||
Nz::Vector2f surfaceVelocity;
|
||||
float elasticity;
|
||||
float friction;
|
||||
};
|
||||
|
||||
VelocityFunc velocityFunc;
|
||||
std::vector<ShapeStates> shapes;
|
||||
Nz::RadianAnglef angularVelocity;
|
||||
Nz::Vector2f massCenter;
|
||||
Nz::Vector2f velocity;
|
||||
bool valid = false;
|
||||
float mass;
|
||||
float momentOfInertia;
|
||||
};
|
||||
|
||||
std::unique_ptr<Nz::RigidBody2D> m_object;
|
||||
PendingPhysObjectStates m_pendingStates;
|
||||
bool m_nodeSynchronizationEnabled;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_PHYSICSCOMPONENT2D_HPP
|
||||
|
|
@ -1,726 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a PhysicsComponent2D object by default
|
||||
*/
|
||||
inline PhysicsComponent2D::PhysicsComponent2D() :
|
||||
m_nodeSynchronizationEnabled(true)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a PhysicsComponent2D object by copy semantic
|
||||
*
|
||||
* \param physics PhysicsComponent2D to copy
|
||||
*/
|
||||
inline PhysicsComponent2D::PhysicsComponent2D(const PhysicsComponent2D& physics) :
|
||||
m_nodeSynchronizationEnabled(physics.m_nodeSynchronizationEnabled)
|
||||
{
|
||||
CopyPhysicsState(*physics.GetRigidBody());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies a physics force to the entity
|
||||
*
|
||||
* \param force Force to apply on the entity
|
||||
* \param coordSys System coordinates to consider
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent2D::AddForce(const Nz::Vector2f& force, Nz::CoordSys coordSys)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->AddForce(force, coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies a physics force to the entity
|
||||
*
|
||||
* \param force Force to apply on the entity
|
||||
* \param point Point where to apply the force
|
||||
* \param coordSys System coordinates to consider
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent2D::AddForce(const Nz::Vector2f& force, const Nz::Vector2f& point, Nz::CoordSys coordSys)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->AddForce(force, point, coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies a impulse to the entity
|
||||
*
|
||||
* \param impulse Impulse to apply on the entity
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent2D::AddImpulse(const Nz::Vector2f& impulse, Nz::CoordSys coordSys)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->AddImpulse(impulse, coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies a impulse to the entity
|
||||
*
|
||||
* \param impulse Impulse to apply on the entity
|
||||
* \param point Point where the impulse is applied
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent2D::AddImpulse(const Nz::Vector2f& impulse, const Nz::Vector2f& point, Nz::CoordSys coordSys)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->AddImpulse(impulse, point, coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies a torque to the entity
|
||||
*
|
||||
* \param torque Torque to apply on the entity
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent2D::AddTorque(const Nz::RadianAnglef& torque)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->AddTorque(torque);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Finds the closest point on the entity relative to a position
|
||||
* \return True if such a point exists (will return false if no collider exists)
|
||||
*
|
||||
* \param position The starting point which will be used for the query
|
||||
* \param closestPoint The closest point on entity surface
|
||||
* \param closestDistance The distance between the closest point and the starting point, may be negative if starting point is inside the entity
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline bool PhysicsComponent2D::ClosestPointQuery(const Nz::Vector2f& position, Nz::Vector2f* closestPoint, float* closestDistance) const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->ClosestPointQuery(position, closestPoint, closestDistance);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables position/rotation synchronization with the NodeComponent
|
||||
*
|
||||
* By default, at every update of the PhysicsSystem2D, the NodeComponent's position and rotation (if any) will be synchronized with
|
||||
* the values of the PhysicsComponent2D. This function allows to enable/disable this behavior on a per-entity basis.
|
||||
*
|
||||
* \param nodeSynchronization Should synchronization occur between NodeComponent and PhysicsComponent2D
|
||||
*/
|
||||
inline void PhysicsComponent2D::EnableNodeSynchronization(bool nodeSynchronization)
|
||||
{
|
||||
m_nodeSynchronizationEnabled = nodeSynchronization;
|
||||
|
||||
if (m_entity)
|
||||
m_entity->Invalidate();
|
||||
}
|
||||
|
||||
/*!
|
||||
TODO
|
||||
*/
|
||||
inline void PhysicsComponent2D::ForceSleep()
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->ForceSleep();
|
||||
}
|
||||
|
||||
/*!
|
||||
TODO
|
||||
*/
|
||||
inline void PhysicsComponent2D::ForEachArbiter(const std::function<void(Nz::Arbiter2D&)>& callback)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->ForEachArbiter(callback);
|
||||
}
|
||||
/*!
|
||||
* \brief Gets the AABB of the physics object
|
||||
* \return AABB of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline Nz::Rectf PhysicsComponent2D::GetAABB() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetAABB();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the angular damping or moment of inertia of the physics object
|
||||
* \return Angular damping of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*
|
||||
* \see GetMomentOfInertia
|
||||
*/
|
||||
|
||||
inline float PhysicsComponent2D::GetAngularDamping() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetAngularDamping();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the angular velocity of the physics object
|
||||
* \return Angular velocity of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline Nz::RadianAnglef PhysicsComponent2D::GetAngularVelocity() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetAngularVelocity();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the gravity center of the physics object
|
||||
* \return Gravity center of the object
|
||||
*
|
||||
* \param coordSys System coordinates to consider
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline Nz::Vector2f PhysicsComponent2D::GetCenterOfGravity(Nz::CoordSys coordSys) const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetMassCenter(coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the elasticity of a shape belonging to this physics object
|
||||
* \return Elasticity of the shape
|
||||
*
|
||||
* \param shapeIndex Shape index of the collider we're interested
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline float PhysicsComponent2D::GetElasticity(std::size_t shapeIndex) const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetElasticity(shapeIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the friction of a shape belonging to this physics object
|
||||
* \return Friction of the shape
|
||||
*
|
||||
* \param shapeIndex Shape index of the collider we're interested
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline float PhysicsComponent2D::GetFriction(std::size_t shapeIndex) const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetFriction(shapeIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the mass of the physics object
|
||||
* \return Mass of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline float PhysicsComponent2D::GetMass() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetMass();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the gravity center of the physics object
|
||||
* \return Gravity center of the object
|
||||
*
|
||||
* \param coordSys System coordinates to consider
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline Nz::Vector2f PhysicsComponent2D::GetMassCenter(Nz::CoordSys coordSys) const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetMassCenter(coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the angular damping or moment of inertia of the physics object
|
||||
* \return Moment of inertia of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*
|
||||
* \see GetAngularDamping
|
||||
*/
|
||||
|
||||
inline float PhysicsComponent2D::GetMomentOfInertia() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetMomentOfInertia();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the position of the physics object
|
||||
* \return Position of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline Nz::Vector2f PhysicsComponent2D::GetPosition() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetPosition();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the rotation of the physics object
|
||||
* \return Rotation of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline Nz::RadianAnglef PhysicsComponent2D::GetRotation() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetRotation();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the surface velocity of a shape belonging to this physics object
|
||||
* \return Surface velocity of the shape
|
||||
*
|
||||
* \param shapeIndex Shape index of the collider we're interested
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline Nz::Vector2f PhysicsComponent2D::GetSurfaceVelocity(std::size_t shapeIndex) const
|
||||
{
|
||||
return m_object->GetSurfaceVelocity(shapeIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the rotation of the physics object
|
||||
* \return Shape count of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline std::size_t PhysicsComponent2D::GetShapeCount() const
|
||||
{
|
||||
return m_object->GetShapeCount();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the velocity of the physics object
|
||||
* \return Velocity of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline Nz::Vector2f PhysicsComponent2D::GetVelocity() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetVelocity();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the custom velocity function of the physics object
|
||||
* \return Velocity function of the object (may be empty if default function is used)
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline auto PhysicsComponent2D::GetVelocityFunction() const -> const VelocityFunc&
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetVelocityFunction();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks if position & rotation are synchronized with NodeComponent
|
||||
* \return true If synchronization is enabled
|
||||
*
|
||||
* \see EnableNodeSynchronization
|
||||
*/
|
||||
inline bool PhysicsComponent2D::IsNodeSynchronizationEnabled() const
|
||||
{
|
||||
return m_nodeSynchronizationEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the entity is currently sleeping
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline bool PhysicsComponent2D::IsSleeping() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->IsSleeping();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks if this component is bound to a valid rigid body
|
||||
*
|
||||
* A component may not be bound to a rigid body if the component is not bound to an entity or if this entity is being destroyed
|
||||
*
|
||||
* \return true If bound, false otherwise
|
||||
*/
|
||||
inline bool PhysicsComponent2D::IsValid() const
|
||||
{
|
||||
return bool(m_object);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Reset velocity function to default one
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent2D::ResetVelocityFunction()
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->ResetVelocityFunction();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the angular damping or moment of inertia of the physics object
|
||||
*
|
||||
* \param angularDamping Angular damping of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*
|
||||
* \see SetMomentOfInertia
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent2D::SetAngularDamping(float angularDamping)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetAngularDamping(angularDamping);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the angular velocity of the physics object
|
||||
*
|
||||
* \param angularVelocity Angular velocity of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetAngularVelocity(const Nz::RadianAnglef& angularVelocity)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetAngularVelocity(angularVelocity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the elasticity of the whole physics object
|
||||
*
|
||||
* Overrides all shapes elasticity with a single value
|
||||
*
|
||||
* \param elasticity Elasticity to be applied
|
||||
*
|
||||
* \remark Elasticity must be positive or zero
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetElasticity(float elasticity)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
NazaraAssert(elasticity >= 0.f, "Friction must be positive");
|
||||
|
||||
m_object->SetElasticity(elasticity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the elasticity of a single shape of the physics object
|
||||
*
|
||||
* \param shapeIndex Target shape index
|
||||
* \param elasticity Elasticity to be applied
|
||||
*
|
||||
* \remark Elasticity must be positive or zero
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetElasticity(std::size_t shapeIndex, float elasticity)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
NazaraAssert(elasticity >= 0.f, "Friction must be positive");
|
||||
|
||||
m_object->SetElasticity(shapeIndex, elasticity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the friction of the whole physics object
|
||||
*
|
||||
* Overrides all shapes friction with a single value
|
||||
*
|
||||
* \param friction Friction to be applied
|
||||
*
|
||||
* \remark Friction must be positive or zero
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetFriction(float friction)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
NazaraAssert(friction >= 0.f, "Friction must be positive");
|
||||
|
||||
m_object->SetFriction(friction);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the friction of a single shape of the physics object
|
||||
*
|
||||
* \param shapeIndex Target shape index
|
||||
* \param friction Friction to be applied
|
||||
*
|
||||
* \remark Friction must be positive or zero
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetFriction(std::size_t shapeIndex, float friction)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
NazaraAssert(friction >= 0.f, "Friction must be positive");
|
||||
|
||||
m_object->SetFriction(shapeIndex, friction);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the mass of the physics object
|
||||
*
|
||||
* \param mass Mass of the object
|
||||
* \param recomputeMoment Should the moment of inertia be recomputed according to the new mass
|
||||
*
|
||||
* \remark Mass must be positive or zero
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetMass(float mass, bool recomputeMoment)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
NazaraAssert(mass >= 0.f, "Mass should be positive");
|
||||
|
||||
m_object->SetMass(mass, recomputeMoment);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the gravity center of the physics object
|
||||
*
|
||||
* \param center Gravity center of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetMassCenter(const Nz::Vector2f& center, Nz::CoordSys coordSys)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetMassCenter(center, coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the angular damping or moment of inertia of the physics object
|
||||
*
|
||||
* \param moment Moment of inertia of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*
|
||||
* \see SetAngularDamping
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetMomentOfInertia(float moment)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetMomentOfInertia(moment);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the physics object
|
||||
*
|
||||
* \param position Position of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetPosition(const Nz::Vector2f& position)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetPosition(position);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the rotation of the physics object
|
||||
*
|
||||
* \param rotation Rotation of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetRotation(const Nz::RadianAnglef& rotation)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetRotation(rotation);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the surface velocity of the whole physics object
|
||||
*
|
||||
* Overrides all shapes surface velocity with a single value
|
||||
*
|
||||
* \param velocity Surface velocity to be applied
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetSurfaceVelocity(const Nz::Vector2f& velocity)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetSurfaceVelocity(velocity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the surface velocity of a single shape of the physics object
|
||||
*
|
||||
* \param shapeIndex Target shape index
|
||||
* \param velocity Surface velocity to be applied
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetSurfaceVelocity(std::size_t shapeIndex, const Nz::Vector2f& velocity)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetSurfaceVelocity(shapeIndex, velocity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the velocity of the physics object
|
||||
*
|
||||
* \param velocity Velocity of the object
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetVelocity(const Nz::Vector2f& velocity)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetVelocity(velocity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets a custom velocity function for the physics object
|
||||
*
|
||||
* A velocity function is called (for non-kinematic and non-static objects) at every physics update to compute the new velocity of the object.
|
||||
* You may call UpdateVelocity (the default velocity function) to let the physics engine compute that itself and then adjust it using GetVelocity/SetVelocity as you need.
|
||||
*
|
||||
* \param velocityFunc New custom velocity function
|
||||
*
|
||||
* \remark Passing an empty VelocityFunc has the same effect as calling ResetVelocityFunction
|
||||
* \see ResetVelocityFunction
|
||||
* \see UpdateVelocity
|
||||
*/
|
||||
inline void PhysicsComponent2D::SetVelocityFunction(VelocityFunc velocityFunc)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetVelocityFunction(std::move(velocityFunc));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Calls the physics engine default velocity function
|
||||
*
|
||||
* \param gravity Physics system gravity
|
||||
* \param damping Physics system damping (adjusted to deltaTime)
|
||||
* \param deltaTime Elapsed time since last physics update
|
||||
*/
|
||||
inline void PhysicsComponent2D::UpdateVelocity(const Nz::Vector2f& gravity, float damping, float deltaTime)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->UpdateVelocity(gravity, damping, deltaTime);
|
||||
}
|
||||
|
||||
/*!
|
||||
TODO
|
||||
*/
|
||||
inline void PhysicsComponent2D::Wakeup()
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->Wakeup();
|
||||
}
|
||||
|
||||
inline void PhysicsComponent2D::ApplyPhysicsState(Nz::RigidBody2D& rigidBody) const
|
||||
{
|
||||
assert(m_pendingStates.valid);
|
||||
|
||||
rigidBody.SetAngularVelocity(m_pendingStates.angularVelocity);
|
||||
rigidBody.SetMass(m_pendingStates.mass);
|
||||
rigidBody.SetMassCenter(m_pendingStates.massCenter);
|
||||
rigidBody.SetMomentOfInertia(m_pendingStates.momentOfInertia);
|
||||
rigidBody.SetVelocity(m_pendingStates.velocity);
|
||||
rigidBody.SetVelocityFunction(m_pendingStates.velocityFunc);
|
||||
|
||||
for (std::size_t i = 0; i < m_pendingStates.shapes.size(); ++i)
|
||||
{
|
||||
auto& shapeData = m_pendingStates.shapes[i];
|
||||
rigidBody.SetElasticity(i, shapeData.elasticity);
|
||||
rigidBody.SetFriction(i, shapeData.friction);
|
||||
rigidBody.SetSurfaceVelocity(i, shapeData.surfaceVelocity);
|
||||
}
|
||||
}
|
||||
|
||||
inline void PhysicsComponent2D::CopyPhysicsState(const Nz::RigidBody2D& rigidBody)
|
||||
{
|
||||
m_pendingStates.valid = true;
|
||||
|
||||
m_pendingStates.angularVelocity = rigidBody.GetAngularVelocity();
|
||||
m_pendingStates.mass = rigidBody.GetMass();
|
||||
m_pendingStates.massCenter = rigidBody.GetMassCenter();
|
||||
m_pendingStates.momentOfInertia = rigidBody.GetMomentOfInertia();
|
||||
m_pendingStates.velocity = rigidBody.GetVelocity();
|
||||
m_pendingStates.velocityFunc = rigidBody.GetVelocityFunction();
|
||||
|
||||
m_pendingStates.shapes.resize(rigidBody.GetShapeCount());
|
||||
for (std::size_t i = 0; i < m_pendingStates.shapes.size(); ++i)
|
||||
{
|
||||
auto& shapeData = m_pendingStates.shapes[i];
|
||||
shapeData.elasticity = rigidBody.GetElasticity(i);
|
||||
shapeData.friction = rigidBody.GetFriction(i);
|
||||
shapeData.surfaceVelocity = rigidBody.GetSurfaceVelocity(i);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the underlying physics object
|
||||
* \return A reference to the physics object
|
||||
*/
|
||||
inline Nz::RigidBody2D* PhysicsComponent2D::GetRigidBody()
|
||||
{
|
||||
return m_object.get();
|
||||
}
|
||||
|
||||
inline const Nz::RigidBody2D* PhysicsComponent2D::GetRigidBody() const
|
||||
{
|
||||
return m_object.get();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_PHYSICSCOMPONENT3D_HPP
|
||||
#define NDK_COMPONENTS_PHYSICSCOMPONENT3D_HPP
|
||||
|
||||
#include <Nazara/Physics3D/RigidBody3D.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class PhysicsComponent3D;
|
||||
|
||||
using PhysicsComponent3DHandle = Nz::ObjectHandle<PhysicsComponent3D>;
|
||||
|
||||
class NDK_API PhysicsComponent3D : public Component<PhysicsComponent3D>
|
||||
{
|
||||
friend class CollisionComponent3D;
|
||||
friend class PhysicsSystem3D;
|
||||
|
||||
public:
|
||||
inline PhysicsComponent3D();
|
||||
PhysicsComponent3D(const PhysicsComponent3D& physics);
|
||||
~PhysicsComponent3D() = default;
|
||||
|
||||
inline void AddForce(const Nz::Vector3f& force, Nz::CoordSys coordSys = Nz::CoordSys::Global);
|
||||
inline void AddForce(const Nz::Vector3f& force, const Nz::Vector3f& point, Nz::CoordSys coordSys = Nz::CoordSys::Global);
|
||||
inline void AddTorque(const Nz::Vector3f& torque, Nz::CoordSys coordSys = Nz::CoordSys::Global);
|
||||
|
||||
inline void EnableAutoSleep(bool autoSleep);
|
||||
inline void EnableNodeSynchronization(bool nodeSynchronization);
|
||||
|
||||
inline Nz::Boxf GetAABB() const;
|
||||
inline Nz::Vector3f GetAngularDamping() const;
|
||||
inline Nz::Vector3f GetAngularVelocity() const;
|
||||
inline float GetGravityFactor() const;
|
||||
inline float GetLinearDamping() const;
|
||||
inline Nz::Vector3f GetLinearVelocity() const;
|
||||
inline float GetMass() const;
|
||||
inline Nz::Vector3f GetMassCenter(Nz::CoordSys coordSys = Nz::CoordSys::Local) const;
|
||||
inline const Nz::Matrix4f& GetMatrix() const;
|
||||
inline Nz::Vector3f GetPosition() const;
|
||||
inline Nz::Quaternionf GetRotation() const;
|
||||
|
||||
inline bool IsAutoSleepEnabled() const;
|
||||
inline bool IsMoveable() const;
|
||||
inline bool IsNodeSynchronizationEnabled() const;
|
||||
inline bool IsSleeping() const;
|
||||
|
||||
inline void SetAngularDamping(const Nz::Vector3f& angularDamping);
|
||||
inline void SetAngularVelocity(const Nz::Vector3f& angularVelocity);
|
||||
inline void SetGravityFactor(float gravityFactor);
|
||||
inline void SetLinearDamping(float damping);
|
||||
inline void SetLinearVelocity(const Nz::Vector3f& velocity);
|
||||
inline void SetMass(float mass);
|
||||
inline void SetMassCenter(const Nz::Vector3f& center);
|
||||
inline void SetMaterial(const std::string& materialName);
|
||||
inline void SetMaterial(int materialIndex);
|
||||
inline void SetPosition(const Nz::Vector3f& position);
|
||||
inline void SetRotation(const Nz::Quaternionf& rotation);
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
inline void ApplyPhysicsState(Nz::RigidBody3D& rigidBody) const;
|
||||
inline void CopyPhysicsState(const Nz::RigidBody3D& rigidBody);
|
||||
inline Nz::RigidBody3D* GetRigidBody();
|
||||
inline const Nz::RigidBody3D& GetRigidBody() const;
|
||||
|
||||
void OnAttached() override;
|
||||
void OnComponentAttached(BaseComponent& component) override;
|
||||
void OnComponentDetached(BaseComponent& component) override;
|
||||
void OnDetached() override;
|
||||
void OnEntityDestruction() override;
|
||||
void OnEntityDisabled() override;
|
||||
void OnEntityEnabled() override;
|
||||
|
||||
struct PendingPhysObjectStates
|
||||
{
|
||||
Nz::Vector3f angularDamping;
|
||||
Nz::Vector3f massCenter;
|
||||
bool autoSleep;
|
||||
bool valid = false;
|
||||
float gravityFactor;
|
||||
float linearDamping;
|
||||
float mass;
|
||||
};
|
||||
|
||||
std::unique_ptr<Nz::RigidBody3D> m_object;
|
||||
PendingPhysObjectStates m_pendingStates;
|
||||
bool m_nodeSynchronizationEnabled;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_PHYSICSCOMPONENT3D_HPP
|
||||
|
|
@ -1,504 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
inline PhysicsComponent3D::PhysicsComponent3D() :
|
||||
m_nodeSynchronizationEnabled(true)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a PhysicsComponent3D object by copy semantic
|
||||
*
|
||||
* \param physics PhysicsComponent3D to copy
|
||||
*/
|
||||
inline PhysicsComponent3D::PhysicsComponent3D(const PhysicsComponent3D& physics) :
|
||||
m_nodeSynchronizationEnabled(physics.m_nodeSynchronizationEnabled)
|
||||
{
|
||||
// We can't make a copy of the RigidBody3D, as we are not attached yet (and will possibly be attached to another world)
|
||||
CopyPhysicsState(physics.GetRigidBody());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies a force to the entity
|
||||
*
|
||||
* \param force Force to apply on the entity
|
||||
* \param coordSys System coordinates to consider
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent3D::AddForce(const Nz::Vector3f& force, Nz::CoordSys coordSys)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->AddForce(force, coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies a force to the entity
|
||||
*
|
||||
* \param force Force to apply on the entity
|
||||
* \param point Point where to apply the force
|
||||
* \param coordSys System coordinates to consider
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent3D::AddForce(const Nz::Vector3f& force, const Nz::Vector3f& point, Nz::CoordSys coordSys)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->AddForce(force, point, coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Applies a torque to the entity
|
||||
*
|
||||
* \param torque Torque to apply on the entity
|
||||
* \param coordSys System coordinates to consider
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent3D::AddTorque(const Nz::Vector3f& torque, Nz::CoordSys coordSys)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->AddTorque(torque, coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables auto sleep of physics object
|
||||
*
|
||||
* \param autoSleep Should the physics of the object be disabled when too far from others
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent3D::EnableAutoSleep(bool autoSleep)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->EnableAutoSleep(autoSleep);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables position/rotation synchronization with the NodeComponent
|
||||
*
|
||||
* By default, at every update of the PhysicsSystem3D, the NodeComponent's position and rotation (if any) will be synchronized with
|
||||
* the values of the PhysicsComponent3D. This function allows to enable/disable this behavior on a per-entity basis.
|
||||
*
|
||||
* \param nodeSynchronization Should synchronization occur between NodeComponent and PhysicsComponent3D
|
||||
*/
|
||||
inline void PhysicsComponent3D::EnableNodeSynchronization(bool nodeSynchronization)
|
||||
{
|
||||
m_nodeSynchronizationEnabled = nodeSynchronization;
|
||||
|
||||
if (m_entity)
|
||||
m_entity->Invalidate();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the AABB of the physics object
|
||||
* \return AABB of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline Nz::Boxf PhysicsComponent3D::GetAABB() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetAABB();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the angular damping of the physics object
|
||||
* \return Angular damping of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline Nz::Vector3f PhysicsComponent3D::GetAngularDamping() const
|
||||
{
|
||||
return m_object->GetAngularDamping();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the angular velocity of the physics object
|
||||
* \return Angular velocity of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline Nz::Vector3f PhysicsComponent3D::GetAngularVelocity() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetAngularVelocity();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the gravity factor of the physics object
|
||||
* \return Gravity factor of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline float PhysicsComponent3D::GetGravityFactor() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetGravityFactor();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the linear damping of the physics object
|
||||
* \return Linear damping of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline float PhysicsComponent3D::GetLinearDamping() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetLinearDamping();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the linear velocity of the physics object
|
||||
* \return Linear velocity of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline Nz::Vector3f PhysicsComponent3D::GetLinearVelocity() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetLinearVelocity();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the mass of the physics object
|
||||
* \return Mass of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline float PhysicsComponent3D::GetMass() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetMass();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the gravity center of the physics object
|
||||
* \return Gravity center of the object
|
||||
*
|
||||
* \param coordSys System coordinates to consider
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline Nz::Vector3f PhysicsComponent3D::GetMassCenter(Nz::CoordSys coordSys) const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetMassCenter(coordSys);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the matrix of the physics object
|
||||
* \return Matrix of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline const Nz::Matrix4f& PhysicsComponent3D::GetMatrix() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetMatrix();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the position of the physics object
|
||||
* \return Position of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline Nz::Vector3f PhysicsComponent3D::GetPosition() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetPosition();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the rotation of the physics object
|
||||
* \return Rotation of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline Nz::Quaternionf PhysicsComponent3D::GetRotation() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->GetRotation();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the auto sleep is enabled
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline bool PhysicsComponent3D::IsAutoSleepEnabled() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->IsAutoSleepEnabled();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the object is moveable
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline bool PhysicsComponent3D::IsMoveable() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->IsMoveable();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks if position & rotation are synchronized with NodeComponent
|
||||
* \return true If synchronization is enabled
|
||||
*
|
||||
* \see EnableNodeSynchronization
|
||||
*/
|
||||
inline bool PhysicsComponent3D::IsNodeSynchronizationEnabled() const
|
||||
{
|
||||
return m_nodeSynchronizationEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the entity is currently sleeping
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline bool PhysicsComponent3D::IsSleeping() const
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
return m_object->IsSleeping();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the angular damping of the physics object
|
||||
*
|
||||
* \param angularDamping Angular damping of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetAngularDamping(const Nz::Vector3f& angularDamping)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetAngularDamping(angularDamping);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the angular velocity of the physics object
|
||||
*
|
||||
* \param angularVelocity Angular velocity of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetAngularVelocity(const Nz::Vector3f& angularVelocity)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetAngularVelocity(angularVelocity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the gravity factor of the physics object
|
||||
*
|
||||
* \param gravityFactor Gravity factor of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetGravityFactor(float gravityFactor)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetGravityFactor(gravityFactor);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the linear damping of the physics object
|
||||
*
|
||||
* \param damping Linear damping of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetLinearDamping(float damping)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetLinearDamping(damping);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the linear velocity of the physics object
|
||||
*
|
||||
* \param velocity New linear velocity of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetLinearVelocity(const Nz::Vector3f& velocity)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetLinearVelocity(velocity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the mass of the physics object
|
||||
*
|
||||
* \param mass Mass of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
* \remark Produces a NazaraAssert if the mass is negative
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetMass(float mass)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
NazaraAssert(mass >= 0.f, "Mass must be positive and finite");
|
||||
NazaraAssert(std::isfinite(mass), "Mass must be positive and finite");
|
||||
|
||||
m_object->SetMass(mass);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the gravity center of the physics object
|
||||
*
|
||||
* \param center Gravity center of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetMassCenter(const Nz::Vector3f& center)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetMassCenter(center);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the material of the object, affecting how object does respond to collisions
|
||||
*
|
||||
* \param materialName Name of the material, previously registered to physics world
|
||||
*
|
||||
* \remark materialName must exists in PhysWorld before this call
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetMaterial(const std::string& materialName)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetMaterial(materialName);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the material of the object, affecting how object does respond to collisions
|
||||
*
|
||||
* \param materialIndex Id of the material, previously retrieved from a physics world
|
||||
*
|
||||
* \remark materialIndex must come from a call to in PhysWorld::CreateMaterial
|
||||
*/
|
||||
inline void PhysicsComponent3D::SetMaterial(int materialIndex)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetMaterial(materialIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position of the physics object
|
||||
*
|
||||
* \param position Position of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent3D::SetPosition(const Nz::Vector3f& position)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetPosition(position);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the rotation of the physics object
|
||||
*
|
||||
* \param rotation Rotation of the object
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the physics object is invalid
|
||||
*/
|
||||
|
||||
inline void PhysicsComponent3D::SetRotation(const Nz::Quaternionf& rotation)
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->SetRotation(rotation);
|
||||
}
|
||||
|
||||
inline void PhysicsComponent3D::ApplyPhysicsState(Nz::RigidBody3D& rigidBody) const
|
||||
{
|
||||
assert(m_pendingStates.valid);
|
||||
|
||||
rigidBody.EnableAutoSleep(m_pendingStates.autoSleep);
|
||||
rigidBody.SetAngularDamping(m_pendingStates.angularDamping);
|
||||
rigidBody.SetGravityFactor(m_pendingStates.gravityFactor);
|
||||
rigidBody.SetLinearDamping(m_pendingStates.linearDamping);
|
||||
rigidBody.SetMass(m_pendingStates.mass);
|
||||
rigidBody.SetMassCenter(m_pendingStates.massCenter);
|
||||
}
|
||||
|
||||
inline void PhysicsComponent3D::CopyPhysicsState(const Nz::RigidBody3D& rigidBody)
|
||||
{
|
||||
m_pendingStates.autoSleep = rigidBody.IsAutoSleepEnabled();
|
||||
m_pendingStates.angularDamping = rigidBody.GetAngularDamping();
|
||||
m_pendingStates.gravityFactor = rigidBody.GetGravityFactor();
|
||||
m_pendingStates.linearDamping = rigidBody.GetLinearDamping();
|
||||
m_pendingStates.mass = rigidBody.GetMass();
|
||||
m_pendingStates.massCenter = rigidBody.GetMassCenter(Nz::CoordSys::Local);
|
||||
m_pendingStates.valid = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the underlying physics object
|
||||
* \return A reference to the physics object
|
||||
*/
|
||||
inline Nz::RigidBody3D* PhysicsComponent3D::GetRigidBody()
|
||||
{
|
||||
return m_object.get();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the underlying physics object
|
||||
* \return A reference to the physics object
|
||||
*/
|
||||
inline const Nz::RigidBody3D& PhysicsComponent3D::GetRigidBody() const
|
||||
{
|
||||
return *m_object.get();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,36 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_COMPONENTS_VELOCITYCOMPONENT_HPP
|
||||
#define NDK_COMPONENTS_VELOCITYCOMPONENT_HPP
|
||||
|
||||
#include <Nazara/Math/Vector3.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class VelocityComponent;
|
||||
|
||||
using VelocityComponentHandle = Nz::ObjectHandle<VelocityComponent>;
|
||||
|
||||
class NDK_API VelocityComponent : public Component<VelocityComponent>
|
||||
{
|
||||
public:
|
||||
VelocityComponent(const Nz::Vector3f& velocity = Nz::Vector3f::Zero(), Nz::CoordSys coordSystem = Nz::CoordSys::Global);
|
||||
~VelocityComponent() = default;
|
||||
|
||||
Nz::Vector3f linearVelocity;
|
||||
Nz::CoordSys coordSys;
|
||||
|
||||
VelocityComponent& operator=(const Nz::Vector3f& vel);
|
||||
|
||||
static ComponentIndex componentIndex;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Components/VelocityComponent.inl>
|
||||
|
||||
#endif // NDK_COMPONENTS_VELOCITYCOMPONENT_HPP
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::VelocityComponent
|
||||
* \brief NDK class that represents the component for velocity
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a VelocityComponent object with a velocity
|
||||
*
|
||||
* \param velocity Linear velocity
|
||||
*/
|
||||
|
||||
inline VelocityComponent::VelocityComponent(const Nz::Vector3f& velocity, Nz::CoordSys coordSystem) :
|
||||
linearVelocity(velocity),
|
||||
coordSys(coordSystem)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Assigns the velocity to this component
|
||||
* \return A reference to this
|
||||
*
|
||||
* \param vel Linear velocity
|
||||
*/
|
||||
|
||||
inline VelocityComponent& VelocityComponent::operator=(const Nz::Vector3f& vel)
|
||||
{
|
||||
linearVelocity = vel;
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,115 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_ENTITY_HPP
|
||||
#define NDK_ENTITY_HPP
|
||||
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <Nazara/Core/MovablePtr.hpp>
|
||||
#include <Nazara/Core/ObjectHandle.hpp>
|
||||
#include <Nazara/Core/Signal.hpp>
|
||||
#include <NazaraSDK/Algorithm.hpp>
|
||||
#include <NazaraSDK/Prerequisites.hpp>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class BaseComponent;
|
||||
class BaseSystem;
|
||||
class Entity;
|
||||
class EntityList;
|
||||
class World;
|
||||
|
||||
using EntityHandle = Nz::ObjectHandle<Entity>;
|
||||
|
||||
class NDK_API Entity : public Nz::HandledObject<Entity>
|
||||
{
|
||||
friend BaseSystem;
|
||||
friend EntityList;
|
||||
friend World;
|
||||
|
||||
public:
|
||||
Entity(const Entity&) = delete;
|
||||
Entity(Entity&& entity) noexcept;
|
||||
~Entity();
|
||||
|
||||
BaseComponent& AddComponent(std::unique_ptr<BaseComponent>&& component);
|
||||
template<typename ComponentType, typename... Args> ComponentType& AddComponent(Args&&... args);
|
||||
|
||||
const EntityHandle& Clone() const;
|
||||
|
||||
inline void Disable();
|
||||
|
||||
std::unique_ptr<BaseComponent> DropComponent(ComponentIndex index);
|
||||
template<typename ComponentType> std::unique_ptr<BaseComponent> DropComponent();
|
||||
|
||||
void Enable(bool enable = true);
|
||||
|
||||
inline BaseComponent& GetComponent(ComponentIndex index);
|
||||
template<typename ComponentType> ComponentType& GetComponent();
|
||||
inline const BaseComponent& GetComponent(ComponentIndex index) const;
|
||||
template<typename ComponentType> const ComponentType& GetComponent() const;
|
||||
inline const Nz::Bitset<>& GetComponentBits() const;
|
||||
inline EntityId GetId() const;
|
||||
inline const Nz::Bitset<>& GetSystemBits() const;
|
||||
inline World* GetWorld() const;
|
||||
|
||||
inline bool HasComponent(ComponentIndex index) const;
|
||||
template<typename ComponentType> bool HasComponent() const;
|
||||
|
||||
void Kill();
|
||||
|
||||
void Invalidate();
|
||||
inline bool IsEnabled() const;
|
||||
bool IsDying() const;
|
||||
inline bool IsValid() const;
|
||||
|
||||
inline void RemoveAllComponents();
|
||||
inline void RemoveComponent(ComponentIndex index);
|
||||
template<typename ComponentType> void RemoveComponent();
|
||||
|
||||
inline std::string ToString() const;
|
||||
|
||||
Entity& operator=(const Entity&) = delete;
|
||||
Entity& operator=(Entity&&) = delete;
|
||||
|
||||
NazaraSignal(OnEntityDestruction, Entity* /*entity*/);
|
||||
NazaraSignal(OnEntityDisabled, Entity* /*entity*/);
|
||||
NazaraSignal(OnEntityEnabled, Entity* /*entity*/);
|
||||
|
||||
private:
|
||||
Entity(World* world, EntityId id);
|
||||
|
||||
void Create();
|
||||
void Destroy();
|
||||
|
||||
inline Nz::Bitset<>& GetRemovedComponentBits();
|
||||
|
||||
inline void RegisterEntityList(EntityList* list);
|
||||
inline void RegisterSystem(SystemIndex index);
|
||||
|
||||
inline void SetWorld(World* world) noexcept;
|
||||
|
||||
inline void UnregisterEntityList(EntityList* list);
|
||||
inline void UnregisterSystem(SystemIndex index);
|
||||
|
||||
std::vector<std::unique_ptr<BaseComponent>> m_components;
|
||||
std::vector<EntityList*> m_containedInLists;
|
||||
Nz::Bitset<> m_componentBits;
|
||||
Nz::Bitset<> m_removedComponentBits;
|
||||
Nz::Bitset<> m_systemBits;
|
||||
Nz::MovablePtr<World> m_world;
|
||||
EntityId m_id;
|
||||
bool m_enabled;
|
||||
bool m_valid;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Entity.inl>
|
||||
|
||||
#endif // NDK_ENTITY_HPP
|
||||
|
|
@ -1,333 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Entity.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <algorithm>
|
||||
#include <cassert>
|
||||
#include <sstream>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Adds a component to the entity
|
||||
* \return A reference to the newly added component
|
||||
*
|
||||
* \param args Arguments to create in place the component to add to the entity
|
||||
*/
|
||||
|
||||
template<typename ComponentType, typename... Args>
|
||||
ComponentType& Entity::AddComponent(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");
|
||||
|
||||
// Affectation and return of the component
|
||||
std::unique_ptr<ComponentType> ptr(new ComponentType(std::forward<Args>(args)...));
|
||||
return static_cast<ComponentType&>(AddComponent(std::move(ptr)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Disables the entity
|
||||
*
|
||||
* This is just a shortcut to Enable(false)
|
||||
*/
|
||||
inline void Entity::Disable()
|
||||
{
|
||||
Enable(false);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a component in the entity by index
|
||||
* \return A reference to the component
|
||||
*
|
||||
* \param index Index of the component
|
||||
*
|
||||
* \remark Produces a NazaraAssert if component is not available in this entity or is invalid
|
||||
*/
|
||||
|
||||
inline BaseComponent& Entity::GetComponent(ComponentIndex index)
|
||||
{
|
||||
NazaraAssert(HasComponent(index), "This component is not part of the entity");
|
||||
|
||||
BaseComponent* component = m_components[index].get();
|
||||
NazaraAssert(component, "Invalid component pointer");
|
||||
|
||||
return *component;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a component in the entity by type
|
||||
* \return A reference to the component
|
||||
*
|
||||
* \remark Produces a NazaraAssert if component is not available in this entity
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
std::unique_ptr<BaseComponent> Entity::DropComponent()
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");
|
||||
|
||||
ComponentIndex index = GetComponentIndex<ComponentType>();
|
||||
return DropComponent(index);
|
||||
}
|
||||
|
||||
template<typename ComponentType>
|
||||
ComponentType& Entity::GetComponent()
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");
|
||||
|
||||
ComponentIndex index = GetComponentIndex<ComponentType>();
|
||||
return static_cast<ComponentType&>(GetComponent(index));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a component in the entity by index
|
||||
* \return A constant reference to the component
|
||||
*
|
||||
* \param index Index of the component
|
||||
*
|
||||
* \remark Produces a NazaraAssert if component is not available in this entity or is invalid
|
||||
*/
|
||||
|
||||
inline const BaseComponent& Entity::GetComponent(ComponentIndex index) const
|
||||
{
|
||||
NazaraAssert(HasComponent(index), "This component is not part of the entity");
|
||||
|
||||
BaseComponent* component = m_components[index].get();
|
||||
NazaraAssert(component, "Invalid component pointer");
|
||||
|
||||
return *component;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a component in the entity by type
|
||||
* \return A constant reference to the component
|
||||
*
|
||||
* \remark Produces a NazaraAssert if component is not available in this entity
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
const ComponentType& Entity::GetComponent() const
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");
|
||||
|
||||
ComponentIndex index = GetComponentIndex<ComponentType>();
|
||||
return static_cast<ComponentType&>(GetComponent(index));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bits representing the components in the entiy
|
||||
* \return A constant reference to the set of component's bits
|
||||
*/
|
||||
|
||||
inline const Nz::Bitset<>& Entity::GetComponentBits() const
|
||||
{
|
||||
return m_componentBits;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the identifier of the entity
|
||||
* \return Identifier of the entity
|
||||
*/
|
||||
|
||||
inline EntityId Entity::GetId() const
|
||||
{
|
||||
return m_id;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bits representing the systems in the entiy
|
||||
* \return A constant reference to the set of system's bits
|
||||
*/
|
||||
|
||||
inline const Nz::Bitset<>& Entity::GetSystemBits() const
|
||||
{
|
||||
return m_systemBits;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the world in which the entity is
|
||||
* \return Pointer to the world
|
||||
*/
|
||||
|
||||
inline World* Entity::GetWorld() const
|
||||
{
|
||||
return m_world;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not a component is present in the entity by index
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param index Index of the component
|
||||
*/
|
||||
|
||||
inline bool Entity::HasComponent(ComponentIndex index) const
|
||||
{
|
||||
return m_componentBits.UnboundedTest(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not a component is present in the entity by type
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
bool Entity::HasComponent() const
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>::value, "ComponentType is not a component");
|
||||
|
||||
ComponentIndex index = GetComponentIndex<ComponentType>();
|
||||
return HasComponent(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not the entity is enabled
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
inline bool Entity::IsEnabled() const
|
||||
{
|
||||
return m_enabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not the entity is valid
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
inline bool Entity::IsValid() const
|
||||
{
|
||||
return m_valid;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes every components
|
||||
*/
|
||||
|
||||
inline void Entity::RemoveAllComponents()
|
||||
{
|
||||
m_removedComponentBits = m_componentBits;
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes a component in the entity by index
|
||||
*
|
||||
* \param index Index of the component
|
||||
*/
|
||||
|
||||
inline void Entity::RemoveComponent(ComponentIndex index)
|
||||
{
|
||||
m_removedComponentBits.UnboundedSet(index);
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes a component in the entity by type
|
||||
*/
|
||||
|
||||
template<typename ComponentType>
|
||||
void Entity::RemoveComponent()
|
||||
{
|
||||
static_assert(std::is_base_of<BaseComponent, ComponentType>(), "ComponentType is not a component");
|
||||
|
||||
ComponentIndex index = GetComponentIndex<ComponentType>();
|
||||
RemoveComponent(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gives a string representation
|
||||
* \return A string representation of the object: "Entity(GetId())"
|
||||
*/
|
||||
|
||||
inline std::string Entity::ToString() const
|
||||
{
|
||||
std::ostringstream ss;
|
||||
ss << "Entity(" << GetId() << ')';
|
||||
|
||||
return ss.str();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the bits representing the removed components in the entiy
|
||||
* \return A constant reference to the set of remove component's bits
|
||||
*/
|
||||
|
||||
inline Nz::Bitset<>& Entity::GetRemovedComponentBits()
|
||||
{
|
||||
return m_removedComponentBits;
|
||||
}
|
||||
|
||||
inline void Entity::RegisterEntityList(EntityList* list)
|
||||
{
|
||||
m_containedInLists.push_back(list);
|
||||
}
|
||||
|
||||
inline void Entity::RegisterSystem(SystemIndex index)
|
||||
{
|
||||
m_systemBits.UnboundedSet(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the world of the entity
|
||||
*
|
||||
* \param world World in which the entity will be
|
||||
*
|
||||
* \remark Produces a NazaraAssert if world is invalid
|
||||
*/
|
||||
|
||||
inline void Entity::SetWorld(World* world) noexcept
|
||||
{
|
||||
NazaraAssert(world, "An entity must be attached to a world at any time");
|
||||
|
||||
m_world = world;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Unregisters a system for the entity
|
||||
*
|
||||
* \param index Index of the system
|
||||
*/
|
||||
|
||||
inline void Entity::UnregisterEntityList(EntityList* list)
|
||||
{
|
||||
auto it = std::find(m_containedInLists.begin(), m_containedInLists.end(), list);
|
||||
assert(it != m_containedInLists.end());
|
||||
|
||||
// Swap and pop idiom
|
||||
*it = m_containedInLists.back();
|
||||
m_containedInLists.pop_back();
|
||||
}
|
||||
|
||||
inline void Entity::UnregisterSystem(SystemIndex index)
|
||||
{
|
||||
m_systemBits.UnboundedReset(index);
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<Ndk::EntityHandle>
|
||||
{
|
||||
/*!
|
||||
* \brief Specialisation of std to hash
|
||||
* \return Result of the hash
|
||||
*
|
||||
* \param handle Entity to hash
|
||||
*/
|
||||
size_t operator()(const Ndk::EntityHandle& handle) const
|
||||
{
|
||||
// Hash the pointer will work until the entity is updated and moved
|
||||
// so, we have to hash the ID of the entity (which is constant)
|
||||
Ndk::EntityId id = (handle.IsValid()) ? handle->GetId() : std::numeric_limits<Ndk::EntityId>::max();
|
||||
|
||||
return hash<Ndk::EntityId>()(id);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_ENTITYLIST_HPP
|
||||
#define NDK_ENTITYLIST_HPP
|
||||
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <NazaraSDK/Prerequisites.hpp>
|
||||
#include <NazaraSDK/Entity.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API EntityList
|
||||
{
|
||||
friend Entity;
|
||||
friend World;
|
||||
|
||||
public:
|
||||
class iterator;
|
||||
friend iterator;
|
||||
using size_type = std::size_t;
|
||||
|
||||
inline EntityList();
|
||||
EntityList(const EntityList& entityList);
|
||||
EntityList(EntityList&& entityList) noexcept;
|
||||
~EntityList();
|
||||
|
||||
void Clear();
|
||||
|
||||
inline bool Has(const Entity* entity) const;
|
||||
inline bool Has(EntityId entity) const;
|
||||
|
||||
void Insert(Entity* entity);
|
||||
|
||||
inline void Remove(Entity* entity);
|
||||
inline void Reserve(std::size_t entityCount);
|
||||
|
||||
// STL API
|
||||
inline iterator begin() const;
|
||||
inline bool empty() const;
|
||||
inline iterator end() const;
|
||||
inline size_type size() const;
|
||||
|
||||
inline EntityList& operator=(const EntityList& entityList);
|
||||
inline EntityList& operator=(EntityList&& entityList) noexcept;
|
||||
|
||||
private:
|
||||
inline std::size_t FindNext(std::size_t currentId) const;
|
||||
inline World* GetWorld() const;
|
||||
inline void NotifyEntityDestruction(const Entity* entity);
|
||||
inline void SetWorld(World* world);
|
||||
|
||||
Nz::Bitset<Nz::UInt64> m_entityBits;
|
||||
World* m_world;
|
||||
};
|
||||
|
||||
class NDK_API EntityList::iterator
|
||||
{
|
||||
friend EntityList;
|
||||
|
||||
public:
|
||||
inline iterator(const iterator& it);
|
||||
|
||||
const EntityHandle& operator*() const;
|
||||
|
||||
inline iterator& operator=(const iterator& it);
|
||||
inline iterator& operator++();
|
||||
inline iterator operator++(int);
|
||||
|
||||
friend inline bool operator==(const iterator& lhs, const iterator& rhs);
|
||||
friend inline bool operator!=(const iterator& lhs, const iterator& rhs);
|
||||
|
||||
friend inline void swap(iterator& lhs, iterator& rhs);
|
||||
|
||||
using difference_type = std::ptrdiff_t;
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
using pointer = EntityHandle*;
|
||||
using reference = EntityHandle&;
|
||||
using value_type = EntityHandle;
|
||||
|
||||
private:
|
||||
inline iterator(const EntityList* world, std::size_t nextId);
|
||||
|
||||
std::size_t m_nextEntityId;
|
||||
const EntityList* m_list;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/EntityList.inl>
|
||||
|
||||
#endif // NDK_ENTITYLIST_HPP
|
||||
|
|
@ -1,181 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/EntityList.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <algorithm>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::EntityList
|
||||
* \brief NDK class that represents a set of entities to help performing batch operations
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Construct a new entity list
|
||||
*/
|
||||
inline EntityList::EntityList() :
|
||||
m_world(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not the EntityList contains the entity
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
*
|
||||
* \remark If the Insert function was called since the EntityList construction (or last call to Clear), the entity passed by parameter must belong to the same world as the previously inserted entities.
|
||||
*/
|
||||
inline bool EntityList::Has(const Entity* entity) const
|
||||
{
|
||||
NazaraAssert(!m_world || !entity || entity->GetWorld() == m_world, "Incompatible world");
|
||||
|
||||
return entity && entity->IsValid() && Has(entity->GetId());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not the set contains the entity by id
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param id Identifier of the entity
|
||||
*/
|
||||
inline bool EntityList::Has(EntityId entity) const
|
||||
{
|
||||
return m_entityBits.UnboundedTest(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes the entity from the set
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
*
|
||||
* \remark If entity is not contained, no action is performed
|
||||
* \remark This function never resets the implicit world member, even if it empties the list. Use the Clear method if you want to reset it.
|
||||
*
|
||||
* \see Clear
|
||||
*/
|
||||
inline void EntityList::Remove(Entity* entity)
|
||||
{
|
||||
if (Has(entity))
|
||||
{
|
||||
m_entityBits.Reset(entity->GetId());
|
||||
|
||||
entity->UnregisterEntityList(this);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Reserves enough space to contains entityCount entities
|
||||
*
|
||||
* \param entityCount Number of entities to reserve
|
||||
*/
|
||||
inline void EntityList::Reserve(std::size_t entityCount)
|
||||
{
|
||||
m_entityBits.Reserve(entityCount);
|
||||
}
|
||||
|
||||
// STL Interface
|
||||
inline EntityList::iterator EntityList::begin() const
|
||||
{
|
||||
return EntityList::iterator(this, m_entityBits.FindFirst());
|
||||
}
|
||||
|
||||
inline bool EntityList::empty() const
|
||||
{
|
||||
return !m_entityBits.TestAny();
|
||||
}
|
||||
|
||||
inline EntityList::iterator EntityList::end() const
|
||||
{
|
||||
return EntityList::iterator(this, m_entityBits.npos);
|
||||
}
|
||||
|
||||
inline EntityList::size_type EntityList::size() const
|
||||
{
|
||||
return m_entityBits.Count();
|
||||
}
|
||||
|
||||
inline std::size_t EntityList::FindNext(std::size_t currentId) const
|
||||
{
|
||||
return m_entityBits.FindNext(currentId);
|
||||
}
|
||||
|
||||
inline World* EntityList::GetWorld() const
|
||||
{
|
||||
return m_world;
|
||||
}
|
||||
|
||||
inline void EntityList::NotifyEntityDestruction(const Entity* entity)
|
||||
{
|
||||
assert(Has(entity));
|
||||
|
||||
m_entityBits.Reset(entity->GetId());
|
||||
}
|
||||
|
||||
inline void EntityList::SetWorld(World* world)
|
||||
{
|
||||
m_world = world;
|
||||
}
|
||||
|
||||
|
||||
inline EntityList::iterator::iterator(const EntityList* list, std::size_t nextId) :
|
||||
m_nextEntityId(nextId),
|
||||
m_list(list)
|
||||
{
|
||||
}
|
||||
|
||||
inline EntityList::iterator::iterator(const iterator& it) :
|
||||
m_nextEntityId(it.m_nextEntityId),
|
||||
m_list(it.m_list)
|
||||
{
|
||||
}
|
||||
|
||||
inline EntityList::iterator& EntityList::iterator::operator=(const iterator& it)
|
||||
{
|
||||
m_nextEntityId = it.m_nextEntityId;
|
||||
m_list = it.m_list;
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline EntityList::iterator& EntityList::iterator::operator++()
|
||||
{
|
||||
m_nextEntityId = m_list->FindNext(m_nextEntityId);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline EntityList::iterator EntityList::iterator::operator++(int)
|
||||
{
|
||||
std::size_t previousId = m_nextEntityId;
|
||||
|
||||
m_nextEntityId = m_list->FindNext(m_nextEntityId);
|
||||
|
||||
return iterator(m_list, previousId);
|
||||
}
|
||||
|
||||
inline bool operator==(const EntityList::iterator& lhs, const EntityList::iterator& rhs)
|
||||
{
|
||||
NazaraAssert(lhs.m_list == rhs.m_list, "Cannot compare iterator coming from different lists");
|
||||
|
||||
return lhs.m_nextEntityId == rhs.m_nextEntityId;
|
||||
}
|
||||
|
||||
inline bool operator!=(const EntityList::iterator& lhs, const EntityList::iterator& rhs)
|
||||
{
|
||||
return !operator==(lhs, rhs);
|
||||
}
|
||||
|
||||
inline void swap(EntityList::iterator& lhs, EntityList::iterator& rhs)
|
||||
{
|
||||
NazaraAssert(lhs.m_list == rhs.m_list, "Cannot compare iterator coming from different lists");
|
||||
|
||||
using std::swap;
|
||||
|
||||
swap(lhs.m_nextEntityId, rhs.m_nextEntityId);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,35 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_ENTITYOWNER_HPP
|
||||
#define NDK_ENTITYOWNER_HPP
|
||||
|
||||
#include <NazaraSDK/Entity.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class EntityOwner : public EntityHandle
|
||||
{
|
||||
public:
|
||||
EntityOwner() = default;
|
||||
EntityOwner(Entity* entity);
|
||||
EntityOwner(const EntityOwner& handle) = delete;
|
||||
EntityOwner(EntityOwner&& handle) noexcept = default;
|
||||
~EntityOwner();
|
||||
|
||||
void Release();
|
||||
void Reset(Entity* entity = nullptr);
|
||||
void Reset(EntityOwner&& handle);
|
||||
|
||||
EntityOwner& operator=(Entity* entity);
|
||||
EntityOwner& operator=(const EntityOwner& handle) = delete;
|
||||
EntityOwner& operator=(EntityOwner&& handle) noexcept;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/EntityOwner.inl>
|
||||
|
||||
#endif // NDK_ENTITYOWNER_HPP
|
||||
|
|
@ -1,104 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/EntityOwner.hpp>
|
||||
#include <functional>
|
||||
#include <limits>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::EntityOwner
|
||||
* \brief NDK class that represents the owner of the entity and so its lifetime
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a EntityOwner object
|
||||
*
|
||||
* \param entity Entity to own
|
||||
*/
|
||||
|
||||
inline EntityOwner::EntityOwner(Entity* entity) :
|
||||
EntityOwner()
|
||||
{
|
||||
Reset(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls Reset
|
||||
*
|
||||
* \see Reset
|
||||
*/
|
||||
inline EntityOwner::~EntityOwner()
|
||||
{
|
||||
Reset(nullptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Release the ownership of the entity without killing it
|
||||
*/
|
||||
inline void EntityOwner::Release()
|
||||
{
|
||||
EntityHandle::Reset(nullptr);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the ownership of the entity, previous is killed
|
||||
*
|
||||
* \param entity Entity to own
|
||||
*/
|
||||
inline void EntityOwner::Reset(Entity* entity)
|
||||
{
|
||||
if (IsValid())
|
||||
GetObject()->Kill();
|
||||
|
||||
EntityHandle::Reset(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the ownership of the entity by move semantic
|
||||
*
|
||||
* \param handle EntityOwner to move into this
|
||||
*/
|
||||
inline void EntityOwner::Reset(EntityOwner&& handle)
|
||||
{
|
||||
Reset(handle.GetObject());
|
||||
handle.Release();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Resets the ownership of the entity to the affected one
|
||||
*
|
||||
* \param entity Entity to own
|
||||
*/
|
||||
inline EntityOwner& EntityOwner::operator=(Entity* entity)
|
||||
{
|
||||
Reset(entity);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Steals ownership of a EntityOwner
|
||||
*
|
||||
* \param handle Handle to the new entity to own, or an invalid handle
|
||||
*/
|
||||
inline EntityOwner& EntityOwner::operator=(EntityOwner&& handle) noexcept
|
||||
{
|
||||
Reset(); //< Kill previously owned entity, if any
|
||||
|
||||
EntityHandle::operator=(std::move(handle));
|
||||
|
||||
return *this;
|
||||
}
|
||||
}
|
||||
|
||||
namespace std
|
||||
{
|
||||
template<>
|
||||
struct hash<Ndk::EntityOwner> : public hash<Ndk::EntityHandle>
|
||||
{
|
||||
};
|
||||
}
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
Nazara Development Kit ("NDK"), also called Nazara Engine - SDK ("Software Development Kit")
|
||||
|
||||
Copyright (C) 2015 Jérôme "Lynix" Leclercq (Lynix680@gmail.com)
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
of the Software, and to permit persons to whom the Software is furnished to do
|
||||
so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
*/
|
||||
|
||||
#ifndef NDK_PREREQUISITES_HPP
|
||||
#define NDK_PREREQUISITES_HPP
|
||||
|
||||
/*!
|
||||
* \defgroup NDK (NazaraSDK) Nazara Development Kit
|
||||
* A library grouping every modules of Nazara into multiple higher-level features suchs as scene management (handled by an ECS), application, lua binding, etc.
|
||||
*/
|
||||
|
||||
#include <Nazara/Prerequisites.hpp>
|
||||
|
||||
// Importation/Exportation of the API
|
||||
#if defined(NAZARA_STATIC)
|
||||
#define NDK_API
|
||||
#else
|
||||
#ifdef NDK_BUILD
|
||||
#define NDK_API NAZARA_EXPORT
|
||||
#else
|
||||
#define NDK_API NAZARA_IMPORT
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
using ComponentId = Nz::UInt64;
|
||||
using ComponentIndex = Nz::UInt32;
|
||||
using EntityId = Nz::UInt32;
|
||||
using SystemIndex = Nz::UInt32;
|
||||
}
|
||||
|
||||
#endif // NDK_PREREQUISITES_HPP
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_SDK_HPP
|
||||
#define NDK_SDK_HPP
|
||||
|
||||
#include <Nazara/Core/ModuleBase.hpp>
|
||||
#include <Nazara/Core/TypeList.hpp>
|
||||
#include <NazaraSDK/Prerequisites.hpp>
|
||||
|
||||
#include <Nazara/Network/Network.hpp>
|
||||
#include <Nazara/Physics2D/Physics2D.hpp>
|
||||
#include <Nazara/Physics3D/Physics3D.hpp>
|
||||
#include <Nazara/Shader/Shader.hpp>
|
||||
#include <Nazara/Utility/Utility.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API Sdk : public Nz::ModuleBase<Sdk>
|
||||
{
|
||||
friend ModuleBase;
|
||||
|
||||
public:
|
||||
using Dependencies = Nz::TypeList<Nz::Network, Nz::Physics2D, Nz::Physics3D, Nz::Utility>;
|
||||
|
||||
struct Config {};
|
||||
|
||||
Sdk(Config /*config*/);
|
||||
~Sdk();
|
||||
|
||||
private:
|
||||
static Sdk* s_instance;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Sdk.inl>
|
||||
|
||||
#endif // NDK_SDK_HPP
|
||||
|
|
@ -1,7 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
}
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_STATE_HPP
|
||||
#define NDK_STATE_HPP
|
||||
|
||||
#include <NazaraSDK/Prerequisites.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class StateMachine;
|
||||
|
||||
class NDK_API State
|
||||
{
|
||||
public:
|
||||
State() = default;
|
||||
virtual ~State();
|
||||
|
||||
virtual void Enter(StateMachine& fsm) = 0;
|
||||
virtual void Leave(StateMachine& fsm) = 0;
|
||||
virtual bool Update(StateMachine& fsm, float elapsedTime) = 0;
|
||||
};
|
||||
}
|
||||
|
||||
#endif // NDK_STATE_HPP
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_STATEMACHINE_HPP
|
||||
#define NDK_STATEMACHINE_HPP
|
||||
|
||||
#include <NazaraSDK/Prerequisites.hpp>
|
||||
#include <NazaraSDK/State.hpp>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class StateMachine
|
||||
{
|
||||
public:
|
||||
inline StateMachine(std::shared_ptr<State> originalState);
|
||||
StateMachine(const StateMachine&) = delete;
|
||||
inline StateMachine(StateMachine&& fsm) = default;
|
||||
inline ~StateMachine();
|
||||
|
||||
inline void ChangeState(std::shared_ptr<State> state);
|
||||
|
||||
inline bool IsTopState(const State* state) const;
|
||||
|
||||
inline void PopState();
|
||||
inline void PopStatesUntil(std::shared_ptr<State> state);
|
||||
inline void PushState(std::shared_ptr<State> state);
|
||||
|
||||
inline void ResetState(std::shared_ptr<State> state);
|
||||
|
||||
inline bool Update(float elapsedTime);
|
||||
|
||||
inline StateMachine& operator=(StateMachine&& fsm) = default;
|
||||
StateMachine& operator=(const StateMachine&) = delete;
|
||||
|
||||
private:
|
||||
enum class TransitionType
|
||||
{
|
||||
Pop,
|
||||
PopUntil,
|
||||
Push,
|
||||
};
|
||||
|
||||
struct StateTransition
|
||||
{
|
||||
TransitionType type;
|
||||
std::shared_ptr<State> state;
|
||||
};
|
||||
|
||||
std::vector<std::shared_ptr<State>> m_states;
|
||||
std::vector<StateTransition> m_transitions;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/StateMachine.inl>
|
||||
|
||||
#endif // NDK_STATEMACHINE_HPP
|
||||
|
|
@ -1,205 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/StateMachine.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::StateMachine
|
||||
* \brief NDK class that represents a state machine, to represent the multiple states of your program as a stack
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a StateMachine object with an original state
|
||||
*
|
||||
* \param originalState State which is the entry point of the application, a nullptr will create an empty state machine
|
||||
*/
|
||||
inline StateMachine::StateMachine(std::shared_ptr<State> originalState)
|
||||
{
|
||||
if (originalState)
|
||||
PushState(std::move(originalState));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object
|
||||
*
|
||||
* \remark Calls "Leave" on all the states from top to bottom
|
||||
*/
|
||||
inline StateMachine::~StateMachine()
|
||||
{
|
||||
// Leave state from top to bottom (as if states were popped out)
|
||||
for (auto it = m_states.rbegin(); it != m_states.rend(); ++it)
|
||||
(*it)->Leave(*this);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Replaces the current state on the top of the machine
|
||||
*
|
||||
* \param state State to replace the top one if it is nullptr, no action is performed
|
||||
*
|
||||
* \remark It is forbidden for a state machine to have (at any moment) the same state in its list multiple times
|
||||
* \remark Like all actions popping or pushing a state, this is not immediate and will only take effect when state machine is updated
|
||||
*/
|
||||
inline void StateMachine::ChangeState(std::shared_ptr<State> state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
// Change state is just a pop followed by a push
|
||||
StateTransition transition;
|
||||
transition.type = TransitionType::Pop;
|
||||
m_transitions.emplace_back(std::move(transition));
|
||||
|
||||
transition.state = std::move(state);
|
||||
transition.type = TransitionType::Push;
|
||||
m_transitions.emplace_back(std::move(transition));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the state is on the top of the machine
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param state State to compare the top with
|
||||
* \remark Because all actions popping or pushing a state don't take effect until next state machine update, this can return false on a just pushed state
|
||||
*/
|
||||
inline bool StateMachine::IsTopState(const State* state) const
|
||||
{
|
||||
if (m_states.empty())
|
||||
return false;
|
||||
|
||||
return m_states.back().get() == state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Pops the state on the top of the machine
|
||||
*
|
||||
* \remark This method can completely empty the stack
|
||||
* \remark Like all actions popping or pushing a state, this is not immediate and will only take effect when state machine is updated
|
||||
*/
|
||||
inline void StateMachine::PopState()
|
||||
{
|
||||
StateTransition transition;
|
||||
transition.type = TransitionType::Pop;
|
||||
|
||||
m_transitions.emplace_back(std::move(transition));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Pops all states of the machine until a specific one is reached
|
||||
*
|
||||
* \param state State to find on the stack. If nullptr is passed, no action is performed
|
||||
*
|
||||
* \remark This method will completely empty the stack if state is not present
|
||||
* \remark Like all actions popping or pushing a state, this is not immediate and will only take effect when state machine is updated
|
||||
*/
|
||||
inline void StateMachine::PopStatesUntil(std::shared_ptr<State> state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
StateTransition transition;
|
||||
transition.state = std::move(state);
|
||||
transition.type = TransitionType::PopUntil;
|
||||
|
||||
m_transitions.emplace_back(std::move(transition));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Pushes a new state on the top of the machine
|
||||
*
|
||||
* \param state Next state to represent if it is nullptr, it performs no action
|
||||
*
|
||||
* \remark It is forbidden for a state machine to have (at any moment) the same state in its list multiple times
|
||||
* \remark Like all actions popping or pushing a state, this is not immediate and will only take effect when state machine is updated
|
||||
*/
|
||||
inline void StateMachine::PushState(std::shared_ptr<State> state)
|
||||
{
|
||||
if (state)
|
||||
{
|
||||
StateTransition transition;
|
||||
transition.state = std::move(state);
|
||||
transition.type = TransitionType::Push;
|
||||
|
||||
m_transitions.emplace_back(std::move(transition));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Pops every states of the machine to put a new one
|
||||
*
|
||||
* \param state State to reset the stack with. If state is invalid, this will clear the state machine
|
||||
*
|
||||
* \remark It is forbidden for a state machine to have (at any moment) the same state in its list multiple times
|
||||
* \remark Like all actions popping or pushing a state, this is not immediate and will only take effect when state machine is updated
|
||||
*/
|
||||
inline void StateMachine::ResetState(std::shared_ptr<State> state)
|
||||
{
|
||||
StateTransition transition;
|
||||
transition.type = TransitionType::PopUntil; //< Pop until nullptr, which basically clears the state machine
|
||||
m_transitions.emplace_back(std::move(transition));
|
||||
|
||||
if (state)
|
||||
{
|
||||
transition.state = std::move(state);
|
||||
transition.type = TransitionType::Push;
|
||||
m_transitions.emplace_back(std::move(transition));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates all the states
|
||||
* \return true If update is successful for everyone of them
|
||||
*
|
||||
* \param elapsedTime Delta time used for the update
|
||||
*/
|
||||
inline bool StateMachine::Update(float elapsedTime)
|
||||
{
|
||||
// Use a classic for instead of a range-for because some state may push/pop on enter/leave, adding new transitions as we iterate
|
||||
// (range-for is a problem here because it doesn't handle mutable containers)
|
||||
|
||||
for (std::size_t i = 0; i < m_transitions.size(); ++i)
|
||||
{
|
||||
StateTransition& transition = m_transitions[i];
|
||||
|
||||
switch (transition.type)
|
||||
{
|
||||
case TransitionType::Pop:
|
||||
{
|
||||
std::shared_ptr<State>& topState = m_states.back();
|
||||
topState->Leave(*this); //< Call leave before popping to ensure consistent IsTopState behavior
|
||||
|
||||
m_states.pop_back();
|
||||
break;
|
||||
}
|
||||
|
||||
case TransitionType::PopUntil:
|
||||
{
|
||||
while (!m_states.empty() && m_states.back() != transition.state)
|
||||
{
|
||||
m_states.back()->Leave(*this);
|
||||
m_states.pop_back();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case TransitionType::Push:
|
||||
{
|
||||
m_states.emplace_back(std::move(transition.state));
|
||||
m_states.back()->Enter(*this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
m_transitions.clear();
|
||||
|
||||
return std::all_of(m_states.begin(), m_states.end(), [=](std::shared_ptr<State>& state) {
|
||||
return state->Update(*this, elapsedTime);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_SYSTEM_HPP
|
||||
#define NDK_SYSTEM_HPP
|
||||
|
||||
#include <NazaraSDK/BaseSystem.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
template<typename SystemType>
|
||||
class System : public BaseSystem
|
||||
{
|
||||
public:
|
||||
System();
|
||||
System(const System&) = delete;
|
||||
System(System&&) noexcept = default;
|
||||
virtual ~System();
|
||||
|
||||
System& operator=(const System&) = delete;
|
||||
System& operator=(System&&) noexcept = default;
|
||||
|
||||
static SystemIndex RegisterSystem();
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/System.inl>
|
||||
|
||||
#endif // NDK_SYSTEM_HPP
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Algorithm.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::System<SystemType>
|
||||
* \brief NDK class that represents a system which interacts on a world
|
||||
*
|
||||
* \remark This class is meant to be derived as CRTP: "System<Subtype>"
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs a System object by default
|
||||
*/
|
||||
|
||||
template<typename SystemType>
|
||||
System<SystemType>::System() :
|
||||
BaseSystem(GetSystemIndex<SystemType>())
|
||||
{
|
||||
}
|
||||
|
||||
template<typename SystemType>
|
||||
System<SystemType>::~System() = default;
|
||||
|
||||
/*!
|
||||
* \brief Registers the system by assigning it an index
|
||||
*/
|
||||
|
||||
template<typename SystemType>
|
||||
SystemIndex System<SystemType>::RegisterSystem()
|
||||
{
|
||||
return GetNextIndex();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
// This file was automatically generated
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_SYSTEMS_GLOBAL_HPP
|
||||
#define NDK_SYSTEMS_GLOBAL_HPP
|
||||
|
||||
#include <NazaraSDK/Systems/DebugSystem.hpp>
|
||||
#include <NazaraSDK/Systems/LifetimeSystem.hpp>
|
||||
#include <NazaraSDK/Systems/ListenerSystem.hpp>
|
||||
#include <NazaraSDK/Systems/ParticleSystem.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem3D.hpp>
|
||||
#include <NazaraSDK/Systems/RenderSystem.hpp>
|
||||
#include <NazaraSDK/Systems/VelocitySystem.hpp>
|
||||
|
||||
#endif // NDK_SYSTEMS_GLOBAL_HPP
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_SYSTEMS_LIFETIMESYSTEM_HPP
|
||||
#define NDK_SYSTEMS_LIFETIMESYSTEM_HPP
|
||||
|
||||
#include <NazaraSDK/System.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API LifetimeSystem : public System<LifetimeSystem>
|
||||
{
|
||||
public:
|
||||
LifetimeSystem();
|
||||
~LifetimeSystem() = default;
|
||||
|
||||
static SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
void OnUpdate(float elapsedTime) override;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Systems/LifetimeSystem.inl>
|
||||
|
||||
#endif // NDK_SYSTEMS_LIFETIMESYSTEM_HPP
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_SYSTEMS_LISTENERSYSTEM_HPP
|
||||
#define NDK_SYSTEMS_LISTENERSYSTEM_HPP
|
||||
|
||||
#include <NazaraSDK/ClientPrerequisites.hpp>
|
||||
#include <NazaraSDK/System.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_CLIENT_API ListenerSystem : public System<ListenerSystem>
|
||||
{
|
||||
public:
|
||||
ListenerSystem();
|
||||
~ListenerSystem() = default;
|
||||
|
||||
static SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
void OnUpdate(float elapsedTime) override;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Systems/ListenerSystem.inl>
|
||||
|
||||
#endif // NDK_SYSTEMS_LISTENERSYSTEM_HPP
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
|
@ -1,132 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_SYSTEMS_PHYSICSSYSTEM2D_HPP
|
||||
#define NDK_SYSTEMS_PHYSICSSYSTEM2D_HPP
|
||||
|
||||
#include <Nazara/Physics2D/PhysWorld2D.hpp>
|
||||
#include <NazaraSDK/EntityList.hpp>
|
||||
#include <NazaraSDK/System.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API PhysicsSystem2D : public System<PhysicsSystem2D>
|
||||
{
|
||||
friend class CollisionComponent2D;
|
||||
friend class PhysicsComponent2D;
|
||||
|
||||
using ContactEndCallback = std::function<void(PhysicsSystem2D& world, Nz::Arbiter2D& arbiter, const EntityHandle& bodyA, const EntityHandle& bodyB, void* userdata)>;
|
||||
using ContactPreSolveCallback = std::function<bool(PhysicsSystem2D& world, Nz::Arbiter2D& arbiter, const EntityHandle& bodyA, const EntityHandle& bodyB, void* userdata)>;
|
||||
using ContactPostSolveCallback = std::function<void(PhysicsSystem2D& world, Nz::Arbiter2D& arbiter, const EntityHandle& bodyA, const EntityHandle& bodyB, void* userdata)>;
|
||||
using ContactStartCallback = std::function<bool(PhysicsSystem2D& world, Nz::Arbiter2D& arbiter, const EntityHandle& bodyA, const EntityHandle& bodyB, void* userdata)>;
|
||||
|
||||
using DebugDrawCircleCallback = std::function<void(const Nz::Vector2f& origin, const Nz::RadianAnglef& rotation, float radius, Nz::Color outlineColor, Nz::Color fillColor, void* userdata)>;
|
||||
using DebugDrawDotCallback = std::function<void(const Nz::Vector2f& origin, float radius, Nz::Color color, void* userdata)>;
|
||||
using DebugDrawPolygonCallback = std::function<void(const Nz::Vector2f* vertices, std::size_t vertexCount, float radius, Nz::Color outlineColor, Nz::Color fillColor, void* userdata)>;
|
||||
using DebugDrawSegmentCallback = std::function<void(const Nz::Vector2f& first, const Nz::Vector2f& second, Nz::Color color, void* userdata)>;
|
||||
using DebugDrawTickSegmentCallback = std::function<void(const Nz::Vector2f& first, const Nz::Vector2f& second, float thickness, Nz::Color outlineColor, Nz::Color fillColor, void* userdata)>;
|
||||
using DebugDrawGetColorCallback = std::function<Nz::Color(const EntityHandle& body, std::size_t shapeIndex, void* userdata)>;
|
||||
|
||||
public:
|
||||
struct Callback;
|
||||
struct DebugDrawOptions;
|
||||
struct NearestQueryResult;
|
||||
struct RaycastHit;
|
||||
|
||||
PhysicsSystem2D();
|
||||
~PhysicsSystem2D() = default;
|
||||
|
||||
void DebugDraw(const DebugDrawOptions& options, bool drawShapes = true, bool drawConstraints = true, bool drawCollisions = true);
|
||||
|
||||
inline float GetDamping() const;
|
||||
inline Nz::Vector2f GetGravity() const;
|
||||
inline std::size_t GetIterationCount() const;
|
||||
inline std::size_t GetMaxStepCount() const;
|
||||
inline float GetStepSize() const;
|
||||
|
||||
bool NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, EntityHandle* nearestBody = nullptr);
|
||||
bool NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result);
|
||||
|
||||
void RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function<void(const RaycastHit&)>& callback);
|
||||
bool RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<RaycastHit>* hitInfos);
|
||||
bool RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo = nullptr);
|
||||
|
||||
void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function<void(const EntityHandle&)>& callback);
|
||||
void RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<EntityHandle>* bodies);
|
||||
|
||||
void RegisterCallbacks(unsigned int collisionId, Callback callbacks);
|
||||
void RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks);
|
||||
|
||||
inline void SetDamping(float dampingValue);
|
||||
inline void SetGravity(const Nz::Vector2f& gravity);
|
||||
inline void SetIterationCount(std::size_t iterationCount);
|
||||
inline void SetMaxStepCount(std::size_t maxStepCount);
|
||||
inline void SetSleepTime(float sleepTime);
|
||||
inline void SetStepSize(float stepSize);
|
||||
|
||||
inline void UseSpatialHash(float cellSize, std::size_t entityCount);
|
||||
|
||||
struct Callback
|
||||
{
|
||||
ContactEndCallback endCallback = nullptr;
|
||||
ContactPreSolveCallback preSolveCallback = nullptr;
|
||||
ContactPostSolveCallback postSolveCallback = nullptr;
|
||||
ContactStartCallback startCallback = nullptr;
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
struct DebugDrawOptions
|
||||
{
|
||||
Nz::Color constraintColor;
|
||||
Nz::Color collisionPointColor;
|
||||
Nz::Color shapeOutlineColor;
|
||||
|
||||
DebugDrawCircleCallback circleCallback;
|
||||
DebugDrawGetColorCallback colorCallback;
|
||||
DebugDrawDotCallback dotCallback;
|
||||
DebugDrawPolygonCallback polygonCallback;
|
||||
DebugDrawSegmentCallback segmentCallback;
|
||||
DebugDrawTickSegmentCallback thickSegmentCallback;
|
||||
|
||||
void* userdata;
|
||||
};
|
||||
|
||||
struct NearestQueryResult
|
||||
{
|
||||
EntityHandle nearestBody;
|
||||
Nz::Vector2f closestPoint;
|
||||
Nz::Vector2f fraction;
|
||||
float distance;
|
||||
};
|
||||
|
||||
struct RaycastHit
|
||||
{
|
||||
EntityHandle body;
|
||||
Nz::Vector2f hitPos;
|
||||
Nz::Vector2f hitNormal;
|
||||
float fraction;
|
||||
};
|
||||
|
||||
static SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
void CreatePhysWorld() const;
|
||||
const EntityHandle& GetEntityFromBody(const Nz::RigidBody2D& body) const;
|
||||
inline Nz::PhysWorld2D& GetPhysWorld();
|
||||
inline const Nz::PhysWorld2D& GetPhysWorld() const;
|
||||
void OnEntityValidation(Entity* entity, bool justAdded) override;
|
||||
void OnUpdate(float elapsedTime) override;
|
||||
|
||||
EntityList m_dynamicObjects;
|
||||
EntityList m_staticObjects;
|
||||
mutable std::unique_ptr<Nz::PhysWorld2D> m_physWorld; ///TODO: std::optional (Should I make a Nz::Optional class?)
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.inl>
|
||||
|
||||
#endif // NDK_SYSTEMS_PHYSICSSYSTEM2D_HPP
|
||||
|
|
@ -1,94 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
inline float PhysicsSystem2D::GetDamping() const
|
||||
{
|
||||
return GetPhysWorld().GetDamping();
|
||||
}
|
||||
|
||||
inline Nz::Vector2f PhysicsSystem2D::GetGravity() const
|
||||
{
|
||||
return GetPhysWorld().GetGravity();
|
||||
}
|
||||
|
||||
inline std::size_t PhysicsSystem2D::GetIterationCount() const
|
||||
{
|
||||
return GetPhysWorld().GetIterationCount();
|
||||
}
|
||||
|
||||
inline std::size_t PhysicsSystem2D::GetMaxStepCount() const
|
||||
{
|
||||
return GetPhysWorld().GetMaxStepCount();
|
||||
}
|
||||
|
||||
inline float PhysicsSystem2D::GetStepSize() const
|
||||
{
|
||||
return GetPhysWorld().GetStepSize();
|
||||
}
|
||||
|
||||
inline void PhysicsSystem2D::SetDamping(float dampingValue)
|
||||
{
|
||||
GetPhysWorld().SetDamping(dampingValue);
|
||||
}
|
||||
|
||||
inline void PhysicsSystem2D::SetGravity(const Nz::Vector2f& gravity)
|
||||
{
|
||||
GetPhysWorld().SetGravity(gravity);
|
||||
}
|
||||
|
||||
inline void PhysicsSystem2D::SetIterationCount(std::size_t iterationCount)
|
||||
{
|
||||
GetPhysWorld().SetIterationCount(iterationCount);
|
||||
}
|
||||
|
||||
inline void PhysicsSystem2D::SetMaxStepCount(std::size_t maxStepCount)
|
||||
{
|
||||
GetPhysWorld().SetMaxStepCount(maxStepCount);
|
||||
}
|
||||
|
||||
inline void PhysicsSystem2D::SetSleepTime(float sleepTime)
|
||||
{
|
||||
GetPhysWorld().SetSleepTime(sleepTime);
|
||||
}
|
||||
|
||||
inline void PhysicsSystem2D::SetStepSize(float stepSize)
|
||||
{
|
||||
GetPhysWorld().SetStepSize(stepSize);
|
||||
}
|
||||
|
||||
inline void PhysicsSystem2D::UseSpatialHash(float cellSize, std::size_t entityCount)
|
||||
{
|
||||
GetPhysWorld().UseSpatialHash(cellSize, entityCount);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the physical world
|
||||
* \return A reference to the physical world
|
||||
*/
|
||||
|
||||
inline Nz::PhysWorld2D& PhysicsSystem2D::GetPhysWorld()
|
||||
{
|
||||
if (!m_physWorld)
|
||||
CreatePhysWorld();
|
||||
|
||||
return *m_physWorld;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the physical world
|
||||
* \return A constant reference to the physical world
|
||||
*/
|
||||
|
||||
inline const Nz::PhysWorld2D& PhysicsSystem2D::GetPhysWorld() const
|
||||
{
|
||||
if (!m_physWorld)
|
||||
CreatePhysWorld();
|
||||
|
||||
return *m_physWorld;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,41 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_SYSTEMS_PHYSICSSYSTEM3D_HPP
|
||||
#define NDK_SYSTEMS_PHYSICSSYSTEM3D_HPP
|
||||
|
||||
#include <Nazara/Physics3D/PhysWorld3D.hpp>
|
||||
#include <NazaraSDK/EntityList.hpp>
|
||||
#include <NazaraSDK/System.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API PhysicsSystem3D : public System<PhysicsSystem3D>
|
||||
{
|
||||
public:
|
||||
PhysicsSystem3D();
|
||||
~PhysicsSystem3D() = default;
|
||||
|
||||
Nz::PhysWorld3D& GetWorld();
|
||||
const Nz::PhysWorld3D& GetWorld() const;
|
||||
|
||||
static SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
void CreatePhysWorld() const;
|
||||
void OnEntityValidation(Entity* entity, bool justAdded) override;
|
||||
void OnUpdate(float elapsedTime) override;
|
||||
|
||||
EntityList m_dynamicObjects;
|
||||
EntityList m_staticObjects;
|
||||
mutable std::unique_ptr<Nz::PhysWorld3D> m_world; ///TODO: std::optional (Should I make a Nz::Optional class?)
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Systems/PhysicsSystem3D.inl>
|
||||
|
||||
#endif // NDK_SYSTEMS_PHYSICSSYSTEM3D_HPP
|
||||
|
|
@ -1,32 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Gets the physical world
|
||||
* \return A reference to the physical world
|
||||
*/
|
||||
|
||||
inline Nz::PhysWorld3D& PhysicsSystem3D::GetWorld()
|
||||
{
|
||||
if (!m_world)
|
||||
CreatePhysWorld();
|
||||
|
||||
return *m_world;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the physical world
|
||||
* \return A constant reference to the physical world
|
||||
*/
|
||||
|
||||
inline const Nz::PhysWorld3D& PhysicsSystem3D::GetWorld() const
|
||||
{
|
||||
if (!m_world)
|
||||
CreatePhysWorld();
|
||||
|
||||
return *m_world;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,29 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_SYSTEMS_VELOCITYSYSTEM_HPP
|
||||
#define NDK_SYSTEMS_VELOCITYSYSTEM_HPP
|
||||
|
||||
#include <NazaraSDK/System.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class NDK_API VelocitySystem : public System<VelocitySystem>
|
||||
{
|
||||
public:
|
||||
VelocitySystem();
|
||||
~VelocitySystem() = default;
|
||||
|
||||
static SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
void OnUpdate(float elapsedTime) override;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/Systems/VelocitySystem.inl>
|
||||
|
||||
#endif // NDK_SYSTEMS_VELOCITYSYSTEM_HPP
|
||||
|
|
@ -1,3 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
|
@ -1,141 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifndef NDK_WORLD_HPP
|
||||
#define NDK_WORLD_HPP
|
||||
|
||||
#include <Nazara/Core/Bitset.hpp>
|
||||
#include <Nazara/Core/HandledObject.hpp>
|
||||
#include <NazaraSDK/Entity.hpp>
|
||||
#include <NazaraSDK/EntityList.hpp>
|
||||
#include <NazaraSDK/System.hpp>
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
class World;
|
||||
|
||||
using WorldHandle = Nz::ObjectHandle<World>;
|
||||
|
||||
class NDK_API World : public Nz::HandledObject<World>
|
||||
{
|
||||
friend BaseSystem;
|
||||
friend Entity;
|
||||
friend EntityList;
|
||||
|
||||
public:
|
||||
using EntityVector = std::vector<EntityHandle>;
|
||||
struct ProfilerData;
|
||||
|
||||
inline World();
|
||||
World(const World&) = delete;
|
||||
inline World(World&& world) noexcept;
|
||||
~World() noexcept;
|
||||
|
||||
inline BaseSystem& AddSystem(std::unique_ptr<BaseSystem>&& system);
|
||||
template<typename SystemType, typename... Args> SystemType& AddSystem(Args&&... args);
|
||||
|
||||
const EntityHandle& CreateEntity();
|
||||
inline EntityVector CreateEntities(unsigned int count);
|
||||
|
||||
void Clear() noexcept;
|
||||
const EntityHandle& CloneEntity(EntityId id);
|
||||
const EntityHandle& CloneEntity(const EntityHandle& entity);
|
||||
|
||||
inline void DisableProfiler();
|
||||
inline void EnableProfiler(bool enable = true);
|
||||
|
||||
template<typename F> void ForEachSystem(const F& iterationFunc);
|
||||
template<typename F> void ForEachSystem(const F& iterationFunc) const;
|
||||
|
||||
inline const EntityHandle& GetEntity(EntityId id);
|
||||
inline const EntityList& GetEntities() const;
|
||||
inline const ProfilerData& GetProfilerData() const;
|
||||
inline BaseSystem& GetSystem(SystemIndex index);
|
||||
inline const BaseSystem& GetSystem(SystemIndex index) const;
|
||||
template<typename SystemType> SystemType& GetSystem();
|
||||
template<typename SystemType> const SystemType& GetSystem() const;
|
||||
|
||||
inline bool HasSystem(SystemIndex index) const;
|
||||
template<typename SystemType> bool HasSystem() const;
|
||||
|
||||
inline void KillEntity(Entity* entity);
|
||||
inline void KillEntities(const EntityVector& list);
|
||||
|
||||
inline bool IsEntityDying(const Entity* entity) const;
|
||||
inline bool IsEntityDying(EntityId id) const;
|
||||
inline bool IsEntityValid(const Entity* entity) const;
|
||||
inline bool IsEntityIdValid(EntityId id) const;
|
||||
inline bool IsProfilerEnabled() const;
|
||||
|
||||
void Refresh();
|
||||
|
||||
inline void RemoveAllSystems();
|
||||
inline void RemoveSystem(SystemIndex index);
|
||||
template<typename SystemType> void RemoveSystem();
|
||||
inline void ResetProfiler();
|
||||
|
||||
void Update(float elapsedTime);
|
||||
|
||||
World& operator=(const World&) = delete;
|
||||
inline World& operator=(World&& world) noexcept;
|
||||
|
||||
struct ProfilerData
|
||||
{
|
||||
Nz::UInt64 refreshTime = 0;
|
||||
std::vector<Nz::UInt64> updateTime;
|
||||
std::size_t updateCount = 0;
|
||||
};
|
||||
|
||||
private:
|
||||
inline void Invalidate();
|
||||
inline void Invalidate(EntityId id);
|
||||
inline void InvalidateSystemOrder();
|
||||
inline void RegisterEntityList(EntityList* list);
|
||||
void ReorderSystems();
|
||||
inline void UnregisterEntityList(EntityList* list);
|
||||
|
||||
struct DoubleBitset
|
||||
{
|
||||
Nz::Bitset<Nz::UInt64> front;
|
||||
Nz::Bitset<Nz::UInt64> back;
|
||||
};
|
||||
|
||||
struct EntityBlock
|
||||
{
|
||||
EntityBlock(Entity&& e) :
|
||||
entity(std::move(e)),
|
||||
handle(&entity)
|
||||
{
|
||||
}
|
||||
|
||||
EntityBlock(EntityBlock&& block) = default;
|
||||
|
||||
Entity entity;
|
||||
EntityHandle handle;
|
||||
};
|
||||
|
||||
std::vector<std::unique_ptr<BaseSystem>> m_systems;
|
||||
std::vector<BaseSystem*> m_orderedSystems;
|
||||
std::vector<EntityBlock> m_entities;
|
||||
std::vector<EntityBlock*> m_entityBlocks;
|
||||
std::vector<EntityList*> m_referencedByLists;
|
||||
std::vector<std::unique_ptr<EntityBlock>> m_waitingEntities;
|
||||
EntityList m_aliveEntities;
|
||||
ProfilerData m_profilerData;
|
||||
DoubleBitset m_dirtyEntities;
|
||||
Nz::Bitset<Nz::UInt64> m_freeEntityIds;
|
||||
DoubleBitset m_killedEntities;
|
||||
bool m_orderedSystemsUpdated;
|
||||
bool m_isProfilerEnabled;
|
||||
};
|
||||
}
|
||||
|
||||
#include <NazaraSDK/World.inl>
|
||||
|
||||
#endif // NDK_WORLD_HPP
|
||||
|
|
@ -1,500 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <type_traits>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Constructs a World object
|
||||
*/
|
||||
|
||||
inline World::World() :
|
||||
m_orderedSystemsUpdated(false),
|
||||
m_isProfilerEnabled(false)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a World object by move semantic
|
||||
*
|
||||
* \param world World to move into this
|
||||
*/
|
||||
|
||||
inline World::World(World&& world) noexcept :
|
||||
HandledObject(std::move(world))
|
||||
{
|
||||
operator=(std::move(world));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a system to the world
|
||||
* \return A reference to the newly created system
|
||||
*
|
||||
* \param system System to add to the world
|
||||
*/
|
||||
|
||||
inline BaseSystem& World::AddSystem(std::unique_ptr<BaseSystem>&& system)
|
||||
{
|
||||
NazaraAssert(system, "System must be valid");
|
||||
|
||||
SystemIndex index = system->GetIndex();
|
||||
|
||||
// We must ensure that the vector is big enough to hold the new system
|
||||
if (index >= m_systems.size())
|
||||
{
|
||||
m_systems.resize(index + 1);
|
||||
m_profilerData.updateTime.resize(index + 1, 0);
|
||||
}
|
||||
|
||||
// Affectation and return of system
|
||||
m_systems[index] = std::move(system);
|
||||
m_systems[index]->SetWorld(this);
|
||||
|
||||
Invalidate(); // We force an update for every entities
|
||||
InvalidateSystemOrder(); // And regenerate the system update list
|
||||
|
||||
return *m_systems[index].get();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a system to the world
|
||||
* \return A reference to the newly created system
|
||||
*
|
||||
* \param args Arguments used to create the system
|
||||
*/
|
||||
|
||||
template<typename SystemType, typename... Args>
|
||||
SystemType& World::AddSystem(Args&&... args)
|
||||
{
|
||||
static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a component");
|
||||
|
||||
// Allocation and affectation of the system
|
||||
std::unique_ptr<SystemType> ptr(new SystemType(std::forward<Args>(args)...));
|
||||
return static_cast<SystemType&>(AddSystem(std::move(ptr)));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates multiple entities in the world
|
||||
* \return The set of entities created
|
||||
*
|
||||
* \param count Number of entities to create
|
||||
*/
|
||||
inline World::EntityVector World::CreateEntities(unsigned int count)
|
||||
{
|
||||
EntityVector list;
|
||||
list.reserve(count);
|
||||
|
||||
for (unsigned int i = 0; i < count; ++i)
|
||||
list.emplace_back(CreateEntity());
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Disables the profiler, clearing up results
|
||||
*
|
||||
* This is just a shortcut to EnableProfiler(false)
|
||||
*
|
||||
* \param enable Should the entity be enabled
|
||||
*
|
||||
* \see EnableProfiler
|
||||
*/
|
||||
inline void World::DisableProfiler()
|
||||
{
|
||||
EnableProfiler(false);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables/Disables the internal profiler
|
||||
*
|
||||
* Worlds come with a built-in profiler, allowing to measure update count along with time passed in refresh and system updates.
|
||||
* This is disabled by default as it adds an small overhead to the update process.
|
||||
*
|
||||
* \param enable Should the profiler be enabled
|
||||
*
|
||||
* \remark Disabling the profiler clears up results, as if ResetProfiler has been called
|
||||
*/
|
||||
inline void World::EnableProfiler(bool enable)
|
||||
{
|
||||
if (m_isProfilerEnabled != enable)
|
||||
{
|
||||
m_isProfilerEnabled = enable;
|
||||
|
||||
if (enable)
|
||||
ResetProfiler();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Executes a function on every present system
|
||||
*
|
||||
* Calls iterationFunc on every previously added system, in the same order as their indexes
|
||||
*
|
||||
* \param iterationFunc Function to be called
|
||||
*/
|
||||
template<typename F>
|
||||
void World::ForEachSystem(const F& iterationFunc)
|
||||
{
|
||||
for (const auto& systemPtr : m_systems)
|
||||
{
|
||||
if (systemPtr)
|
||||
iterationFunc(*systemPtr);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Executes a function on every present system
|
||||
*
|
||||
* Calls iterationFunc on every previously added system, in the same order as their indexes
|
||||
*
|
||||
* \param iterationFunc Function to be called
|
||||
*/
|
||||
template<typename F>
|
||||
void World::ForEachSystem(const F& iterationFunc) const
|
||||
{
|
||||
for (const auto& systemPtr : m_systems)
|
||||
{
|
||||
if (systemPtr)
|
||||
iterationFunc(static_cast<const Ndk::BaseSystem&>(*systemPtr)); //< Force const reference
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets an entity
|
||||
* \return A constant reference to a handle of the entity
|
||||
*
|
||||
* \param id Identifier of the entity
|
||||
*
|
||||
* \remark Handle referenced by this function can move in memory when updating the world, do not keep a handle reference from a world update to another
|
||||
* \remark If an invalid identifier is provided, an error got triggered and an invalid handle is returned
|
||||
*/
|
||||
inline const EntityHandle& World::GetEntity(EntityId id)
|
||||
{
|
||||
if (IsEntityIdValid(id))
|
||||
return m_entityBlocks[id]->handle;
|
||||
else
|
||||
{
|
||||
NazaraError("Invalid ID");
|
||||
return EntityHandle::InvalidHandle;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets every entities in the world
|
||||
* \return A constant reference to the entities
|
||||
*/
|
||||
inline const EntityList& World::GetEntities() const
|
||||
{
|
||||
return m_aliveEntities;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the latest profiler data
|
||||
* \return A constant reference to the profiler data
|
||||
*/
|
||||
inline const World::ProfilerData& World::GetProfilerData() const
|
||||
{
|
||||
return m_profilerData;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a system in the world by index
|
||||
* \return A reference to the system
|
||||
*
|
||||
* \param index Index of the system
|
||||
*
|
||||
* \remark The world must have the system before calling this function
|
||||
*/
|
||||
inline BaseSystem& World::GetSystem(SystemIndex index)
|
||||
{
|
||||
NazaraAssert(HasSystem(index), "This system is not part of the world");
|
||||
|
||||
BaseSystem* system = m_systems[index].get();
|
||||
NazaraAssert(system, "Invalid system pointer");
|
||||
|
||||
return *system;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a system in the world by index
|
||||
* \return A const reference to the system
|
||||
*
|
||||
* \param index Index of the system
|
||||
*
|
||||
* \remark The world must have the system before calling this function
|
||||
*/
|
||||
inline const BaseSystem& World::GetSystem(SystemIndex index) const
|
||||
{
|
||||
NazaraAssert(HasSystem(index), "This system is not part of the world");
|
||||
|
||||
const BaseSystem* system = m_systems[index].get();
|
||||
NazaraAssert(system, "Invalid system pointer");
|
||||
|
||||
return *system;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a system in the world by type
|
||||
* \return A reference to the system
|
||||
*
|
||||
* \remark Produces a NazaraAssert if system is not available in this world
|
||||
*/
|
||||
template<typename SystemType>
|
||||
SystemType& World::GetSystem()
|
||||
{
|
||||
static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a system");
|
||||
|
||||
SystemIndex index = GetSystemIndex<SystemType>();
|
||||
return static_cast<SystemType&>(GetSystem(index));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets a system in the world by type
|
||||
* \return A const reference to the system
|
||||
*
|
||||
* \remark Produces a NazaraAssert if system is not available in this world
|
||||
*/
|
||||
template<typename SystemType>
|
||||
const SystemType& World::GetSystem() const
|
||||
{
|
||||
static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a system");
|
||||
|
||||
SystemIndex index = GetSystemIndex<SystemType>();
|
||||
return static_cast<const SystemType&>(GetSystem(index));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not a system is present in the world by index
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param index Index of the system
|
||||
*/
|
||||
|
||||
inline bool World::HasSystem(SystemIndex index) const
|
||||
{
|
||||
return index < m_systems.size() && m_systems[index];
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not a system is present in the world by type
|
||||
* \return true If it is the case
|
||||
*/
|
||||
|
||||
template<typename SystemType>
|
||||
bool World::HasSystem() const
|
||||
{
|
||||
static_assert(std::is_base_of<BaseSystem, SystemType>::value, "SystemType is not a component");
|
||||
|
||||
SystemIndex index = GetSystemIndex<SystemType>();
|
||||
return HasSystem(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Marks an entity for deletion
|
||||
*
|
||||
* \param Pointer to the entity
|
||||
*
|
||||
* \remark If the entity pointer is invalid, nothing is done
|
||||
* \remark For safety, entities are not killed until the next world update
|
||||
*/
|
||||
inline void World::KillEntity(Entity* entity)
|
||||
{
|
||||
if (IsEntityValid(entity))
|
||||
m_killedEntities.front.UnboundedSet(entity->GetId(), true);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Kills a set of entities
|
||||
*
|
||||
* This function has the same effect as calling KillEntity for every entity contained in the vector
|
||||
*
|
||||
* \param list Set of entities to kill
|
||||
*/
|
||||
inline void World::KillEntities(const EntityVector& list)
|
||||
{
|
||||
for (const EntityHandle& entity : list)
|
||||
KillEntity(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not an entity is dying (has been killed this update)
|
||||
* \return true If the entity exists and is dying
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
*/
|
||||
inline bool World::IsEntityDying(const Entity* entity) const
|
||||
{
|
||||
return entity && IsEntityDying(entity->GetId());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not an entity is dying (has been killed this update)
|
||||
* \return true If it is the case, false if the entity is alive (and hasn't been killed yet) or if the entity id is invalid
|
||||
*
|
||||
* \param id Identifier of the entity
|
||||
*/
|
||||
inline bool World::IsEntityDying(EntityId id) const
|
||||
{
|
||||
return m_killedEntities.front.UnboundedTest(id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not an entity is valid
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
*/
|
||||
inline bool World::IsEntityValid(const Entity* entity) const
|
||||
{
|
||||
return entity && entity->GetWorld() == this && IsEntityIdValid(entity->GetId());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not an entity is valid
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param id Identifier of the entity
|
||||
*/
|
||||
inline bool World::IsEntityIdValid(EntityId id) const
|
||||
{
|
||||
return id < m_entityBlocks.size() && m_entityBlocks[id]->entity.IsValid();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether or not the profiler is enabled
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \see EnableProfiler
|
||||
*/
|
||||
inline bool World::IsProfilerEnabled() const
|
||||
{
|
||||
return m_isProfilerEnabled;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes each system from the world
|
||||
*/
|
||||
|
||||
inline void World::RemoveAllSystems()
|
||||
{
|
||||
m_systems.clear();
|
||||
|
||||
InvalidateSystemOrder();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes a system from the world by index
|
||||
*
|
||||
* \param index Index of the system
|
||||
*
|
||||
* \remark No change is done if system is not present
|
||||
*/
|
||||
|
||||
inline void World::RemoveSystem(SystemIndex index)
|
||||
{
|
||||
if (HasSystem(index))
|
||||
{
|
||||
m_systems[index].reset();
|
||||
|
||||
InvalidateSystemOrder();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clear profiler results
|
||||
*
|
||||
* This reset the profiler results, filling all counters with zero
|
||||
*/
|
||||
inline void World::ResetProfiler()
|
||||
{
|
||||
m_profilerData.refreshTime = 0;
|
||||
m_profilerData.updateCount = 0;
|
||||
std::fill(m_profilerData.updateTime.begin(), m_profilerData.updateTime.end(), 0);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Removes a system from the world by type
|
||||
*/
|
||||
template<typename SystemType>
|
||||
void World::RemoveSystem()
|
||||
{
|
||||
static_assert(std::is_base_of<BaseSystem, SystemType>(), "SystemType is not a system");
|
||||
|
||||
SystemIndex index = GetSystemIndex<SystemType>();
|
||||
RemoveSystem(index);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Moves a world into another world object
|
||||
* \return A reference to the object
|
||||
*/
|
||||
|
||||
inline World& World::operator=(World&& world) noexcept
|
||||
{
|
||||
m_aliveEntities = std::move(world.m_aliveEntities);
|
||||
m_dirtyEntities = std::move(world.m_dirtyEntities);
|
||||
m_entityBlocks = std::move(world.m_entityBlocks);
|
||||
m_freeEntityIds = std::move(world.m_freeEntityIds);
|
||||
m_isProfilerEnabled = world.m_isProfilerEnabled;
|
||||
m_killedEntities = std::move(world.m_killedEntities);
|
||||
m_orderedSystems = std::move(world.m_orderedSystems);
|
||||
m_orderedSystemsUpdated = world.m_orderedSystemsUpdated;
|
||||
m_profilerData = std::move(world.m_profilerData);
|
||||
m_referencedByLists = std::move(world.m_referencedByLists);
|
||||
|
||||
m_entities = std::move(world.m_entities);
|
||||
for (EntityBlock& block : m_entities)
|
||||
block.entity.SetWorld(this);
|
||||
|
||||
for (EntityList* list : m_referencedByLists)
|
||||
list->SetWorld(this);
|
||||
|
||||
m_waitingEntities = std::move(world.m_waitingEntities);
|
||||
for (auto& blockPtr : m_waitingEntities)
|
||||
blockPtr->entity.SetWorld(this);
|
||||
|
||||
m_systems = std::move(world.m_systems);
|
||||
for (const auto& systemPtr : m_systems)
|
||||
{
|
||||
if (systemPtr)
|
||||
systemPtr->SetWorld(this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
inline void World::Invalidate()
|
||||
{
|
||||
m_dirtyEntities.front.Resize(m_entityBlocks.size(), false);
|
||||
m_dirtyEntities.front.Set(true); // Activation of all bits
|
||||
}
|
||||
|
||||
inline void World::Invalidate(EntityId id)
|
||||
{
|
||||
m_dirtyEntities.front.UnboundedSet(id, true);
|
||||
}
|
||||
|
||||
inline void World::InvalidateSystemOrder()
|
||||
{
|
||||
m_orderedSystemsUpdated = false;
|
||||
}
|
||||
|
||||
inline void World::RegisterEntityList(EntityList* list)
|
||||
{
|
||||
m_referencedByLists.push_back(list);
|
||||
}
|
||||
|
||||
inline void World::UnregisterEntityList(EntityList* list)
|
||||
{
|
||||
auto it = std::find(m_referencedByLists.begin(), m_referencedByLists.end(), list);
|
||||
assert(it != m_referencedByLists.end());
|
||||
|
||||
// Swap and pop idiom
|
||||
*it = m_referencedByLists.back();
|
||||
m_referencedByLists.pop_back();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Application.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/StringExt.hpp>
|
||||
#include <regex>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::Application
|
||||
* \brief NDK class that represents the application, it offers a set of tools to ease the development
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an Application object with command-line arguments
|
||||
*
|
||||
* Pass the argc and argv arguments from the main function.
|
||||
*
|
||||
* Command-line arguments can be retrieved by application methods
|
||||
*
|
||||
* This calls Sdk::Initialize()
|
||||
*
|
||||
* \remark Only one Application instance can exist at a time
|
||||
*/
|
||||
Application::Application(int argc, char* argv[]) :
|
||||
Application()
|
||||
{
|
||||
ParseCommandline(argc, argv);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Runs the application by updating worlds, taking care about windows, ...
|
||||
*/
|
||||
bool Application::Run()
|
||||
{
|
||||
if (m_shouldQuit)
|
||||
return false;
|
||||
|
||||
m_updateTime = m_updateClock.Restart() / 1'000'000.f;
|
||||
|
||||
for (World& world : m_worlds)
|
||||
world.Update(m_updateTime);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void Application::ClearWorlds()
|
||||
{
|
||||
m_worlds.clear();
|
||||
}
|
||||
|
||||
void Application::ParseCommandline(int argc, char* argv[])
|
||||
{
|
||||
std::regex optionRegex(R"(-(\w+))");
|
||||
std::regex valueRegex(R"(-(\w+)\s*=\s*(.+))");
|
||||
|
||||
std::smatch results;
|
||||
|
||||
for (int i = 1; i < argc; ++i)
|
||||
{
|
||||
std::string argument(argv[i]);
|
||||
if (std::regex_match(argument, results, valueRegex))
|
||||
{
|
||||
std::string key = Nz::ToLower(results[1].str());
|
||||
std::string value(results[2].str());
|
||||
|
||||
m_parameters[key] = value;
|
||||
NazaraDebug("Registred parameter from command-line: " + key + "=" + value);
|
||||
}
|
||||
else if (std::regex_match(argument, results, optionRegex))
|
||||
{
|
||||
std::string option(results[1].str());
|
||||
|
||||
m_options.insert(option);
|
||||
NazaraDebug("Registred option from command-line: " + option);
|
||||
}
|
||||
else
|
||||
NazaraWarning("Ignored command-line argument #" + Nz::NumberToString(i) + " \"" + argument + '"');
|
||||
}
|
||||
}
|
||||
|
||||
Application* Application::s_application = nullptr;
|
||||
}
|
||||
|
|
@ -1,88 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/BaseComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::BaseComponent
|
||||
* \brief NDK class that represents the common base of all components
|
||||
*
|
||||
* \remark This class is meant to be purely abstract, for type erasure
|
||||
*/
|
||||
|
||||
BaseComponent::~BaseComponent() = default;
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to an entity
|
||||
*/
|
||||
|
||||
void BaseComponent::OnAttached()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to this component
|
||||
*
|
||||
* \param component Component being attached
|
||||
*/
|
||||
|
||||
void BaseComponent::OnComponentAttached(BaseComponent& component)
|
||||
{
|
||||
NazaraUnused(component);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from this component
|
||||
*
|
||||
* \param component Component being detached
|
||||
*/
|
||||
|
||||
void BaseComponent::OnComponentDetached(BaseComponent& component)
|
||||
{
|
||||
NazaraUnused(component);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from an entity
|
||||
*/
|
||||
|
||||
void BaseComponent::OnDetached()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when the entity is destroyed and we're still attached to it
|
||||
*
|
||||
* \remark This is always called before the entity proper destruction, and thus its components.
|
||||
*/
|
||||
void BaseComponent::OnEntityDestruction()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when the entity is disabled
|
||||
*
|
||||
* \remark Disabling an entity will remove it from systems it belongs to, but sometimes the entity will need to do
|
||||
* additional work in order to be properly disabled (i.e.: disabling physics simulation & collisions)
|
||||
*/
|
||||
void BaseComponent::OnEntityDisabled()
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when the entity is disabled
|
||||
*
|
||||
* \remark Enabling an entity will add it back to systems it belongs to, but sometimes the entity will need to do
|
||||
* additional work in order to be properly re-enabled (i.e.: enabling physics simulation & collisions)
|
||||
*/
|
||||
void BaseComponent::OnEntityEnabled()
|
||||
{
|
||||
}
|
||||
|
||||
std::vector<BaseComponent::ComponentEntry> BaseComponent::s_entries;
|
||||
std::unordered_map<ComponentId, ComponentIndex> BaseComponent::s_idToIndex;
|
||||
}
|
||||
|
|
@ -1,116 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/BaseSystem.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::BaseSystem
|
||||
* \brief NDK class that represents the common base of all systems
|
||||
*
|
||||
* \remark This class is meant to be purely abstract, for type erasure
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and unregisters it-self on every entities
|
||||
*/
|
||||
|
||||
BaseSystem::~BaseSystem()
|
||||
{
|
||||
for (const EntityHandle& entity : m_entities)
|
||||
entity->UnregisterSystem(m_systemIndex);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Checks whether the key of the entity matches the lock of the system
|
||||
* \return true If it is the case
|
||||
*
|
||||
* \param Pointer to the entity
|
||||
*/
|
||||
|
||||
bool BaseSystem::Filters(const Entity* entity) const
|
||||
{
|
||||
if (!entity)
|
||||
return false;
|
||||
|
||||
const Nz::Bitset<>& components = entity->GetComponentBits();
|
||||
|
||||
m_filterResult.PerformsAND(m_requiredComponents, components);
|
||||
if (m_filterResult != m_requiredComponents)
|
||||
return false; // At least one required component is not available
|
||||
|
||||
m_filterResult.PerformsAND(m_excludedComponents, components);
|
||||
if (m_filterResult.TestAny())
|
||||
return false; // At least one excluded component is available
|
||||
|
||||
// If we have a list of needed components
|
||||
if (m_requiredAnyComponents.TestAny())
|
||||
{
|
||||
if (!m_requiredAnyComponents.Intersects(components))
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the update order of this system
|
||||
*
|
||||
* The system update order is used by the world it belongs to in order to know in which order they should be updated, as some application logic may rely a specific update order.
|
||||
* A system with a greater update order (ex: 1) is guaranteed to be updated after a system with a lesser update order (ex: -1), otherwise the order is unspecified (and is not guaranteed to be stable).
|
||||
*
|
||||
* \param updateOrder The relative update order of the system
|
||||
*
|
||||
* \remark The update order is only used by World::Update(float) and does not have any effect regarding a call to BaseSystem::Update(float)
|
||||
*
|
||||
* \see GetUpdateOrder
|
||||
*/
|
||||
void BaseSystem::SetUpdateOrder(int updateOrder)
|
||||
{
|
||||
m_updateOrder = updateOrder;
|
||||
|
||||
if (m_world)
|
||||
m_world->InvalidateSystemOrder();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when entity is added to the system
|
||||
*
|
||||
* \param Pointer to the entity
|
||||
*/
|
||||
|
||||
void BaseSystem::OnEntityAdded(Entity* entity)
|
||||
{
|
||||
NazaraUnused(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when entity is removed to the system
|
||||
*
|
||||
* \param Pointer to the entity
|
||||
*/
|
||||
|
||||
void BaseSystem::OnEntityRemoved(Entity* entity)
|
||||
{
|
||||
NazaraUnused(entity);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when entity is validated for the system
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
* \param justAdded Is the entity newly added
|
||||
*/
|
||||
|
||||
void BaseSystem::OnEntityValidation(Entity* entity, bool justAdded)
|
||||
{
|
||||
NazaraUnused(entity);
|
||||
NazaraUnused(justAdded);
|
||||
}
|
||||
|
||||
SystemIndex BaseSystem::s_nextIndex;
|
||||
}
|
||||
|
|
@ -1,69 +0,0 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/ClientApplication.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <regex>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::ClientApplication
|
||||
* \brief NDK class that represents a client-side application, it offers a set of tools to ease the development
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an ClientApplication object with command-line arguments
|
||||
*
|
||||
* Pass the argc and argv arguments from the main function.
|
||||
*
|
||||
* Command-line arguments can be retrieved by application methods
|
||||
*
|
||||
* This calls Sdk::Initialize()
|
||||
*
|
||||
* \remark Only one Application instance can exist at a time
|
||||
*/
|
||||
ClientApplication::ClientApplication(int argc, char* argv[]) :
|
||||
ClientApplication()
|
||||
{
|
||||
ParseCommandline(argc, argv);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Runs the application by updating worlds, taking care about windows, ...
|
||||
*/
|
||||
bool ClientApplication::Run()
|
||||
{
|
||||
if (!Application::Run())
|
||||
return false;
|
||||
|
||||
bool hasAtLeastOneActiveWindow = false;
|
||||
|
||||
auto it = m_windows.begin();
|
||||
while (it != m_windows.end())
|
||||
{
|
||||
Nz::Window& window = *it->window;
|
||||
|
||||
window.ProcessEvents();
|
||||
|
||||
if (!window.IsOpen(true))
|
||||
{
|
||||
it = m_windows.erase(it);
|
||||
continue;
|
||||
}
|
||||
|
||||
hasAtLeastOneActiveWindow = true;
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
if (m_exitOnClosedWindows && !hasAtLeastOneActiveWindow)
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
ClientApplication* ClientApplication::s_clientApplication = nullptr;
|
||||
}
|
||||
|
|
@ -1,56 +0,0 @@
|
|||
// Copyright (C) 2017 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/ClientSdk.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Physics2D/Physics2D.hpp>
|
||||
#include <Nazara/Physics3D/Physics3D.hpp>
|
||||
#include <Nazara/Platform/Platform.hpp>
|
||||
#include <Nazara/Utility/Utility.hpp>
|
||||
#include <NazaraSDK/Algorithm.hpp>
|
||||
#include <NazaraSDK/BaseSystem.hpp>
|
||||
#include <NazaraSDK/Sdk.hpp>
|
||||
#include <NazaraSDK/Components/ListenerComponent.hpp>
|
||||
#include <NazaraSDK/Systems/ListenerSystem.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::Sdk
|
||||
* \brief NDK class that represents the software development kit, a set of tools made to ease the conception of application
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Initializes the Sdk module
|
||||
* \return true if initialization is successful
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
*/
|
||||
ClientSdk::ClientSdk(Config /*config*/) :
|
||||
ModuleBase("ClientSDK", this)
|
||||
{
|
||||
Nz::ErrorFlags errFlags(Nz::ErrorMode::ThrowException, true);
|
||||
|
||||
// Client components
|
||||
InitializeComponent<ListenerComponent>("NdkList");
|
||||
|
||||
// Systems
|
||||
|
||||
// Client systems
|
||||
InitializeSystem<ListenerSystem>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Uninitializes the Sdk module
|
||||
*
|
||||
* \remark Produces a NazaraNotice
|
||||
*/
|
||||
ClientSdk::~ClientSdk() = default;
|
||||
|
||||
ClientSdk* ClientSdk::s_instance = nullptr;
|
||||
}
|
||||
|
|
@ -1,172 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/CollisionComponent2D.hpp>
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::CollisionComponent2D
|
||||
* \brief NDK class that represents a two-dimensional collision geometry
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Gets the collision box representing the entity
|
||||
* \return The physics collision box
|
||||
*/
|
||||
Nz::Rectf CollisionComponent2D::GetAABB() const
|
||||
{
|
||||
return GetRigidBody()->GetAABB();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Gets the position offset between the actual rigid body center of mass position and the origin of the geometry
|
||||
* \return Position offset
|
||||
*/
|
||||
const Nz::Vector2f& CollisionComponent2D::GetGeomOffset() const
|
||||
{
|
||||
return GetRigidBody()->GetPositionOffset();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Convenience function to align center of geometry to a specific point
|
||||
*
|
||||
* \param geomOffset Position offset
|
||||
*
|
||||
* \remark This does not change the center of mass
|
||||
*/
|
||||
void CollisionComponent2D::Recenter(const Nz::Vector2f& origin)
|
||||
{
|
||||
const Nz::RigidBody2D* rigidBody = GetRigidBody();
|
||||
SetGeomOffset(origin - rigidBody->GetAABB().GetCenter() + rigidBody->GetPositionOffset());
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets geometry for the entity
|
||||
*
|
||||
* \param geom Geometry used for collisions
|
||||
*/
|
||||
void CollisionComponent2D::SetGeom(std::shared_ptr<Nz::Collider2D> geom, bool recomputeMoment, bool recomputeMassCenter)
|
||||
{
|
||||
m_geom = std::move(geom);
|
||||
|
||||
GetRigidBody()->SetGeom(m_geom, recomputeMoment, recomputeMassCenter);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Sets the position offset between the actual rigid body center of mass position and the origin of the geometry
|
||||
*
|
||||
* \param geomOffset Position offset
|
||||
*/
|
||||
void CollisionComponent2D::SetGeomOffset(const Nz::Vector2f& geomOffset)
|
||||
{
|
||||
GetRigidBody()->SetPositionOffset(geomOffset);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the static body
|
||||
*
|
||||
* \remark Produces a NazaraAssert if entity is invalid
|
||||
* \remark Produces a NazaraAssert if entity is not linked to a world, or the world has no physics system
|
||||
*/
|
||||
void CollisionComponent2D::InitializeStaticBody()
|
||||
{
|
||||
NazaraAssert(m_entity, "Invalid entity");
|
||||
World* entityWorld = m_entity->GetWorld();
|
||||
|
||||
NazaraAssert(entityWorld, "Entity must have world");
|
||||
NazaraAssert(entityWorld->HasSystem<PhysicsSystem2D>(), "World must have a physics system");
|
||||
Nz::PhysWorld2D& physWorld = entityWorld->GetSystem<PhysicsSystem2D>().GetPhysWorld();
|
||||
|
||||
m_staticBody = std::make_unique<Nz::RigidBody2D>(&physWorld, 0.f, m_geom);
|
||||
m_staticBody->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
|
||||
|
||||
Nz::Matrix4f matrix;
|
||||
if (m_entity->HasComponent<NodeComponent>())
|
||||
matrix = m_entity->GetComponent<NodeComponent>().GetTransformMatrix();
|
||||
else
|
||||
matrix.MakeIdentity();
|
||||
|
||||
m_staticBody->SetPosition(Nz::Vector2f(matrix.GetTranslation()));
|
||||
}
|
||||
|
||||
Nz::RigidBody2D* CollisionComponent2D::GetRigidBody()
|
||||
{
|
||||
if (m_entity->HasComponent<PhysicsComponent2D>())
|
||||
{
|
||||
PhysicsComponent2D& physComponent = m_entity->GetComponent<PhysicsComponent2D>();
|
||||
return physComponent.GetRigidBody();
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraAssert(m_staticBody, "An entity without physics component should have a static body");
|
||||
return m_staticBody.get();
|
||||
}
|
||||
}
|
||||
|
||||
const Nz::RigidBody2D* CollisionComponent2D::GetRigidBody() const
|
||||
{
|
||||
if (m_entity->HasComponent<PhysicsComponent2D>())
|
||||
{
|
||||
PhysicsComponent2D& physComponent = m_entity->GetComponent<PhysicsComponent2D>();
|
||||
return physComponent.GetRigidBody();
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraAssert(m_staticBody, "An entity without physics component should have a static body");
|
||||
return m_staticBody.get();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to an entity
|
||||
*/
|
||||
|
||||
void CollisionComponent2D::OnAttached()
|
||||
{
|
||||
if (!m_entity->HasComponent<PhysicsComponent2D>())
|
||||
InitializeStaticBody();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to this component
|
||||
*
|
||||
* \param component Component being attached
|
||||
*/
|
||||
|
||||
void CollisionComponent2D::OnComponentAttached(BaseComponent& component)
|
||||
{
|
||||
if (IsComponent<PhysicsComponent2D>(component))
|
||||
m_staticBody.reset();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from this component
|
||||
*
|
||||
* \param component Component being detached
|
||||
*/
|
||||
|
||||
void CollisionComponent2D::OnComponentDetached(BaseComponent& component)
|
||||
{
|
||||
if (IsComponent<PhysicsComponent2D>(component))
|
||||
InitializeStaticBody();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from an entity
|
||||
*/
|
||||
|
||||
void CollisionComponent2D::OnDetached()
|
||||
{
|
||||
m_staticBody.reset();
|
||||
}
|
||||
|
||||
ComponentIndex CollisionComponent2D::componentIndex;
|
||||
}
|
||||
|
|
@ -1,121 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/CollisionComponent3D.hpp>
|
||||
#include <Nazara/Physics3D/RigidBody3D.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem3D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::CollisionComponent3D
|
||||
* \brief NDK class that represents the component for collision (meant for static objects)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Sets geometry for the entity
|
||||
*
|
||||
* \param geom Geometry used for collisions
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the entity has no physics component and has no static body
|
||||
*/
|
||||
|
||||
void CollisionComponent3D::SetGeom(std::shared_ptr<Nz::Collider3D> geom)
|
||||
{
|
||||
m_geom = std::move(geom);
|
||||
|
||||
if (m_entity->HasComponent<PhysicsComponent3D>())
|
||||
{
|
||||
// We update the geometry of the PhysiscsObject linked to the PhysicsComponent3D
|
||||
PhysicsComponent3D& physComponent = m_entity->GetComponent<PhysicsComponent3D>();
|
||||
physComponent.GetRigidBody()->SetGeom(m_geom);
|
||||
}
|
||||
else
|
||||
{
|
||||
NazaraAssert(m_staticBody, "An entity without physics component should have a static body");
|
||||
m_staticBody->SetGeom(m_geom);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Initializes the static body
|
||||
*
|
||||
* \remark Produces a NazaraAssert if entity is invalid
|
||||
* \remark Produces a NazaraAssert if entity is not linked to a world, or the world has no physics system
|
||||
*/
|
||||
|
||||
void CollisionComponent3D::InitializeStaticBody()
|
||||
{
|
||||
NazaraAssert(m_entity, "Invalid entity");
|
||||
World* entityWorld = m_entity->GetWorld();
|
||||
|
||||
NazaraAssert(entityWorld, "Entity must have world");
|
||||
NazaraAssert(entityWorld->HasSystem<PhysicsSystem3D>(), "World must have a physics system");
|
||||
Nz::PhysWorld3D& physWorld = entityWorld->GetSystem<PhysicsSystem3D>().GetWorld();
|
||||
|
||||
m_staticBody = std::make_unique<Nz::RigidBody3D>(&physWorld, m_geom);
|
||||
m_staticBody->EnableAutoSleep(false);
|
||||
m_staticBody->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to an entity
|
||||
*/
|
||||
|
||||
void CollisionComponent3D::OnAttached()
|
||||
{
|
||||
if (!m_entity->HasComponent<PhysicsComponent3D>())
|
||||
InitializeStaticBody();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to this component
|
||||
*
|
||||
* \param component Component being attached
|
||||
*/
|
||||
|
||||
void CollisionComponent3D::OnComponentAttached(BaseComponent& component)
|
||||
{
|
||||
if (IsComponent<PhysicsComponent3D>(component))
|
||||
m_staticBody.reset();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from this component
|
||||
*
|
||||
* \param component Component being detached
|
||||
*/
|
||||
|
||||
void CollisionComponent3D::OnComponentDetached(BaseComponent& component)
|
||||
{
|
||||
if (IsComponent<PhysicsComponent3D>(component))
|
||||
InitializeStaticBody();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from an entity
|
||||
*/
|
||||
|
||||
void CollisionComponent3D::OnDetached()
|
||||
{
|
||||
m_staticBody.reset();
|
||||
}
|
||||
|
||||
void CollisionComponent3D::OnEntityDisabled()
|
||||
{
|
||||
if (m_staticBody)
|
||||
m_staticBody->EnableSimulation(false);
|
||||
}
|
||||
|
||||
void CollisionComponent3D::OnEntityEnabled()
|
||||
{
|
||||
if (m_staticBody)
|
||||
m_staticBody->EnableSimulation(true);
|
||||
}
|
||||
|
||||
ComponentIndex CollisionComponent3D::componentIndex;
|
||||
}
|
||||
|
|
@ -1,23 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/ConstraintComponent2D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
ConstraintComponent2D::ConstraintComponent2D(const ConstraintComponent2D& /*joint*/)
|
||||
{
|
||||
}
|
||||
|
||||
bool ConstraintComponent2D::RemoveConstraint(Nz::Constraint2D* constraintPtr)
|
||||
{
|
||||
auto it = std::find_if(m_constraints.begin(), m_constraints.end(), [constraintPtr](const ConstraintData& constraintData) { return constraintData.constraint.get() == constraintPtr; });
|
||||
if (it != m_constraints.end())
|
||||
m_constraints.erase(it);
|
||||
|
||||
return !m_constraints.empty();
|
||||
}
|
||||
|
||||
ComponentIndex ConstraintComponent2D::componentIndex;
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/LifetimeComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
ComponentIndex LifetimeComponent::componentIndex;
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/ListenerComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
ComponentIndex ListenerComponent::componentIndex;
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
ComponentIndex NodeComponent::componentIndex;
|
||||
}
|
||||
|
|
@ -1,135 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <memory>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::PhysicsComponent2D
|
||||
* \brief NDK class that represents a physics point, without any collision
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to an entity
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the world does not have a physics system
|
||||
*/
|
||||
|
||||
void PhysicsComponent2D::OnAttached()
|
||||
{
|
||||
World* entityWorld = m_entity->GetWorld();
|
||||
NazaraAssert(entityWorld->HasSystem<PhysicsSystem2D>(), "World must have a 2D physics system");
|
||||
|
||||
Nz::PhysWorld2D& world = entityWorld->GetSystem<PhysicsSystem2D>().GetPhysWorld();
|
||||
|
||||
Nz::Vector2f positionOffset;
|
||||
|
||||
std::shared_ptr<Nz::Collider2D> geom;
|
||||
if (m_entity->HasComponent<CollisionComponent2D>())
|
||||
{
|
||||
const CollisionComponent2D& entityCollision = m_entity->GetComponent<CollisionComponent2D>();
|
||||
geom = entityCollision.GetGeom();
|
||||
positionOffset = entityCollision.GetStaticBody()->GetPositionOffset(); //< Calling GetGeomOffset would retrieve current component which is not yet initialized
|
||||
}
|
||||
else
|
||||
positionOffset = Nz::Vector2f::Zero();
|
||||
|
||||
Nz::Matrix4f matrix;
|
||||
if (m_entity->HasComponent<NodeComponent>())
|
||||
matrix = m_entity->GetComponent<NodeComponent>().GetTransformMatrix();
|
||||
else
|
||||
matrix.MakeIdentity();
|
||||
|
||||
m_object = std::make_unique<Nz::RigidBody2D>(&world, 1.f, geom);
|
||||
m_object->SetPositionOffset(positionOffset);
|
||||
m_object->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
|
||||
|
||||
if (m_entity->HasComponent<NodeComponent>())
|
||||
{
|
||||
auto& entityNode = m_entity->GetComponent<NodeComponent>();
|
||||
m_object->SetPosition(Nz::Vector2f(entityNode.GetPosition()));
|
||||
m_object->SetRotation(entityNode.GetRotation().To2DAngle());
|
||||
}
|
||||
|
||||
if (m_pendingStates.valid)
|
||||
ApplyPhysicsState(*m_object);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to this component
|
||||
*
|
||||
* \param component Component being attached
|
||||
*
|
||||
* \remark Produces a NazaraAssert if physical object is invalid
|
||||
*/
|
||||
|
||||
void PhysicsComponent2D::OnComponentAttached(BaseComponent& component)
|
||||
{
|
||||
if (IsComponent<CollisionComponent2D>(component))
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid object");
|
||||
m_object->SetGeom(static_cast<CollisionComponent2D&>(component).GetGeom(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from this component
|
||||
*
|
||||
* \param component Component being detached
|
||||
*
|
||||
* \remark Produces a NazaraAssert if physical object is invalid
|
||||
*/
|
||||
|
||||
void PhysicsComponent2D::OnComponentDetached(BaseComponent& component)
|
||||
{
|
||||
if (IsComponent<CollisionComponent2D>(component))
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid object");
|
||||
m_object->SetGeom(std::make_shared<Nz::NullCollider2D>(), false, false);
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from an entity
|
||||
*/
|
||||
|
||||
void PhysicsComponent2D::OnDetached()
|
||||
{
|
||||
if (m_object)
|
||||
{
|
||||
CopyPhysicsState(*m_object);
|
||||
m_object.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsComponent2D::OnEntityDestruction()
|
||||
{
|
||||
// Kill rigidbody before entity destruction to force contact callbacks to be called while the entity is still valid
|
||||
m_object.reset();
|
||||
}
|
||||
|
||||
void PhysicsComponent2D::OnEntityDisabled()
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->EnableSimulation(false);
|
||||
}
|
||||
|
||||
void PhysicsComponent2D::OnEntityEnabled()
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->EnableSimulation(true);
|
||||
}
|
||||
|
||||
ComponentIndex PhysicsComponent2D::componentIndex;
|
||||
}
|
||||
|
|
@ -1,122 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <Nazara/Physics3D/RigidBody3D.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem3D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::PhysicsComponent3D
|
||||
* \brief NDK class that represents the component for physics (meant for dynamic objects)
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to an entity
|
||||
*
|
||||
* \remark Produces a NazaraAssert if the world does not have a physics system
|
||||
*/
|
||||
|
||||
void PhysicsComponent3D::OnAttached()
|
||||
{
|
||||
World* entityWorld = m_entity->GetWorld();
|
||||
NazaraAssert(entityWorld->HasSystem<PhysicsSystem3D>(), "World must have a physics system");
|
||||
|
||||
Nz::PhysWorld3D& world = entityWorld->GetSystem<PhysicsSystem3D>().GetWorld();
|
||||
|
||||
std::shared_ptr<Nz::Collider3D> geom;
|
||||
if (m_entity->HasComponent<CollisionComponent3D>())
|
||||
geom = m_entity->GetComponent<CollisionComponent3D>().GetGeom();
|
||||
|
||||
Nz::Matrix4f matrix;
|
||||
if (m_entity->HasComponent<NodeComponent>())
|
||||
matrix = m_entity->GetComponent<NodeComponent>().GetTransformMatrix();
|
||||
else
|
||||
matrix.MakeIdentity();
|
||||
|
||||
m_object = std::make_unique<Nz::RigidBody3D>(&world, geom, matrix);
|
||||
m_object->SetUserdata(reinterpret_cast<void*>(static_cast<std::ptrdiff_t>(m_entity->GetId())));
|
||||
|
||||
if (m_pendingStates.valid)
|
||||
ApplyPhysicsState(*m_object);
|
||||
else
|
||||
m_object->SetMass(1.f);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is attached to this component
|
||||
*
|
||||
* \param component Component being attached
|
||||
*
|
||||
* \remark Produces a NazaraAssert if physical object is invalid
|
||||
*/
|
||||
|
||||
void PhysicsComponent3D::OnComponentAttached(BaseComponent& component)
|
||||
{
|
||||
if (IsComponent<CollisionComponent3D>(component))
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid object");
|
||||
|
||||
m_object->SetGeom(static_cast<CollisionComponent3D&>(component).GetGeom());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from this component
|
||||
*
|
||||
* \param component Component being detached
|
||||
*
|
||||
* \remark Produces a NazaraAssert if physical object is invalid
|
||||
*/
|
||||
|
||||
void PhysicsComponent3D::OnComponentDetached(BaseComponent& component)
|
||||
{
|
||||
if (IsComponent<CollisionComponent3D>(component))
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid object");
|
||||
|
||||
m_object->SetGeom(std::make_shared<Nz::NullCollider3D>());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from an entity
|
||||
*/
|
||||
|
||||
void PhysicsComponent3D::OnDetached()
|
||||
{
|
||||
if (m_object)
|
||||
{
|
||||
CopyPhysicsState(*m_object);
|
||||
m_object.reset();
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsComponent3D::OnEntityDestruction()
|
||||
{
|
||||
// Kill rigid body before entity destruction to force contact callbacks to be called while the entity is still valid
|
||||
m_object.reset();
|
||||
}
|
||||
|
||||
void PhysicsComponent3D::OnEntityDisabled()
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->EnableSimulation(false);
|
||||
}
|
||||
|
||||
void PhysicsComponent3D::OnEntityEnabled()
|
||||
{
|
||||
NazaraAssert(m_object, "Invalid physics object");
|
||||
|
||||
m_object->EnableSimulation(true);
|
||||
}
|
||||
|
||||
ComponentIndex PhysicsComponent3D::componentIndex;
|
||||
}
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Components/VelocityComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
ComponentIndex VelocityComponent::componentIndex;
|
||||
}
|
||||
|
|
@ -1,241 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Entity.hpp>
|
||||
#include <NazaraSDK/BaseComponent.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::Entity
|
||||
* \brief NDK class that represents an entity in a world
|
||||
*/
|
||||
|
||||
// Must exists in .cpp file because of BaseComponent unique_ptr
|
||||
Entity::Entity(Entity&&) noexcept = default;
|
||||
|
||||
/*!
|
||||
* \brief Constructs a Entity object linked to a world and with an id
|
||||
*
|
||||
* \param world World in which the entity interact
|
||||
* \param id Identifier of the entity
|
||||
*/
|
||||
Entity::Entity(World* world, EntityId id) :
|
||||
m_world(world),
|
||||
m_id(id)
|
||||
{
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls Destroy
|
||||
*
|
||||
* \see Destroy
|
||||
*/
|
||||
Entity::~Entity()
|
||||
{
|
||||
if (m_world && m_valid)
|
||||
Destroy();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Adds a component to the entity
|
||||
* \return A reference to the newly added component
|
||||
*
|
||||
* \param componentPtr Component to add to the entity
|
||||
*
|
||||
* \remark Produces a NazaraAssert if component is nullptr
|
||||
*/
|
||||
|
||||
BaseComponent& Entity::AddComponent(std::unique_ptr<BaseComponent>&& componentPtr)
|
||||
{
|
||||
NazaraAssert(componentPtr, "Component must be valid");
|
||||
|
||||
ComponentIndex index = componentPtr->GetIndex();
|
||||
|
||||
// We ensure that the vector has enough space
|
||||
if (index >= m_components.size())
|
||||
m_components.resize(index + 1);
|
||||
|
||||
// Affectation and return of the component
|
||||
m_components[index] = std::move(componentPtr);
|
||||
m_componentBits.UnboundedSet(index);
|
||||
m_removedComponentBits.UnboundedReset(index);
|
||||
|
||||
Invalidate();
|
||||
|
||||
// We get the new component and we alert other existing components of the new one
|
||||
BaseComponent& component = *m_components[index].get();
|
||||
component.SetEntity(this);
|
||||
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
{
|
||||
if (i != index)
|
||||
m_components[i]->OnComponentAttached(component);
|
||||
}
|
||||
|
||||
// If we are currently disabled, inform the component
|
||||
if (!m_enabled)
|
||||
component.OnEntityDisabled();
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clones the entity
|
||||
* \return The clone newly created
|
||||
*
|
||||
* \remark The close is enable by default, even if the original is disabled
|
||||
* \remark Produces a NazaraAssert if the entity is not valid
|
||||
*/
|
||||
const EntityHandle& Entity::Clone() const
|
||||
{
|
||||
NazaraAssert(IsValid(), "Invalid entity");
|
||||
|
||||
return m_world->CloneEntity(m_id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Detaches a component from the entity
|
||||
* \return An owning pointer to the component
|
||||
*
|
||||
* Instantly detaches a component from the entity and returns it, allowing to attach it to another entity
|
||||
*
|
||||
* \remark Unlike RemoveComponent, this function instantly removes the component
|
||||
*/
|
||||
std::unique_ptr<BaseComponent> Entity::DropComponent(ComponentIndex index)
|
||||
{
|
||||
if (!HasComponent(index))
|
||||
return nullptr;
|
||||
|
||||
// We get the component and we alert existing components of the deleted one
|
||||
std::unique_ptr<BaseComponent> component = std::move(m_components[index]);
|
||||
m_components[index].reset();
|
||||
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
{
|
||||
if (i != index)
|
||||
m_components[i]->OnComponentDetached(*component);
|
||||
}
|
||||
m_componentBits.Reset(index);
|
||||
m_removedComponentBits.UnboundedReset(index);
|
||||
|
||||
component->SetEntity(nullptr);
|
||||
|
||||
return component;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Enables the entity
|
||||
*
|
||||
* \param enable Should the entity be enabled
|
||||
*/
|
||||
void Entity::Enable(bool enable)
|
||||
{
|
||||
if (m_enabled != enable)
|
||||
{
|
||||
m_enabled = enable;
|
||||
if (m_enabled)
|
||||
{
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
m_components[i]->OnEntityEnabled();
|
||||
|
||||
OnEntityEnabled(this);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
m_components[i]->OnEntityDisabled();
|
||||
|
||||
OnEntityDisabled(this);
|
||||
}
|
||||
|
||||
Invalidate();
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Kills the entity
|
||||
*/
|
||||
void Entity::Kill()
|
||||
{
|
||||
m_world->KillEntity(this);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Invalidates the entity
|
||||
*/
|
||||
void Entity::Invalidate()
|
||||
{
|
||||
// We alert everyone that we have been updated
|
||||
m_world->Invalidate(m_id);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Checks if the entity has been killed this update
|
||||
* \return True if the entity is currently dying and will be dead at next world refresh
|
||||
*/
|
||||
bool Entity::IsDying() const
|
||||
{
|
||||
return m_world->IsEntityDying(m_id);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates the entity
|
||||
*/
|
||||
|
||||
void Entity::Create()
|
||||
{
|
||||
m_enabled = true;
|
||||
m_valid = true;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Destroys the entity
|
||||
*/
|
||||
|
||||
void Entity::Destroy()
|
||||
{
|
||||
OnEntityDestruction(this);
|
||||
OnEntityDestruction.Clear();
|
||||
|
||||
// We prepare components for entity destruction (some components needs this to handle some final callbacks while the entity is still valid)
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
m_components[i]->OnEntityDestruction();
|
||||
|
||||
// Detach components while they're still attached to systems
|
||||
for (std::size_t i = m_componentBits.FindFirst(); i != m_componentBits.npos; i = m_componentBits.FindNext(i))
|
||||
m_components[i]->SetEntity(nullptr);
|
||||
|
||||
// We alert each system
|
||||
for (std::size_t index = m_systemBits.FindFirst(); index != m_systemBits.npos; index = m_systemBits.FindNext(index))
|
||||
{
|
||||
auto sysIndex = static_cast<Ndk::SystemIndex>(index);
|
||||
|
||||
if (m_world->HasSystem(sysIndex))
|
||||
{
|
||||
BaseSystem& system = m_world->GetSystem(sysIndex);
|
||||
system.RemoveEntity(this);
|
||||
}
|
||||
}
|
||||
m_systemBits.Clear();
|
||||
|
||||
// Destroy components
|
||||
m_components.clear();
|
||||
m_componentBits.Reset();
|
||||
|
||||
// Free every handle
|
||||
UnregisterAllHandles();
|
||||
|
||||
// Remove from every list
|
||||
for (EntityList* list : m_containedInLists)
|
||||
list->NotifyEntityDestruction(this);
|
||||
|
||||
m_containedInLists.clear();
|
||||
|
||||
m_valid = false;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,157 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/EntityList.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \brief Construct a new entity list by copying another one
|
||||
*/
|
||||
EntityList::EntityList(const EntityList& entityList) :
|
||||
m_entityBits(entityList.m_entityBits),
|
||||
m_world(entityList.m_world)
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : *this)
|
||||
entity->RegisterEntityList(this);
|
||||
|
||||
if (m_world)
|
||||
m_world->RegisterEntityList(this);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Construct a new entity list by moving a list into this one
|
||||
*/
|
||||
EntityList::EntityList(EntityList&& entityList) noexcept :
|
||||
m_entityBits(std::move(entityList.m_entityBits)),
|
||||
m_world(entityList.m_world)
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : *this)
|
||||
{
|
||||
entity->UnregisterEntityList(&entityList);
|
||||
entity->RegisterEntityList(this);
|
||||
}
|
||||
|
||||
if (m_world)
|
||||
{
|
||||
m_world->UnregisterEntityList(&entityList);
|
||||
m_world->RegisterEntityList(this);
|
||||
|
||||
entityList.m_world = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
EntityList::~EntityList()
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : *this)
|
||||
entity->UnregisterEntityList(this);
|
||||
|
||||
if (m_world)
|
||||
m_world->UnregisterEntityList(this);
|
||||
}
|
||||
|
||||
|
||||
/*!
|
||||
* \brief Clears the set from every entities
|
||||
*
|
||||
* \remark This resets the implicit world member, allowing you to insert entities from a different world than previously
|
||||
*/
|
||||
void EntityList::Clear()
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : *this)
|
||||
entity->UnregisterEntityList(this);
|
||||
|
||||
m_entityBits.Clear();
|
||||
|
||||
if (m_world)
|
||||
{
|
||||
m_world->UnregisterEntityList(this);
|
||||
m_world = nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Inserts the entity into the set
|
||||
*
|
||||
* Marks an entity as present in this entity list, it must belongs to the same world as others entities contained in this list.
|
||||
*
|
||||
* \param entity Valid pointer to an entity
|
||||
*
|
||||
* \remark If entity is already contained, no action is performed
|
||||
* \remark If any entity has been inserted since construction (or last Clear call), the entity must belong to the same world as the previously inserted entities
|
||||
*/
|
||||
void EntityList::Insert(Entity* entity)
|
||||
{
|
||||
NazaraAssert(entity, "Invalid entity");
|
||||
|
||||
if (!Has(entity))
|
||||
{
|
||||
entity->RegisterEntityList(this);
|
||||
|
||||
m_entityBits.UnboundedSet(entity->GetId(), true);
|
||||
if (!m_world)
|
||||
{
|
||||
m_world = entity->GetWorld();
|
||||
m_world->RegisterEntityList(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EntityList& EntityList::operator=(const EntityList& entityList)
|
||||
{
|
||||
if (m_world)
|
||||
m_world->UnregisterEntityList(this);
|
||||
|
||||
for (const Ndk::EntityHandle& entity : *this)
|
||||
entity->UnregisterEntityList(this);
|
||||
|
||||
m_entityBits = entityList.m_entityBits;
|
||||
m_world = entityList.m_world;
|
||||
|
||||
for (const Ndk::EntityHandle& entity : *this)
|
||||
entity->RegisterEntityList(this);
|
||||
|
||||
if (m_world)
|
||||
m_world->RegisterEntityList(this);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
EntityList& EntityList::operator=(EntityList&& entityList) noexcept
|
||||
{
|
||||
if (this == &entityList)
|
||||
return *this;
|
||||
|
||||
if (m_world)
|
||||
m_world->UnregisterEntityList(this);
|
||||
|
||||
for (const Ndk::EntityHandle& entity : *this)
|
||||
entity->UnregisterEntityList(this);
|
||||
|
||||
m_entityBits = std::move(entityList.m_entityBits);
|
||||
m_world = entityList.m_world;
|
||||
|
||||
if (m_world)
|
||||
{
|
||||
m_world->UnregisterEntityList(&entityList);
|
||||
m_world->RegisterEntityList(this);
|
||||
|
||||
entityList.m_world = nullptr;
|
||||
}
|
||||
|
||||
for (const Ndk::EntityHandle& entity : *this)
|
||||
{
|
||||
entity->UnregisterEntityList(&entityList);
|
||||
entity->RegisterEntityList(this);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
const EntityHandle& EntityList::iterator::operator*() const
|
||||
{
|
||||
return m_list->GetWorld()->GetEntity(static_cast<EntityId>(m_nextEntityId));
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -1,71 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Sdk.hpp>
|
||||
#include <Nazara/Core/ErrorFlags.hpp>
|
||||
#include <NazaraSDK/Algorithm.hpp>
|
||||
#include <NazaraSDK/BaseSystem.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NazaraSDK/Components/LifetimeComponent.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <NazaraSDK/Components/VelocityComponent.hpp>
|
||||
#include <NazaraSDK/Components/ConstraintComponent2D.hpp>
|
||||
#include <NazaraSDK/Systems/LifetimeSystem.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem3D.hpp>
|
||||
#include <NazaraSDK/Systems/VelocitySystem.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::Sdk
|
||||
* \brief NDK class that represents the software development kit, a set of tools made to ease the conception of application
|
||||
*/
|
||||
|
||||
Sdk::Sdk(Config /*config*/) :
|
||||
ModuleBase("SDK", this)
|
||||
{
|
||||
Nz::ErrorFlags errFlags(Nz::ErrorMode::ThrowException, true);
|
||||
|
||||
// SDK Initialization
|
||||
|
||||
// Components
|
||||
BaseComponent::Initialize();
|
||||
|
||||
// Shared components
|
||||
InitializeComponent<CollisionComponent2D>("NdkColl2");
|
||||
InitializeComponent<CollisionComponent3D>("NdkColl3");
|
||||
InitializeComponent<LifetimeComponent>("NdkLiftm");
|
||||
InitializeComponent<NodeComponent>("NdkNode");
|
||||
InitializeComponent<PhysicsComponent2D>("NdkPhys2");
|
||||
InitializeComponent<PhysicsComponent3D>("NdkPhys3");
|
||||
InitializeComponent<VelocityComponent>("NdkVeloc");
|
||||
InitializeComponent<VelocityComponent>("NdkCons2");
|
||||
|
||||
// Systems
|
||||
|
||||
BaseSystem::Initialize();
|
||||
|
||||
// Shared systems
|
||||
InitializeSystem<LifetimeSystem>();
|
||||
InitializeSystem<PhysicsSystem2D>();
|
||||
InitializeSystem<PhysicsSystem3D>();
|
||||
InitializeSystem<VelocitySystem>();
|
||||
}
|
||||
|
||||
Sdk::~Sdk()
|
||||
{
|
||||
// Components
|
||||
BaseComponent::Uninitialize();
|
||||
|
||||
// Systems
|
||||
BaseSystem::Uninitialize();
|
||||
}
|
||||
|
||||
Sdk* Sdk::s_instance;
|
||||
}
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/State.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::State
|
||||
* \brief NDK class that represents a state of your application
|
||||
*/
|
||||
|
||||
State::~State() = default;
|
||||
}
|
||||
|
|
@ -1,27 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Systems/LifetimeSystem.hpp>
|
||||
#include <NazaraSDK/Components/LifetimeComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
LifetimeSystem::LifetimeSystem()
|
||||
{
|
||||
Requires<LifetimeComponent>();
|
||||
}
|
||||
|
||||
void LifetimeSystem::OnUpdate(float elapsedTime)
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : GetEntities())
|
||||
{
|
||||
auto& lifetime = entity->GetComponent<LifetimeComponent>();
|
||||
|
||||
if (lifetime.UpdateLifetime(elapsedTime))
|
||||
entity->Kill();
|
||||
}
|
||||
}
|
||||
|
||||
SystemIndex LifetimeSystem::systemIndex;
|
||||
}
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Systems/ListenerSystem.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <NazaraSDK/Components/ListenerComponent.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <cassert>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::ListenerSystem
|
||||
* \brief NDK class that represents the audio system
|
||||
*
|
||||
* \remark This system is enabled if the entity owns the trait: ListenerComponent and NodeComponent
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an ListenerSystem object by default
|
||||
*/
|
||||
|
||||
ListenerSystem::ListenerSystem()
|
||||
{
|
||||
Requires<ListenerComponent, NodeComponent>();
|
||||
SetUpdateOrder(100); //< Update last, after every movement is done
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when system is updated
|
||||
*
|
||||
* \param elapsedTime Delta time used for the update
|
||||
*/
|
||||
|
||||
void ListenerSystem::OnUpdate(float elapsedTime)
|
||||
{
|
||||
std::size_t activeListenerCount = 0;
|
||||
|
||||
Nz::Audio* audio = Nz::Audio::Instance();
|
||||
assert(audio);
|
||||
|
||||
for (const Ndk::EntityHandle& entity : GetEntities())
|
||||
{
|
||||
// Is the listener actif ?
|
||||
const ListenerComponent& listener = entity->GetComponent<ListenerComponent>();
|
||||
if (!listener.IsActive())
|
||||
continue;
|
||||
|
||||
Nz::Vector3f oldPos = audio->GetListenerPosition();
|
||||
|
||||
// We get the position and the rotation to affect these to the listener
|
||||
const NodeComponent& node = entity->GetComponent<NodeComponent>();
|
||||
Nz::Vector3f newPos = node.GetPosition(Nz::CoordSys::Global);
|
||||
|
||||
audio->SetListenerPosition(newPos);
|
||||
audio->SetListenerRotation(node.GetRotation(Nz::CoordSys::Global));
|
||||
|
||||
// Compute listener velocity based on their old/new position
|
||||
Nz::Vector3f velocity = (newPos - oldPos) / elapsedTime;
|
||||
audio->SetListenerVelocity(velocity);
|
||||
|
||||
activeListenerCount++;
|
||||
}
|
||||
|
||||
if (activeListenerCount > 1)
|
||||
NazaraWarning(Nz::NumberToString(activeListenerCount) + " listeners were active in the same update loop");
|
||||
}
|
||||
|
||||
SystemIndex ListenerSystem::systemIndex;
|
||||
}
|
||||
|
|
@ -1,348 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::PhysicsSystem2D
|
||||
* \brief NDK class that represents a two-dimensional physics system
|
||||
*
|
||||
* \remark This system is enabled if the entity has the trait: NodeComponent and any of these two: CollisionComponent3D or PhysicsComponent3D
|
||||
* \remark Static objects do not have a velocity specified by the physical engine
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an PhysicsSystem object by default
|
||||
*/
|
||||
|
||||
PhysicsSystem2D::PhysicsSystem2D()
|
||||
{
|
||||
Requires<NodeComponent>();
|
||||
RequiresAny<CollisionComponent2D, PhysicsComponent2D>();
|
||||
Excludes<PhysicsComponent3D>();
|
||||
}
|
||||
|
||||
void PhysicsSystem2D::CreatePhysWorld() const
|
||||
{
|
||||
NazaraAssert(!m_physWorld, "Physics world should not be created twice");
|
||||
|
||||
m_physWorld = std::make_unique<Nz::PhysWorld2D>();
|
||||
}
|
||||
|
||||
void PhysicsSystem2D::DebugDraw(const DebugDrawOptions& options, bool drawShapes, bool drawConstraints, bool drawCollisions)
|
||||
{
|
||||
Nz::PhysWorld2D::DebugDrawOptions worldOptions{ options.constraintColor, options.collisionPointColor, options.shapeOutlineColor };
|
||||
|
||||
if (options.colorCallback)
|
||||
{
|
||||
worldOptions.colorCallback = [&options, this](Nz::RigidBody2D& body, std::size_t shapeIndex, void* userdata)
|
||||
{
|
||||
return options.colorCallback(GetEntityFromBody(body), shapeIndex, userdata);
|
||||
};
|
||||
}
|
||||
|
||||
worldOptions.circleCallback = options.circleCallback;
|
||||
worldOptions.dotCallback = options.dotCallback;
|
||||
worldOptions.polygonCallback = options.polygonCallback;
|
||||
worldOptions.segmentCallback = options.segmentCallback;
|
||||
worldOptions.thickSegmentCallback = options.thickSegmentCallback;
|
||||
|
||||
worldOptions.userdata = options.userdata;
|
||||
|
||||
GetPhysWorld().DebugDraw(worldOptions, drawShapes, drawConstraints, drawCollisions);
|
||||
}
|
||||
|
||||
const EntityHandle& PhysicsSystem2D::GetEntityFromBody(const Nz::RigidBody2D& body) const
|
||||
{
|
||||
auto entityId = static_cast<EntityId>(reinterpret_cast<std::uintptr_t>(body.GetUserdata()));
|
||||
|
||||
auto& world = GetWorld();
|
||||
|
||||
NazaraAssert(world.IsEntityIdValid(entityId), "All Bodies of this world must be part of the physics world by using PhysicsComponent");
|
||||
|
||||
return world.GetEntity(entityId);
|
||||
}
|
||||
|
||||
bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, EntityHandle* nearestBody)
|
||||
{
|
||||
Nz::RigidBody2D* body;
|
||||
bool res = GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &body);
|
||||
|
||||
(*nearestBody) = GetEntityFromBody(*body);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool PhysicsSystem2D::NearestBodyQuery(const Nz::Vector2f& from, float maxDistance, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, NearestQueryResult* result)
|
||||
{
|
||||
Nz::PhysWorld2D::NearestQueryResult queryResult;
|
||||
if (GetPhysWorld().NearestBodyQuery(from, maxDistance, collisionGroup, categoryMask, collisionMask, &queryResult))
|
||||
{
|
||||
result->nearestBody = GetEntityFromBody(*queryResult.nearestBody);
|
||||
result->closestPoint = std::move(queryResult.closestPoint);
|
||||
result->fraction = std::move(queryResult.fraction);
|
||||
result->distance = queryResult.distance;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void PhysicsSystem2D::RaycastQuery(const Nz::Vector2f & from, const Nz::Vector2f & to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function<void(const RaycastHit&)>& callback)
|
||||
{
|
||||
return GetPhysWorld().RaycastQuery(from, to, radius, collisionGroup, categoryMask, collisionMask, [this, &callback](const Nz::PhysWorld2D::RaycastHit& hitInfo)
|
||||
{
|
||||
callback({
|
||||
GetEntityFromBody(*hitInfo.nearestBody),
|
||||
hitInfo.hitPos,
|
||||
hitInfo.hitNormal,
|
||||
hitInfo.fraction
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
bool PhysicsSystem2D::RaycastQuery(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<RaycastHit>* hitInfos)
|
||||
{
|
||||
std::vector<Nz::PhysWorld2D::RaycastHit> queryResult;
|
||||
bool res = GetPhysWorld().RaycastQuery(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult);
|
||||
|
||||
for (auto& hitResult : queryResult)
|
||||
{
|
||||
hitInfos->push_back({
|
||||
GetEntityFromBody(*hitResult.nearestBody),
|
||||
std::move(hitResult.hitPos),
|
||||
std::move(hitResult.hitNormal),
|
||||
hitResult.fraction
|
||||
});
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
bool PhysicsSystem2D::RaycastQueryFirst(const Nz::Vector2f& from, const Nz::Vector2f& to, float radius, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, RaycastHit* hitInfo)
|
||||
{
|
||||
Nz::PhysWorld2D::RaycastHit queryResult;
|
||||
if (GetPhysWorld().RaycastQueryFirst(from, to, radius, collisionGroup, categoryMask, collisionMask, &queryResult))
|
||||
{
|
||||
hitInfo->body = GetEntityFromBody(*queryResult.nearestBody);
|
||||
hitInfo->hitPos = std::move(queryResult.hitPos);
|
||||
hitInfo->hitNormal = std::move(queryResult.hitNormal);
|
||||
hitInfo->fraction = queryResult.fraction;
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, const std::function<void(const EntityHandle&)>& callback)
|
||||
{
|
||||
return GetPhysWorld().RegionQuery(boundingBox, collisionGroup, categoryMask, collisionMask, [this, &callback](Nz::RigidBody2D* body)
|
||||
{
|
||||
callback(GetEntityFromBody(*body));
|
||||
});
|
||||
}
|
||||
|
||||
void PhysicsSystem2D::RegionQuery(const Nz::Rectf& boundingBox, Nz::UInt32 collisionGroup, Nz::UInt32 categoryMask, Nz::UInt32 collisionMask, std::vector<EntityHandle>* bodies)
|
||||
{
|
||||
std::vector<Nz::RigidBody2D*> queryResult;
|
||||
GetPhysWorld().RegionQuery(boundingBox, collisionGroup, categoryMask, collisionMask, &queryResult);
|
||||
|
||||
for (auto& body : queryResult)
|
||||
{
|
||||
bodies->emplace_back(GetEntityFromBody(*body));
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when entity is validated for the system
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
* \param justAdded Is the entity newly added
|
||||
*/
|
||||
|
||||
void PhysicsSystem2D::OnEntityValidation(Entity* entity, bool justAdded)
|
||||
{
|
||||
if (entity->HasComponent<PhysicsComponent2D>())
|
||||
{
|
||||
if (entity->GetComponent<PhysicsComponent2D>().IsNodeSynchronizationEnabled())
|
||||
m_dynamicObjects.Insert(entity);
|
||||
else
|
||||
m_dynamicObjects.Remove(entity);
|
||||
|
||||
m_staticObjects.Remove(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dynamicObjects.Remove(entity);
|
||||
m_staticObjects.Insert(entity);
|
||||
|
||||
// If entities just got added to the system, teleport them to their NodeComponent position/rotation
|
||||
// This will prevent the physics engine to mess with the scene while correcting position/rotation
|
||||
if (justAdded)
|
||||
{
|
||||
auto& collision = entity->GetComponent<CollisionComponent2D>();
|
||||
auto& node = entity->GetComponent<NodeComponent>();
|
||||
|
||||
Nz::RigidBody2D* physObj = collision.GetStaticBody();
|
||||
physObj->SetPosition(Nz::Vector2f(node.GetPosition(Nz::CoordSys::Global)));
|
||||
//physObj->SetRotation(node.GetRotation());
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_physWorld)
|
||||
CreatePhysWorld();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when system is updated
|
||||
*
|
||||
* \param elapsedTime Delta time used for the update
|
||||
*/
|
||||
|
||||
void PhysicsSystem2D::OnUpdate(float elapsedTime)
|
||||
{
|
||||
if (!m_physWorld)
|
||||
return;
|
||||
|
||||
m_physWorld->Step(elapsedTime);
|
||||
|
||||
for (const Ndk::EntityHandle& entity : m_dynamicObjects)
|
||||
{
|
||||
NodeComponent& node = entity->GetComponent<NodeComponent>();
|
||||
PhysicsComponent2D& phys = entity->GetComponent<PhysicsComponent2D>();
|
||||
|
||||
Nz::RigidBody2D* body = phys.GetRigidBody();
|
||||
node.SetRotation(body->GetRotation(), Nz::CoordSys::Global);
|
||||
node.SetPosition(Nz::Vector3f(body->GetPosition(), node.GetPosition(Nz::CoordSys::Global).z), Nz::CoordSys::Global);
|
||||
}
|
||||
|
||||
float invElapsedTime = 1.f / elapsedTime;
|
||||
for (const Ndk::EntityHandle& entity : m_staticObjects)
|
||||
{
|
||||
CollisionComponent2D& collision = entity->GetComponent<CollisionComponent2D>();
|
||||
NodeComponent& node = entity->GetComponent<NodeComponent>();
|
||||
|
||||
Nz::RigidBody2D* body = collision.GetStaticBody();
|
||||
|
||||
Nz::Vector2f oldPosition = body->GetPosition();
|
||||
Nz::Vector2f newPosition = Nz::Vector2f(node.GetPosition(Nz::CoordSys::Global));
|
||||
|
||||
// To move static objects and ensure their collisions, we have to specify them a velocity
|
||||
// (/!\: the physical engine does not apply the speed on static objects)
|
||||
if (newPosition != oldPosition)
|
||||
{
|
||||
body->SetPosition(newPosition);
|
||||
body->SetVelocity((newPosition - oldPosition) * invElapsedTime);
|
||||
}
|
||||
else
|
||||
body->SetVelocity(Nz::Vector2f::Zero());
|
||||
|
||||
Nz::RadianAnglef oldRotation = body->GetRotation();
|
||||
Nz::RadianAnglef newRotation = node.GetRotation(Nz::CoordSys::Global).To2DAngle();
|
||||
|
||||
if (newRotation != oldRotation)
|
||||
{
|
||||
body->SetRotation(oldRotation);
|
||||
body->SetAngularVelocity((newRotation - oldRotation) * invElapsedTime);
|
||||
}
|
||||
else
|
||||
body->SetAngularVelocity(Nz::RadianAnglef::Zero());
|
||||
}
|
||||
}
|
||||
|
||||
void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionId, Callback callbacks)
|
||||
{
|
||||
Nz::PhysWorld2D::Callback worldCallbacks;
|
||||
|
||||
if (callbacks.endCallback)
|
||||
{
|
||||
worldCallbacks.endCallback = [this, cb = std::move(callbacks.endCallback)](Nz::PhysWorld2D& /*world*/, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
|
||||
{
|
||||
cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
|
||||
};
|
||||
}
|
||||
|
||||
if (callbacks.preSolveCallback)
|
||||
{
|
||||
worldCallbacks.preSolveCallback = [this, cb = std::move(callbacks.preSolveCallback)](Nz::PhysWorld2D& /*world*/, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
|
||||
{
|
||||
return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
|
||||
};
|
||||
}
|
||||
|
||||
if (callbacks.postSolveCallback)
|
||||
{
|
||||
worldCallbacks.postSolveCallback = [this, cb = std::move(callbacks.postSolveCallback)](Nz::PhysWorld2D& /*world*/, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
|
||||
{
|
||||
cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
|
||||
};
|
||||
}
|
||||
|
||||
if (callbacks.startCallback)
|
||||
{
|
||||
worldCallbacks.startCallback = [this, cb = std::move(callbacks.startCallback)](Nz::PhysWorld2D& /*world*/, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
|
||||
{
|
||||
return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
|
||||
};
|
||||
}
|
||||
|
||||
worldCallbacks.userdata = callbacks.userdata;
|
||||
|
||||
m_physWorld->RegisterCallbacks(collisionId, worldCallbacks);
|
||||
}
|
||||
|
||||
void PhysicsSystem2D::RegisterCallbacks(unsigned int collisionIdA, unsigned int collisionIdB, Callback callbacks)
|
||||
{
|
||||
Nz::PhysWorld2D::Callback worldCallbacks;
|
||||
|
||||
if (callbacks.endCallback)
|
||||
{
|
||||
worldCallbacks.endCallback = [this, cb = std::move(callbacks.endCallback)](Nz::PhysWorld2D& /*world*/, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
|
||||
{
|
||||
cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
|
||||
};
|
||||
}
|
||||
|
||||
if (callbacks.preSolveCallback)
|
||||
{
|
||||
worldCallbacks.preSolveCallback = [this, cb = std::move(callbacks.preSolveCallback)](Nz::PhysWorld2D& /*world*/, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
|
||||
{
|
||||
return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
|
||||
};
|
||||
}
|
||||
|
||||
if (callbacks.postSolveCallback)
|
||||
{
|
||||
worldCallbacks.postSolveCallback = [this, cb = std::move(callbacks.postSolveCallback)](Nz::PhysWorld2D& /*world*/, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
|
||||
{
|
||||
cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
|
||||
};
|
||||
}
|
||||
|
||||
if (callbacks.startCallback)
|
||||
{
|
||||
worldCallbacks.startCallback = [this, cb = std::move(callbacks.startCallback)](Nz::PhysWorld2D& /*world*/, Nz::Arbiter2D& arbiter, Nz::RigidBody2D& bodyA, Nz::RigidBody2D& bodyB, void* userdata)
|
||||
{
|
||||
return cb(*this, arbiter, GetEntityFromBody(bodyA), GetEntityFromBody(bodyB), userdata);
|
||||
};
|
||||
}
|
||||
|
||||
worldCallbacks.userdata = callbacks.userdata;
|
||||
|
||||
m_physWorld->RegisterCallbacks(collisionIdA, collisionIdB, worldCallbacks);
|
||||
}
|
||||
|
||||
SystemIndex PhysicsSystem2D::systemIndex;
|
||||
}
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Systems/PhysicsSystem3D.hpp>
|
||||
#include <Nazara/Physics3D/RigidBody3D.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::PhysicsSystem
|
||||
* \brief NDK class that represents the physics system
|
||||
*
|
||||
* \remark This system is enabled if the entity has the trait: NodeComponent and any of these two: CollisionComponent3D or PhysicsComponent3D
|
||||
* \remark Static objects do not have a velocity specified by the physical engine
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an PhysicsSystem object by default
|
||||
*/
|
||||
|
||||
PhysicsSystem3D::PhysicsSystem3D()
|
||||
{
|
||||
Requires<NodeComponent>();
|
||||
RequiresAny<CollisionComponent3D, PhysicsComponent3D>();
|
||||
Excludes<PhysicsComponent2D>();
|
||||
}
|
||||
|
||||
void PhysicsSystem3D::CreatePhysWorld() const
|
||||
{
|
||||
NazaraAssert(!m_world, "Physics world should not be created twice");
|
||||
|
||||
m_world = std::make_unique<Nz::PhysWorld3D>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when entity is validated for the system
|
||||
*
|
||||
* \param entity Pointer to the entity
|
||||
* \param justAdded Is the entity newly added
|
||||
*/
|
||||
|
||||
void PhysicsSystem3D::OnEntityValidation(Entity* entity, bool justAdded)
|
||||
{
|
||||
if (entity->HasComponent<PhysicsComponent3D>())
|
||||
{
|
||||
if (entity->GetComponent<PhysicsComponent3D>().IsNodeSynchronizationEnabled())
|
||||
m_dynamicObjects.Insert(entity);
|
||||
else
|
||||
m_dynamicObjects.Remove(entity);
|
||||
|
||||
m_staticObjects.Remove(entity);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_dynamicObjects.Remove(entity);
|
||||
m_staticObjects.Insert(entity);
|
||||
|
||||
// If entities just got added to the system, teleport them to their NodeComponent position/rotation
|
||||
// This will prevent the physics engine to mess with the scene while correcting position/rotation
|
||||
if (justAdded)
|
||||
{
|
||||
auto& collision = entity->GetComponent<CollisionComponent3D>();
|
||||
auto& node = entity->GetComponent<NodeComponent>();
|
||||
|
||||
Nz::RigidBody3D* physObj = collision.GetStaticBody();
|
||||
physObj->SetPosition(node.GetPosition(Nz::CoordSys::Global));
|
||||
physObj->SetRotation(node.GetRotation(Nz::CoordSys::Global));
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_world)
|
||||
CreatePhysWorld();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when system is updated
|
||||
*
|
||||
* \param elapsedTime Delta time used for the update
|
||||
*/
|
||||
|
||||
void PhysicsSystem3D::OnUpdate(float elapsedTime)
|
||||
{
|
||||
if (!m_world)
|
||||
return;
|
||||
|
||||
m_world->Step(elapsedTime);
|
||||
|
||||
for (const Ndk::EntityHandle& entity : m_dynamicObjects)
|
||||
{
|
||||
NodeComponent& node = entity->GetComponent<NodeComponent>();
|
||||
PhysicsComponent3D& phys = entity->GetComponent<PhysicsComponent3D>();
|
||||
|
||||
Nz::RigidBody3D* physObj = phys.GetRigidBody();
|
||||
node.SetRotation(physObj->GetRotation(), Nz::CoordSys::Global);
|
||||
node.SetPosition(physObj->GetPosition(), Nz::CoordSys::Global);
|
||||
}
|
||||
|
||||
float invElapsedTime = 1.f / elapsedTime;
|
||||
for (const Ndk::EntityHandle& entity : m_staticObjects)
|
||||
{
|
||||
CollisionComponent3D& collision = entity->GetComponent<CollisionComponent3D>();
|
||||
NodeComponent& node = entity->GetComponent<NodeComponent>();
|
||||
|
||||
Nz::RigidBody3D* physObj = collision.GetStaticBody();
|
||||
|
||||
Nz::Quaternionf oldRotation = physObj->GetRotation();
|
||||
Nz::Vector3f oldPosition = physObj->GetPosition();
|
||||
Nz::Quaternionf newRotation = node.GetRotation(Nz::CoordSys::Global);
|
||||
Nz::Vector3f newPosition = node.GetPosition(Nz::CoordSys::Global);
|
||||
|
||||
// To move static objects and ensure their collisions, we have to specify them a velocity
|
||||
// (/!\: the physical motor does not apply the speed on static objects)
|
||||
if (newPosition != oldPosition)
|
||||
{
|
||||
physObj->SetPosition(newPosition);
|
||||
physObj->SetLinearVelocity((newPosition - oldPosition) * invElapsedTime);
|
||||
}
|
||||
else
|
||||
physObj->SetLinearVelocity(Nz::Vector3f::Zero());
|
||||
|
||||
if (newRotation != oldRotation)
|
||||
{
|
||||
Nz::Quaternionf transition = newRotation * oldRotation.GetConjugate();
|
||||
Nz::EulerAnglesf angles = transition.ToEulerAngles();
|
||||
Nz::Vector3f angularVelocity((angles.pitch * invElapsedTime).ToRadians(), (angles.yaw * invElapsedTime).ToRadians(), (angles.roll * invElapsedTime).ToRadians());
|
||||
|
||||
physObj->SetRotation(oldRotation);
|
||||
physObj->SetAngularVelocity(angularVelocity);
|
||||
}
|
||||
else
|
||||
physObj->SetAngularVelocity(Nz::Vector3f::Zero());
|
||||
}
|
||||
}
|
||||
|
||||
SystemIndex PhysicsSystem3D::systemIndex;
|
||||
}
|
||||
|
|
@ -1,50 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/Systems/VelocitySystem.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <NazaraSDK/Components/VelocityComponent.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::VelocitySystem
|
||||
* \brief NDK class that represents the velocity system
|
||||
*
|
||||
* \remark This system is enabled if the entity owns the traits NodeComponent and VelocityComponent
|
||||
* but it's disabled with the traits: PhysicsComponent2D, PhysicsComponent3D
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Constructs an VelocitySystem object by default
|
||||
*/
|
||||
VelocitySystem::VelocitySystem()
|
||||
{
|
||||
Excludes<PhysicsComponent2D, PhysicsComponent3D>();
|
||||
Requires<NodeComponent, VelocityComponent>();
|
||||
SetUpdateOrder(10); //< Since some systems may want to stop us
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when system is updated
|
||||
*
|
||||
* \param elapsedTime Delta time used for the update
|
||||
*/
|
||||
|
||||
void VelocitySystem::OnUpdate(float elapsedTime)
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : GetEntities())
|
||||
{
|
||||
NodeComponent& node = entity->GetComponent<NodeComponent>();
|
||||
const VelocityComponent& velocity = entity->GetComponent<VelocityComponent>();
|
||||
|
||||
node.Move(velocity.linearVelocity * elapsedTime, velocity.coordSys);
|
||||
}
|
||||
}
|
||||
|
||||
SystemIndex VelocitySystem::systemIndex;
|
||||
}
|
||||
|
|
@ -1,312 +0,0 @@
|
|||
// Copyright (C) 2020 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequisites.hpp
|
||||
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <Nazara/Core/Clock.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <NazaraSDK/BaseComponent.hpp>
|
||||
#include <NazaraSDK/Systems/LifetimeSystem.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem3D.hpp>
|
||||
#include <NazaraSDK/Systems/VelocitySystem.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::World
|
||||
* \brief NDK class that represents a world
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \brief Destructs the object and calls Clear
|
||||
*
|
||||
* \see Clear
|
||||
*/
|
||||
|
||||
World::~World() noexcept
|
||||
{
|
||||
// The destruct must be done in an ordered way
|
||||
Clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Creates an entity in the world
|
||||
* \return The entity created
|
||||
*/
|
||||
|
||||
const EntityHandle& World::CreateEntity()
|
||||
{
|
||||
EntityId id;
|
||||
EntityBlock* entBlock;
|
||||
|
||||
std::size_t freeEntityId = m_freeEntityIds.FindFirst();
|
||||
if (freeEntityId != m_freeEntityIds.npos)
|
||||
{
|
||||
// We get an identifier
|
||||
m_freeEntityIds.Reset(freeEntityId); //< Remove id from free entity id
|
||||
|
||||
id = static_cast<EntityId>(freeEntityId);
|
||||
|
||||
entBlock = &m_entities[id];
|
||||
entBlock->handle.Reset(&entBlock->entity); //< Reset handle (as it was reset when entity got destroyed)
|
||||
|
||||
m_entityBlocks[id] = entBlock;
|
||||
}
|
||||
else
|
||||
{
|
||||
// We allocate a new entity
|
||||
id = static_cast<Ndk::EntityId>(m_entityBlocks.size());
|
||||
|
||||
if (m_entities.capacity() > m_entities.size())
|
||||
{
|
||||
NazaraAssert(m_waitingEntities.empty(), "There should be no waiting entities if space is available in main container");
|
||||
|
||||
m_entities.emplace_back(Entity(this, id)); //< We can't make our vector create the entity due to the scope
|
||||
entBlock = &m_entities.back();
|
||||
}
|
||||
else
|
||||
{
|
||||
// Pushing to entities would reallocate vector and thus, invalidate EntityHandles (which we don't want until world update)
|
||||
// To prevent this, allocate them into a separate vector and move them at update
|
||||
// For now, we are counting on m_entities grow strategy to keep allocation frequency low
|
||||
m_waitingEntities.emplace_back(std::make_unique<EntityBlock>(Entity(this, id)));
|
||||
entBlock = m_waitingEntities.back().get();
|
||||
}
|
||||
|
||||
if (id >= m_entityBlocks.size())
|
||||
m_entityBlocks.resize(id + 1);
|
||||
|
||||
m_entityBlocks[id] = entBlock;
|
||||
}
|
||||
|
||||
// We initialize the entity and we add it to the list of alive entities
|
||||
entBlock->entity.Create();
|
||||
|
||||
m_aliveEntities.Insert(&entBlock->entity);
|
||||
|
||||
return entBlock->handle;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clears the world from every entities
|
||||
*
|
||||
* \remark Every handles are correctly invalidated, entities are immediately invalidated
|
||||
*/
|
||||
|
||||
void World::Clear() noexcept
|
||||
{
|
||||
// Destroy every valid entity first, to ensure entities are still accessible by ID while being destroyed
|
||||
for (EntityBlock* entBlock : m_entityBlocks)
|
||||
{
|
||||
if (entBlock->entity.IsValid())
|
||||
entBlock->entity.Destroy();
|
||||
}
|
||||
m_entityBlocks.clear();
|
||||
|
||||
// Reset world for entity lists
|
||||
for (EntityList* list : m_referencedByLists)
|
||||
list->SetWorld(nullptr);
|
||||
m_referencedByLists.clear();
|
||||
|
||||
m_entities.clear();
|
||||
m_waitingEntities.clear();
|
||||
|
||||
m_aliveEntities.Clear();
|
||||
m_dirtyEntities.front.Clear();
|
||||
m_freeEntityIds.Clear();
|
||||
m_killedEntities.front.Clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clones the entity
|
||||
* \return The clone newly created
|
||||
*
|
||||
* \param id Identifier of the entity
|
||||
*
|
||||
* \remark Cloning a disabled entity will produce an enabled clone
|
||||
*/
|
||||
const EntityHandle& World::CloneEntity(EntityId id)
|
||||
{
|
||||
const EntityHandle& original = GetEntity(id);
|
||||
if (!original)
|
||||
{
|
||||
NazaraError("Invalid entity ID");
|
||||
return EntityHandle::InvalidHandle;
|
||||
}
|
||||
|
||||
return CloneEntity(original);
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Clones the entity
|
||||
* \return The clone newly created
|
||||
*
|
||||
* \param original Entity handle
|
||||
*
|
||||
* \remark Cloning a disabled entity will produce an enabled clone
|
||||
*/
|
||||
const EntityHandle& World::CloneEntity(const EntityHandle& original)
|
||||
{
|
||||
const EntityHandle& clone = CreateEntity();
|
||||
if (!original->IsEnabled())
|
||||
clone->Disable();
|
||||
|
||||
const Nz::Bitset<>& componentBits = original->GetComponentBits();
|
||||
for (std::size_t i = componentBits.FindFirst(); i != componentBits.npos; i = componentBits.FindNext(i))
|
||||
clone->AddComponent(original->GetComponent(ComponentIndex(i)).Clone());
|
||||
|
||||
clone->Enable();
|
||||
|
||||
return clone;
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Refreshes the world
|
||||
*
|
||||
* This function will perform all pending operations in the following order:
|
||||
* - Reorder systems according to their update order if needed
|
||||
* - Moving newly created entities (whose which allocate never-used id) data and handles to normal entity list, this will invalidate references to world EntityHandle
|
||||
* - Destroying dead entities and allowing their ids to be used by newly created entities
|
||||
* - Update dirty entities, destroying their removed components and filtering them along systems
|
||||
*
|
||||
* \remark This is called automatically by Update and you most likely won't need to call it yourself
|
||||
* \remark Calling this outside of Update will not increase the profiler values
|
||||
*
|
||||
* \see GetProfilerData
|
||||
* \see Update
|
||||
*/
|
||||
void World::Refresh()
|
||||
{
|
||||
if (!m_orderedSystemsUpdated)
|
||||
ReorderSystems();
|
||||
|
||||
// Move waiting entities to entity list
|
||||
if (!m_waitingEntities.empty())
|
||||
{
|
||||
constexpr std::size_t MinEntityCapacity = 10; //< We want to be able to grow maximum entity count by at least ten without going to the waiting list
|
||||
|
||||
m_entities.reserve(m_entities.size() + m_waitingEntities.size() + MinEntityCapacity);
|
||||
for (auto& blockPtr : m_waitingEntities)
|
||||
m_entities.push_back(std::move(*blockPtr));
|
||||
|
||||
m_waitingEntities.clear();
|
||||
|
||||
// Update entity blocks pointers
|
||||
for (std::size_t i = 0; i < m_entities.size(); ++i)
|
||||
m_entityBlocks[i] = &m_entities[i];
|
||||
}
|
||||
|
||||
// Handle killed entities before last call
|
||||
std::swap(m_killedEntities.front, m_killedEntities.back);
|
||||
for (std::size_t i = m_killedEntities.back.FindFirst(); i != m_killedEntities.back.npos; i = m_killedEntities.back.FindNext(i))
|
||||
{
|
||||
NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range");
|
||||
|
||||
Entity* entity = &m_entityBlocks[i]->entity;
|
||||
|
||||
// Destruction of the entity (invalidation of handle by the same way)
|
||||
entity->Destroy();
|
||||
|
||||
// Send back the identifier of the entity to the free queue
|
||||
m_freeEntityIds.UnboundedSet(i);
|
||||
}
|
||||
m_killedEntities.back.Clear();
|
||||
|
||||
// Handle of entities which need an update from the systems
|
||||
std::swap(m_dirtyEntities.front, m_dirtyEntities.back);
|
||||
for (std::size_t i = m_dirtyEntities.back.FindFirst(); i != m_dirtyEntities.back.npos; i = m_dirtyEntities.back.FindNext(i))
|
||||
{
|
||||
NazaraAssert(i < m_entityBlocks.size(), "Entity index out of range");
|
||||
|
||||
Entity* entity = &m_entityBlocks[i]->entity;
|
||||
|
||||
// Check entity validity (as it could have been reported as dirty and killed during the same iteration)
|
||||
if (!entity->IsValid())
|
||||
continue;
|
||||
|
||||
Nz::Bitset<>& removedComponents = entity->GetRemovedComponentBits();
|
||||
for (std::size_t j = removedComponents.FindFirst(); j != m_dirtyEntities.back.npos; j = removedComponents.FindNext(j))
|
||||
entity->DropComponent(static_cast<Ndk::ComponentIndex>(j));
|
||||
|
||||
for (auto& system : m_orderedSystems)
|
||||
{
|
||||
// Is our entity already part of this system?
|
||||
bool partOfSystem = system->HasEntity(entity);
|
||||
|
||||
// Should it be part of it?
|
||||
if (entity->IsEnabled() && system->Filters(entity))
|
||||
{
|
||||
// Yes it should, add it to the system if not already done and validate it (again)
|
||||
if (!partOfSystem)
|
||||
system->AddEntity(entity);
|
||||
|
||||
system->ValidateEntity(entity, !partOfSystem);
|
||||
}
|
||||
else
|
||||
{
|
||||
// No it shouldn't, remove it if it's part of the system
|
||||
if (partOfSystem)
|
||||
system->RemoveEntity(entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
m_dirtyEntities.back.Clear();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Updates the world
|
||||
* \param elapsedTime Delta time used for the update
|
||||
*
|
||||
* This function Refreshes the world and calls the Update function of every active system part of it with the elapsedTime value.
|
||||
* It also increase the profiler data with the elapsed time passed in Refresh and every system update.
|
||||
*/
|
||||
void World::Update(float elapsedTime)
|
||||
{
|
||||
if (m_isProfilerEnabled)
|
||||
{
|
||||
Nz::UInt64 t1 = Nz::GetElapsedMicroseconds();
|
||||
Refresh();
|
||||
Nz::UInt64 t2 = Nz::GetElapsedMicroseconds();
|
||||
|
||||
m_profilerData.refreshTime += t2 - t1;
|
||||
|
||||
for (auto& systemPtr : m_orderedSystems)
|
||||
{
|
||||
systemPtr->Update(elapsedTime);
|
||||
|
||||
Nz::UInt64 t3 = Nz::GetElapsedMicroseconds();
|
||||
m_profilerData.updateTime[systemPtr->GetIndex()] += t3 - t2;
|
||||
t2 = t3;
|
||||
}
|
||||
|
||||
m_profilerData.updateCount++;
|
||||
}
|
||||
else
|
||||
{
|
||||
Refresh();
|
||||
|
||||
for (auto& systemPtr : m_orderedSystems)
|
||||
systemPtr->Update(elapsedTime);
|
||||
}
|
||||
}
|
||||
|
||||
void World::ReorderSystems()
|
||||
{
|
||||
m_orderedSystems.clear();
|
||||
|
||||
for (auto& systemPtr : m_systems)
|
||||
{
|
||||
if (systemPtr)
|
||||
m_orderedSystems.push_back(systemPtr.get());
|
||||
}
|
||||
|
||||
std::sort(m_orderedSystems.begin(), m_orderedSystems.end(), [] (BaseSystem* first, BaseSystem* second)
|
||||
{
|
||||
return first->GetUpdateOrder() < second->GetUpdateOrder();
|
||||
});
|
||||
|
||||
m_orderedSystemsUpdated = true;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
#include <NazaraSDK/ClientApplication.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
|
||||
SCENARIO("Application", "[NDK][APPLICATION]")
|
||||
{
|
||||
GIVEN("An application")
|
||||
{
|
||||
Nz::Window& window = Ndk::ClientApplication::Instance()->AddWindow<Nz::Window>();
|
||||
|
||||
WHEN("We open a window")
|
||||
{
|
||||
REQUIRE(window.Create(Nz::VideoMode(800, 600, 32), "Nazara Unit Tests"));
|
||||
|
||||
AND_WHEN("We close the open window")
|
||||
{
|
||||
window.Close();
|
||||
|
||||
THEN("Application should close")
|
||||
{
|
||||
REQUIRE(!Ndk::Application::Instance()->Run());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,65 +0,0 @@
|
|||
#include <NazaraSDK/System.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/VelocityComponent.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
class TestSystem : public Ndk::System<TestSystem>
|
||||
{
|
||||
public:
|
||||
TestSystem()
|
||||
{
|
||||
Requires<Ndk::VelocityComponent>();
|
||||
Excludes<Ndk::NodeComponent>();
|
||||
}
|
||||
|
||||
~TestSystem() = default;
|
||||
|
||||
static Ndk::SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
void OnUpdate(float /*elapsedTime*/) override
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
Ndk::SystemIndex TestSystem::systemIndex;
|
||||
}
|
||||
|
||||
SCENARIO("BaseSystem", "[NDK][BASESYSTEM]")
|
||||
{
|
||||
GIVEN("Our TestSystem")
|
||||
{
|
||||
Ndk::World world;
|
||||
|
||||
Ndk::BaseSystem& system = world.AddSystem<TestSystem>();
|
||||
REQUIRE(&system.GetWorld() == &world);
|
||||
|
||||
WHEN("We add an entity")
|
||||
{
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
entity->AddComponent<Ndk::VelocityComponent>();
|
||||
|
||||
THEN("System should have it")
|
||||
{
|
||||
world.Update(1.f);
|
||||
REQUIRE(system.HasEntity(entity));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We add an entity with excluded component")
|
||||
{
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
entity->AddComponent<Ndk::VelocityComponent>();
|
||||
entity->AddComponent<Ndk::NodeComponent>();
|
||||
|
||||
THEN("System should not have it")
|
||||
{
|
||||
world.Update(1.f);
|
||||
REQUIRE(!system.HasEntity(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
#include <NazaraSDK/Component.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
class TestComponent : public Ndk::Component<TestComponent>
|
||||
{
|
||||
public:
|
||||
TestComponent(int value) :
|
||||
m_value(value)
|
||||
{
|
||||
}
|
||||
|
||||
int GetValue() const
|
||||
{
|
||||
return m_value;
|
||||
}
|
||||
|
||||
int m_value;
|
||||
|
||||
static Ndk::ComponentIndex componentIndex;
|
||||
};
|
||||
|
||||
Ndk::ComponentIndex TestComponent::componentIndex;
|
||||
}
|
||||
|
||||
SCENARIO("Component", "[NDK][COMPONENT]")
|
||||
{
|
||||
GIVEN("Our TestComponent")
|
||||
{
|
||||
TestComponent testComponent(42);
|
||||
|
||||
WHEN("We clone it")
|
||||
{
|
||||
std::unique_ptr<Ndk::BaseComponent> clone = testComponent.Clone();
|
||||
|
||||
THEN("We should get a copy")
|
||||
{
|
||||
REQUIRE(static_cast<TestComponent*>(clone.get())->GetValue() == 42);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,102 +0,0 @@
|
|||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
class UpdatableComponent : public Ndk::Component<UpdatableComponent>
|
||||
{
|
||||
public:
|
||||
bool IsUpdated()
|
||||
{
|
||||
return m_updated;
|
||||
}
|
||||
|
||||
void SetUpdated()
|
||||
{
|
||||
m_updated = true;
|
||||
}
|
||||
|
||||
static Ndk::ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
bool m_updated = false;
|
||||
};
|
||||
|
||||
Ndk::ComponentIndex UpdatableComponent::componentIndex;
|
||||
|
||||
class UpdateSystem : public Ndk::System<UpdateSystem>
|
||||
{
|
||||
public:
|
||||
UpdateSystem()
|
||||
{
|
||||
Requires<UpdatableComponent>();
|
||||
}
|
||||
|
||||
~UpdateSystem() = default;
|
||||
|
||||
static Ndk::SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
void OnUpdate(float /*elapsedTime*/) override
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : GetEntities())
|
||||
{
|
||||
UpdatableComponent& updatable = entity->GetComponent<UpdatableComponent>();
|
||||
updatable.SetUpdated();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ndk::SystemIndex UpdateSystem::systemIndex;
|
||||
}
|
||||
|
||||
SCENARIO("Entity", "[NDK][ENTITY]")
|
||||
{
|
||||
GIVEN("A world & an entity")
|
||||
{
|
||||
Ndk::World world;
|
||||
|
||||
Ndk::BaseSystem& system = world.AddSystem<UpdateSystem>();
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
|
||||
WHEN("We add our UpdateComponent")
|
||||
{
|
||||
UpdatableComponent& updatableComponent = entity->AddComponent<UpdatableComponent>();
|
||||
CHECK(!updatableComponent.IsUpdated());
|
||||
|
||||
THEN("Update the world should update the entity's component")
|
||||
{
|
||||
world.Update(1.f);
|
||||
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
|
||||
CHECK(updatableComponentGet.IsUpdated());
|
||||
}
|
||||
|
||||
THEN("Update the world should not update the entity's component if it's disabled")
|
||||
{
|
||||
entity->Enable(false);
|
||||
world.Update(1.f);
|
||||
UpdatableComponent& updatableComponentGet = entity->GetComponent<UpdatableComponent>();
|
||||
CHECK(!updatableComponentGet.IsUpdated());
|
||||
}
|
||||
|
||||
THEN("We can remove its component")
|
||||
{
|
||||
entity->RemoveComponent(Ndk::GetComponentIndex<UpdatableComponent>());
|
||||
world.Update(1.f);
|
||||
CHECK(!entity->HasComponent<UpdatableComponent>());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We kill our entity")
|
||||
{
|
||||
entity->Kill();
|
||||
world.Update(1.f);
|
||||
|
||||
THEN("It's no more valid")
|
||||
{
|
||||
CHECK(!world.IsEntityValid(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,42 +0,0 @@
|
|||
#include <NazaraSDK/EntityList.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
SCENARIO("EntityList", "[NDK][ENTITYLIST]")
|
||||
{
|
||||
GIVEN("A world & a set of entities")
|
||||
{
|
||||
Ndk::World world;
|
||||
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
Ndk::EntityList entityList;
|
||||
entityList.Insert(entity);
|
||||
|
||||
WHEN("We ask if entity is in there")
|
||||
{
|
||||
THEN("These results are expected")
|
||||
{
|
||||
REQUIRE(entityList.Has(entity->GetId()));
|
||||
const Ndk::EntityHandle& newEntity = world.CreateEntity();
|
||||
REQUIRE(!entityList.Has(newEntity->GetId()));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We remove then insert")
|
||||
{
|
||||
entityList.Remove(*entityList.begin());
|
||||
|
||||
THEN("Set should be empty")
|
||||
{
|
||||
REQUIRE(entityList.empty());
|
||||
}
|
||||
|
||||
entityList.Insert(entity);
|
||||
|
||||
THEN("With one element")
|
||||
{
|
||||
REQUIRE(!entityList.empty());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,129 +0,0 @@
|
|||
#include <NazaraSDK/EntityOwner.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
SCENARIO("EntityOwner", "[NDK][ENTITYOWNER]")
|
||||
{
|
||||
GIVEN("A world & an entity")
|
||||
{
|
||||
Ndk::World world;
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
|
||||
WHEN("We set the ownership of the entity to our owner")
|
||||
{
|
||||
THEN("Entity is still valid")
|
||||
{
|
||||
REQUIRE(entity.IsValid());
|
||||
|
||||
Ndk::EntityOwner entityOwner(entity);
|
||||
|
||||
world.Refresh();
|
||||
CHECK(entity.IsValid());
|
||||
}
|
||||
|
||||
THEN("Moving an entity owner by constructor works")
|
||||
{
|
||||
REQUIRE(entity.IsValid());
|
||||
|
||||
Ndk::EntityOwner entityOwner(entity);
|
||||
Ndk::EntityOwner entityOwner2(std::move(entityOwner));
|
||||
entityOwner.Reset();
|
||||
|
||||
world.Refresh();
|
||||
CHECK(entity.IsValid());
|
||||
|
||||
entityOwner2.Reset();
|
||||
|
||||
world.Refresh();
|
||||
CHECK(!entity.IsValid());
|
||||
}
|
||||
|
||||
THEN("Moving an entity owner by operator= works")
|
||||
{
|
||||
REQUIRE(entity.IsValid());
|
||||
|
||||
Ndk::EntityOwner entityOwner(entity);
|
||||
Ndk::EntityOwner entityOwner2;
|
||||
entityOwner2 = std::move(entityOwner);
|
||||
entityOwner.Reset();
|
||||
|
||||
world.Refresh();
|
||||
CHECK(entity.IsValid());
|
||||
|
||||
entityOwner2.Reset();
|
||||
|
||||
world.Refresh();
|
||||
CHECK(!entity.IsValid());
|
||||
}
|
||||
|
||||
THEN("Destroying an entity owner destroys its entity")
|
||||
{
|
||||
REQUIRE(entity.IsValid());
|
||||
|
||||
{
|
||||
Ndk::EntityOwner entityOwner(entity);
|
||||
}
|
||||
|
||||
world.Refresh();
|
||||
CHECK(!entity.IsValid());
|
||||
}
|
||||
|
||||
|
||||
THEN("Resetting an entity owner destroys its entity")
|
||||
{
|
||||
REQUIRE(entity.IsValid());
|
||||
|
||||
Ndk::EntityOwner entityOwner(entity);
|
||||
entityOwner.Reset();
|
||||
|
||||
world.Refresh();
|
||||
CHECK(!entity.IsValid());
|
||||
}
|
||||
|
||||
THEN("Assigning another entity destroys the first entity")
|
||||
{
|
||||
REQUIRE(entity.IsValid());
|
||||
|
||||
Ndk::EntityOwner entityOwner(entity);
|
||||
entityOwner = world.CreateEntity();
|
||||
|
||||
world.Refresh();
|
||||
CHECK(!entity.IsValid());
|
||||
}
|
||||
|
||||
THEN("Moving another entity destroys the first entity")
|
||||
{
|
||||
REQUIRE(entity.IsValid());
|
||||
|
||||
Ndk::EntityOwner entityOwner(entity);
|
||||
Ndk::EntityHandle entity2 = world.CreateEntity();
|
||||
|
||||
entityOwner = std::move(entity2);
|
||||
|
||||
world.Refresh();
|
||||
CHECK(!entity.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A vector of EntityOwner")
|
||||
{
|
||||
Ndk::World world;
|
||||
|
||||
std::vector<Ndk::EntityOwner> entityOwners;
|
||||
for (std::size_t i = 1; i <= 10; ++i)
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : world.CreateEntities(10 * i))
|
||||
entityOwners.emplace_back(entity);
|
||||
|
||||
entityOwners.clear();
|
||||
world.Refresh();
|
||||
|
||||
std::size_t aliveEntities = 0;
|
||||
for (const Ndk::EntityHandle& entity : world.GetEntities())
|
||||
aliveEntities++;
|
||||
|
||||
CHECK(aliveEntities == 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,105 +0,0 @@
|
|||
#include <NazaraSDK/StateMachine.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
class TestState : public Ndk::State
|
||||
{
|
||||
public:
|
||||
void Enter(Ndk::StateMachine& /*fsm*/) override
|
||||
{
|
||||
m_isUpdated = false;
|
||||
}
|
||||
|
||||
bool IsUpdated() const
|
||||
{
|
||||
return m_isUpdated;
|
||||
}
|
||||
|
||||
void Leave(Ndk::StateMachine& /*fsm*/) override
|
||||
{
|
||||
}
|
||||
|
||||
bool Update(Ndk::StateMachine& /*fsm*/, float /*elapsedTime*/) override
|
||||
{
|
||||
m_isUpdated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_isUpdated;
|
||||
};
|
||||
|
||||
class SecondTestState : public Ndk::State
|
||||
{
|
||||
public:
|
||||
void Enter(Ndk::StateMachine& /*fsm*/) override
|
||||
{
|
||||
m_isUpdated = false;
|
||||
}
|
||||
|
||||
bool IsUpdated() const
|
||||
{
|
||||
return m_isUpdated;
|
||||
}
|
||||
|
||||
void Leave(Ndk::StateMachine& /*fsm*/) override
|
||||
{
|
||||
}
|
||||
|
||||
bool Update(Ndk::StateMachine& fsm, float /*elapsedTime*/) override
|
||||
{
|
||||
if (fsm.IsTopState(this))
|
||||
m_isUpdated = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
private:
|
||||
bool m_isUpdated;
|
||||
};
|
||||
|
||||
SCENARIO("State & StateMachine", "[NDK][STATE]")
|
||||
{
|
||||
GIVEN("A statemachine with our test states")
|
||||
{
|
||||
std::shared_ptr<TestState> testState = std::make_shared<TestState>();
|
||||
std::shared_ptr<SecondTestState> secondTestState = std::make_shared<SecondTestState>();
|
||||
Ndk::StateMachine stateMachine(secondTestState);
|
||||
stateMachine.PushState(testState);
|
||||
CHECK(!testState->IsUpdated());
|
||||
CHECK(!secondTestState->IsUpdated());
|
||||
|
||||
WHEN("We update our machine")
|
||||
{
|
||||
stateMachine.Update(1.f);
|
||||
|
||||
THEN("Our state on the top has been updated but not the bottom one")
|
||||
{
|
||||
CHECK(stateMachine.IsTopState(testState.get()));
|
||||
CHECK(!stateMachine.IsTopState(secondTestState.get()));
|
||||
|
||||
CHECK(testState->IsUpdated());
|
||||
CHECK(!secondTestState->IsUpdated());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We exchange the states' positions while emptying the stack")
|
||||
{
|
||||
stateMachine.PopStatesUntil(secondTestState);
|
||||
stateMachine.Update(1.f);
|
||||
CHECK(stateMachine.IsTopState(secondTestState.get()));
|
||||
|
||||
stateMachine.ResetState(testState);
|
||||
stateMachine.PushState(secondTestState);
|
||||
|
||||
stateMachine.Update(1.f);
|
||||
|
||||
THEN("Both states should be updated")
|
||||
{
|
||||
CHECK(!stateMachine.IsTopState(testState.get()));
|
||||
CHECK(stateMachine.IsTopState(secondTestState.get()));
|
||||
|
||||
CHECK(testState->IsUpdated());
|
||||
CHECK(secondTestState->IsUpdated());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,107 +0,0 @@
|
|||
#include <NazaraSDK/System.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
class TestSystem : public Ndk::System<TestSystem>
|
||||
{
|
||||
public:
|
||||
TestSystem() :
|
||||
m_updateCounter(0),
|
||||
m_elapsedTime(0.f)
|
||||
{
|
||||
}
|
||||
|
||||
~TestSystem() = default;
|
||||
|
||||
float GetElapsedTime() const
|
||||
{
|
||||
return m_elapsedTime;
|
||||
}
|
||||
|
||||
std::size_t GetLoopCount() const
|
||||
{
|
||||
return m_updateCounter;
|
||||
}
|
||||
|
||||
static Ndk::SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
std::size_t m_updateCounter;
|
||||
float m_elapsedTime;
|
||||
|
||||
void OnUpdate(float elapsedTime) override
|
||||
{
|
||||
++m_updateCounter;
|
||||
|
||||
m_elapsedTime += elapsedTime;
|
||||
}
|
||||
};
|
||||
|
||||
Ndk::SystemIndex TestSystem::systemIndex;
|
||||
}
|
||||
|
||||
SCENARIO("System", "[NDK][SYSTEM]")
|
||||
{
|
||||
GIVEN("Our TestSystem")
|
||||
{
|
||||
TestSystem testSystem;
|
||||
testSystem.SetMaximumUpdateRate(30.f);
|
||||
|
||||
float maxTimePerFrame = 1 / 30.f;
|
||||
|
||||
WHEN("We update it with a higher framerate")
|
||||
{
|
||||
float timePerFrame = maxTimePerFrame / 2.f;
|
||||
float elapsedTime = 2.f;
|
||||
|
||||
std::size_t loopCount = static_cast<std::size_t>(std::round(elapsedTime / timePerFrame));
|
||||
|
||||
for (std::size_t i = 0; i < loopCount; ++i)
|
||||
testSystem.Update(timePerFrame);
|
||||
|
||||
CHECK(testSystem.GetLoopCount() == loopCount / 2);
|
||||
CHECK(testSystem.GetElapsedTime() == Approx(elapsedTime).epsilon(timePerFrame));
|
||||
}
|
||||
|
||||
WHEN("We update it with a lower framerate")
|
||||
{
|
||||
float timePerFrame = maxTimePerFrame * 2.f;
|
||||
float elapsedTime = 10.f;
|
||||
|
||||
std::size_t loopCount = static_cast<std::size_t>(std::round(elapsedTime / timePerFrame));
|
||||
|
||||
for (std::size_t i = 0; i < loopCount; ++i)
|
||||
testSystem.Update(timePerFrame);
|
||||
|
||||
CHECK(testSystem.GetLoopCount() == loopCount);
|
||||
CHECK(testSystem.GetElapsedTime() == Approx(elapsedTime).epsilon(timePerFrame));
|
||||
|
||||
AND_WHEN("We suddenly increase framerate")
|
||||
{
|
||||
float newTimePerFrame = 1 / 300.f;
|
||||
float newElapsedTime = 100.f;
|
||||
|
||||
std::size_t newLoopCount = static_cast<std::size_t>(std::round(newElapsedTime / newTimePerFrame));
|
||||
|
||||
for (std::size_t i = 0; i < newLoopCount; ++i)
|
||||
testSystem.Update(newTimePerFrame);
|
||||
|
||||
CHECK(testSystem.GetLoopCount() == loopCount + newLoopCount / 10);
|
||||
CHECK(testSystem.GetElapsedTime() == Approx(elapsedTime + newElapsedTime).epsilon(newTimePerFrame));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WHEN("We update it with a very low framerate")
|
||||
{
|
||||
float timePerFrame = 0.5f;
|
||||
|
||||
for (std::size_t i = 0; i < 10; ++i)
|
||||
testSystem.Update(timePerFrame);
|
||||
|
||||
CHECK(testSystem.GetLoopCount() == 10);
|
||||
CHECK(testSystem.GetElapsedTime() == Approx(5.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
#include <NazaraSDK/Systems/ListenerSystem.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/ListenerComponent.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/VelocityComponent.hpp>
|
||||
#include <Nazara/Audio/Audio.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
|
||||
SCENARIO("ListenerSystem", "[NDK][LISTENERSYSTEM]")
|
||||
{
|
||||
GIVEN("A world and an entity with listener & node components")
|
||||
{
|
||||
Ndk::World world;
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
Ndk::ListenerComponent& listenerComponent = entity->AddComponent<Ndk::ListenerComponent>();
|
||||
Ndk::NodeComponent& nodeComponent = entity->AddComponent<Ndk::NodeComponent>();
|
||||
|
||||
WHEN("We move our entity")
|
||||
{
|
||||
Nz::Vector3f position = Nz::Vector3f::Unit() * 3.f;
|
||||
nodeComponent.SetPosition(position);
|
||||
Nz::Quaternionf rotation = Nz::Quaternionf::RotationBetween(Nz::Vector3f::Forward(), Nz::Vector3f::Up());
|
||||
nodeComponent.SetRotation(rotation);
|
||||
world.Update(1.f);
|
||||
|
||||
THEN("Our listener should have moved")
|
||||
{
|
||||
REQUIRE(Nz::Audio::Instance()->GetListenerPosition() == position);
|
||||
REQUIRE(Nz::Audio::Instance()->GetListenerRotation() == rotation);
|
||||
}
|
||||
|
||||
THEN("With a component of velocity")
|
||||
{
|
||||
Ndk::VelocityComponent& velocityComponent = entity->AddComponent<Ndk::VelocityComponent>();
|
||||
Nz::Vector3f velocity = Nz::Vector3f::Unit() * 2.f;
|
||||
velocityComponent.linearVelocity = velocity;
|
||||
|
||||
world.Update(1.f);
|
||||
REQUIRE(Nz::Audio::Instance()->GetListenerVelocity() == velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,164 +0,0 @@
|
|||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
#include <limits>
|
||||
|
||||
Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf& AABB);
|
||||
|
||||
SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]")
|
||||
{
|
||||
GIVEN("A world and an entity")
|
||||
{
|
||||
Ndk::World world;
|
||||
world.AddSystem<Ndk::PhysicsSystem2D>();
|
||||
|
||||
Nz::Vector2f position(2.f, 3.f);
|
||||
Nz::Rectf movingAABB(0.f, 0.f, 16.f, 18.f);
|
||||
Ndk::EntityHandle movingEntity = CreateBaseEntity(world, position, movingAABB);
|
||||
Ndk::NodeComponent& nodeComponent = movingEntity->GetComponent<Ndk::NodeComponent>();
|
||||
Ndk::PhysicsComponent2D& physicsComponent2D = movingEntity->AddComponent<Ndk::PhysicsComponent2D>();
|
||||
|
||||
world.GetSystem<Ndk::PhysicsSystem2D>().SetMaximumUpdateRate(0.f);
|
||||
world.GetSystem<Ndk::PhysicsSystem2D>().SetMaxStepCount(std::numeric_limits<std::size_t>::max());
|
||||
|
||||
WHEN("We update the world")
|
||||
{
|
||||
world.Update(1.f);
|
||||
|
||||
THEN("Entity should have correct bounding box")
|
||||
{
|
||||
REQUIRE(nodeComponent.GetPosition() == position);
|
||||
movingAABB.Translate(position);
|
||||
REQUIRE(physicsComponent2D.GetAABB() == movingAABB);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We make it collide with a wall")
|
||||
{
|
||||
int rawDistance = 3;
|
||||
Nz::Vector2f distance(float(rawDistance), 0.f);
|
||||
Nz::Vector2f wallPosition = position + Nz::Vector2f(movingAABB.width, 0.f) + distance;
|
||||
Nz::Rectf wallAABB(0.f, 0.f, 100.f, 100.f);
|
||||
Ndk::EntityHandle wallEntity = CreateBaseEntity(world, wallPosition, wallAABB);
|
||||
|
||||
world.Update(1.f);
|
||||
|
||||
THEN("It should move freely")
|
||||
{
|
||||
REQUIRE(nodeComponent.GetPosition() == position);
|
||||
movingAABB.Translate(position);
|
||||
REQUIRE(physicsComponent2D.GetAABB() == movingAABB);
|
||||
|
||||
physicsComponent2D.SetVelocity(Nz::Vector2f::UnitX());
|
||||
|
||||
for (int i = 0; i < rawDistance; ++i)
|
||||
{
|
||||
world.Update(1.f);
|
||||
position += Nz::Vector2f::UnitX();
|
||||
REQUIRE(nodeComponent.GetPosition() == position);
|
||||
movingAABB.Translate(Nz::Vector2f::UnitX());
|
||||
REQUIRE(physicsComponent2D.GetAABB() == movingAABB);
|
||||
}
|
||||
}
|
||||
|
||||
AND_THEN("It should be stopped by it")
|
||||
{
|
||||
world.Update(1.f);
|
||||
REQUIRE(nodeComponent.GetPosition().SquaredDistance(position) < 0.1f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A world and a simple entity")
|
||||
{
|
||||
Ndk::World world;
|
||||
world.AddSystem<Ndk::PhysicsSystem2D>();
|
||||
|
||||
Nz::Vector2f position(0.f, 0.f);
|
||||
Nz::Rectf movingAABB(0.f, 0.f, 1.f, 2.f);
|
||||
Ndk::EntityHandle movingEntity = CreateBaseEntity(world, position, movingAABB);
|
||||
Ndk::NodeComponent& nodeComponent = movingEntity->GetComponent<Ndk::NodeComponent>();
|
||||
Ndk::PhysicsComponent2D& physicsComponent2D = movingEntity->AddComponent<Ndk::PhysicsComponent2D>();
|
||||
physicsComponent2D.SetMassCenter(Nz::Vector2f::Zero());
|
||||
physicsComponent2D.SetPosition(position);
|
||||
|
||||
world.GetSystem<Ndk::PhysicsSystem2D>().SetFixedUpdateRate(30.f);
|
||||
|
||||
WHEN("We make rotate our entity")
|
||||
{
|
||||
Nz::RadianAnglef angularSpeed = Nz::RadianAnglef::FromDegrees(45.f);
|
||||
physicsComponent2D.SetAngularVelocity(angularSpeed);
|
||||
world.Update(2.f);
|
||||
|
||||
THEN("It should have been rotated")
|
||||
{
|
||||
CHECK(physicsComponent2D.GetAngularVelocity() == angularSpeed);
|
||||
CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(-2.f, 0.f, 2.f, 1.f));
|
||||
CHECK(physicsComponent2D.GetRotation() == Nz::RadianAnglef::FromDegrees(90.f));
|
||||
CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Nz::DegreeAnglef(90.f));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We put a force on it")
|
||||
{
|
||||
float stepSize = world.GetSystem<Ndk::PhysicsSystem2D>().GetStepSize();
|
||||
Nz::Vector2f velocity = Nz::Vector2f::UnitX();
|
||||
physicsComponent2D.AddForce(velocity / stepSize);
|
||||
world.Update(1.f);
|
||||
|
||||
THEN("Velocity should be the one targetted")
|
||||
{
|
||||
REQUIRE(physicsComponent2D.GetVelocity() == velocity);
|
||||
world.Update(99.f);
|
||||
REQUIRE(physicsComponent2D.GetPosition().Distance(Nz::Vector2f::UnitX() * 100.f) < 1.f);
|
||||
REQUIRE(nodeComponent.GetPosition().Distance(Nz::Vector2f::UnitX() * 100.f) < 1.f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A world and a simple entity not at the origin")
|
||||
{
|
||||
Ndk::World world;
|
||||
world.AddSystem<Ndk::PhysicsSystem2D>();
|
||||
|
||||
Nz::Vector2f position(3.f, 4.f);
|
||||
Nz::Rectf movingAABB(0.f, 0.f, 1.f, 2.f);
|
||||
Ndk::EntityHandle movingEntity = CreateBaseEntity(world, position, movingAABB);
|
||||
Ndk::NodeComponent& nodeComponent = movingEntity->GetComponent<Ndk::NodeComponent>();
|
||||
Ndk::PhysicsComponent2D& physicsComponent2D = movingEntity->AddComponent<Ndk::PhysicsComponent2D>();
|
||||
physicsComponent2D.SetMassCenter(Nz::Vector2f::Zero());
|
||||
physicsComponent2D.SetPosition(position);
|
||||
|
||||
world.GetSystem<Ndk::PhysicsSystem2D>().SetFixedUpdateRate(30.f);
|
||||
|
||||
WHEN("We make rotate our entity")
|
||||
{
|
||||
Nz::RadianAnglef angularSpeed = Nz::RadianAnglef::FromDegrees(45.f);
|
||||
physicsComponent2D.SetAngularVelocity(angularSpeed);
|
||||
world.Update(2.f);
|
||||
|
||||
THEN("It should have been rotated")
|
||||
{
|
||||
CHECK(physicsComponent2D.GetAngularVelocity() == angularSpeed);
|
||||
CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(1.f, 4.f, 2.f, 1.f));
|
||||
CHECK(physicsComponent2D.GetRotation() == 2.f * angularSpeed);
|
||||
CHECK(nodeComponent.GetPosition() == position);
|
||||
CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Nz::DegreeAnglef(90.f));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ndk::EntityHandle CreateBaseEntity(Ndk::World& world, const Nz::Vector2f& position, const Nz::Rectf& AABB)
|
||||
{
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
Ndk::NodeComponent& nodeComponent = entity->AddComponent<Ndk::NodeComponent>();
|
||||
nodeComponent.SetPosition(position);
|
||||
std::shared_ptr<Nz::BoxCollider2D> collisionBox = std::make_shared<Nz::BoxCollider2D>(AABB);
|
||||
entity->AddComponent<Ndk::CollisionComponent2D>(collisionBox);
|
||||
return entity;
|
||||
}
|
||||
|
|
@ -1,37 +0,0 @@
|
|||
#include <NazaraSDK/Systems/PhysicsSystem3D.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <NazaraSDK/Systems/PhysicsSystem3D.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
SCENARIO("PhysicsSystem3D", "[NDK][PHYSICSSYSTEM3D]")
|
||||
{
|
||||
GIVEN("A world and a static entity & a dynamic entity")
|
||||
{
|
||||
Ndk::World world;
|
||||
world.AddSystem<Ndk::PhysicsSystem3D>();
|
||||
|
||||
const Ndk::EntityHandle& staticEntity = world.CreateEntity();
|
||||
Ndk::CollisionComponent3D& collisionComponentStatic = staticEntity->AddComponent<Ndk::CollisionComponent3D>();
|
||||
Ndk::NodeComponent& nodeComponentStatic = staticEntity->AddComponent<Ndk::NodeComponent>();
|
||||
|
||||
const Ndk::EntityHandle& dynamicEntity = world.CreateEntity();
|
||||
Ndk::NodeComponent& nodeComponentDynamic = dynamicEntity->AddComponent<Ndk::NodeComponent>();
|
||||
Ndk::PhysicsComponent3D& physicsComponentDynamic = dynamicEntity->AddComponent<Ndk::PhysicsComponent3D>();
|
||||
|
||||
WHEN("We make collide these two entities")
|
||||
{
|
||||
nodeComponentDynamic.SetPosition(-Nz::Vector3f::UnitZ());
|
||||
physicsComponentDynamic.AddForce(Nz::Vector3f::UnitZ());
|
||||
|
||||
THEN("The dynamic entity should have hit the static one")
|
||||
{
|
||||
world.Update(1.f); // On origin
|
||||
world.Update(1.f); // On origin due to collision
|
||||
REQUIRE(nodeComponentStatic.GetPosition().SquaredDistance(nodeComponentDynamic.GetPosition()) < 0.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
#include <NazaraSDK/Systems/VelocitySystem.hpp>
|
||||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Components/NodeComponent.hpp>
|
||||
#include <NazaraSDK/Components/VelocityComponent.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
SCENARIO("VelocitySystem", "[NDK][VELOCITYSYSTEM]")
|
||||
{
|
||||
GIVEN("A world and an entity with velocity & node components")
|
||||
{
|
||||
Ndk::World world;
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
Ndk::VelocityComponent& velocityComponent = entity->AddComponent<Ndk::VelocityComponent>();
|
||||
Ndk::NodeComponent& nodeComponent = entity->AddComponent<Ndk::NodeComponent>();
|
||||
|
||||
world.AddSystem<Ndk::VelocitySystem>().SetFixedUpdateRate(30.f);
|
||||
|
||||
WHEN("We give a speed to our entity")
|
||||
{
|
||||
Nz::Vector3f velocity = Nz::Vector3f::Unit() * 2.f;
|
||||
velocityComponent.linearVelocity = velocity;
|
||||
world.Update(1.f);
|
||||
|
||||
THEN("Our entity should have moved")
|
||||
{
|
||||
REQUIRE(nodeComponent.GetPosition().SquaredDistance(velocity) < 0.2f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,162 +0,0 @@
|
|||
#include <NazaraSDK/World.hpp>
|
||||
#include <NazaraSDK/Component.hpp>
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
namespace
|
||||
{
|
||||
class UpdatableComponent : public Ndk::Component<UpdatableComponent>
|
||||
{
|
||||
public:
|
||||
bool IsUpdated()
|
||||
{
|
||||
return m_updated;
|
||||
}
|
||||
|
||||
void SetUpdated()
|
||||
{
|
||||
m_updated = true;
|
||||
}
|
||||
|
||||
static Ndk::ComponentIndex componentIndex;
|
||||
|
||||
private:
|
||||
bool m_updated = false;
|
||||
};
|
||||
|
||||
Ndk::ComponentIndex UpdatableComponent::componentIndex;
|
||||
|
||||
class UpdateSystem : public Ndk::System<UpdateSystem>
|
||||
{
|
||||
public:
|
||||
UpdateSystem()
|
||||
{
|
||||
Requires<UpdatableComponent>();
|
||||
}
|
||||
|
||||
~UpdateSystem() = default;
|
||||
|
||||
static Ndk::SystemIndex systemIndex;
|
||||
|
||||
private:
|
||||
void OnUpdate(float /*elapsedTime*/) override
|
||||
{
|
||||
for (const Ndk::EntityHandle& entity : GetEntities())
|
||||
{
|
||||
UpdatableComponent& updatable = entity->GetComponent<UpdatableComponent>();
|
||||
updatable.SetUpdated();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Ndk::SystemIndex UpdateSystem::systemIndex;
|
||||
}
|
||||
|
||||
SCENARIO("World", "[NDK][WORLD]")
|
||||
{
|
||||
GIVEN("A brave new world and the update system")
|
||||
{
|
||||
Ndk::World world;
|
||||
Ndk::BaseSystem& system = world.AddSystem<UpdateSystem>();
|
||||
|
||||
WHEN("We had a new entity with an updatable component and a system")
|
||||
{
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
UpdatableComponent& component = entity->AddComponent<UpdatableComponent>();
|
||||
|
||||
THEN("We can get our entity and our system")
|
||||
{
|
||||
const Ndk::EntityHandle& fetchedEntity = world.GetEntity(entity->GetId());
|
||||
REQUIRE(fetchedEntity->GetWorld() == &world);
|
||||
}
|
||||
|
||||
THEN("We can clone it")
|
||||
{
|
||||
const Ndk::EntityHandle& clone = world.CloneEntity(entity->GetId());
|
||||
REQUIRE(world.IsEntityValid(clone));
|
||||
}
|
||||
}
|
||||
|
||||
AND_WHEN("We update our world with our entity")
|
||||
{
|
||||
REQUIRE(&world.GetSystem(UpdateSystem::systemIndex) == &world.GetSystem<UpdateSystem>());
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
UpdatableComponent& component = entity->AddComponent<UpdatableComponent>();
|
||||
|
||||
THEN("Our entity component must be updated")
|
||||
{
|
||||
world.Update(1.f);
|
||||
|
||||
REQUIRE(component.IsUpdated());
|
||||
}
|
||||
|
||||
THEN("We kill our entity")
|
||||
{
|
||||
REQUIRE(entity->IsValid());
|
||||
|
||||
world.KillEntity(entity);
|
||||
world.Update(1.f);
|
||||
|
||||
REQUIRE(!world.IsEntityValid(entity));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A newly created entity")
|
||||
{
|
||||
Ndk::World world;
|
||||
Ndk::EntityHandle entity = world.CreateEntity();
|
||||
|
||||
REQUIRE(entity.IsValid());
|
||||
REQUIRE(entity->IsValid());
|
||||
CHECK_FALSE(entity->IsDying());
|
||||
|
||||
WHEN("We kill it")
|
||||
{
|
||||
entity->Kill();
|
||||
|
||||
CHECK(entity.IsValid());
|
||||
CHECK(entity->IsValid());
|
||||
CHECK(entity->IsDying());
|
||||
|
||||
THEN("We refresh the world")
|
||||
{
|
||||
world.Refresh();
|
||||
|
||||
CHECK_FALSE(entity.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("An empty world")
|
||||
{
|
||||
Ndk::World world;
|
||||
|
||||
WHEN("We create two entities")
|
||||
{
|
||||
Ndk::EntityHandle a = world.CreateEntity();
|
||||
REQUIRE(a->GetId() == 0);
|
||||
Ndk::EntityHandle b = world.CreateEntity();
|
||||
REQUIRE(b->GetId() == 1);
|
||||
|
||||
b->OnEntityDestruction.Connect([a](Ndk::Entity*)
|
||||
{
|
||||
REQUIRE(a.IsValid());
|
||||
a->Kill();
|
||||
});
|
||||
|
||||
THEN("We kill the second entity which will kill the first one")
|
||||
{
|
||||
b->Kill();
|
||||
world.Refresh();
|
||||
|
||||
AND_THEN("Both entities should be dead next refresh")
|
||||
{
|
||||
world.Refresh();
|
||||
|
||||
REQUIRE_FALSE(a.IsValid());
|
||||
REQUIRE_FALSE(b.IsValid());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -4,15 +4,13 @@
|
|||
#include <Nazara/Core/Log.hpp>
|
||||
#include <Nazara/Core/AbstractLogger.hpp>
|
||||
#include <Nazara/Core/Modules.hpp>
|
||||
#include <NazaraSDK/Application.hpp>
|
||||
#include <NazaraSDK/Sdk.hpp>
|
||||
#include <Nazara/Network/Network.hpp>
|
||||
#include <Nazara/Physics2D/Physics2D.hpp>
|
||||
#include <Nazara/Shader/Shader.hpp>
|
||||
|
||||
int main(int argc, char* argv[])
|
||||
{
|
||||
Nz::Modules<Ndk::Sdk> nazaza;
|
||||
Ndk::Application app(argc, argv);
|
||||
|
||||
Nz::Log::GetLogger()->EnableStdReplication(false);
|
||||
Nz::Modules<Nz::Network, Nz::Physics2D, Nz::Shader> nazaza;
|
||||
|
||||
int result = Catch::Session().run(argc, argv);
|
||||
|
||||
|
|
|
|||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue