diff --git a/physics/box2d_chain_terrain/all.texture_profiles b/physics/box2d_chain_terrain/all.texture_profiles new file mode 100644 index 00000000..5b0d7762 --- /dev/null +++ b/physics/box2d_chain_terrain/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_chain_terrain/box2D_V2.appmanifest b/physics/box2d_chain_terrain/box2D_V2.appmanifest new file mode 100644 index 00000000..b3abe8c8 --- /dev/null +++ b/physics/box2d_chain_terrain/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_chain_terrain/box2D_V3.appmanifest b/physics/box2d_chain_terrain/box2D_V3.appmanifest new file mode 100644 index 00000000..9751deca --- /dev/null +++ b/physics/box2d_chain_terrain/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_chain_terrain/example.md b/physics/box2d_chain_terrain/example.md new file mode 100644 index 00000000..4c09de75 --- /dev/null +++ b/physics/box2d_chain_terrain/example.md @@ -0,0 +1,47 @@ +--- +tags: physics, box2d +title: Box2D Chain Terrain +brief: Create Box2D chain terrain from script using scripting with Box2D V2 (legacy) and V3. +author: Defold Foundation +scripts: box2d_chain_terrain_v3.script, box2d_chain_terrain_v2.script +thumbnail: thumbnail.webp +--- + +This example creates connected Box2D chain terrain at runtime. It works with both Box2D V2 and V3 by attaching one script for each backend. Each script checks `b2d.get_version()` during `init()` and becomes a no-op when the other backend is active. + +Click or tap the window to reset the ball and watch it roll over the same chain again. + +## What You'll Learn + +- How to get a Box2D body from a Defold collision object +- How to detect the active Box2D version with `b2d.get_version()` +- How to create chain terrain with `b2d.body.create_fixture()` in Box2D V2 Legacy Defold version. +- How to create chain terrain with `b2d.body.create_chain()` in Box2D V3. + +## Setup + +The collection contains a static `terrain` game object with one collision object. This is required because the runtime-created terrain is attached to an existing Box2D body. Defold creates that body from the collision object in the collection. + +The small box shape on `terrain` sits below the view. It is only a placeholder that gives the script a static body to attach the runtime chain to; the visible terrain is the chain itself, drawn with `@render:draw_line`. + +The `controller` game object has both backend scripts, a label, and a local factory component named `ball_factory`. The factory points at `/example/ball.go`, a shared prototype with one sprite and one dynamic circle collision object. + +![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`. + +![game_project](game_project.png) + +## How It Works + +Both scripts read `b2d.get_version()` once. `box2d_chain_terrain_v2.script` only continues when the major version is 2 (Defold legacy version), while `box2d_chain_terrain_v3.script` only continues when the major version is 3. + +`b2d.get_body()` returns the Box2D body owned by the hidden `terrain` collision object. The active script then builds the chain with the backend-specific chain API. + +In Box2D V2 Legacy Defold version., the script passes a chain shape definition to `b2d.body.create_fixture()`, which creates connected segments on the same static body. + +In Box2D V3, the script uses `b2d.body.create_chain()`, which creates a true chain with segment adjacency and ghost vertices. + +The shape definition includes `prev_vertex` and `next_vertex`. These are ghost vertices placed just outside the first and last terrain points. They do not add visible terrain segments; they tell Box2D how the open chain would continue past its endpoints so endpoint collision normals stay consistent. + +The script redraws the chain vertices each frame with `@render:draw_line`, because the chain itself is a physics shape and has no sprite. The ball is created from the factory, given an initial velocity with `b2d.body.set_linear_velocity()`, and then reset on a timer or when the user clicks or taps. diff --git a/physics/box2d_chain_terrain/example/ball.go b/physics/box2d_chain_terrain/example/ball.go new file mode 100644 index 00000000..4428e736 --- /dev/null +++ b/physics/box2d_chain_terrain/example/ball.go @@ -0,0 +1,43 @@ +embedded_components { + id: "sprite" + type: "sprite" + data: "default_animation: \"ball\"\n" + "material: \"/builtins/materials/sprite.material\"\n" + "size {\n" + " x: 254.0\n" + " y: 254.0\n" + "}\n" + "textures {\n" + " sampler: \"texture_sampler\"\n" + " texture: \"/textures/textures.atlas\"\n" + "}\n" + "" + scale { + x: 0.5 + y: 0.5 + } +} +embedded_components { + id: "collisionobject" + type: "collisionobject" + data: "type: COLLISION_OBJECT_TYPE_DYNAMIC\n" + "mass: 0.5\n" + "friction: 0.4\n" + "restitution: 0.05\n" + "group: \"default\"\n" + "mask: \"default\"\n" + "embedded_collision_shape {\n" + " shapes {\n" + " shape_type: TYPE_SPHERE\n" + " position {\n" + " }\n" + " rotation {\n" + " }\n" + " index: 0\n" + " count: 1\n" + " }\n" + " data: 31.5\n" + "}\n" + "angular_damping: 0.02\n" + "" +} diff --git a/physics/box2d_chain_terrain/example/box2d_chain_terrain.collection b/physics/box2d_chain_terrain/example/box2d_chain_terrain.collection new file mode 100644 index 00000000..fb07f1b3 --- /dev/null +++ b/physics/box2d_chain_terrain/example/box2d_chain_terrain.collection @@ -0,0 +1,70 @@ +name: "box2d_chain_terrain" +scale_along_z: 0 +embedded_instances { + id: "terrain" + data: "embedded_components {\n" + " id: \"collisionobject\"\n" + " type: \"collisionobject\"\n" + " data: \"type: COLLISION_OBJECT_TYPE_STATIC\\n" + "mass: 0.0\\n" + "friction: 0.65\\n" + "restitution: 0.0\\n" + "group: \\\"default\\\"\\n" + "mask: \\\"default\\\"\\n" + "embedded_collision_shape {\\n" + " shapes {\\n" + " shape_type: TYPE_BOX\\n" + " position {\\n" + " x: 360.0\\n" + " y: -120.0\\n" + " }\\n" + " rotation {\\n" + " }\\n" + " index: 0\\n" + " count: 3\\n" + " }\\n" + " data: 10.0\\n" + " data: 10.0\\n" + " data: 10.0\\n" + "}\\n" + "event_collision: false\\n" + "event_contact: false\\n" + "event_trigger: false\\n" + "\"\n" + "}\n" + "" +} +embedded_instances { + id: "controller" + data: "components {\n" + " id: \"box2d_v2\"\n" + " component: \"/example/box2d_chain_terrain_v2.script\"\n" + "}\n" + "components {\n" + " id: \"box2d_v3\"\n" + " component: \"/example/box2d_chain_terrain_v3.script\"\n" + "}\n" + "embedded_components {\n" + " id: \"label\"\n" + " type: \"label\"\n" + " data: \"size {\\n" + " x: 640.0\\n" + " y: 100.0\\n" + "}\\n" + "text: \\\"Click or touch to reset\\\"\\n" + "font: \\\"/fonts/text28.font\\\"\\n" + "material: \\\"/builtins/fonts/label-df.material\\\"\\n" + "\"\n" + " position {\n" + " x: 360.0\n" + " y: 660.0\n" + " }\n" + "}\n" + "embedded_components {\n" + " id: \"ball_factory\"\n" + " type: \"factory\"\n" + " data: \"prototype: \\\"/example/ball.go\\\"\\n" + "\"\n" + "}\n" + "" +} diff --git a/physics/box2d_chain_terrain/example/box2d_chain_terrain_v2.script b/physics/box2d_chain_terrain/example/box2d_chain_terrain_v2.script new file mode 100644 index 00000000..81dc437c --- /dev/null +++ b/physics/box2d_chain_terrain/example/box2d_chain_terrain_v2.script @@ -0,0 +1,148 @@ +local BALL_START = vmath.vector3(650, 545, 0) +local BALL_VELOCITY = vmath.vector3(-140, 0, 0) +local CHAIN_COLOR = vmath.vector4(0.0, 0.9, 0.88, 1.0) +local PREV_GHOST_VERTEX = vmath.vector3(715, 505, 0) +local NEXT_GHOST_VERTEX = vmath.vector3(35, 235, 0) + +local TERRAIN_VERTICES = { + vmath.vector3(650, 480, 0), + vmath.vector3(560, 455, 0), + vmath.vector3(470, 395, 0), + vmath.vector3(380, 380, 0), + vmath.vector3(300, 315, 0), + vmath.vector3(210, 275, 0), + vmath.vector3(95, 265, 0), +} + +local function draw_line(from, to, color) + msg.post("@render:", "draw_line", { start_point = from, end_point = to, color = color }) -- <1> +end + +local function get_major_version() + local version = b2d.get_version() + if type(version) == "table" then + return version.major + end + return tonumber(string.match(version, "^(%d+)")) +end + +local function clear_fixtures(body) + local fixtures = b2d.body.get_fixtures(body) -- <2> + for i = #fixtures, 1, -1 do + b2d.body.destroy_fixture(body, fixtures[i].index) -- <3> + end +end + +local function create_chain(body) + clear_fixtures(body) + + return b2d.body.create_fixture(body, { + density = 0.0, + friction = 0.65, + restitution = 0.2, + shape = { + type = b2d.shape.SHAPE_TYPE_CHAIN, + vertices = TERRAIN_VERTICES, + prev_vertex = PREV_GHOST_VERTEX, + next_vertex = NEXT_GHOST_VERTEX, + }, + }) -- <4> +end + +local function delete_ball(self) + if self.ball_id then + go.delete(self.ball_id) + end +end + +local function spawn_ball(self) + delete_ball(self) + self.ball_id = factory.create("#ball_factory", BALL_START) -- <5> + + local ball_body = b2d.get_body(msg.url(nil, self.ball_id, "collisionobject")) + if b2d.body.set_active then + b2d.body.set_active(ball_body, true) -- <6> + end + b2d.body.set_linear_velocity(ball_body, BALL_VELOCITY) -- <7> + b2d.body.set_angular_velocity(ball_body, -4.0) +end + +local function draw_chain() + for i = 1, #TERRAIN_VERTICES - 1 do + draw_line(TERRAIN_VERTICES[i], TERRAIN_VERTICES[i + 1], CHAIN_COLOR) -- <8> + end +end + +local function start_reset_timer(self) + self.reset_timer = timer.delay(2.5, true, function() spawn_ball(self) end) -- <9> +end + +local function cancel_reset_timer(self) + if self.reset_timer then + timer.cancel(self.reset_timer) + self.reset_timer = nil + end +end + +function init(self) + self.active = get_major_version() == 2 -- <10> + + if not self.active then -- <11> + return + end + + msg.post(".", "acquire_input_focus") + local terrain_body = b2d.get_body(msg.url(nil, "terrain", "collisionobject")) -- <12> + self.chain = create_chain(terrain_body) -- <13> + label.set_text("#label", "Box2D V2 chain\nClick or touch to reset") + spawn_ball(self) + start_reset_timer(self) +end + +function update(self, dt) + if self.active then + draw_chain() + end +end + +local TOUCH = hash("touch") + +function on_input(self, action_id, action) + if not self.active then + return + end + + if action_id == TOUCH and action.pressed then -- <14> + spawn_ball(self) + cancel_reset_timer(self) -- <15> + start_reset_timer(self) + end +end + +function final(self) + if not self.active then + return + end + + delete_ball(self) + cancel_reset_timer(self) + msg.post(".", "release_input_focus") +end + +--[[ +1. Draw each terrain segment through the render socket. The lines are transient, so the chain is redrawn every frame. +2. Read the existing Box2D V2 fixtures from the placeholder body. +3. Remove the placeholder fixture so only the runtime chain remains. +4. Attach a V2 chain fixture to the terrain body with `b2d.body.create_fixture()` and `b2d.shape.SHAPE_TYPE_CHAIN`. +5. Spawn one dynamic ball from the local factory at the start of the chain. +6. Explicitly activate the spawned body on backends that expose body activation. +7. Give the ball an initial velocity so it rolls across the terrain immediately. +8. Draw the runtime terrain again each frame because the render line messages do not persist. +9. Replay the ball automatically so the example stays active without input. +10. Detect whether the running engine uses the Box2D V2 backend. The helper accepts both table and string version formats. +11. Leave this script as a no-op when the project uses another backend. +12. Get the Box2D body owned by the hidden `terrain` collision object in the collection. +13. Build the V2 chain terrain. +14. Clicks and taps reset the ball manually. +15. Reset the repeating timer after manual input so the next automatic reset waits for a full interval. +]] diff --git a/physics/box2d_chain_terrain/example/box2d_chain_terrain_v3.script b/physics/box2d_chain_terrain/example/box2d_chain_terrain_v3.script new file mode 100644 index 00000000..6223a79b --- /dev/null +++ b/physics/box2d_chain_terrain/example/box2d_chain_terrain_v3.script @@ -0,0 +1,144 @@ +local BALL_START = vmath.vector3(650, 545, 0) +local BALL_VELOCITY = vmath.vector3(-140, 0, 0) +local CHAIN_COLOR = vmath.vector4(0.0, 0.9, 0.88, 1.0) +local PREV_GHOST_VERTEX = vmath.vector3(715, 505, 0) +local NEXT_GHOST_VERTEX = vmath.vector3(35, 235, 0) + +local TERRAIN_VERTICES = { + vmath.vector3(650, 480, 0), + vmath.vector3(560, 455, 0), + vmath.vector3(470, 395, 0), + vmath.vector3(380, 380, 0), + vmath.vector3(300, 315, 0), + vmath.vector3(210, 275, 0), + vmath.vector3(95, 265, 0), +} + +local function draw_line(from, to, color) + msg.post("@render:", "draw_line", { start_point = from, end_point = to, color = color }) -- <1> +end + +local function get_major_version() + local version = b2d.get_version() + if type(version) == "table" then + return version.major + end + return tonumber(string.match(version, "^(%d+)")) +end + +local function clear_shapes(body) + local shapes = b2d.body.get_shapes(body) -- <2> + for i = #shapes, 1, -1 do + b2d.body.destroy_shape(body, shapes[i].index) -- <3> + end +end + +local function create_chain(body) + clear_shapes(body) + + return b2d.body.create_chain(body, { + vertices = TERRAIN_VERTICES, + prev_vertex = PREV_GHOST_VERTEX, + next_vertex = NEXT_GHOST_VERTEX, + friction = 0.65, + restitution = 0.2, + }) -- <4> +end + +local function delete_ball(self) + if self.ball_id then + go.delete(self.ball_id) + end +end + +local function spawn_ball(self) + delete_ball(self) + self.ball_id = factory.create("#ball_factory", BALL_START) -- <5> + + local ball_body = b2d.get_body(msg.url(nil, self.ball_id, "collisionobject")) + if b2d.body.set_active then + b2d.body.set_active(ball_body, true) -- <6> + end + b2d.body.set_linear_velocity(ball_body, BALL_VELOCITY) -- <7> + b2d.body.set_angular_velocity(ball_body, -4.0) +end + +local function draw_chain() + for i = 1, #TERRAIN_VERTICES - 1 do + draw_line(TERRAIN_VERTICES[i], TERRAIN_VERTICES[i + 1], CHAIN_COLOR) -- <8> + end +end + +local function start_reset_timer(self) + self.reset_timer = timer.delay(2.5, true, function() spawn_ball(self) end) -- <9> +end + +local function cancel_reset_timer(self) + if self.reset_timer then + timer.cancel(self.reset_timer) + self.reset_timer = nil + end +end + +function init(self) + self.active = get_major_version() == 3 -- <10> + + if not self.active then -- <11> + return + end + + msg.post(".", "acquire_input_focus") + local terrain_body = b2d.get_body(msg.url(nil, "terrain", "collisionobject")) -- <12> + self.chain, self.chain_segments = create_chain(terrain_body) -- <13> + label.set_text("#label", "Box2D V3 chain\nClick or touch to reset") + spawn_ball(self) + start_reset_timer(self) +end + +function update(self, dt) + if self.active then + draw_chain() + end +end + +local TOUCH = hash("touch") + +function on_input(self, action_id, action) + if not self.active then + return + end + + if action_id == TOUCH and action.pressed then -- <14> + spawn_ball(self) + cancel_reset_timer(self) -- <15> + start_reset_timer(self) + end +end + +function final(self) + if not self.active then + return + end + + delete_ball(self) + cancel_reset_timer(self) + msg.post(".", "release_input_focus") +end + +--[[ +1. Draw each terrain segment through the render socket. The lines are transient, so the chain is redrawn every frame. +2. Read the existing Box2D V3 shapes from the placeholder body. +3. Remove the placeholder shape before creating the V3 chain. +4. Create V3 chain terrain with `b2d.body.create_chain()` so ghost vertices are preserved. +5. Spawn one dynamic ball from the local factory at the start of the chain. +6. Explicitly activate the spawned body on backends that expose body activation. +7. Give the ball an initial velocity so it rolls across the terrain immediately. +8. Draw the runtime terrain again each frame because the render line messages do not persist. +9. Replay the ball automatically so the example stays active without input. +10. Detect whether the running engine uses the Box2D V3 backend. The helper accepts both table and string version formats. +11. Leave this script as a no-op when the project uses another backend. +12. Get the Box2D body owned by the hidden `terrain` collision object in the collection. +13. Build the V3 chain terrain and keep both returned handles alive. +14. Clicks and taps reset the ball manually. +15. Reset the repeating timer after manual input so the next automatic reset waits for a full interval. +]] diff --git a/physics/box2d_chain_terrain/fonts/SourceSansPro-Semibold.ttf b/physics/box2d_chain_terrain/fonts/SourceSansPro-Semibold.ttf new file mode 100644 index 00000000..50205948 Binary files /dev/null and b/physics/box2d_chain_terrain/fonts/SourceSansPro-Semibold.ttf differ diff --git a/physics/box2d_chain_terrain/fonts/text28.font b/physics/box2d_chain_terrain/fonts/text28.font new file mode 100644 index 00000000..3d9c4a8e --- /dev/null +++ b/physics/box2d_chain_terrain/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_chain_terrain/game.project b/physics/box2d_chain_terrain/game.project new file mode 100644 index 00000000..0a07d101 --- /dev/null +++ b/physics/box2d_chain_terrain/game.project @@ -0,0 +1,36 @@ +[bootstrap] +main_collection = /example/box2d_chain_terrain.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] +scale_mode = stretch + +[input] +game_binding = /builtins/input/all.input_bindingc + +[project] +title = Box2D Chain Terrain + +[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_chain_terrain/game_project.png b/physics/box2d_chain_terrain/game_project.png new file mode 100644 index 00000000..e3ed2380 Binary files /dev/null and b/physics/box2d_chain_terrain/game_project.png differ diff --git a/physics/box2d_chain_terrain/setup.png b/physics/box2d_chain_terrain/setup.png new file mode 100644 index 00000000..c78046b7 Binary files /dev/null and b/physics/box2d_chain_terrain/setup.png differ diff --git a/physics/box2d_chain_terrain/textures/ball.png b/physics/box2d_chain_terrain/textures/ball.png new file mode 100644 index 00000000..01976c24 Binary files /dev/null and b/physics/box2d_chain_terrain/textures/ball.png differ diff --git a/physics/box2d_chain_terrain/textures/textures.atlas b/physics/box2d_chain_terrain/textures/textures.atlas new file mode 100644 index 00000000..4c4ae4fb --- /dev/null +++ b/physics/box2d_chain_terrain/textures/textures.atlas @@ -0,0 +1,4 @@ +images { + image: "/textures/ball.png" +} +extrude_borders: 2 diff --git a/physics/box2d_chain_terrain/thumbnail.webp b/physics/box2d_chain_terrain/thumbnail.webp new file mode 100644 index 00000000..4b83e0db Binary files /dev/null and b/physics/box2d_chain_terrain/thumbnail.webp differ