Physics2D tests (#129)
* Quaternion: Fix singularity on Z axis when converting to euler angles * CollisionComponent2D: Add method to retrieve AABB * Collider2D: Fix constructor for Box with Vector2 * Physics2D: Fix rotation (Chipmunk works with radian and Nazara degrees) and copy constructor of RigidBody2D * Colider2D: Add New for convex and tests for the new classes
This commit is contained in:
committed by
Jérôme Leclercq
parent
9806231b5c
commit
41a1b5d493
@@ -5,19 +5,19 @@
|
||||
#include <NDK/Components/PhysicsComponent2D.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
|
||||
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;
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
Ndk::NodeComponent& nodeComponent = entity->AddComponent<Ndk::NodeComponent>();
|
||||
|
||||
Nz::Vector2f position(2.f, 3.f);
|
||||
nodeComponent.SetPosition(position);
|
||||
Nz::Rectf aabb(0.f, 0.f, 16.f, 18.f);
|
||||
Nz::BoxCollider2DRef collisionBox = Nz::BoxCollider2D::New(aabb);
|
||||
Ndk::CollisionComponent2D& collisionComponent = entity->AddComponent<Ndk::CollisionComponent2D>(collisionBox);
|
||||
Ndk::PhysicsComponent2D& physicsComponent = entity->AddComponent<Ndk::PhysicsComponent2D>();
|
||||
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>();
|
||||
|
||||
WHEN("We update the world")
|
||||
{
|
||||
@@ -26,9 +26,123 @@ SCENARIO("PhysicsSystem2D", "[NDK][PHYSICSSYSTEM2D]")
|
||||
THEN("Entity should have correct bounding box")
|
||||
{
|
||||
REQUIRE(nodeComponent.GetPosition() == position);
|
||||
aabb.Translate(position);
|
||||
REQUIRE(physicsComponent.GetAABB() == aabb);
|
||||
movingAABB.Translate(position);
|
||||
REQUIRE(physicsComponent2D.GetAABB() == movingAABB);
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We make it collide with a wall")
|
||||
{
|
||||
int rawDistance = 3;
|
||||
Nz::Vector2f distance(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 moved 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;
|
||||
|
||||
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>();
|
||||
|
||||
WHEN("We make rotate our entity")
|
||||
{
|
||||
float angularSpeed = Nz::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() == Approx(Nz::FromDegrees(90.f)));
|
||||
CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Approx(Nz::FromDegrees(90.f)));
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We put a force on it")
|
||||
{
|
||||
float stepSize = world.GetSystem<Ndk::PhysicsSystem2D>().GetWorld().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;
|
||||
|
||||
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>();
|
||||
|
||||
WHEN("We make rotate our entity")
|
||||
{
|
||||
float angularSpeed = Nz::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() == Approx(Nz::FromDegrees(90.f)));
|
||||
CHECK(nodeComponent.GetPosition() == position);
|
||||
CHECK(nodeComponent.GetRotation().ToEulerAngles().roll == Approx(Nz::FromDegrees(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);
|
||||
Nz::BoxCollider2DRef collisionBox = Nz::BoxCollider2D::New(AABB);
|
||||
entity->AddComponent<Ndk::CollisionComponent2D>(collisionBox);
|
||||
return entity;
|
||||
}
|
||||
|
||||
@@ -1,13 +1,11 @@
|
||||
#include <NDK/Systems/RenderSystem.hpp>
|
||||
#include <NDK/World.hpp>
|
||||
#include <NDK/Components/CameraComponent.hpp>
|
||||
#include <NDK/Components/GraphicsComponent.hpp>
|
||||
#include <NDK/Components/LightComponent.hpp>
|
||||
#include <NDK/Components/NodeComponent.hpp>
|
||||
#include <NDK/Components/ParticleGroupComponent.hpp>
|
||||
#include <NDK/Components.hpp>
|
||||
#include <Nazara/Graphics/Sprite.hpp>
|
||||
#include <Catch/catch.hpp>
|
||||
|
||||
void CompareAABB(const Nz::Rectf& aabb, const Nz::BoundingVolumef& boundingVolume);
|
||||
|
||||
SCENARIO("RenderSystem", "[NDK][RenderSystem]")
|
||||
{
|
||||
GIVEN("A world with a camera, a drawable, a light and some particles")
|
||||
@@ -41,4 +39,79 @@ SCENARIO("RenderSystem", "[NDK][RenderSystem]")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GIVEN("A world with 2D coordinates (upper-left) and an entity with graphics and physics")
|
||||
{
|
||||
Ndk::World world;
|
||||
world.GetSystem<Ndk::RenderSystem>().SetGlobalUp(Nz::Vector3f::Down());
|
||||
const Ndk::EntityHandle& entity = world.CreateEntity();
|
||||
|
||||
Nz::Vector2f position(3.f, 4.f);
|
||||
Ndk::NodeComponent& nodeComponent = entity->AddComponent<Ndk::NodeComponent>();
|
||||
nodeComponent.SetPosition(position);
|
||||
|
||||
Nz::Vector2f dimensions(1.f, 2.f);
|
||||
Ndk::GraphicsComponent& graphicsComponent = entity->AddComponent<Ndk::GraphicsComponent>();
|
||||
Nz::SpriteRef sprite = Nz::Sprite::New();
|
||||
sprite->SetSize(dimensions);
|
||||
graphicsComponent.Attach(sprite);
|
||||
|
||||
Nz::Rectf aabb(Nz::Vector2f::Zero(), dimensions);
|
||||
Nz::BoxCollider2DRef boxCollider2D = Nz::BoxCollider2D::New(aabb);
|
||||
entity->AddComponent<Ndk::CollisionComponent2D>(boxCollider2D);
|
||||
Ndk::PhysicsComponent2D& physicsComponent2D = entity->AddComponent<Ndk::PhysicsComponent2D>();
|
||||
|
||||
world.Update(1.f);
|
||||
|
||||
WHEN("We move it")
|
||||
{
|
||||
Nz::Vector2f velocity = Nz::Vector2f::UnitY();
|
||||
physicsComponent2D.SetVelocity(velocity);
|
||||
world.Update(1.f);
|
||||
|
||||
THEN("Graphics and physics should be synchronised")
|
||||
{
|
||||
CHECK(nodeComponent.GetPosition() == position + velocity);
|
||||
CHECK(physicsComponent2D.GetAABB() == aabb.Translate(position + velocity));
|
||||
CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetBoundingVolume());
|
||||
}
|
||||
}
|
||||
|
||||
WHEN("We set an angular velocity")
|
||||
{
|
||||
float angularSpeed = Nz::FromDegrees(90.f);
|
||||
physicsComponent2D.SetAngularVelocity(angularSpeed);
|
||||
world.Update(1.f);
|
||||
|
||||
THEN("We expect those to be true")
|
||||
{
|
||||
CHECK(physicsComponent2D.GetAngularVelocity() == Approx(angularSpeed));
|
||||
CHECK(physicsComponent2D.GetRotation() == Approx(angularSpeed));
|
||||
CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(1.f, 4.f, 2.f, 1.f));
|
||||
CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetBoundingVolume());
|
||||
|
||||
world.Update(1.f);
|
||||
CHECK(physicsComponent2D.GetRotation() == Approx(2.f * angularSpeed));
|
||||
CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(2.f, 2.f, 1.f, 2.f));
|
||||
CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetBoundingVolume());
|
||||
|
||||
world.Update(1.f);
|
||||
CHECK(physicsComponent2D.GetRotation() == Approx(3.f * angularSpeed));
|
||||
CHECK(physicsComponent2D.GetAABB() == Nz::Rectf(3.f, 3.f, 2.f, 1.f));
|
||||
CompareAABB(physicsComponent2D.GetAABB(), graphicsComponent.GetBoundingVolume());
|
||||
|
||||
world.Update(1.f);
|
||||
CHECK(physicsComponent2D.GetRotation() == Approx(4.f * angularSpeed));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CompareAABB(const Nz::Rectf& aabb, const Nz::BoundingVolumef& boundingVolume)
|
||||
{
|
||||
Nz::Boxf box = boundingVolume.aabb;
|
||||
CHECK(aabb.x == Approx(box.x));
|
||||
CHECK(aabb.y == Approx(box.y));
|
||||
CHECK(aabb.width == Approx(box.width));
|
||||
CHECK(aabb.height == Approx(box.height));
|
||||
}
|
||||
Reference in New Issue
Block a user