From 4fa64f456c4a3f2dd64473657f648728fcdb3253 Mon Sep 17 00:00:00 2001 From: eduardodoria Date: Wed, 16 Aug 2023 14:33:19 -0300 Subject: [PATCH] Added basic Box2D integration --- engine/core/component/Body2DComponent.h | 12 +- engine/core/object/Object.cpp | 6 + engine/core/object/Object.h | 2 + engine/core/script/binding/CoreClassesLua.cpp | 2 +- engine/core/subsystem/PhysicsSystem.cpp | 136 +++++++++++++++++- engine/core/subsystem/PhysicsSystem.h | 12 ++ 6 files changed, 161 insertions(+), 9 deletions(-) diff --git a/engine/core/component/Body2DComponent.h b/engine/core/component/Body2DComponent.h index 4b809cc0..61c7fc36 100644 --- a/engine/core/component/Body2DComponent.h +++ b/engine/core/component/Body2DComponent.h @@ -4,9 +4,10 @@ #include "Supernova.h" #define MAX_SHAPES 10 -#define MAX_SHAPE_VERTICES 30 class b2Body; +class b2Shape; +class b2Fixture; namespace Supernova{ @@ -19,15 +20,16 @@ namespace Supernova{ struct CollisionShape2D{ CollisionShape2DType type = CollisionShape2DType::POLYGON; - float radius = 0; - float center = 0; - Vector2 vertices[MAX_SHAPE_VERTICES]; + + b2Shape* shape = NULL; + b2Fixture* fixture = NULL; }; struct Body2DComponent{ - b2Body* groundBody = NULL; + b2Body* body = NULL; CollisionShape2D shapes[MAX_SHAPES]; + int numShapes = 0; }; } diff --git a/engine/core/object/Object.cpp b/engine/core/object/Object.cpp index b630d5e8..dd4fe92c 100644 --- a/engine/core/object/Object.cpp +++ b/engine/core/object/Object.cpp @@ -5,6 +5,7 @@ #include "Object.h" #include "subsystem/RenderSystem.h" +#include "subsystem/PhysicsSystem.h" using namespace Supernova; @@ -199,3 +200,8 @@ void Object::updateTransform(){ scene->getSystem()->updateTransform(transform); } + +void Object::createRectangularBody(float width, float height){ + scene->getSystem()->createBody2D(entity); + scene->getSystem()->addRectangleShape2D(entity, width, height); +} diff --git a/engine/core/object/Object.h b/engine/core/object/Object.h index dcec1eb5..8934bbaa 100644 --- a/engine/core/object/Object.h +++ b/engine/core/object/Object.h @@ -59,6 +59,8 @@ namespace Supernova{ void setModelMatrix(Matrix4 modelMatrix); void updateTransform(); + + void createRectangularBody(float width, float height); }; } diff --git a/engine/core/script/binding/CoreClassesLua.cpp b/engine/core/script/binding/CoreClassesLua.cpp index 1674ef47..2990ca6f 100644 --- a/engine/core/script/binding/CoreClassesLua.cpp +++ b/engine/core/script/binding/CoreClassesLua.cpp @@ -456,7 +456,7 @@ void LuaBinding::registerCoreClasses(lua_State *L){ .beginClass("System") .addStaticFunction("getScreenWidth", [] () { return System::instance().getScreenWidth(); }) .addStaticFunction("getScreenHeight", [] () { return System::instance().getScreenHeight(); }) - .addStaticFunction("showVirtualKeyboard", [] () { System::instance().showVirtualKeyboard(); }) + .addStaticFunction("showVirtualKeyboard", [] (std::wstring text) { System::instance().showVirtualKeyboard(text); }) .addStaticFunction("hideVirtualKeyboard", [] () { System::instance().hideVirtualKeyboard(); }) .addStaticFunction("isFullscreen", [] () { return System::instance().isFullscreen(); }) .addStaticFunction("requestFullscreen", [] () { System::instance().requestFullscreen(); }) diff --git a/engine/core/subsystem/PhysicsSystem.cpp b/engine/core/subsystem/PhysicsSystem.cpp index d78a79f7..75735057 100644 --- a/engine/core/subsystem/PhysicsSystem.cpp +++ b/engine/core/subsystem/PhysicsSystem.cpp @@ -4,6 +4,7 @@ #include "PhysicsSystem.h" #include "Scene.h" +#include "util/Angle.h" #include "box2d.h" @@ -15,23 +16,148 @@ PhysicsSystem::PhysicsSystem(Scene* scene): SubSystem(scene){ signature.set(scene->getComponentType()); this->scene = scene; + + this->world2D = NULL; } PhysicsSystem::~PhysicsSystem(){ + if (world2D){ + delete world2D; + world2D = NULL; + } +} + +void PhysicsSystem::createBody2D(Entity entity){ + Signature signature = scene->getSignature(entity); + + if (!signature.test(scene->getComponentType())){ + scene->addComponent(entity, {}); + } +} + +void PhysicsSystem::addRectangleShape2D(Entity entity, float width, float height){ + Body2DComponent* body = scene->findComponent(entity); + + if (body){ + if (body->numShapes < MAX_SHAPES){ + body->shapes[body->numShapes].shape = new b2PolygonShape(); + body->shapes[body->numShapes].type = CollisionShape2DType::POLYGON; + + ((b2PolygonShape*)body->shapes[body->numShapes].shape)->SetAsBox(width, height); + + body->numShapes++; + }else{ + Log::error("Cannot add more shapes in this body, please increase value MAX_SHAPES"); + } + } +} + +bool PhysicsSystem::loadBody2D(Body2DComponent& body){ + if (world2D && !body.body){ + b2BodyDef bodyDef; + bodyDef.position.Set(0.0f, 0.0f); + bodyDef.angle = 0.0f; + bodyDef.type = b2_dynamicBody; + + body.body = world2D->CreateBody(&bodyDef); + + for (int i = 0; i < body.numShapes; i++){ + body.shapes[i].fixture = body.body->CreateFixture(body.shapes[i].shape, 1.0f); + } + + return true; + } + + return false; } +void PhysicsSystem::destroyBody2D(Body2DComponent& body){ + // When a world leaves scope or is deleted by calling delete on a pointer + // all the memory reserved for bodies, fixtures, and joints is freed + if (world2D && body.body){ + for (int i = 0; i < body.numShapes; i++){ + body.body->DestroyFixture(body.shapes[i].fixture); + + body.shapes[i].shape = NULL; + body.shapes[i].fixture = NULL; + } + + world2D->DestroyBody(body.body); + + body.body = NULL; + } +} void PhysicsSystem::load(){ - b2Vec2 gravity(0.0f, -10.0f); - b2World world(gravity); + if (!world2D){ + b2Vec2 gravity(0.0f, -10.0f); + world2D = new b2World(gravity); + } } void PhysicsSystem::destroy(){ - + if (world2D){ + delete world2D; + world2D = NULL; + } } void PhysicsSystem::update(double dt){ + auto bodies2d = scene->getComponentArray(); + for (int i = 0; i < bodies2d->size(); i++){ + Body2DComponent& body = bodies2d->getComponentFromIndex(i); + Entity entity = bodies2d->getEntity(i); + Signature signature = scene->getSignature(entity); + + bool isNewBody = loadBody2D(body); + + if (signature.test(scene->getComponentType())){ + Transform& transform = scene->getComponent(entity); + + if (isNewBody || transform.needUpdate){ + float scale = 1.0; + + b2Vec2 bPosition(transform.worldPosition.x / scale, transform.worldPosition.y / scale); + body.body->SetTransform(bPosition, transform.worldRotation.getRoll()); + } + } + } + + if (bodies2d->size() > 0){ + int32 velocityIterations = 6; + int32 positionIterations = 2; + + world2D->Step(dt, velocityIterations, positionIterations); + } + + for (int i = 0; i < bodies2d->size(); i++){ + Body2DComponent& body = bodies2d->getComponentFromIndex(i); + Entity entity = bodies2d->getEntity(i); + Signature signature = scene->getSignature(entity); + + b2Vec2 position = body.body->GetPosition(); + float angle = body.body->GetAngle(); + if (signature.test(scene->getComponentType())){ + Transform& transform = scene->getComponent(entity); + + float scale = 1.0; + + Vector3 nPosition = Vector3(position.x * scale, position.y * scale, transform.worldPosition.z); + if (transform.position != nPosition){ + transform.position = nPosition; + transform.needUpdate = true; + } + + if (transform.worldRotation.getRoll() != angle){ + Quaternion rotation; + rotation.fromAngle(Angle::radToDefault(angle)); + + transform.rotation = rotation; + transform.needUpdate = true; + } + } + } } void PhysicsSystem::draw(){ @@ -39,5 +165,9 @@ void PhysicsSystem::draw(){ } void PhysicsSystem::entityDestroyed(Entity entity){ + Signature signature = scene->getSignature(entity); + if (signature.test(scene->getComponentType())){ + destroyBody2D(scene->getComponent(entity)); + } } diff --git a/engine/core/subsystem/PhysicsSystem.h b/engine/core/subsystem/PhysicsSystem.h index fe90e84a..90d699e2 100644 --- a/engine/core/subsystem/PhysicsSystem.h +++ b/engine/core/subsystem/PhysicsSystem.h @@ -6,15 +6,27 @@ #define PHYSICSSYSTEM_H #include "SubSystem.h" +#include "component/Body2DComponent.h" + +class b2World; namespace Supernova{ class PhysicsSystem : public SubSystem { + private: + b2World* world2D; + public: PhysicsSystem(Scene* scene); virtual ~PhysicsSystem(); + void createBody2D(Entity entity); + void addRectangleShape2D(Entity entity, float width, float height); + + bool loadBody2D(Body2DComponent& body); + void destroyBody2D(Body2DComponent& body); + virtual void load(); virtual void destroy(); virtual void update(double dt);