SDK: Add components and system for 2D physics
This commit is contained in:
108
SDK/src/NDK/Components/CollisionComponent2D.cpp
Normal file
108
SDK/src/NDK/Components/CollisionComponent2D.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||
|
||||
#include <NDK/Components/CollisionComponent2D.hpp>
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <NDK/Algorithm.hpp>
|
||||
#include <NDK/World.hpp>
|
||||
#include <NDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NDK/Systems/PhysicsSystem2D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
{
|
||||
/*!
|
||||
* \ingroup NDK
|
||||
* \class Ndk::CollisionComponent2D
|
||||
* \brief NDK class that represents a two-dimensional collision geometry
|
||||
*/
|
||||
|
||||
/*!
|
||||
* \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 CollisionComponent2D::SetGeom(Nz::Collider2DRef geom)
|
||||
{
|
||||
m_geom = std::move(geom);
|
||||
|
||||
if (m_entity->HasComponent<PhysicsComponent2D>())
|
||||
{
|
||||
// We update the geometry of the PhysiscsObject linked to the PhysicsComponent2D
|
||||
PhysicsComponent2D& physComponent = m_entity->GetComponent<PhysicsComponent2D>();
|
||||
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 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>().GetWorld();
|
||||
|
||||
m_staticBody.reset(new Nz::RigidBody2D(&physWorld, m_geom));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ namespace Ndk
|
||||
{
|
||||
// We update the geometry of the PhysiscsObject linked to the PhysicsComponent3D
|
||||
PhysicsComponent3D& physComponent = m_entity->GetComponent<PhysicsComponent3D>();
|
||||
physComponent.GetPhysObject().SetGeom(m_geom);
|
||||
physComponent.GetRigidBody().SetGeom(m_geom);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
92
SDK/src/NDK/Components/PhysicsComponent2D.cpp
Normal file
92
SDK/src/NDK/Components/PhysicsComponent2D.cpp
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||
|
||||
#include <NDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <NDK/Algorithm.hpp>
|
||||
#include <NDK/World.hpp>
|
||||
#include <NDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NDK/Components/NodeComponent.hpp>
|
||||
#include <NDK/Systems/PhysicsSystem3D.hpp>
|
||||
|
||||
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>().GetWorld();
|
||||
|
||||
Nz::Collider2DRef geom;
|
||||
if (m_entity->HasComponent<CollisionComponent2D>())
|
||||
geom = m_entity->GetComponent<CollisionComponent2D>().GetGeom();
|
||||
|
||||
Nz::Matrix4f matrix;
|
||||
if (m_entity->HasComponent<NodeComponent>())
|
||||
matrix = m_entity->GetComponent<NodeComponent>().GetTransformMatrix();
|
||||
else
|
||||
matrix.MakeIdentity();
|
||||
|
||||
m_object.reset(new Nz::RigidBody2D(&world, 1.f, geom));
|
||||
m_object->SetPosition(Nz::Vector2f(matrix.GetTranslation()));
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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(Nz::NullCollider2D::New());
|
||||
}
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when component is detached from an entity
|
||||
*/
|
||||
|
||||
void PhysicsComponent2D::OnDetached()
|
||||
{
|
||||
m_object.reset();
|
||||
}
|
||||
|
||||
ComponentIndex PhysicsComponent2D::componentIndex;
|
||||
}
|
||||
@@ -9,14 +9,18 @@
|
||||
#include <Nazara/Graphics/Graphics.hpp>
|
||||
#include <Nazara/Lua/Lua.hpp>
|
||||
#include <Nazara/Noise/Noise.hpp>
|
||||
#include <Nazara/Physics2D/Physics2D.hpp>
|
||||
#include <Nazara/Physics3D/Physics3D.hpp>
|
||||
#include <Nazara/Utility/Utility.hpp>
|
||||
#include <NDK/Algorithm.hpp>
|
||||
#include <NDK/BaseSystem.hpp>
|
||||
#include <NDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NDK/Components/NodeComponent.hpp>
|
||||
#include <NDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NDK/Components/PhysicsComponent3D.hpp>
|
||||
#include <NDK/Components/VelocityComponent.hpp>
|
||||
#include <NDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <NDK/Systems/PhysicsSystem3D.hpp>
|
||||
#include <NDK/Systems/VelocitySystem.hpp>
|
||||
|
||||
@@ -68,6 +72,7 @@ namespace Ndk
|
||||
|
||||
Nz::Lua::Initialize();
|
||||
Nz::Noise::Initialize();
|
||||
Nz::Physics2D::Initialize();
|
||||
Nz::Physics3D::Initialize();
|
||||
Nz::Utility::Initialize();
|
||||
|
||||
@@ -83,9 +88,11 @@ namespace Ndk
|
||||
BaseComponent::Initialize();
|
||||
|
||||
// Shared components
|
||||
InitializeComponent<CollisionComponent3D>("NdkColli");
|
||||
InitializeComponent<CollisionComponent2D>("NdkColl2");
|
||||
InitializeComponent<CollisionComponent3D>("NdkColl3");
|
||||
InitializeComponent<NodeComponent>("NdkNode");
|
||||
InitializeComponent<PhysicsComponent3D>("NdkPhys");
|
||||
InitializeComponent<PhysicsComponent2D>("NdkPhys2");
|
||||
InitializeComponent<PhysicsComponent3D>("NdkPhys3");
|
||||
InitializeComponent<VelocityComponent>("NdkVeloc");
|
||||
|
||||
#ifndef NDK_SERVER
|
||||
@@ -103,6 +110,7 @@ namespace Ndk
|
||||
BaseSystem::Initialize();
|
||||
|
||||
// Shared systems
|
||||
InitializeSystem<PhysicsSystem2D>();
|
||||
InitializeSystem<PhysicsSystem3D>();
|
||||
InitializeSystem<VelocitySystem>();
|
||||
|
||||
@@ -161,6 +169,7 @@ namespace Ndk
|
||||
// Shared modules
|
||||
Nz::Lua::Uninitialize();
|
||||
Nz::Noise::Uninitialize();
|
||||
Nz::Physics2D::Uninitialize();
|
||||
Nz::Physics3D::Uninitialize();
|
||||
Nz::Utility::Uninitialize();
|
||||
|
||||
|
||||
140
SDK/src/NDK/Systems/PhysicsSystem2D.cpp
Normal file
140
SDK/src/NDK/Systems/PhysicsSystem2D.cpp
Normal file
@@ -0,0 +1,140 @@
|
||||
// Copyright (C) 2015 Jérôme Leclercq
|
||||
// This file is part of the "Nazara Development Kit"
|
||||
// For conditions of distribution and use, see copyright notice in Prerequesites.hpp
|
||||
|
||||
#include <NDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <Nazara/Physics2D/RigidBody2D.hpp>
|
||||
#include <NDK/Components/CollisionComponent2D.hpp>
|
||||
#include <NDK/Components/NodeComponent.hpp>
|
||||
#include <NDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NDK/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>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Constructs a PhysicsSystem object by copy semantic
|
||||
*
|
||||
* \param system PhysicsSystem to copy
|
||||
*/
|
||||
|
||||
PhysicsSystem2D::PhysicsSystem2D(const PhysicsSystem2D& system) :
|
||||
System(system),
|
||||
m_world()
|
||||
{
|
||||
}
|
||||
|
||||
void PhysicsSystem2D::CreatePhysWorld() const
|
||||
{
|
||||
NazaraAssert(!m_world, "Physics world should not be created twice");
|
||||
|
||||
m_world = std::make_unique<Nz::PhysWorld2D>();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \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)
|
||||
{
|
||||
// It's possible our entity got revalidated because of the addition/removal of a PhysicsComponent3D
|
||||
if (!justAdded)
|
||||
{
|
||||
// We take the opposite array from which the entity should belong to
|
||||
auto& entities = (entity->HasComponent<PhysicsComponent2D>()) ? m_staticObjects : m_dynamicObjects;
|
||||
entities.Remove(entity);
|
||||
}
|
||||
|
||||
auto& entities = (entity->HasComponent<PhysicsComponent2D>()) ? m_dynamicObjects : m_staticObjects;
|
||||
entities.Insert(entity);
|
||||
|
||||
if (!m_world)
|
||||
CreatePhysWorld();
|
||||
}
|
||||
|
||||
/*!
|
||||
* \brief Operation to perform when system is updated
|
||||
*
|
||||
* \param elapsedTime Delta time used for the update
|
||||
*/
|
||||
|
||||
void PhysicsSystem2D::OnUpdate(float elapsedTime)
|
||||
{
|
||||
if (!m_world)
|
||||
return;
|
||||
|
||||
m_world->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(Nz::EulerAnglesf(0.f, 0.f, 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 motor 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());
|
||||
|
||||
/*
|
||||
if (newRotation != oldRotation)
|
||||
{
|
||||
Nz::Quaternionf transition = newRotation * oldRotation.GetConjugate();
|
||||
Nz::EulerAnglesf angles = transition.ToEulerAngles();
|
||||
Nz::Vector3f angularVelocity(Nz::ToRadians(angles.pitch * invElapsedTime),
|
||||
Nz::ToRadians(angles.yaw * invElapsedTime),
|
||||
Nz::ToRadians(angles.roll * invElapsedTime));
|
||||
|
||||
physObj->SetRotation(oldRotation);
|
||||
physObj->SetAngularVelocity(angularVelocity);
|
||||
}
|
||||
else
|
||||
physObj->SetAngularVelocity(Nz::Vector3f::Zero());
|
||||
*/
|
||||
}
|
||||
}
|
||||
|
||||
SystemIndex PhysicsSystem2D::systemIndex;
|
||||
}
|
||||
@@ -6,6 +6,7 @@
|
||||
#include <Nazara/Physics3D/RigidBody3D.hpp>
|
||||
#include <NDK/Components/CollisionComponent3D.hpp>
|
||||
#include <NDK/Components/NodeComponent.hpp>
|
||||
#include <NDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <NDK/Components/PhysicsComponent3D.hpp>
|
||||
|
||||
namespace Ndk
|
||||
@@ -27,6 +28,7 @@ namespace Ndk
|
||||
{
|
||||
Requires<NodeComponent>();
|
||||
RequiresAny<CollisionComponent3D, PhysicsComponent3D>();
|
||||
Excludes<PhysicsComponent2D>();
|
||||
}
|
||||
|
||||
/*!
|
||||
@@ -90,7 +92,7 @@ namespace Ndk
|
||||
NodeComponent& node = entity->GetComponent<NodeComponent>();
|
||||
PhysicsComponent3D& phys = entity->GetComponent<PhysicsComponent3D>();
|
||||
|
||||
Nz::RigidBody3D& physObj = phys.GetPhysObject();
|
||||
Nz::RigidBody3D& physObj = phys.GetRigidBody();
|
||||
node.SetRotation(physObj.GetRotation(), Nz::CoordSys_Global);
|
||||
node.SetPosition(physObj.GetPosition(), Nz::CoordSys_Global);
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include <NDK/World.hpp>
|
||||
#include <Nazara/Core/Error.hpp>
|
||||
#include <NDK/BaseComponent.hpp>
|
||||
#include <NDK/Systems/PhysicsSystem2D.hpp>
|
||||
#include <NDK/Systems/PhysicsSystem3D.hpp>
|
||||
#include <NDK/Systems/VelocitySystem.hpp>
|
||||
|
||||
@@ -40,6 +41,7 @@ namespace Ndk
|
||||
|
||||
void World::AddDefaultSystems()
|
||||
{
|
||||
AddSystem<PhysicsSystem2D>();
|
||||
AddSystem<PhysicsSystem3D>();
|
||||
AddSystem<VelocitySystem>();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user