9.22 routine backup
This commit is contained in:
@ -14,56 +14,174 @@
|
||||
// You should have received a copy of the GNU General Public License
|
||||
// along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include <IAEngine/IAEngine.hpp>
|
||||
#include <IAEngine/Physics/Physics.hpp>
|
||||
|
||||
#include <IAEngine/Nodes/Node.hpp>
|
||||
|
||||
#include <box2d/box2d.h>
|
||||
|
||||
#include <map>
|
||||
|
||||
namespace ia::iae
|
||||
{
|
||||
Vector<BoxCollider2DComponent *> g_colliders;
|
||||
struct Body
|
||||
{
|
||||
struct Collider
|
||||
{
|
||||
b2ShapeId ShapeId{};
|
||||
BoxCollider2DComponent *ColliderComponent{};
|
||||
};
|
||||
|
||||
b2BodyId BodyId{.world0 = 0xFFFF};
|
||||
PhysicsBody2DComponent *BodyComponent;
|
||||
Vector<Collider> Colliders;
|
||||
};
|
||||
|
||||
b2WorldId g_worldId{};
|
||||
Vector<Body> g_bodies;
|
||||
std::map<Handle, BoxCollider2DComponent*> g_shapeColliders;
|
||||
|
||||
INLINE Handle ShapeIdToHandle(IN b2ShapeId id)
|
||||
{
|
||||
return *reinterpret_cast<Handle*>(&id.index1);
|
||||
}
|
||||
|
||||
VOID Physics::Initialize()
|
||||
{
|
||||
auto worldDef = b2DefaultWorldDef();
|
||||
worldDef.gravity = b2Vec2{0.0f, 1000.0f};
|
||||
g_worldId = b2CreateWorld(&worldDef);
|
||||
}
|
||||
|
||||
VOID Physics::Terminate()
|
||||
{
|
||||
}
|
||||
|
||||
INLINE BOOL IsIntersectingH(IN CONST glm::vec4 &shape, IN FLOAT32 x)
|
||||
{
|
||||
return (x >= shape.x) && (x <= shape.z);
|
||||
}
|
||||
|
||||
INLINE BOOL IsIntersectingV(IN CONST glm::vec4 &shape, IN FLOAT32 y)
|
||||
{
|
||||
return (y >= shape.y) && (y <= shape.w);
|
||||
b2DestroyWorld(g_worldId);
|
||||
}
|
||||
|
||||
VOID Physics::Update()
|
||||
{
|
||||
for (SIZE_T i = 0; i < g_colliders.size(); i++)
|
||||
CONSTEXPR FLOAT32 TIME_STEP = 1.0f / 60.0f;
|
||||
CONSTEXPR INT32 SUB_STEP_COUNT = 4;
|
||||
b2World_Step(g_worldId, TIME_STEP, SUB_STEP_COUNT);
|
||||
|
||||
// Process contact events
|
||||
const auto contactEvents = b2World_GetContactEvents(g_worldId);
|
||||
for(INT32 i = 0; i < contactEvents.beginCount; i++)
|
||||
{
|
||||
for (SIZE_T j = i + 1; j < g_colliders.size(); j++)
|
||||
const auto& shapeA = g_shapeColliders[ShapeIdToHandle(contactEvents.beginEvents[i].shapeIdA)];
|
||||
const auto& shapeB = g_shapeColliders[ShapeIdToHandle(contactEvents.beginEvents[i].shapeIdB)];
|
||||
shapeA->OnCollisionEnter(shapeB->GetNode());
|
||||
shapeB->OnCollisionEnter(shapeA->GetNode());
|
||||
}
|
||||
for(INT32 i = 0; i < contactEvents.endCount; i++)
|
||||
{
|
||||
const auto& shapeA = g_shapeColliders[ShapeIdToHandle(contactEvents.endEvents[i].shapeIdA)];
|
||||
const auto& shapeB = g_shapeColliders[ShapeIdToHandle(contactEvents.endEvents[i].shapeIdB)];
|
||||
shapeA->OnCollisionExit(shapeB->GetNode());
|
||||
shapeB->OnCollisionExit(shapeA->GetNode());
|
||||
}
|
||||
|
||||
// Process sensor events
|
||||
const auto sensorEvents = b2World_GetSensorEvents(g_worldId);
|
||||
for(INT32 i = 0; i < sensorEvents.beginCount; i++)
|
||||
{
|
||||
const auto& shapeA = g_shapeColliders[ShapeIdToHandle(sensorEvents.beginEvents[i].sensorShapeId)];
|
||||
const auto& shapeB = g_shapeColliders[ShapeIdToHandle(sensorEvents.beginEvents[i].visitorShapeId)];
|
||||
shapeA->OnCollisionEnter(shapeB->GetNode());
|
||||
shapeB->OnCollisionEnter(shapeA->GetNode());
|
||||
}
|
||||
for(INT32 i = 0; i < sensorEvents.endCount; i++)
|
||||
{
|
||||
const auto& shapeA = g_shapeColliders[ShapeIdToHandle(sensorEvents.endEvents[i].sensorShapeId)];
|
||||
const auto& shapeB = g_shapeColliders[ShapeIdToHandle(sensorEvents.endEvents[i].visitorShapeId)];
|
||||
shapeA->OnCollisionExit(shapeB->GetNode());
|
||||
shapeB->OnCollisionExit(shapeA->GetNode());
|
||||
}
|
||||
}
|
||||
|
||||
VOID Physics::Bake()
|
||||
{
|
||||
for (auto &b : g_bodies)
|
||||
{
|
||||
const auto pos = b.BodyComponent->GetNode()->GetPosition();
|
||||
|
||||
auto bodyDef = b2DefaultBodyDef();
|
||||
if (b.BodyComponent->IsDynamic())
|
||||
bodyDef.type = b2_dynamicBody;
|
||||
bodyDef.position = b2Vec2{pos.x, pos.y};
|
||||
if (b.BodyId.world0 != 0xFFFF)
|
||||
b2DestroyBody(b.BodyId);
|
||||
b.BodyId = b2CreateBody(g_worldId, &bodyDef);
|
||||
|
||||
for (auto &c : b.Colliders)
|
||||
{
|
||||
const auto boxA = g_colliders[i]->AbsoluteShape();
|
||||
const auto boxB = g_colliders[j]->AbsoluteShape();
|
||||
const auto nodeA = g_colliders[i]->GetNode();
|
||||
|
||||
if(IsIntersectingH(boxB, boxA.z) && (IsIntersectingV(boxB, boxA.y) || IsIntersectingV(boxB, boxA.w)))
|
||||
nodeA->SetLocalPosition(nodeA->GetLocalPosition() + glm::vec2(-boxA.z + boxB.x, 0));
|
||||
else if(IsIntersectingH(boxB, boxA.x) && (IsIntersectingV(boxB, boxA.y) || IsIntersectingV(boxB, boxA.w)))
|
||||
nodeA->SetLocalPosition(nodeA->GetLocalPosition() + glm::vec2(-boxA.x + boxB.z, 0));
|
||||
else if(IsIntersectingV(boxB, boxA.w) && (IsIntersectingH(boxB, boxA.x) || IsIntersectingH(boxB, boxA.z)))
|
||||
nodeA->SetLocalPosition(nodeA->GetLocalPosition() + glm::vec2(0, -boxA.w + boxB.y));
|
||||
else if(IsIntersectingV(boxB, boxA.y) && (IsIntersectingH(boxB, boxA.x) || IsIntersectingH(boxB, boxA.z)))
|
||||
nodeA->SetLocalPosition(nodeA->GetLocalPosition() + glm::vec2(0, -boxA.y + boxB.w));
|
||||
const auto rect = c.ColliderComponent->Rect();
|
||||
const auto halfW = rect.z/2.0f;
|
||||
const auto halfH = rect.w/2.0f;
|
||||
const auto box = b2MakeOffsetBox(halfW, halfH, {rect.x, rect.y - halfH/2.0f}, b2MakeRot(0));
|
||||
auto boxShapeDef = b2DefaultShapeDef();
|
||||
boxShapeDef.density = 1.0f;
|
||||
boxShapeDef.isSensor = c.ColliderComponent->IsTrigger();
|
||||
boxShapeDef.enableContactEvents = c.ColliderComponent->CollisionsEnabled();
|
||||
boxShapeDef.enableSensorEvents = boxShapeDef.enableContactEvents;
|
||||
c.ShapeId = b2CreatePolygonShape(b.BodyId, &boxShapeDef, &box);
|
||||
g_shapeColliders[ShapeIdToHandle(c.ShapeId)] = c.ColliderComponent;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID Physics::AddCollider(IN BoxCollider2DComponent *collider)
|
||||
Handle Physics::AddBody(IN PhysicsBody2DComponent *body)
|
||||
{
|
||||
g_colliders.pushBack(collider);
|
||||
g_bodies.pushBack(Body{
|
||||
.BodyComponent = body,
|
||||
});
|
||||
return g_bodies.size() - 1;
|
||||
}
|
||||
|
||||
Handle Physics::AddColliderToBody(IN Handle bodyHandle, IN BoxCollider2DComponent *collider)
|
||||
{
|
||||
auto &b = g_bodies[bodyHandle];
|
||||
b.Colliders.pushBack(Body::Collider{
|
||||
.ColliderComponent = collider,
|
||||
});
|
||||
return b.Colliders.size() - 1;
|
||||
}
|
||||
|
||||
FLOAT32 Physics::GetBodyRotation(IN Handle handle)
|
||||
{
|
||||
const auto &b = g_bodies[handle];
|
||||
return acosf(b2Body_GetRotation(b.BodyId).c);
|
||||
}
|
||||
|
||||
glm::vec2 Physics::GetBodyPosition(IN Handle handle)
|
||||
{
|
||||
const auto &b = g_bodies[handle];
|
||||
const auto v = b2Body_GetPosition(b.BodyId);
|
||||
return {v.x, v.y};
|
||||
}
|
||||
|
||||
VOID Physics::ApplyBodyForce(IN Handle handle, IN glm::vec2 force)
|
||||
{
|
||||
const auto &b = g_bodies[handle];
|
||||
b2Body_ApplyForce(b.BodyId, {force.x, force.y}, b2Body_GetLocalCenterOfMass(b.BodyId), true);
|
||||
}
|
||||
|
||||
VOID Physics::SetBodyVelocity(IN Handle handle, IN glm::vec2 v)
|
||||
{
|
||||
const auto &b = g_bodies[handle];
|
||||
b2Body_SetLinearVelocity(b.BodyId, {v.x, v.y});
|
||||
}
|
||||
|
||||
VOID Physics::SetBodyVelocityX(IN Handle handle, IN FLOAT32 v)
|
||||
{
|
||||
const auto &b = g_bodies[handle];
|
||||
b2Body_SetLinearVelocity(b.BodyId, {v, b2Body_GetLinearVelocity(b.BodyId).y});
|
||||
}
|
||||
|
||||
VOID Physics::SetBodyVelocityY(IN Handle handle, IN FLOAT32 v)
|
||||
{
|
||||
const auto &b = g_bodies[handle];
|
||||
b2Body_SetLinearVelocity(b.BodyId, {b2Body_GetLinearVelocity(b.BodyId).x, v});
|
||||
}
|
||||
} // namespace ia::iae
|
||||
Reference in New Issue
Block a user