diff --git a/physics/box2d_prismatic_joint/all.texture_profiles b/physics/box2d_prismatic_joint/all.texture_profiles new file mode 100644 index 00000000..5b0d7762 --- /dev/null +++ b/physics/box2d_prismatic_joint/all.texture_profiles @@ -0,0 +1,18 @@ +path_settings { + path: "**" + profile: "Default" +} +profiles { + name: "Default" + platforms { + os: OS_ID_GENERIC + formats { + format: TEXTURE_FORMAT_RGBA + compression_level: BEST + compression_type: COMPRESSION_TYPE_DEFAULT + } + mipmaps: false + max_texture_size: 0 + premultiply_alpha: true + } +} diff --git a/physics/box2d_prismatic_joint/box2d_v2.appmanifest b/physics/box2d_prismatic_joint/box2d_v2.appmanifest new file mode 100644 index 00000000..b3abe8c8 --- /dev/null +++ b/physics/box2d_prismatic_joint/box2d_v2.appmanifest @@ -0,0 +1,95 @@ +platforms: + arm64-ios: + context: + excludeLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + frameworks: [] + linkFlags: [] + x86_64-ios: + context: + excludeLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + frameworks: [] + linkFlags: [] + armv7-android: + context: + excludeLibs: [] + excludeJars: [] + excludeSymbols: [] + symbols: [] + libs: [] + linkFlags: [] + jetifier: true + arm64-android: + context: + excludeLibs: [] + excludeJars: [] + excludeSymbols: [] + symbols: [] + libs: [] + linkFlags: [] + jetifier: true + arm64-osx: + context: + excludeLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + frameworks: [] + linkFlags: [] + x86_64-osx: + context: + excludeLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + frameworks: [] + linkFlags: [] + x86_64-linux: + context: + excludeLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + linkFlags: [] + arm64-linux: + context: + excludeLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + linkFlags: [] + x86-win32: + context: + excludeLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + linkFlags: [] + x86_64-win32: + context: + excludeLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + linkFlags: [] + wasm-web: + context: + excludeLibs: [] + excludeJsLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + linkFlags: [] + wasm_pthread-web: + context: + excludeLibs: [] + excludeJsLibs: [] + excludeSymbols: [] + symbols: [] + libs: [] + linkFlags: [] diff --git a/physics/box2d_prismatic_joint/box2d_v3.appmanifest b/physics/box2d_prismatic_joint/box2d_v3.appmanifest new file mode 100644 index 00000000..9751deca --- /dev/null +++ b/physics/box2d_prismatic_joint/box2d_v3.appmanifest @@ -0,0 +1,100 @@ +platforms: + armv7-ios: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeSymbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + arm64-ios: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + frameworks: [] + linkFlags: [] + x86_64-ios: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + frameworks: [] + linkFlags: [] + armv7-android: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeJars: [] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + linkFlags: [] + jetifier: true + arm64-android: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeJars: [] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + linkFlags: [] + jetifier: true + arm64-osx: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + frameworks: [] + linkFlags: [] + x86_64-osx: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + frameworks: [] + linkFlags: [] + x86_64-linux: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + linkFlags: [] + arm64-linux: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + linkFlags: [] + x86-win32: + context: + excludeLibs: [libphysics, libbox2d_defold, script_box2d_defold] + excludeSymbols: [] + symbols: [] + libs: [libphysics_2d.lib, libbox2d.lib, libscript_box2d.lib, libphysics_3d.lib] + linkFlags: [] + x86_64-win32: + context: + excludeLibs: [libphysics, libbox2d_defold, script_box2d_defold] + excludeSymbols: [] + symbols: [] + libs: [libphysics_2d.lib, libbox2d.lib, libscript_box2d.lib, libphysics_3d.lib] + linkFlags: [] + wasm-web: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeJsLibs: [] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + linkFlags: [] + wasm_pthread-web: + context: + excludeLibs: [physics, box2d_defold, script_box2d_defold] + excludeJsLibs: [] + excludeSymbols: [] + symbols: [] + libs: [physics_2d, box2d, script_box2d, physics_3d] + linkFlags: [] diff --git a/physics/box2d_prismatic_joint/example.md b/physics/box2d_prismatic_joint/example.md new file mode 100644 index 00000000..4a282c61 --- /dev/null +++ b/physics/box2d_prismatic_joint/example.md @@ -0,0 +1,56 @@ +--- +tags: physics, box2d +title: Box2D Prismatic Joint +brief: Create a motorized Box2D prismatic joint with translation limits from script using Box2D. +author: Defold Foundation +scripts: box2d_prismatic_joint.script +thumbnail: thumbnail.webp +--- + +This example creates a Box2D prismatic joint at runtime. +The blue dynamic body (slider) is constrained to a diagonal rail, +moves between two translation limits, and reverses its motor when it reaches either end. + +Click or tap the window to reverse the motor manually. + +There are no differences in scripting between Box2D V2 and V3 in this example. + +## What You'll Learn + +- How to get Box2D body handles from Defold collision objects +- How to create a prismatic joint with `b2d.joint.create_prismatic()` +- How `local_axis_a`, `lower_translation`, and `upper_translation` define the slide rail +- How to control a prismatic joint motor with `b2d.joint.set_motor_speed()` + +## Setup + +The collection contains: + +- `controller` game object with the main script and labels with informations +- `rail` game object with static collision object for frame reference for the prismatic joint and a sprite rotated by 45 degrees around Z axis to indicate the "rail" +- `slider` game object with a dynamic collision object and a sprite to indicate where the slider is + +The `rail` and `slider` bodies start at the same world position in the middle. + +![setup](setup.png) + +The `game.project` of this example is configured to build with `/box2d_v3.appmanifest` by default. +To test V2 locally after downloading the example, change `Native Extensions -> App Manifest` in `game.project` to `/box2d_v2.appmanifest`. + +## How It Works + +The script uses `b2d.get_body()` to fetch the Box2D bodies owned by the `rail` and `slider` collision objects. +Then calls `b2d.joint.create_prismatic()` which creates the prismatic joint between them, +with `local_axis_a` set to the same diagonal direction as the visible rail (rotated 45 degrees areound Z axis), +enables limits from `-110` to `110` project units, and a motor, sets a maximum motor force, and starts the slider moving along the rail. + +The prismatic joint is a constraint solver - only defines *how* two bodies are allowed to move, not *why* they should move. +So normally, the slider would fall in the gravity direction, but would be moving constrained like a slider along a rail. +We enable the motor in the example to move in both direction along the rail. +Motor applied on a prismatic joint moves the object along the joint axis at the given linear speed. + +During `update()`, the script reads `b2d.joint.get_joint_translation()`, which returns the position alongside the constraint, +and reverses the motor when the translation reaches either limit. + +On input (touch or mouse click) the direction of the motor that applies force to the slider changes too. + diff --git a/physics/box2d_prismatic_joint/example/box2d_prismatic_joint.collection b/physics/box2d_prismatic_joint/example/box2d_prismatic_joint.collection new file mode 100644 index 00000000..4d39c841 --- /dev/null +++ b/physics/box2d_prismatic_joint/example/box2d_prismatic_joint.collection @@ -0,0 +1,150 @@ +name: "box2d_prismatic_joint" +scale_along_z: 0 +embedded_instances { + id: "controller" + data: "components {\n" + " id: \"script\"\n" + " component: \"/example/box2d_prismatic_joint.script\"\n" + "}\n" + "embedded_components {\n" + " id: \"label\"\n" + " type: \"label\"\n" + " data: \"size {\\n" + " x: 640.0\\n" + " y: 128.0\\n" + "}\\n" + "text: \\\"Box2D prismatic joint\\\"\\n" + "font: \\\"/fonts/text28.font\\\"\\n" + "material: \\\"/builtins/fonts/label-df.material\\\"\\n" + "\"\n" + " position {\n" + " y: -280.0\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"info\"\n" + " type: \"label\"\n" + " data: \"size {\\n" + " x: 640.0\\n" + " y: 128.0\\n" + "}\\n" + "text: \\\"Click or touch to change movement\\\"\\n" + "font: \\\"/fonts/text28.font\\\"\\n" + "material: \\\"/builtins/fonts/label-df.material\\\"\\n" + "\"\n" + " position {\n" + " y: 280.0\n" + " }\n" + "}\n" + "" + position { + x: 360.0 + y: 360.0 + } +} +embedded_instances { + id: "slider" + data: "embedded_components {\n" + " id: \"collisionobject\"\n" + " type: \"collisionobject\"\n" + " data: \"type: COLLISION_OBJECT_TYPE_DYNAMIC\\n" + "mass: 1.0\\n" + "friction: 0.0\\n" + "restitution: 0.0\\n" + "group: \\\"default\\\"\\n" + "embedded_collision_shape {\\n" + " shapes {\\n" + " shape_type: TYPE_BOX\\n" + " position {\\n" + " }\\n" + " rotation {\\n" + " }\\n" + " index: 0\\n" + " count: 3\\n" + " }\\n" + " data: 28.0\\n" + " data: 28.0\\n" + " data: 10.0\\n" + "}\\n" + "linear_damping: 0.05\\n" + "locked_rotation: true\\n" + "\"\n" + "}\n" + "embedded_components {\n" + " id: \"sprite\"\n" + " type: \"sprite\"\n" + " data: \"default_animation: \\\"pixel_blue\\\"\\n" + "material: \\\"/builtins/materials/sprite.material\\\"\\n" + "size {\\n" + " x: 56.0\\n" + " y: 56.0\\n" + "}\\n" + "size_mode: SIZE_MODE_MANUAL\\n" + "textures {\\n" + " sampler: \\\"texture_sampler\\\"\\n" + " texture: \\\"/textures/textures.atlas\\\"\\n" + "}\\n" + "\"\n" + "}\n" + "" + position { + x: 360.0 + y: 360.0 + } + rotation { + z: 0.38268343 + w: 0.9238795 + } +} +embedded_instances { + id: "rail" + data: "embedded_components {\n" + " id: \"collisionobject\"\n" + " type: \"collisionobject\"\n" + " data: \"type: COLLISION_OBJECT_TYPE_STATIC\\n" + "mass: 0.0\\n" + "friction: 0.0\\n" + "restitution: 0.0\\n" + "group: \\\"default\\\"\\n" + "embedded_collision_shape {\\n" + " shapes {\\n" + " shape_type: TYPE_BOX\\n" + " position {\\n" + " }\\n" + " rotation {\\n" + " }\\n" + " index: 0\\n" + " count: 3\\n" + " }\\n" + " data: 8.0\\n" + " data: 8.0\\n" + " data: 10.0\\n" + "}\\n" + "\"\n" + "}\n" + "embedded_components {\n" + " id: \"sprite\"\n" + " type: \"sprite\"\n" + " data: \"default_animation: \\\"pixel_white\\\"\\n" + "material: \\\"/builtins/materials/sprite.material\\\"\\n" + "size {\\n" + " x: 260.0\\n" + " y: 6.0\\n" + "}\\n" + "size_mode: SIZE_MODE_MANUAL\\n" + "textures {\\n" + " sampler: \\\"texture_sampler\\\"\\n" + " texture: \\\"/textures/textures.atlas\\\"\\n" + "}\\n" + "\"\n" + " rotation {\n" + " z: 0.38268343\n" + " w: 0.9238795\n" + " }\n" + "}\n" + "" + position { + x: 360.0 + y: 360.0 + } +} diff --git a/physics/box2d_prismatic_joint/example/box2d_prismatic_joint.script b/physics/box2d_prismatic_joint/example/box2d_prismatic_joint.script new file mode 100644 index 00000000..0e1f2043 --- /dev/null +++ b/physics/box2d_prismatic_joint/example/box2d_prismatic_joint.script @@ -0,0 +1,95 @@ +-- Unit vector for a 45 degree rail. This is the same direction as the rail sprite. +local AXIS = vmath.vector3(0.70710678, 0.70710678, 0) + +-- Prismatic translation is measured along `local_axis_a`, in project units. +-- Define farthest limits on both ends: +local LOWER_TRANSLATION = -110 +local UPPER_TRANSLATION = 110 + +-- Define motor speed that will be used to move the slider +local MOTOR_SPEED = 50 + +-- Some maximum motor force allows to apply a force on the slider to push it +local MAX_MOTOR_FORCE = 1200 + +function init(self) + -- This will be storing a current direction of the slider + self.direction = 1 + + -- Acquire input focus to handle inputs + msg.post(".", "acquire_input_focus") + + -- `b2d.get_body()` returns the native Box2D body created by the given collision object. + local slider = b2d.get_body("/slider#collisionobject") + local anchor = b2d.get_body("/rail#collisionobject") + + -- This creates a prismatic joint in runtime between the 2 bodies - an anchor and a slider. + -- The joint axis matches the visible diagonal rail in the collection. + self.joint = b2d.joint.create_prismatic(anchor, slider, { + -- Both bodies start at the same position, so zero local anchors share the same joint origin. + local_anchor_a = vmath.vector3(), + local_anchor_b = vmath.vector3(), + + -- The axis is local to body A, the static anchor. + local_axis_a = AXIS, + + -- Limits keep the dynamic body between the two ends of the rail. + enable_limit = true, + lower_translation = LOWER_TRANSLATION, + upper_translation = UPPER_TRANSLATION, + + -- The motor pushes the slider along the axis without extra forces in update(). + enable_motor = true, + max_motor_force = MAX_MOTOR_FORCE, + motor_speed = self.direction * MOTOR_SPEED, + + -- The connected bodies do not need to collide with each other in this example. + collide_connected = false, + }) +end + +-- Helper function to reverse the motor direction +local function reverse_motor(self) + -- Assign a negative direction to the current direction variable + self.direction = -self.direction + + -- Positive and negative speed move the slider in opposite directions along the axis. + b2d.joint.set_motor_speed(self.joint, self.direction * MOTOR_SPEED) +end + +function update(self, dt) + -- The function returns a translation on the defined joint in project units + local translation = b2d.joint.get_joint_translation(self.joint) + + -- Reverse automatically when the slider reaches either translation limit. + if self.direction > 0 and translation > UPPER_TRANSLATION then + reverse_motor(self) + elseif self.direction < 0 and translation < LOWER_TRANSLATION then + reverse_motor(self) + end + + -- Create a string describing the current direction + local direction_string = self.direction > 0 and "up-right" or "down-left" + + -- Update the information on the label + label.set_text("#label", string.format("Motor: %s\nTranslation: %.0f", direction_string, translation)) +end + +function on_input(self, action_id, action) + -- The built-in touch action also covers mouse clicks in the built-in all.input_binding. + if action_id == hash("touch") and action.pressed then + -- When click or touch is pressed we reverse the motor direction + reverse_motor(self) + end +end + +function final(self) + -- Joints created through b2d.joint should be explicitly destroyed. + if self.joint then + b2d.joint.destroy(self.joint) + self.joint = nil + end + + -- Release input focus + msg.post(".", "release_input_focus") +end diff --git a/physics/box2d_prismatic_joint/fonts/SourceSansPro-Semibold.ttf b/physics/box2d_prismatic_joint/fonts/SourceSansPro-Semibold.ttf new file mode 100644 index 00000000..50205948 Binary files /dev/null and b/physics/box2d_prismatic_joint/fonts/SourceSansPro-Semibold.ttf differ diff --git a/physics/box2d_prismatic_joint/fonts/text28.font b/physics/box2d_prismatic_joint/fonts/text28.font new file mode 100644 index 00000000..3d9c4a8e --- /dev/null +++ b/physics/box2d_prismatic_joint/fonts/text28.font @@ -0,0 +1,5 @@ +font: "/fonts/SourceSansPro-Semibold.ttf" +material: "/builtins/fonts/font-df.material" +size: 28 +output_format: TYPE_DISTANCE_FIELD +characters: " !\"#$%&\'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~" diff --git a/physics/box2d_prismatic_joint/game.project b/physics/box2d_prismatic_joint/game.project new file mode 100644 index 00000000..f43b8340 --- /dev/null +++ b/physics/box2d_prismatic_joint/game.project @@ -0,0 +1,39 @@ +[bootstrap] +main_collection = /example/box2d_prismatic_joint.collectionc + +[script] +shared_state = 1 + +[display] +width = 720 +height = 720 +high_dpi = 1 + +[android] +input_method = HiddenInputField + +[physics] +gravity_y = -900.0 +scale = 0.01 +use_fixed_timestep = 1 + +[html5] +show_fullscreen_button = 0 +show_made_with_defold = 0 +scale_mode = no_scale +heap_size = 64 + +[input] +game_binding = /builtins/input/all.input_bindingc + +[project] +title = Box2D Prismatic Joint + +[native_extension] +app_manifest = /box2d_v3.appmanifest + +[render] +clear_color_red = 0.160156 +clear_color_green = 0.164063 +clear_color_blue = 0.183594 + diff --git a/physics/box2d_prismatic_joint/setup.png b/physics/box2d_prismatic_joint/setup.png new file mode 100644 index 00000000..3e16b106 Binary files /dev/null and b/physics/box2d_prismatic_joint/setup.png differ diff --git a/physics/box2d_prismatic_joint/textures/pixel_blue.png b/physics/box2d_prismatic_joint/textures/pixel_blue.png new file mode 100644 index 00000000..2db50d55 Binary files /dev/null and b/physics/box2d_prismatic_joint/textures/pixel_blue.png differ diff --git a/physics/box2d_prismatic_joint/textures/pixel_white.png b/physics/box2d_prismatic_joint/textures/pixel_white.png new file mode 100644 index 00000000..0e34154f Binary files /dev/null and b/physics/box2d_prismatic_joint/textures/pixel_white.png differ diff --git a/physics/box2d_prismatic_joint/textures/textures.atlas b/physics/box2d_prismatic_joint/textures/textures.atlas new file mode 100644 index 00000000..83eabe2e --- /dev/null +++ b/physics/box2d_prismatic_joint/textures/textures.atlas @@ -0,0 +1,7 @@ +images { + image: "/textures/pixel_white.png" +} +images { + image: "/textures/pixel_blue.png" +} +extrude_borders: 2 diff --git a/physics/box2d_prismatic_joint/thumbnail.webp b/physics/box2d_prismatic_joint/thumbnail.webp new file mode 100644 index 00000000..89e97489 Binary files /dev/null and b/physics/box2d_prismatic_joint/thumbnail.webp differ