Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions animation/spine_ik/.gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Defold Protocol Buffer Text Files (https://github.com/github/linguist/issues/5091)
*.animationset linguist-language=JSON5
*.atlas linguist-language=JSON5
*.camera linguist-language=JSON5
*.collection linguist-language=JSON5
*.collectionfactory linguist-language=JSON5
*.collectionproxy linguist-language=JSON5
*.collisionobject linguist-language=JSON5
*.cubemap linguist-language=JSON5
*.display_profiles linguist-language=JSON5
*.factory linguist-language=JSON5
*.font linguist-language=JSON5
*.gamepads linguist-language=JSON5
*.go linguist-language=JSON5
*.gui linguist-language=JSON5
*.input_binding linguist-language=JSON5
*.label linguist-language=JSON5
*.material linguist-language=JSON5
*.mesh linguist-language=JSON5
*.model linguist-language=JSON5
*.particlefx linguist-language=JSON5
*.render linguist-language=JSON5
*.sound linguist-language=JSON5
*.sprite linguist-language=JSON5
*.spinemodel linguist-language=JSON5
*.spinescene linguist-language=JSON5
*.texture_profiles linguist-language=JSON5
*.tilemap linguist-language=JSON5
*.tilesource linguist-language=JSON5

# Defold JSON Files
*.buffer linguist-language=JSON

# Defold GLSL Shaders
*.fp linguist-language=GLSL
*.vp linguist-language=GLSL

# Defold Lua Files
*.editor_script linguist-language=Lua
*.render_script linguist-language=Lua
*.script linguist-language=Lua
*.gui_script linguist-language=Lua
11 changes: 11 additions & 0 deletions animation/spine_ik/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
/.editor_settings
/.internal
/build
.externalToolBuilders
.DS_Store
Thumbs.db
.lock-wscript
*.pyc
.project
.cproject
builtins
33 changes: 33 additions & 0 deletions animation/spine_ik/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
---
title: Handle Spine IK constraints
brief: Learn how to control Spine IK constraints by assigning a game object as the IK target.
author_ids:
- evgenii-starostin
scripts: area.script, cursor.script, manipulator.script
thumbnail: thumbnail.webp
tags: animation
---
This example demonstrates how to control Spine Inverse Kinematics (IK) constraints in Defold by assigning a game object as the IK target.

Move the mouse or touch in the active area (white rectangle in the background) to move the robot's arm with IK constraints.


## Project Structure
```
- root
- active_area.go
- collisionobject
- area.script
- sprite
- cursor.go
- collisionobject
- cursor.script
- manipulator.script
- spinemodel
```

## How It Works
The `cursor.go` game object is controlled by the user and has a collision object configured as a trigger.
When the cursor overlaps with the trigger in `active_area.go`, it sends a message to `manipulator.script`.
The script uses the Defold Spine API to assign `cursor.go` as the target of an IK constraint with spine.set_ik_target().
When the target is no longer needed, spine.reset_ik_target() resets the constraint to its original target position.
25 changes: 25 additions & 0 deletions animation/spine_ik/game.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[bootstrap]
main_collection = /main/main.collectionc

[script]
shared_state = 1

[display]
width = 960
height = 640
high_dpi = 1

[android]
input_method = HiddenInputField

[physics]
gravity_y = -1000.0
scale = 0.01

[html5]
scale_mode = stretch

[project]
title = spine_ik
dependencies#0 = https://github.com/defold/extension-spine/archive/refs/tags/4.9.4.zip

4 changes: 4 additions & 0 deletions animation/spine_ik/input/game.input_binding
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
mouse_trigger {
input: MOUSE_BUTTON_1
action: "touch"
}
6 changes: 6 additions & 0 deletions animation/spine_ik/main/area.script
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
local NORMAL_ALPHA = 0.8
local ALPHA_PROPERTY = hash("tint.w")

function init(self)
go.set("#sprite", ALPHA_PROPERTY, NORMAL_ALPHA)
end
25 changes: 25 additions & 0 deletions animation/spine_ik/main/base.atlas
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
images {
image: "/main/images/base_bot.png"
}
images {
image: "/main/images/base_top.png"
}
images {
image: "/main/images/blue_pin_min_bot.png"
}
images {
image: "/main/images/blue_pin_min_top.png"
}
images {
image: "/main/images/blue_pin_top.png"
}
images {
image: "/main/images/circle_pin_front.png"
}
images {
image: "/main/images/red_stick_bot.png"
}
images {
image: "/main/images/rect.png"
}
extrude_borders: 2
22 changes: 22 additions & 0 deletions animation/spine_ik/main/cursor.script
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
local MSG_TRIGGER = hash("trigger_response")
local MSG_PARENT = hash("parent")

function init(self)
msg.post(".", "acquire_input_focus")
end

function final(self)
msg.post(".", "release_input_focus")
end

function on_input(self, action_id, action)
if action.x and action.y then
go.set_position(vmath.vector3(action.x, action.y, 1))
end
end

function on_message(self, message_id, message, sender)
if message_id == MSG_TRIGGER then
msg.post("/root#manipulator", MSG_PARENT, { parent = message.enter })
end
end
Binary file added animation/spine_ik/main/images/base_bot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added animation/spine_ik/main/images/base_top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added animation/spine_ik/main/images/blue_pin_top.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added animation/spine_ik/main/images/rect.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added animation/spine_ik/main/images/red_stick_bot.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
128 changes: 128 additions & 0 deletions animation/spine_ik/main/main.collection
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
name: "main"
scale_along_z: 0
embedded_instances {
id: "root"
children: "active_area"
children: "cursor"
data: "components {\n"
" id: \"manipulator\"\n"
" component: \"/main/manipulator.script\"\n"
"}\n"
"embedded_components {\n"
" id: \"spinemodel\"\n"
" type: \"spinemodel\"\n"
" data: \"spine_scene: \\\"/main/spine/manipulator.spinescene\\\"\\n"
"default_animation: \\\"idle\\\"\\n"
"skin: \\\"\\\"\\n"
"material: \\\"/defold-spine/assets/spine.material\\\"\\n"
"create_go_bones: true\\n"
"\"\n"
" position {\n"
" x: 480.0\n"
" }\n"
"}\n"
""
}
embedded_instances {
id: "cursor"
data: "components {\n"
" id: \"cursor\"\n"
" component: \"/main/cursor.script\"\n"
"}\n"
"embedded_components {\n"
" id: \"collisionobject\"\n"
" type: \"collisionobject\"\n"
" data: \"type: COLLISION_OBJECT_TYPE_TRIGGER\\n"
"mass: 0.0\\n"
"friction: 0.1\\n"
"restitution: 0.5\\n"
"group: \\\"cursor\\\"\\n"
"mask: \\\"area\\\"\\n"
"embedded_collision_shape {\\n"
" shapes {\\n"
" shape_type: TYPE_BOX\\n"
" position {\\n"
" }\\n"
" rotation {\\n"
" }\\n"
" index: 0\\n"
" count: 3\\n"
" id: \\\"box\\\"\\n"
" }\\n"
" data: 2.5\\n"
" data: 2.5\\n"
" data: 10.0\\n"
"}\\n"
"event_collision: false\\n"
"event_contact: false\\n"
"\"\n"
"}\n"
""
position {
x: 689.0
y: 369.0
}
}
embedded_instances {
id: "active_area"
data: "components {\n"
" id: \"area\"\n"
" component: \"/main/area.script\"\n"
"}\n"
"embedded_components {\n"
" id: \"collisionobject\"\n"
" type: \"collisionobject\"\n"
" data: \"type: COLLISION_OBJECT_TYPE_TRIGGER\\n"
"mass: 0.0\\n"
"friction: 0.1\\n"
"restitution: 0.5\\n"
"group: \\\"area\\\"\\n"
"mask: \\\"cursor\\\"\\n"
"embedded_collision_shape {\\n"
" shapes {\\n"
" shape_type: TYPE_BOX\\n"
" position {\\n"
" }\\n"
" rotation {\\n"
" }\\n"
" index: 0\\n"
" count: 3\\n"
" id: \\\"base\\\"\\n"
" }\\n"
" data: 150.0\\n"
" data: 100.0\\n"
" data: 10.0\\n"
"}\\n"
"event_collision: false\\n"
"event_contact: false\\n"
"\"\n"
"}\n"
"embedded_components {\n"
" id: \"sprite\"\n"
" type: \"sprite\"\n"
" data: \"default_animation: \\\"rect\\\"\\n"
"material: \\\"/builtins/materials/sprite.material\\\"\\n"
"slice9 {\\n"
" x: 8.0\\n"
" y: 8.0\\n"
" z: 8.0\\n"
" w: 8.0\\n"
"}\\n"
"size {\\n"
" x: 300.0\\n"
" y: 200.0\\n"
"}\\n"
"size_mode: SIZE_MODE_MANUAL\\n"
"textures {\\n"
" sampler: \\\"texture_sampler\\\"\\n"
" texture: \\\"/main/base.atlas\\\"\\n"
"}\\n"
"\"\n"
"}\n"
""
position {
x: 480.0
y: 360.0
z: -0.5
}
}
17 changes: 17 additions & 0 deletions animation/spine_ik/main/manipulator.script
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
local IK_BONE = hash("RED_IK")
local SPINE_COMPONENT = "#spinemodel"
local MSG_PARENT = hash("parent")

function init(self)
self.target = go.get_id("cursor")
end

function on_message(self, message_id, message, sender)
if message_id == MSG_PARENT then
if message.parent then
spine.set_ik_target(SPINE_COMPONENT, IK_BONE, self.target)
else
spine.reset_ik_target(SPINE_COMPONENT, IK_BONE)
end
end
end
1 change: 1 addition & 0 deletions animation/spine_ik/main/spine/manipulator.spinejson
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"skeleton":{"hash":"OCs+C0uVJzw","spine":"4.2.43","x":-180.19,"y":1.91,"width":350.73,"height":556.54,"images":"../../manipulator/export/images/","audio":"./audio"},"bones":[{"name":"root"},{"name":"base","parent":"root"},{"name":"red_stick","parent":"base","length":157.89,"rotation":117.63,"x":-42.06,"y":111.65},{"name":"red_stick2","parent":"red_stick","length":138.98,"rotation":-68.81,"x":158.5,"y":1.16},{"name":"RED_IK","parent":"root","rotation":-12.89,"x":-25.06,"y":356.13,"color":"ff3f00ff","icon":"ik"},{"name":"blue_pin_top_1","parent":"red_stick2","length":114.16,"rotation":21.09,"x":170.1,"y":22.02,"color":"abe323ff"},{"name":"blue_pin_top_2","parent":"blue_pin_top_1","length":105.84,"rotation":-95.52,"x":136.17,"y":-3.08,"color":"abe323ff"},{"name":"blue_pin_bot_1","parent":"red_stick2","length":107.39,"rotation":-103.72,"x":152.81,"y":-0.67,"color":"abe323ff"},{"name":"blue_pin_bot_2","parent":"blue_pin_bot_1","length":92.62,"rotation":91.04,"x":141.91,"y":-2.49,"color":"abe323ff"}],"slots":[{"name":"base_bot","bone":"base","attachment":"base_bot"},{"name":"circle_pin_clone_back","bone":"red_stick","attachment":"circle_pin_front"},{"name":"circle_pin_clone_top_front","bone":"red_stick2","attachment":"circle_pin_front"},{"name":"red_stick_bot","bone":"red_stick","attachment":"red_stick_bot"},{"name":"base_top","bone":"base","attachment":"base_top"},{"name":"red_stick_top","bone":"red_stick2","attachment":"red_stick_top"},{"name":"blue_pin_top","bone":"blue_pin_top_1","attachment":"blue_pin_top"},{"name":"blue_pin_bot","bone":"blue_pin_bot_1","attachment":"blue_pin_top"},{"name":"circle_pin_front","bone":"red_stick","attachment":"circle_pin_front"},{"name":"circle_pin_clone_back_top","bone":"blue_pin_top_1","attachment":"circle_pin_front"},{"name":"circle_pin_clone_back_bot","bone":"blue_pin_bot_1","attachment":"circle_pin_front"},{"name":"blue_pin_min_top","bone":"blue_pin_top_2","attachment":"blue_pin_min_top"},{"name":"blue_pin_min_bot","bone":"blue_pin_bot_2","attachment":"blue_pin_min_bot"},{"name":"circle_pin_clone_front","bone":"red_stick2","attachment":"circle_pin_front"},{"name":"circle_pin_clone_front_top","bone":"blue_pin_top_1","attachment":"circle_pin_front"},{"name":"circle_pin_clone_front_bot","bone":"blue_pin_bot_1","attachment":"circle_pin_front"}],"ik":[{"name":"RED_IK","bones":["red_stick","red_stick2"],"target":"RED_IK","bendPositive":false}],"physics":[{"name":"blue_pin_bot_1","order":2,"bone":"blue_pin_bot_1","x":0.2,"y":0.2,"rotate":1,"inertia":0.5,"damping":0.85},{"name":"blue_pin_bot_2","order":4,"bone":"blue_pin_bot_2","x":0.1,"y":0.1,"rotate":1,"inertia":0.5,"damping":0.85},{"name":"blue_pin_top_1","order":1,"bone":"blue_pin_top_1","x":0.2,"y":0.2,"rotate":1,"inertia":0.5,"damping":0.85},{"name":"blue_pin_top_2","order":3,"bone":"blue_pin_top_2","x":0.1,"y":0.1,"rotate":1,"inertia":0.5,"damping":0.85}],"skins":[{"name":"default","attachments":{"base_bot":{"base_bot":{"x":27.86,"y":67.91,"width":227,"height":132}},"base_top":{"base_top":{"x":-44.95,"y":67.91,"width":227,"height":132}},"blue_pin_bot":{"blue_pin_top":{"x":55.9,"y":5.09,"rotation":108.94,"width":94,"height":143}},"blue_pin_min_bot":{"blue_pin_min_bot":{"x":60.8,"y":-4.81,"rotation":-36.14,"width":109,"height":85}},"blue_pin_min_top":{"blue_pin_min_top":{"x":71.53,"y":5.56,"rotation":25.62,"width":113,"height":78}},"blue_pin_top":{"blue_pin_top":{"x":60.58,"y":-5.57,"rotation":-69.9,"width":94,"height":143}},"circle_pin_clone_back":{"circle_pin_front":{"x":138.61,"y":-20.2,"rotation":-117.63,"width":116,"height":107}},"circle_pin_clone_back_bot":{"circle_pin_front":{"x":138.92,"y":27.3,"scaleX":0.806,"scaleY":0.806,"rotation":54.9,"width":116,"height":107}},"circle_pin_clone_back_top":{"circle_pin_front":{"x":136.26,"y":-35.98,"scaleX":0.8555,"scaleY":0.8555,"rotation":-69.9,"width":116,"height":107}},"circle_pin_clone_front":{"circle_pin_front":{"x":154.9,"y":7.59,"rotation":-48.81,"width":116,"height":107}},"circle_pin_clone_front_bot":{"circle_pin_front":{"x":124.71,"y":9.42,"scaleX":0.8586,"scaleY":0.8586,"rotation":54.9,"width":116,"height":107}},"circle_pin_clone_front_top":{"circle_pin_front":{"x":129.37,"y":-12.52,"scaleX":0.8824,"scaleY":0.8824,"rotation":-69.9,"width":116,"height":107}},"circle_pin_clone_top_front":{"circle_pin_front":{"x":167.4,"y":-5.06,"rotation":-48.81,"width":116,"height":107}},"circle_pin_front":{"circle_pin_front":{"x":153.2,"y":-0.55,"rotation":-117.63,"width":116,"height":107}},"red_stick_bot":{"red_stick_bot":{"x":69.41,"y":-8.5,"rotation":-117.63,"width":141,"height":181}},"red_stick_top":{"red_stick_top":{"path":"red_stick_bot","x":59.08,"y":-11.55,"rotation":-115.12,"width":141,"height":181}}}}],"animations":{"idle":{"bones":{"RED_IK":{"translate":[{"curve":[0.444,0,0.889,-2.95,0.444,0,0.889,-12.87]},{"time":1.3333,"x":-2.95,"y":-12.87,"curve":[1.778,-2.95,2.222,0,1.778,-12.87,2.222,0]},{"time":2.6667}]}}},"parent":{}}}
2 changes: 2 additions & 0 deletions animation/spine_ik/main/spine/manipulator.spinescene
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
spine_json: "/main/spine/manipulator.spinejson"
atlas: "/main/base.atlas"
Binary file added animation/spine_ik/thumbnail.webp
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading