Skip to content

Commit 7066158

Browse files
Site changes
1 parent 59a678d commit 7066158

653 files changed

Lines changed: 7567 additions & 1070 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

_data/examplesindex.json

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,32 @@
10921092
"title": "Box2D Chain Terrain",
10931093
"twitter_image": "https://www.defold.com/examples/physics/box2d_chain_terrain/thumbnail.webp"
10941094
},
1095+
{
1096+
"author": "Defold Foundation",
1097+
"brief": "Create a mouse joint that pulls dynamic bodies toward a moving target.",
1098+
"category": "physics",
1099+
"layout": "example",
1100+
"opengraph_image": "https://www.defold.com/examples/physics/box2d_mouse_joint/thumbnail.webp",
1101+
"path": "physics/box2d_mouse_joint",
1102+
"scripts": "box2d_mouse_joint_v3.script, box2d_mouse_joint_v2.script",
1103+
"tags": "physics, box2d",
1104+
"thumbnail": "thumbnail.webp",
1105+
"title": "Box2D Mouse Joint",
1106+
"twitter_image": "https://www.defold.com/examples/physics/box2d_mouse_joint/thumbnail.webp"
1107+
},
1108+
{
1109+
"author": "Defold Foundation",
1110+
"brief": "Create a bridge from revolute joints between existing Defold collision objects.",
1111+
"category": "physics",
1112+
"layout": "example",
1113+
"opengraph_image": "https://www.defold.com/examples/physics/box2d_revolute_bridge/thumbnail.webp",
1114+
"path": "physics/box2d_revolute_bridge",
1115+
"scripts": "box2d_revolute_bridge_v3.script, box2d_revolute_bridge_v2.script",
1116+
"tags": "physics, box2d",
1117+
"thumbnail": "thumbnail.webp",
1118+
"title": "Box2D Revolute Bridge",
1119+
"twitter_image": "https://www.defold.com/examples/physics/box2d_revolute_bridge/thumbnail.webp"
1120+
},
10951121
{
10961122
"brief": "This example shows a simple setup with dynamic physics objects.",
10971123
"category": "physics",
Lines changed: 252 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,252 @@
1+
local TOUCH = hash("touch")
2+
3+
local START_TARGET = vmath.vector3(360, 420, 0)
4+
local SOFT_START = vmath.vector3(270, 310, 0)
5+
local TIGHT_START = vmath.vector3(450, 310, 0)
6+
7+
local SOFT_LINE_COLOR = vmath.vector4(1.0, 0.65, 0.22, 1.0)
8+
local TIGHT_LINE_COLOR = vmath.vector4(0.35, 0.85, 1.0, 1.0)
9+
local TARGET_LINE_COLOR = vmath.vector4(0.45, 1.0, 0.65, 1.0)
10+
11+
local function draw_line(from, to, color)
12+
-- <1> Draw a debug/helper line through the render socket.
13+
-- The line exists for one frame only, so it must be redrawn every update.
14+
msg.post("@render:", "draw_line", {
15+
start_point = from,
16+
end_point = to,
17+
color = color
18+
})
19+
end
20+
21+
local function set_target(self, position)
22+
-- <2> Store the current mouse-joint target as a world-space point.
23+
-- The mouse/touch pointer is not a Box2D body. It is only a target position
24+
-- that the mouse joint tries to pull the dynamic body toward.
25+
self.target = vmath.vector3(position.x, position.y, 0)
26+
27+
-- <3> Move the visible target marker so the user can see the point followed
28+
-- by both mouse joints.
29+
go.set_position(self.target, self.target_url)
30+
end
31+
32+
local function reset_body(body, position)
33+
-- <4> Set the Box2D body transform directly.
34+
-- This is good for example setup/reset. Do not use this as normal per-frame
35+
-- movement, because it teleports the body and can produce non-physical motion.
36+
b2d.body.set_transform(body, position, 0)
37+
38+
-- <5> Clear previous motion so the example starts from a deterministic state.
39+
b2d.body.set_linear_velocity(body, vmath.vector3())
40+
b2d.body.set_angular_velocity(body, 0)
41+
42+
-- <6> Wake the body so it reacts immediately after reset.
43+
b2d.body.set_awake(body, true)
44+
end
45+
46+
local function setup_body(body)
47+
-- <7> Disable gravity for this body.
48+
-- This keeps the example focused on the mouse-joint spring behaviour.
49+
b2d.body.set_gravity_scale(body, 0)
50+
51+
-- <8> Prevent the body from rotating.
52+
-- Rotation would add noise to the visual explanation, while this example is
53+
-- about soft versus tight positional following.
54+
b2d.body.set_fixed_rotation(body, true)
55+
56+
-- <9> Add linear damping.
57+
-- This reduces endless sliding and helps the body settle after movement.
58+
b2d.body.set_linear_damping(body, 1.5)
59+
end
60+
61+
local function create_mouse_joints(self)
62+
-- <10> Get native Box2D body handles from Defold collision object components.
63+
-- `target` acts as the static/reference body for the mouse joints.
64+
local anchor_body = b2d.get_body(msg.url(nil, "target", "collisionobject"))
65+
self.soft_body = b2d.get_body(msg.url(nil, "soft_body", "collisionobject"))
66+
self.tight_body = b2d.get_body(msg.url(nil, "tight_body", "collisionobject"))
67+
68+
setup_body(self.soft_body)
69+
setup_body(self.tight_body)
70+
71+
reset_body(self.soft_body, SOFT_START)
72+
reset_body(self.tight_body, TIGHT_START)
73+
74+
-- <11> Create a soft V2 mouse joint.
75+
-- In Box2D V2-style definitions, spring frequency is controlled by
76+
-- `frequency`, not `hertz`.
77+
self.soft_joint = b2d.joint.create_mouse(anchor_body, self.soft_body, {
78+
-- <12> Initial world target. This value is later updated every frame.
79+
target = self.target,
80+
81+
-- <13> Maximum force the joint can apply.
82+
-- Lower max force allows more visible lag/stretch.
83+
max_force = 850,
84+
85+
-- <14> V2 spring frequency.
86+
-- Lower frequency makes the body follow more softly and slowly.
87+
frequency = 1.5,
88+
89+
-- <15> Damping ratio.
90+
-- Lower damping allows more bounce/overshoot.
91+
damping_ratio = 0.35,
92+
93+
-- <16> The connected bodies should not collide with each other.
94+
collide_connected = false,
95+
})
96+
97+
-- <17> Create a tighter V2 mouse joint.
98+
-- It follows the same target, but uses stronger/stiffer parameters.
99+
self.tight_joint = b2d.joint.create_mouse(anchor_body, self.tight_body, {
100+
target = self.target,
101+
102+
-- <18> Higher max force means the body can be pulled more aggressively.
103+
max_force = 6500,
104+
105+
-- <19> Higher frequency means a stiffer/faster spring response.
106+
frequency = 8.0,
107+
108+
-- <20> Higher damping removes more oscillation.
109+
damping_ratio = 0.9,
110+
111+
collide_connected = false,
112+
})
113+
end
114+
115+
local function update_auto_target(self, dt)
116+
if self.user_control then
117+
return
118+
end
119+
120+
-- <21> Animate the target automatically before user interaction.
121+
-- This makes the example demonstrate itself on the examples website.
122+
self.time = self.time + dt
123+
124+
set_target(self, vmath.vector3(
125+
360 + math.cos(self.time * 1.35) * 170,
126+
395 + math.sin(self.time * 1.10) * 95,
127+
0
128+
))
129+
end
130+
131+
local function update_joints(self)
132+
-- <22> Update both mouse joints with the current world target.
133+
-- The joints are created once, but their target can be changed every frame.
134+
b2d.joint.set_mouse_target(self.soft_joint, self.target)
135+
b2d.joint.set_mouse_target(self.tight_joint, self.target)
136+
137+
-- <23> Keep the bodies awake while the target moves.
138+
-- This avoids relying on b2d.joint.wake_bodies(), which may not exist in
139+
-- the active V2 runtime.
140+
b2d.body.set_awake(self.soft_body, true)
141+
b2d.body.set_awake(self.tight_body, true)
142+
end
143+
144+
local function draw_connections(self)
145+
-- <24> Read the current simulated positions from Box2D.
146+
-- These positions are the result of the physics step, not manually animated
147+
-- sprite positions.
148+
local soft_position = b2d.body.get_position(self.soft_body)
149+
local tight_position = b2d.body.get_position(self.tight_body)
150+
151+
-- <25> Draw spring-like helper lines from the target to each body.
152+
-- The longer the line, the more that body is lagging/stretching.
153+
draw_line(self.target, soft_position, SOFT_LINE_COLOR)
154+
draw_line(self.target, tight_position, TIGHT_LINE_COLOR)
155+
156+
-- <26> Draw a small cross at the target point.
157+
draw_line(self.target + vmath.vector3(-18, 0, 0), self.target + vmath.vector3(18, 0, 0), TARGET_LINE_COLOR)
158+
draw_line(self.target + vmath.vector3(0, -18, 0), self.target + vmath.vector3(0, 18, 0), TARGET_LINE_COLOR)
159+
end
160+
161+
function init(self)
162+
-- <27> Run this script only when the active Box2D backend is V2.
163+
-- The same collection may contain both V2 and V3 scripts, but only the
164+
-- matching one should initialize.
165+
self.active = b2d.get_version().major == 2
166+
167+
if not self.active then
168+
return
169+
end
170+
171+
self.target_url = msg.url(nil, "target", nil)
172+
self.time = 0
173+
self.user_control = false
174+
175+
set_target(self, START_TARGET)
176+
create_mouse_joints(self)
177+
178+
-- <28> Show which backend-specific script is active.
179+
label.set_text("/info#version_label", "Box2D V2 mouse joint")
180+
181+
-- <29> Required before this script receives on_input() callbacks.
182+
msg.post(".", "acquire_input_focus")
183+
end
184+
185+
function update(self, dt)
186+
if not self.active then
187+
return
188+
end
189+
190+
update_auto_target(self, dt)
191+
update_joints(self)
192+
draw_connections(self)
193+
end
194+
195+
function on_input(self, action_id, action)
196+
if not self.active then
197+
return
198+
end
199+
200+
-- <30> Mouse input usually comes with action_id == nil, while touch input
201+
-- uses the configured "touch" binding. Both provide x/y screen coordinates.
202+
if (action_id == TOUCH or action_id == nil) and action.x and action.y then
203+
self.user_control = true
204+
set_target(self, vmath.vector3(action.x, action.y, 0))
205+
end
206+
end
207+
208+
function final(self)
209+
if not self.active then
210+
return
211+
end
212+
213+
-- <31> Destroy scripted joints explicitly when the script is finalized.
214+
b2d.joint.destroy(self.soft_joint)
215+
b2d.joint.destroy(self.tight_joint)
216+
217+
msg.post(".", "release_input_focus")
218+
end
219+
220+
--[[
221+
1. `@render:` is Defold's render socket. The "draw_line" message draws a temporary helper line.
222+
2. A mouse joint follows a world-space target point. The pointer itself is not a physics body.
223+
3. The target marker is only visual. It helps show what the bodies are trying to follow.
224+
4. `b2d.body.set_transform()` directly changes the body's world transform. Good for setup/reset, not continuous movement.
225+
5. Clearing linear and angular velocity removes previous momentum.
226+
6. `b2d.body.set_awake()` wakes the body so it reacts immediately in the simulation.
227+
7. `b2d.body.set_gravity_scale(body, 0)` disables gravity for this body only.
228+
8. `b2d.body.set_fixed_rotation(body, true)` prevents rotation and keeps the visual demonstration clean.
229+
9. `b2d.body.set_linear_damping()` damps velocity over time and reduces endless drift.
230+
10. `b2d.get_body()` converts a Defold collision object URL into a Box2D body handle used by the b2d API.
231+
11. `b2d.joint.create_mouse()` creates a mouse joint between two bodies. The second body is the one visibly pulled toward the target.
232+
12. `target` is the initial world-space target point.
233+
13. `max_force` caps how strongly the joint can pull. Lower values create more visible stretch.
234+
14. `frequency` is the V2 spring frequency. Lower values feel softer; higher values feel tighter.
235+
15. `damping_ratio` controls bounce and overshoot. Lower values oscillate more; higher values settle faster.
236+
16. `collide_connected = false` prevents the connected bodies from colliding with each other.
237+
17. The tight joint uses the same mouse-joint API but different parameters.
238+
18. Higher `max_force` lets the joint correct the body's position more strongly.
239+
19. Higher `frequency` makes the spring respond faster.
240+
20. Higher `damping_ratio` removes more oscillation.
241+
21. Automatic target motion keeps the example animated before the user interacts.
242+
22. `b2d.joint.set_mouse_target()` updates the world target of an existing mouse joint.
243+
23. Waking the bodies avoids sleeping-body cases where the target changes but the body does not visibly react immediately.
244+
24. `b2d.body.get_position()` reads the current simulated world position of a body.
245+
25. The helper lines visualize how far each body stretches away from the target.
246+
26. The target cross is a visual helper, not part of the physics simulation.
247+
27. `b2d.get_version().major` selects the backend-specific script.
248+
28. `label.set_text()` updates the label. It uses message passing internally, so the URL must be correct.
249+
29. `acquire_input_focus` is needed to receive `on_input()`.
250+
30. Pointer input switches the example from automatic motion to direct user-controlled target movement.
251+
31. `b2d.joint.destroy()` removes joints created through the scripted joint API.
252+
]]

0 commit comments

Comments
 (0)