retrieval of collision events
This commit is contained in:
parent
52b972167a
commit
3a2dfb0833
@ -75,166 +75,33 @@ end
|
|||||||
local useDistance = 6
|
local useDistance = 6
|
||||||
local pullDistance = useDistance * 4
|
local pullDistance = useDistance * 4
|
||||||
|
|
||||||
-- on tick
|
local function tickFlashlight( transform, inputs )
|
||||||
ent:bind( "tick", function(self)
|
-- update light position
|
||||||
local inControl = scene:globalFindByName("Gui: Menu"):uid() == 0
|
|
||||||
|
|
||||||
local keyE = inputs.key("E") or inputs.key("R_Y")
|
|
||||||
local keyF = inputs.key("F")
|
|
||||||
local mouse1 = inputs.key("Mouse1") or inputs.key("L_TRIGGER");
|
|
||||||
local mouse2 = inputs.key("Mouse2") or inputs.key("R_TRIGGER");
|
|
||||||
local mouse3 = inputs.key("Mouse3");
|
|
||||||
local wheel = inputs.analog("MouseWheel")
|
|
||||||
|
|
||||||
if not inControl then
|
|
||||||
keyE = false
|
|
||||||
keyF = false
|
|
||||||
mouse1 = false
|
|
||||||
mouse2 = false
|
|
||||||
mouse3 = false
|
|
||||||
wheel = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- eye transform
|
|
||||||
local flattenedTransform = nil
|
|
||||||
|
|
||||||
if fixedCamera then
|
|
||||||
flattenedTransform = transform:flatten()
|
|
||||||
else
|
|
||||||
flattenedTransform = cameraTransform:flatten()
|
|
||||||
end
|
|
||||||
|
|
||||||
-- toggle flashlight
|
|
||||||
if light.enabled then
|
if light.enabled then
|
||||||
local center = flattenedTransform.position
|
local center = transform.position
|
||||||
local direction = flattenedTransform.forward * 8
|
local direction = transform.forward * 8
|
||||||
|
|
||||||
local offset = 0.25
|
local offset = 0.25
|
||||||
local _, depth = physicsBody:rayCast( center, direction )
|
local _, depth = physicsBody:rayCast(center, direction)
|
||||||
if depth >= 0.5 then
|
depth = math.clamp(depth, 0, 0.5)
|
||||||
depth = 0.5
|
|
||||||
elseif depth < 0 then
|
|
||||||
depth = 0.5
|
|
||||||
end
|
|
||||||
light.transform.position = center + direction * (depth - offset)
|
light.transform.position = center + direction * (depth - offset)
|
||||||
end
|
end
|
||||||
|
|
||||||
if timers.flashlight:elapsed() > 0.5 and keyF then
|
-- toggle
|
||||||
|
if timers.flashlight:elapsed() > 0.5 and inputs["F"] then
|
||||||
timers.flashlight:reset()
|
timers.flashlight:reset()
|
||||||
|
light.enabled = (light.metadata.power ~= light.power)
|
||||||
if light.metadata.power ~= light.power then
|
light.metadata.power = light.enabled and light.power or 0
|
||||||
light.metadata.power = light.power
|
|
||||||
light.enabled = true
|
|
||||||
else
|
|
||||||
light.metadata.power = 0
|
|
||||||
light.enabled = false
|
|
||||||
end
|
|
||||||
|
|
||||||
playSound("flashlight")
|
playSound("flashlight")
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- fire use ray
|
local function onUse( payload )
|
||||||
if timers.use:elapsed() > 0.5 and keyE and inControl then
|
|
||||||
timers.use:reset()
|
|
||||||
|
|
||||||
local center = flattenedTransform.position
|
|
||||||
local direction = flattenedTransform.forward * useDistance
|
|
||||||
|
|
||||||
local prop, depth = physicsBody:rayCast( center, direction )
|
|
||||||
local payload = {
|
|
||||||
user = ent:uid(),
|
|
||||||
uid = prop and prop:uid() or 0,
|
|
||||||
depth = depth,
|
|
||||||
}
|
|
||||||
if prop then
|
|
||||||
prop:lazyCallHook("entity:Use.%UID%", payload)
|
|
||||||
end
|
|
||||||
ent:lazyCallHook("entity:Use.%UID%", payload)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- update HOLP
|
|
||||||
if heldObject.uid == 0 then
|
|
||||||
if mouse2 then
|
|
||||||
--[[
|
|
||||||
local center = transform.position + cameraTransform.position
|
|
||||||
local direction = transform.forward + Vector3f( 0, cameraTransform.forward.y, 0 )
|
|
||||||
direction = direction:normalize() * 4
|
|
||||||
]]
|
|
||||||
local center = flattenedTransform.position
|
|
||||||
local direction = flattenedTransform.forward * pullDistance
|
|
||||||
local prop, depth = physicsBody:rayCast( center, direction )
|
|
||||||
if depth >= 0 and prop and not string.matched( prop:name(), "/^worldspawn/" ) then
|
|
||||||
local heldObjectTransform = prop:getComponent("Transform")
|
|
||||||
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
|
||||||
|
|
||||||
local strength = 500
|
|
||||||
local distanceSquared = (heldObjectTransform.position - flattenedTransform.position):magnitude()
|
|
||||||
|
|
||||||
heldObjectPhysicsBody:applyImpulse( flattenedTransform.forward * -heldObjectPhysicsBody:getMass() * strength / distanceSquared )
|
|
||||||
if timers.physcannon:elapsed() > 1.0 then
|
|
||||||
timers.physcannon:reset()
|
|
||||||
|
|
||||||
playSound("phys_tooHeavy")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
|
|
||||||
if wheel ~= 0 then
|
|
||||||
heldObject.distance = heldObject.distance + (wheel / 120 * heldObject.scrollSpeed) * time.delta()
|
|
||||||
end
|
|
||||||
if mouse3 then
|
|
||||||
heldObject.rotate = not heldObject.rotate
|
|
||||||
end
|
|
||||||
|
|
||||||
local prop = entities.get( heldObject.uid )
|
|
||||||
local heldObjectTransform = prop:getComponent("Transform")
|
|
||||||
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
|
||||||
|
|
||||||
if mouse1 and timers.physcannon:elapsed() > 0.5 then
|
|
||||||
timers.physcannon:reset()
|
|
||||||
|
|
||||||
heldObject.uid = 0
|
|
||||||
heldObjectPhysicsBody:enableGravity(true)
|
|
||||||
heldObjectPhysicsBody:applyImpulse( flattenedTransform.forward * heldObjectPhysicsBody:getMass() * 50 )
|
|
||||||
|
|
||||||
playSound("phys_launch"..math.random(1,4))
|
|
||||||
else
|
|
||||||
if heldObject.rotate then
|
|
||||||
heldObjectTransform.orientation = Quaternion.lookAt( (heldObjectTransform.position - flattenedTransform.position):normalize(), transform.up )
|
|
||||||
end
|
|
||||||
|
|
||||||
local forward = flattenedTransform.forward * heldObject.distance --flattenedTransform.orientation:rotate( Vector3f(0,0,1) )
|
|
||||||
if heldObject.smoothSpeed ~= 0 then
|
|
||||||
local heldObjectFlattened = heldObjectTransform:flatten()
|
|
||||||
|
|
||||||
local target = flattenedTransform.position + forward
|
|
||||||
local offset = target - heldObjectFlattened.position
|
|
||||||
|
|
||||||
local stiffness = 15.0
|
|
||||||
local damping = 2.0
|
|
||||||
local currentVelocity = heldObjectPhysicsBody:getVelocity()
|
|
||||||
local mass = heldObjectPhysicsBody:getMass()
|
|
||||||
|
|
||||||
local springForce = offset * stiffness
|
|
||||||
local dampingForce = currentVelocity * -damping
|
|
||||||
|
|
||||||
heldObjectPhysicsBody:applyImpulse((springForce + dampingForce) * mass * time.delta())
|
|
||||||
else
|
|
||||||
heldObjectTransform.position = flattenedTransform.position + forward
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end )
|
|
||||||
-- on use
|
|
||||||
ent:addHook( "entity:Use.%UID%", function( payload )
|
|
||||||
if payload.user ~= ent:uid() then return end
|
|
||||||
|
|
||||||
local validUse = false
|
local validUse = false
|
||||||
|
-- not currently holding anything, and hit something
|
||||||
if heldObject.uid == 0 and payload.depth > 0 then
|
if heldObject.uid == 0 and payload.depth > 0 then
|
||||||
local prop = entities.get( payload.uid )
|
local prop = entities.get( payload.uid )
|
||||||
local propMetadata = prop:getComponent("Metadata")
|
local propMetadata = prop:getComponent("Metadata")
|
||||||
|
-- entity is holdable, pick it up
|
||||||
if propMetadata["holdable"] then
|
if propMetadata["holdable"] then
|
||||||
validUse = true
|
validUse = true
|
||||||
local heldObjectTransform = prop:getComponent("Transform")
|
local heldObjectTransform = prop:getComponent("Transform")
|
||||||
@ -246,11 +113,10 @@ ent:addHook( "entity:Use.%UID%", function( payload )
|
|||||||
|
|
||||||
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
||||||
heldObjectPhysicsBody:enableGravity(false)
|
heldObjectPhysicsBody:enableGravity(false)
|
||||||
|
|
||||||
print( prop:name() )
|
|
||||||
else
|
else
|
||||||
validUse = not string.matched( prop:name(), "/^worldspawn/" )
|
validUse = not string.matched( prop:name(), "/^worldspawn/" )
|
||||||
end
|
end
|
||||||
|
-- currently holding something, drop it
|
||||||
elseif heldObject.uid ~= 0 then
|
elseif heldObject.uid ~= 0 then
|
||||||
validUse = true
|
validUse = true
|
||||||
local prop = entities.get( heldObject.uid )
|
local prop = entities.get( heldObject.uid )
|
||||||
@ -263,9 +129,149 @@ ent:addHook( "entity:Use.%UID%", function( payload )
|
|||||||
heldObject.momentum = Vector3f(0,0,0)
|
heldObject.momentum = Vector3f(0,0,0)
|
||||||
end
|
end
|
||||||
|
|
||||||
if validUse then
|
playSound(validUse and "select" or "deny")
|
||||||
playSound("select")
|
end
|
||||||
else
|
|
||||||
playSound("deny")
|
local function tickUse( transform, inputs )
|
||||||
|
-- trigger use
|
||||||
|
if timers.use:elapsed() > 0.5 and inputs["E"] then
|
||||||
|
timers.use:reset()
|
||||||
|
local center = transform.position
|
||||||
|
local direction = transform.forward * useDistance
|
||||||
|
local prop, depth = physicsBody:rayCast(center, direction)
|
||||||
|
|
||||||
|
local payload = {
|
||||||
|
user = ent:uid(),
|
||||||
|
uid = prop and prop:uid() or 0,
|
||||||
|
depth = depth,
|
||||||
|
}
|
||||||
|
if prop then prop:lazyCallHook("entity:Use.%UID%", payload) end
|
||||||
|
ent:lazyCallHook("entity:Use.%UID%", payload)
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function tickGravGun( transform, inputs )
|
||||||
|
-- not holding anything
|
||||||
|
if heldObject.uid == 0 then
|
||||||
|
-- try and launch object in sights
|
||||||
|
if inputs["mouse2"] then
|
||||||
|
local center = transform.position
|
||||||
|
local direction = transform.forward * pullDistance
|
||||||
|
local prop, depth = physicsBody:rayCast( center, direction )
|
||||||
|
if depth >= 0 and prop and not string.matched( prop:name(), "/^worldspawn/" ) then
|
||||||
|
local heldObjectTransform = prop:getComponent("Transform")
|
||||||
|
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
||||||
|
|
||||||
|
local strength = 500
|
||||||
|
local distanceSquared = (heldObjectTransform.position - transform.position):magnitude()
|
||||||
|
|
||||||
|
heldObjectPhysicsBody:applyImpulse( transform.forward * -heldObjectPhysicsBody:getMass() * strength / distanceSquared )
|
||||||
|
if timers.physcannon:elapsed() > 1.0 then
|
||||||
|
timers.physcannon:reset()
|
||||||
|
|
||||||
|
playSound("phys_tooHeavy")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- holding something
|
||||||
|
else
|
||||||
|
-- adjust hold distance
|
||||||
|
if inputs["wheel"] ~= 0 then
|
||||||
|
heldObject.distance = heldObject.distance + (inputs["wheel"] / 120 * heldObject.scrollSpeed) * time.delta()
|
||||||
|
end
|
||||||
|
-- update rotation mode
|
||||||
|
if inputs["mouse3"] then
|
||||||
|
heldObject.rotate = not heldObject.rotate
|
||||||
|
end
|
||||||
|
|
||||||
|
local prop = entities.get( heldObject.uid )
|
||||||
|
local heldObjectTransform = prop:getComponent("Transform")
|
||||||
|
local heldObjectPhysicsBody = prop:getComponent("PhysicsBody")
|
||||||
|
|
||||||
|
-- launch held object
|
||||||
|
if inputs["mouse1"] and timers.physcannon:elapsed() > 0.5 then
|
||||||
|
timers.physcannon:reset()
|
||||||
|
|
||||||
|
heldObject.uid = 0
|
||||||
|
heldObjectPhysicsBody:enableGravity(true)
|
||||||
|
heldObjectPhysicsBody:applyImpulse( transform.forward * heldObjectPhysicsBody:getMass() * 50 )
|
||||||
|
|
||||||
|
playSound("phys_launch"..math.random(1,4))
|
||||||
|
else
|
||||||
|
-- update rotation
|
||||||
|
if heldObject.rotate then
|
||||||
|
heldObjectTransform.orientation = Quaternion.lookAt( (heldObjectTransform.position - transform.position):normalize(), transform.up )
|
||||||
|
end
|
||||||
|
|
||||||
|
-- move held object
|
||||||
|
local forward = transform.forward * heldObject.distance
|
||||||
|
if heldObject.smoothSpeed ~= 0 then
|
||||||
|
local heldObjectFlattened = heldObjectTransform:flatten()
|
||||||
|
|
||||||
|
local target = transform.position + forward
|
||||||
|
local offset = target - heldObjectFlattened.position
|
||||||
|
|
||||||
|
local stiffness = 15.0
|
||||||
|
local damping = 2.0
|
||||||
|
local currentVelocity = heldObjectPhysicsBody:getVelocity()
|
||||||
|
local mass = heldObjectPhysicsBody:getMass()
|
||||||
|
|
||||||
|
local springForce = offset * stiffness
|
||||||
|
local dampingForce = currentVelocity * -damping
|
||||||
|
|
||||||
|
heldObjectPhysicsBody:applyImpulse((springForce + dampingForce) * mass * time.delta())
|
||||||
|
else
|
||||||
|
heldObjectTransform.position = transform.position + forward
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- on tick
|
||||||
|
ent:bind( "tick", function(self)
|
||||||
|
local inControl = scene:globalFindByName("Gui: Menu"):uid() == 0
|
||||||
|
|
||||||
|
local inputs = {
|
||||||
|
E = inputs.key("E") or inputs.key("R_Y"),
|
||||||
|
F = inputs.key("F"),
|
||||||
|
mouse1 = inputs.key("Mouse1") or inputs.key("L_TRIGGER"),
|
||||||
|
mouse2 = inputs.key("Mouse2") or inputs.key("R_TRIGGER"),
|
||||||
|
mouse3 = inputs.key("Mouse3"),
|
||||||
|
wheel = inputs.analog("MouseWheel"),
|
||||||
|
}
|
||||||
|
|
||||||
|
if not inControl then
|
||||||
|
inputs["E"] = false
|
||||||
|
inputs["F"] = false
|
||||||
|
inputs["mouse1"] = false
|
||||||
|
inputs["mouse2"] = false
|
||||||
|
inputs["mouse3"] = false
|
||||||
|
inputs["wheel"] = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
-- eye transform
|
||||||
|
local flattenedTransform = fixedCamera and transform:flatten() or cameraTransform:flatten()
|
||||||
|
|
||||||
|
-- update flashlight
|
||||||
|
tickFlashlight( flattenedTransform, inputs )
|
||||||
|
|
||||||
|
-- update use
|
||||||
|
tickUse( flattenedTransform, inputs )
|
||||||
|
|
||||||
|
-- update HOLP
|
||||||
|
tickGravGun( flattenedTransform, inputs )
|
||||||
|
|
||||||
|
-- get collision events
|
||||||
|
--[[
|
||||||
|
local collisionEvents = physicsBody:getCollisionEvents()
|
||||||
|
for i, event in ipairs(collisionEvents) do
|
||||||
|
print( event.state, event.a, event.b, event.point, event.normal, event.impulse )
|
||||||
|
end
|
||||||
|
]]
|
||||||
|
end )
|
||||||
|
|
||||||
|
-- on use
|
||||||
|
ent:addHook( "entity:Use.%UID%", function( payload )
|
||||||
|
if payload.user ~= ent:uid() then return end
|
||||||
|
onUse( payload )
|
||||||
end )
|
end )
|
||||||
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
void solveConstraint( pod::Constraint& constraint, float dt );
|
void solveConstraint( pod::Constraint& constraint, float dt );
|
||||||
|
void solveConstraints( uf::stl::vector<pod::Constraint*>& constraint, float dt );
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace uf {
|
namespace uf {
|
||||||
|
|||||||
@ -4,19 +4,21 @@
|
|||||||
|
|
||||||
namespace impl {
|
namespace impl {
|
||||||
void bindManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt = 0 );
|
void bindManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt = 0 );
|
||||||
bool generateContactsGjk( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt );
|
bool generateManifoldGjk( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt );
|
||||||
bool generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt );
|
bool generateManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt );
|
||||||
void computeLocalContacts( pod::Manifold& manifold );
|
void computeLocalManifold( pod::Manifold& manifold );
|
||||||
bool similarContact( const pod::Contact& a, const pod::Contact& b, float distSqThreshold = 1.0e-2f, float normThreshold = 0.9f );
|
bool similarContact( const pod::Contact& a, const pod::Contact& b, float distSqThreshold = 1.0e-2f, float normThreshold = 0.9f );
|
||||||
void reduceContacts( pod::Manifold& manifold );
|
void reduceManifold( pod::Manifold& manifold );
|
||||||
void mergeContacts( pod::Manifold& manifold );
|
void mergeManifold( pod::Manifold& manifold );
|
||||||
void retrieveContacts( pod::Manifold& current, const pod::Manifold& previous, float distanceThreshold = 0.1f, float separationThreshold = 0.1f, float decay = 0.85f );
|
void retrieveManifold( pod::Manifold& current, const pod::Manifold& previous, float distanceThreshold = 0.1f, float separationThreshold = 0.1f, float decay = 0.85f );
|
||||||
void prepareManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>& cache, const uf::stl::vector<pod::Island>& islands, const uf::stl::vector<pod::PhysicsBody*>& bodies );
|
void prepareManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>& cache, const uf::stl::vector<pod::Island>& islands, const uf::stl::vector<pod::PhysicsBody*>& bodies );
|
||||||
void updateManifoldCache( const uf::stl::vector<pod::Manifold>& manifolds, uf::stl::unordered_map<size_t, pod::Manifold>& cache );
|
void updateManifoldCache( const uf::stl::vector<pod::Manifold>& manifolds, uf::stl::unordered_map<size_t, pod::Manifold>& cache );
|
||||||
void pruneManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>& cache );
|
void pruneManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>& cache );
|
||||||
void warmupContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Contact& c, float dt );
|
void warmupContact( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Contact& c, float dt );
|
||||||
void warmupManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Manifold& manifold, float dt );
|
void warmupManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Manifold& manifold, float dt );
|
||||||
|
|
||||||
void resolveManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt );
|
void resolveManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt );
|
||||||
void solveContacts( uf::stl::vector<pod::Manifold>& manifolds, float dt );
|
void solveManifold( uf::stl::vector<pod::Manifold>& manifolds, float dt );
|
||||||
|
|
||||||
|
void dispatchManifold( pod::Manifold& manifold, pod::CollisionEvent::events_t& events, pod::CollisionEvent::map_t& active, const pod::CollisionEvent::map_t& previous );
|
||||||
}
|
}
|
||||||
@ -55,6 +55,8 @@ namespace uf {
|
|||||||
void UF_API applyRotation( pod::PhysicsBody& body, const pod::Vector3f& axis, float angle );
|
void UF_API applyRotation( pod::PhysicsBody& body, const pod::Vector3f& axis, float angle );
|
||||||
|
|
||||||
pod::World& UF_API getWorld();
|
pod::World& UF_API getWorld();
|
||||||
|
const pod::CollisionEvent::events_t& UF_API getCollisionEvents( const pod::World& world );
|
||||||
|
pod::CollisionEvent::events_t UF_API getCollisionEvents( const pod::PhysicsBody& body );
|
||||||
|
|
||||||
pod::PhysicsBody& UF_API create( uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
|
pod::PhysicsBody& UF_API create( uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||||
pod::PhysicsBody& UF_API create( pod::World&, uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
|
pod::PhysicsBody& UF_API create( pod::World&, uf::Object&, float mass = 0.0f, const pod::Vector3f& = {} );
|
||||||
|
|||||||
@ -376,6 +376,25 @@ namespace pod {
|
|||||||
static constexpr float linearSleepEpsilon = 0.2f; // m/s
|
static constexpr float linearSleepEpsilon = 0.2f; // m/s
|
||||||
static constexpr float angularSleepEpsilon = 0.2f; // rad/s
|
static constexpr float angularSleepEpsilon = 0.2f; // rad/s
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class CollisionState {
|
||||||
|
ENTER,
|
||||||
|
SUSTAIN,
|
||||||
|
EXIT
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CollisionEvent {
|
||||||
|
typedef std::pair<pod::PhysicsBody*, pod::PhysicsBody*> pairs_t;
|
||||||
|
typedef uf::stl::vector<pod::CollisionEvent> events_t;
|
||||||
|
typedef uf::stl::unordered_map<uint64_t, pod::CollisionEvent::pairs_t> map_t;
|
||||||
|
|
||||||
|
pod::CollisionState state = {};
|
||||||
|
pod::PhysicsBody* a = NULL;
|
||||||
|
pod::PhysicsBody* b = NULL;
|
||||||
|
pod::Vector3f point = {};
|
||||||
|
pod::Vector3f normal = {};
|
||||||
|
float impulse = 0;
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace pod {
|
namespace pod {
|
||||||
@ -473,6 +492,9 @@ namespace pod {
|
|||||||
pod::Vector3f gravity = { 0, -9.81f, 0 };
|
pod::Vector3f gravity = { 0, -9.81f, 0 };
|
||||||
pod::BVH dynamicBvh;
|
pod::BVH dynamicBvh;
|
||||||
pod::BVH staticBvh;
|
pod::BVH staticBvh;
|
||||||
|
|
||||||
|
pod::CollisionEvent::events_t collisionEvents;
|
||||||
|
pod::CollisionEvent::map_t activeCollisions;
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -573,6 +573,16 @@ void ext::PlayerBehavior::tick( uf::Object& self ) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if 0
|
||||||
|
{
|
||||||
|
int count = 0;
|
||||||
|
auto events = uf::physics::getCollisionEvents( physicsBody );
|
||||||
|
for ( const auto& event : events ) {
|
||||||
|
// do something
|
||||||
|
}
|
||||||
|
UF_MSG_DEBUG("count={}", events.size());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#if UF_USE_OPENAL
|
#if UF_USE_OPENAL
|
||||||
if ( stats.floored && !stats.noclipped ) {
|
if ( stats.floored && !stats.noclipped ) {
|
||||||
if ( stats.walking ) {
|
if ( stats.walking ) {
|
||||||
|
|||||||
@ -36,6 +36,11 @@ namespace binds {
|
|||||||
return uf::transform::flatten( t );
|
return uf::transform::flatten( t );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto getCollisionEvents( const pod::PhysicsBody& body ) {
|
||||||
|
auto events = uf::physics::getCollisionEvents( body );
|
||||||
|
return sol::as_table( events );
|
||||||
|
}
|
||||||
|
|
||||||
std::tuple<uf::Object*, float> rayCast( pod::PhysicsBody& self, const pod::Vector3f& center, const pod::Vector3f& direction ) {
|
std::tuple<uf::Object*, float> rayCast( pod::PhysicsBody& self, const pod::Vector3f& center, const pod::Vector3f& direction ) {
|
||||||
pod::RayQuery query = uf::physics::rayCast( pod::Ray{center, uf::vector::normalize( direction )}, self, uf::vector::norm( direction ) );
|
pod::RayQuery query = uf::physics::rayCast( pod::Ray{center, uf::vector::normalize( direction )}, self, uf::vector::norm( direction ) );
|
||||||
uf::Object* object = query.hit ? query.body->object : NULL;
|
uf::Object* object = query.hit ? query.body->object : NULL;
|
||||||
@ -102,6 +107,14 @@ namespace binds {
|
|||||||
|
|
||||||
#include <uf/ext/lua/component.h>
|
#include <uf/ext/lua/component.h>
|
||||||
|
|
||||||
|
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::CollisionEvent,
|
||||||
|
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::state),
|
||||||
|
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::a),
|
||||||
|
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::b),
|
||||||
|
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::point),
|
||||||
|
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::normal),
|
||||||
|
UF_LUA_REGISTER_USERTYPE_MEMBER(pod::CollisionEvent::impulse)
|
||||||
|
)
|
||||||
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::AABB,
|
UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::AABB,
|
||||||
sol::call_constructor, sol::initializers(
|
sol::call_constructor, sol::initializers(
|
||||||
[]( pod::AABB& self ) {
|
[]( pod::AABB& self ) {
|
||||||
@ -206,6 +219,7 @@ UF_LUA_REGISTER_USERTYPE_AND_COMPONENT(pod::PhysicsBody,
|
|||||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyImpulse, UF_LUA_C_FUN(uf::physics::applyImpulse) ),
|
UF_LUA_REGISTER_USERTYPE_DEFINE( applyImpulse, UF_LUA_C_FUN(uf::physics::applyImpulse) ),
|
||||||
UF_LUA_REGISTER_USERTYPE_DEFINE( applyRotation, UF_LUA_C_FUN(::binds::body::applyRotation) ),
|
UF_LUA_REGISTER_USERTYPE_DEFINE( applyRotation, UF_LUA_C_FUN(::binds::body::applyRotation) ),
|
||||||
UF_LUA_REGISTER_USERTYPE_DEFINE( getTransform, UF_LUA_C_FUN(::binds::body::getTransform) ),
|
UF_LUA_REGISTER_USERTYPE_DEFINE( getTransform, UF_LUA_C_FUN(::binds::body::getTransform) ),
|
||||||
|
UF_LUA_REGISTER_USERTYPE_DEFINE( getCollisionEvents, UF_LUA_C_FUN(::binds::body::getCollisionEvents) ),
|
||||||
UF_LUA_REGISTER_USERTYPE_DEFINE( setGravity, UF_LUA_C_FUN(::binds::body::setGravity) ),
|
UF_LUA_REGISTER_USERTYPE_DEFINE( setGravity, UF_LUA_C_FUN(::binds::body::setGravity) ),
|
||||||
UF_LUA_REGISTER_USERTYPE_DEFINE( enableGravity, UF_LUA_C_FUN(::binds::body::enableGravity) ),
|
UF_LUA_REGISTER_USERTYPE_DEFINE( enableGravity, UF_LUA_C_FUN(::binds::body::enableGravity) ),
|
||||||
UF_LUA_REGISTER_USERTYPE_DEFINE( rayCast, UF_LUA_C_FUN(::binds::body::rayCast) ),
|
UF_LUA_REGISTER_USERTYPE_DEFINE( rayCast, UF_LUA_C_FUN(::binds::body::rayCast) ),
|
||||||
|
|||||||
@ -1,6 +1,11 @@
|
|||||||
#include <uf/utils/math/physics/common.h>
|
#include <uf/utils/math/physics/common.h>
|
||||||
#include <uf/utils/math/physics/constraints.h>
|
#include <uf/utils/math/physics/constraints.h>
|
||||||
|
|
||||||
|
void impl::solveConstraints( uf::stl::vector<pod::Constraint*>& constraints, float dt ) {
|
||||||
|
for ( uint32_t i = 0; i < uf::physics::settings.solverIterations; ++i ) {
|
||||||
|
for ( auto* constraint : constraints ) impl::solveConstraint( *constraint, dt );
|
||||||
|
}
|
||||||
|
}
|
||||||
void impl::solveConstraint( pod::Constraint& constraint, float dt ) {
|
void impl::solveConstraint( pod::Constraint& constraint, float dt ) {
|
||||||
switch ( constraint.type ) {
|
switch ( constraint.type ) {
|
||||||
case pod::ConstraintType::BALL_AND_SOCKET: {
|
case pod::ConstraintType::BALL_AND_SOCKET: {
|
||||||
|
|||||||
@ -11,7 +11,7 @@ void impl::bindManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold
|
|||||||
manifold.points.reserve(4);
|
manifold.points.reserve(4);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool impl::generateContactsGjk( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
|
bool impl::generateManifoldGjk( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
|
||||||
impl::bindManifold( a, b, manifold, dt );
|
impl::bindManifold( a, b, manifold, dt );
|
||||||
|
|
||||||
pod::Simplex simplex;
|
pod::Simplex simplex;
|
||||||
@ -23,11 +23,11 @@ bool impl::generateContactsGjk( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::M
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool impl::generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
|
bool impl::generateManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manifold& manifold, float dt ) {
|
||||||
bool useGjk = uf::physics::settings.useGjk;
|
bool useGjk = uf::physics::settings.useGjk;
|
||||||
if ( a.collider.type == pod::ShapeType::MESH || b.collider.type == pod::ShapeType::MESH ) useGjk = false;
|
if ( a.collider.type == pod::ShapeType::MESH || b.collider.type == pod::ShapeType::MESH ) useGjk = false;
|
||||||
//if ( a.collider.type == pod::ShapeType::PLANE || b.collider.type == pod::ShapeType::PLANE ) useGjk = false;
|
//if ( a.collider.type == pod::ShapeType::PLANE || b.collider.type == pod::ShapeType::PLANE ) useGjk = false;
|
||||||
if ( useGjk ) return generateContactsGjk( a, b, manifold, dt );
|
if ( useGjk ) return generateManifoldGjk( a, b, manifold, dt );
|
||||||
impl::bindManifold( a, b, manifold, dt );
|
impl::bindManifold( a, b, manifold, dt );
|
||||||
|
|
||||||
#define CHECK_CONTACT( A, B, fun )\
|
#define CHECK_CONTACT( A, B, fun )\
|
||||||
@ -94,7 +94,7 @@ bool impl::generateContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Mani
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void impl::computeLocalContacts( pod::Manifold& manifold ) {
|
void impl::computeLocalManifold( pod::Manifold& manifold ) {
|
||||||
if ( manifold.points.empty() ) return;
|
if ( manifold.points.empty() ) return;
|
||||||
|
|
||||||
auto& a = *manifold.a;
|
auto& a = *manifold.a;
|
||||||
@ -113,7 +113,7 @@ bool impl::similarContact( const pod::Contact& a, const pod::Contact& b, float d
|
|||||||
return uf::vector::distanceSquared(a.point, b.point) < distSqThreshold && uf::vector::dot(a.normal, b.normal) > normThreshold;
|
return uf::vector::distanceSquared(a.point, b.point) < distSqThreshold && uf::vector::dot(a.normal, b.normal) > normThreshold;
|
||||||
}
|
}
|
||||||
|
|
||||||
void impl::reduceContacts( pod::Manifold& manifold ) {
|
void impl::reduceManifold( pod::Manifold& manifold ) {
|
||||||
if ( manifold.points.size() <= 4 ) return;
|
if ( manifold.points.size() <= 4 ) return;
|
||||||
|
|
||||||
#if 1
|
#if 1
|
||||||
@ -210,7 +210,7 @@ void impl::reduceContacts( pod::Manifold& manifold ) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void impl::mergeContacts( pod::Manifold& manifold ) {
|
void impl::mergeManifold( pod::Manifold& manifold ) {
|
||||||
STATIC_THREAD_LOCAL(uf::stl::vector<pod::Contact>, result);
|
STATIC_THREAD_LOCAL(uf::stl::vector<pod::Contact>, result);
|
||||||
result.reserve(4);
|
result.reserve(4);
|
||||||
|
|
||||||
@ -231,7 +231,7 @@ void impl::mergeContacts( pod::Manifold& manifold ) {
|
|||||||
manifold.points = result;
|
manifold.points = result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void impl::retrieveContacts( pod::Manifold& current, const pod::Manifold& previous, float distanceThreshold, float separationThreshold, float decay ) {
|
void impl::retrieveManifold( pod::Manifold& current, const pod::Manifold& previous, float distanceThreshold, float separationThreshold, float decay ) {
|
||||||
auto& a = *current.a;
|
auto& a = *current.a;
|
||||||
auto& b = *current.b;
|
auto& b = *current.b;
|
||||||
|
|
||||||
@ -320,7 +320,7 @@ void impl::pruneManifoldCache( uf::stl::unordered_map<size_t, pod::Manifold>& ca
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void impl::warmupContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Contact& c, float dt ) {
|
void impl::warmupContact( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Contact& c, float dt ) {
|
||||||
if ( !c.lifetime ) return; // too new
|
if ( !c.lifetime ) return; // too new
|
||||||
|
|
||||||
// build relative offsets
|
// build relative offsets
|
||||||
@ -337,7 +337,7 @@ void impl::warmupContacts( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::
|
|||||||
}
|
}
|
||||||
void impl::warmupManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Manifold& manifold, float dt ) {
|
void impl::warmupManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, const pod::Manifold& manifold, float dt ) {
|
||||||
for ( auto& contact : manifold.points ) {
|
for ( auto& contact : manifold.points ) {
|
||||||
impl::warmupContacts( a, b, contact, dt );
|
impl::warmupContact( a, b, contact, dt );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -348,7 +348,25 @@ void impl::resolveManifold( pod::PhysicsBody& a, pod::PhysicsBody& b, pod::Manif
|
|||||||
for ( auto& contact : manifold.points ) impl::iterativeImpulseSolver( a, b, contact, dt );
|
for ( auto& contact : manifold.points ) impl::iterativeImpulseSolver( a, b, contact, dt );
|
||||||
}
|
}
|
||||||
|
|
||||||
void impl::solveContacts( uf::stl::vector<pod::Manifold>& manifolds, float dt ) {
|
void impl::solveManifold( uf::stl::vector<pod::Manifold>& manifolds, float dt ) {
|
||||||
if ( uf::physics::settings.warmupSolver ) for ( auto& manifold : manifolds ) impl::warmupManifold( *manifold.a, *manifold.b, manifold, dt );
|
if ( uf::physics::settings.warmupSolver ) for ( auto& manifold : manifolds ) impl::warmupManifold( *manifold.a, *manifold.b, manifold, dt );
|
||||||
for ( auto i = 0; i < uf::physics::settings.solverIterations; ++i ) for ( auto& manifold : manifolds ) impl::resolveManifold( *manifold.a, *manifold.b, manifold, dt );
|
for ( auto i = 0; i < uf::physics::settings.solverIterations; ++i ) for ( auto& manifold : manifolds ) impl::resolveManifold( *manifold.a, *manifold.b, manifold, dt );
|
||||||
|
}
|
||||||
|
|
||||||
|
void impl::dispatchManifold( pod::Manifold& manifold, pod::CollisionEvent::events_t& events, pod::CollisionEvent::map_t& active, const pod::CollisionEvent::map_t& previous ) {
|
||||||
|
auto pairKey = impl::makePairKey( *manifold.a, *manifold.b );
|
||||||
|
// find largest impulse
|
||||||
|
float maxImpulse = 0.0f;
|
||||||
|
for ( const auto& c : manifold.points ) maxImpulse = std::max( maxImpulse, c.accumulatedNormalImpulse );
|
||||||
|
// mark as an active collision
|
||||||
|
active[pairKey] = { manifold.a, manifold.b };
|
||||||
|
// dispatch
|
||||||
|
events.emplace_back(pod::CollisionEvent{
|
||||||
|
.state = previous.count( pairKey ) == 0 ? pod::CollisionState::ENTER : pod::CollisionState::SUSTAIN,
|
||||||
|
.a = manifold.a,
|
||||||
|
.b = manifold.b,
|
||||||
|
.point = manifold.points[0].point,
|
||||||
|
.normal = manifold.points[0].normal,
|
||||||
|
.impulse = maxImpulse,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
@ -90,6 +90,14 @@ void uf::physics::step( pod::World& world, float dt ) {
|
|||||||
auto& constraints = world.constraints;
|
auto& constraints = world.constraints;
|
||||||
auto& dynamicBvh = world.dynamicBvh;
|
auto& dynamicBvh = world.dynamicBvh;
|
||||||
auto& staticBvh = world.staticBvh;
|
auto& staticBvh = world.staticBvh;
|
||||||
|
auto& activeCollisions = world.activeCollisions;
|
||||||
|
auto& collisionEvents = world.collisionEvents;
|
||||||
|
|
||||||
|
STATIC_THREAD_LOCAL(pod::CollisionEvent::events_t, previousCollisionEvents);
|
||||||
|
STATIC_THREAD_LOCAL(pod::CollisionEvent::map_t, previousCollisions);
|
||||||
|
|
||||||
|
std::swap( previousCollisions, activeCollisions );
|
||||||
|
std::swap( previousCollisionEvents, collisionEvents );
|
||||||
|
|
||||||
if ( bodies.empty() ) return;
|
if ( bodies.empty() ) return;
|
||||||
|
|
||||||
@ -148,10 +156,10 @@ void uf::physics::step( pod::World& world, float dt ) {
|
|||||||
|
|
||||||
pod::Manifold manifold;
|
pod::Manifold manifold;
|
||||||
// did not collide
|
// did not collide
|
||||||
if ( !impl::generateContacts( a, b, manifold, dt ) ) continue;
|
if ( !impl::generateManifold( a, b, manifold, dt ) ) continue;
|
||||||
|
|
||||||
// compute local points (for reprojection)
|
// compute local points (for reprojection)
|
||||||
impl::computeLocalContacts( manifold );
|
impl::computeLocalManifold( manifold );
|
||||||
|
|
||||||
// bodies with meshes already reorient the normal to the triangle's center
|
// bodies with meshes already reorient the normal to the triangle's center
|
||||||
bool shouldReorient = true;
|
bool shouldReorient = true;
|
||||||
@ -165,14 +173,14 @@ void uf::physics::step( pod::World& world, float dt ) {
|
|||||||
// retrieve accumulated impulses
|
// retrieve accumulated impulses
|
||||||
if ( uf::physics::settings.warmupSolver ) {
|
if ( uf::physics::settings.warmupSolver ) {
|
||||||
auto it = uf::physics::settings.manifoldsCache.find( impl::makePairKey( a, b ) );
|
auto it = uf::physics::settings.manifoldsCache.find( impl::makePairKey( a, b ) );
|
||||||
if ( it != uf::physics::settings.manifoldsCache.end() ) impl::retrieveContacts( manifold, it->second );
|
if ( it != uf::physics::settings.manifoldsCache.end() ) impl::retrieveManifold( manifold, it->second );
|
||||||
}
|
}
|
||||||
// merge similar contacts from a mesh to ensure continuity
|
// merge similar contacts from a mesh to ensure continuity
|
||||||
if ( a.collider.type == pod::ShapeType::MESH || b.collider.type == pod::ShapeType::MESH ) {
|
if ( a.collider.type == pod::ShapeType::MESH || b.collider.type == pod::ShapeType::MESH ) {
|
||||||
impl::mergeContacts( manifold );
|
impl::mergeManifold( manifold );
|
||||||
}
|
}
|
||||||
// keep four most important contacts
|
// keep four most important contacts
|
||||||
impl::reduceContacts( manifold );
|
impl::reduceManifold( manifold );
|
||||||
// no points remained, skip
|
// no points remained, skip
|
||||||
if ( manifold.points.empty() ) continue;
|
if ( manifold.points.empty() ) continue;
|
||||||
// wake up bodies
|
// wake up bodies
|
||||||
@ -188,36 +196,42 @@ void uf::physics::step( pod::World& world, float dt ) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// store manifold
|
// store manifold
|
||||||
manifolds.emplace_back(manifold);
|
manifolds.emplace_back( manifold );
|
||||||
}
|
}
|
||||||
|
|
||||||
// pass manifolds to solver
|
// pass manifolds to solver
|
||||||
impl::solveContacts( manifolds, dt );
|
impl::solveManifold( manifolds, dt );
|
||||||
// do position correction
|
// do position correction
|
||||||
impl::solvePositions( manifolds, dt );
|
impl::solvePositions( manifolds, dt );
|
||||||
// solve constraints
|
// solve constraints
|
||||||
for ( uint32_t i = 0; i < uf::physics::settings.solverIterations; ++i ) {
|
impl::solveConstraints( constraints, dt );
|
||||||
for ( auto& constraint : constraints ) {
|
|
||||||
impl::solveConstraint( *constraint, dt );
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// cache manifold positions
|
// cache manifold positions
|
||||||
if ( uf::physics::settings.warmupSolver ) {
|
if ( uf::physics::settings.warmupSolver ) impl::updateManifoldCache( manifolds, uf::physics::settings.manifoldsCache );
|
||||||
impl::updateManifoldCache( manifolds, uf::physics::settings.manifoldsCache );
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
uf::thread::execute( tasks );
|
uf::thread::execute( tasks );
|
||||||
|
|
||||||
|
// prune expired manifolds in the cache
|
||||||
if ( uf::physics::settings.warmupSolver ) impl::pruneManifoldCache( uf::physics::settings.manifoldsCache );
|
if ( uf::physics::settings.warmupSolver ) impl::pruneManifoldCache( uf::physics::settings.manifoldsCache );
|
||||||
|
|
||||||
if ( uf::physics::settings.debugDraw ) {
|
for ( auto& island : islands ) for ( auto& manifold : island.manifolds ) {
|
||||||
for ( auto& island : islands ) for ( auto& manifold : island.manifolds ) impl::drawManifold( manifold );
|
// dispatch collision events
|
||||||
|
impl::dispatchManifold( manifold, collisionEvents, activeCollisions, previousCollisions );
|
||||||
|
// draw collision events
|
||||||
|
if ( uf::physics::settings.debugDraw ) impl::drawManifold( manifold );
|
||||||
|
}
|
||||||
|
// dispatch exiting collisions
|
||||||
|
for ( auto& [ key, pair ] : previousCollisions ) {
|
||||||
|
// sustained collision
|
||||||
|
if ( activeCollisions.count( key ) > 0 ) continue;
|
||||||
|
// mark as exiting
|
||||||
|
collisionEvents.emplace_back(pod::CollisionEvent{
|
||||||
|
.state = pod::CollisionState::EXIT,
|
||||||
|
.a = pair.first,
|
||||||
|
.b = pair.second,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
for ( auto* b : bodies ) {
|
// snap velocities of bodies
|
||||||
if ( b->inverseMass == 0.0f ) continue;
|
for ( auto* b : bodies ) impl::snapVelocity( *b, dt );
|
||||||
impl::snapVelocity( *b, dt );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void uf::physics::setMass( pod::PhysicsBody& body, float mass ) {
|
void uf::physics::setMass( pod::PhysicsBody& body, float mass ) {
|
||||||
@ -447,7 +461,18 @@ pod::World& uf::physics::getWorld() {
|
|||||||
auto& scene = uf::scene::getCurrentScene();
|
auto& scene = uf::scene::getCurrentScene();
|
||||||
return scene.getComponent<pod::World>();
|
return scene.getComponent<pod::World>();
|
||||||
}
|
}
|
||||||
|
const pod::CollisionEvent::events_t& uf::physics::getCollisionEvents( const pod::World& world ) {
|
||||||
|
return world.collisionEvents;
|
||||||
|
}
|
||||||
|
pod::CollisionEvent::events_t uf::physics::getCollisionEvents( const pod::PhysicsBody& body ) {
|
||||||
|
const auto& events = uf::physics::getCollisionEvents( *body.world );
|
||||||
|
pod::CollisionEvent::events_t res;
|
||||||
|
for ( auto& event : events ) {
|
||||||
|
if ( event.a != &body && event.b != &body ) continue;
|
||||||
|
res.emplace_back( event );
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
// body creation
|
// body creation
|
||||||
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, float mass, const pod::Vector3f& offset ) {
|
pod::PhysicsBody& uf::physics::create( pod::World& world, uf::Object& object, float mass, const pod::Vector3f& offset ) {
|
||||||
auto& root = object.getComponent<pod::PhysicsBody>();
|
auto& root = object.getComponent<pod::PhysicsBody>();
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user