Previously, physics interactions in Defold were handled by broadcasting messages to all components of colliding objects. However, starting with version 1.6.4, Defold offers a more centralized approach through the physics.set_listener()
function. This function allows you to set a custom listener to handle all physics interaction events in one place, thereby streamlining your code and improving efficiency.
In Defold, each collection proxy creates its own separate physics world. Therefore, when you are working with multiple collection proxies, it’s essential to manage the distinct physics worlds associated with each. To ensure that physics events are handled correctly in each world, you must set a physics world listener specifically for each collection proxy’s world.
This setup means that the listener for physics events must be set from within the context of the collection that the proxy represents. By doing so, you associate the listener directly with the relevant physics world, enabling it to process physics events accurately.
Here is an example of how to set a physics world listener within a collection proxy:
function init(self)
-- Assuming this script is attached to a game object within the collection loaded by the proxy
-- Set the physics world listener for the physics world of this collection proxy
physics.set_listener(physics_world_listener)
end
By implementing this method, you ensure that each physics world generated by a collection proxy has its dedicated listener. This is crucial for handling physics events effectively in projects that utilize multiple collection proxies.
If a listener is set, physics messages will no longer be sent for the physics world where this listener is set.
Each physics event provides a data
table containing specific information relevant to the event.
Contact Point Event (contact_point_event
):
This event reports a contact point between two collision objects. It is useful for detailed collision handling, such as calculating impact forces or custom collision responses.
applied_impulse
: The impulse resulting from the contact.distance
: The penetration distance between the objects.a
and b
: Objects representing the colliding entities, each containing:
position
: World position of contact point (vector3).instance_position
: World position game object instance (vector3).id
: Instance ID (hash).group
: Collision group (hash).relative_velocity
: Velocity relative to the other object (vector3).mass
: Mass in kilograms (number).normal
: Contact normal, pointing from the other object (vector3).Collision Event (collision_event
):
This event indicates that a collision has occurred between two objects. It is a more generalized event compared to the contact point event, ideal for detecting collisions without needing detailed information about the contact points.
a
and b
: Objects representing the colliding entities, each containing:
position
: World position (vector3).id
: Instance ID (hash).group
: Collision group (hash).Trigger Event (trigger_event
):
This event is sent when an object interacts with a trigger object. It’s useful for creating areas in your game that cause something to happen when an object enters or exits.
enter
: Indicates if the interaction was an entry (true) or an exit (false).a
and b
: Objects involved in the trigger event, each containing:
id
: Instance ID (hash).group
: Collision group (hash).Ray Cast Response (ray_cast_response
):
This event is sent in response to a raycast, providing information about the object hit by the ray.
group
: Collision group of the hit object (hash).request_id
: Identifier of the raycast request (number).position
: Hit position (vector3).fraction
: The fraction of the ray’s length at which the hit occurred (number).normal
: Normal at the hit position (vector3).id
: Instance ID of the hit object (hash).Ray Cast Missed (ray_cast_missed
):
This event is sent when a raycast does not hit any object.
request_id
: Identifier of the raycast request that missed (number).local function physics_world_listener(self, event, data)
if event == hash("contact_point_event") then
-- Handle detailed contact point data
pprint(data)
elseif event == hash("collision_event") then
-- Handle general collision data
pprint(data)
elseif event == hash("trigger_event") then
-- Handle trigger interaction data
pprint(data)
elseif event == hash("ray_cast_response") then
-- Handle raycast hit data
pprint(data)
elseif event == hash("ray_cast_missed") then
-- Handle raycast miss data
pprint(data)
end
end
function init(self)
physics.set_listener(physics_world_listener)
end
The listener calls synchronously at the moment it occurs. It happens in the middle of a timestep, which means that the physics world is locked. This makes it impossible to use functions that may affect physics world simulations, e.g., physics.create_joint()
.
Here is a small example of how to avoid these limitations:
local function physics_world_listener(self, event, data)
if event == hash("contact_point_event") then
local position_a = data.a.normal * SIZE
local position_b = data.b.normal * SIZE
local url_a = msg.url(nil, data.a.id, "collisionobject")
local url_b = msg.url(nil, data.b.id, "collisionobject")
-- fill the message in the same way arguments should be passed to `physics.create_joint()`
local message = {physics.JOINT_TYPE_FIXED, url_a, "joind_id", position_a, url_b, position_b, {max_length = SIZE}}
-- send message to the object itself
msg.post(".", "create_joint", message)
end
end
function on_message(self, message_id, message)
if message_id == hash("create_joint") then
-- unpack message with function arguments
physics.create_joint(unpack(message))
end
end
function init(self)
physics.set_listener(physics_world_listener)
end
Did you spot an error or do you have a suggestion? Please let us know on GitHub!
GITHUB