Skip to content

Commit

Permalink
Add look rotation example (#55)
Browse files Browse the repository at this point in the history
  • Loading branch information
aglitchman authored Oct 30, 2024
1 parent 8042b97 commit c251282
Show file tree
Hide file tree
Showing 8 changed files with 251 additions and 1 deletion.
Binary file not shown.
Binary file not shown.
2 changes: 1 addition & 1 deletion examples/_main/examples.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ local examples = {}

examples["basics"] = { "message_passing", "parent_child", "z_order" }
examples["factory"] = { "basic", "bullets", "dynamic" }
examples["movement"] = { "simple_move", "follow", "move_to", "move_forward", "movement_speed", "look_at" }
examples["movement"] = { "simple_move", "follow", "move_to", "move_forward", "movement_speed", "look_at", "look_rotation" }
examples["physics"] = { "dynamic", "kinematic", "raycast", "trigger", "hinge_joint", "pendulum", "knockback"}
examples["animation"] = { "euler_rotation", "spinner", "flipbook", "chained_tween", "basic_tween", "spine", "cursor", "easing" }
examples["gui"] = {
Expand Down
6 changes: 6 additions & 0 deletions examples/_main/loader.go
Original file line number Diff line number Diff line change
Expand Up @@ -466,3 +466,9 @@ embedded_components {
data: "collection: \"/examples/render/orbit_camera/orbit_camera.collection\"\n"
""
}
embedded_components {
id: "movement/look_rotation"
type: "collectionproxy"
data: "collection: \"/examples/movement/look_rotation/look_rotation.collection\"\n"
""
}
3 changes: 3 additions & 0 deletions examples/movement/look_at/look_at.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
---
name: Look at
title: Look at
brief: This example shows how to rotate a game object to look at the mouse cursor
scripts: look_at.script
---

This example shows how to rotate a game object to look at the mouse cursor. It reads the mouse position in `on_input` and uses the mathematical function `math.atan2(x, y)` to calculate the angle between the ray to the point to look at and the positive x-axis. This angle is used to set the rotation of the game object to always look at the mouse position.

The example is suitable for the movement in two dimensions, for platformers or top-down games. For 3D objects, check out the [next example](/examples/movement/look_rotation/).
163 changes: 163 additions & 0 deletions examples/movement/look_rotation/look_rotation.collection
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
name: "look_rotation"
scale_along_z: 1
embedded_instances {
id: "main"
data: "components {\n"
" id: \"look_rotation\"\n"
" component: \"/examples/movement/look_rotation/look_rotation.script\"\n"
"}\n"
"components {\n"
" id: \"orbit_camera\"\n"
" component: \"/examples/render/orbit_camera/orbit_camera.script\"\n"
" properties {\n"
" id: \"zoom\"\n"
" value: \"6.0\"\n"
" type: PROPERTY_TYPE_NUMBER\n"
" }\n"
"}\n"
"embedded_components {\n"
" id: \"camera\"\n"
" type: \"camera\"\n"
" data: \"aspect_ratio: 1.0\\n"
"fov: 0.7854\\n"
"near_z: 0.1\\n"
"far_z: 1000.0\\n"
"auto_aspect_ratio: 1\\n"
"\"\n"
"}\n"
""
}
embedded_instances {
id: "sword"
data: "embedded_components {\n"
" id: \"model\"\n"
" type: \"model\"\n"
" data: \"mesh: \\\"/assets/models/kenney_prototype-kit/weapon-sword.glb\\\"\\n"
"name: \\\"{{NAME}}\\\"\\n"
"materials {\\n"
" name: \\\"colormap\\\"\\n"
" material: \\\"/examples/material/unlit/unlit.material\\\"\\n"
" textures {\\n"
" sampler: \\\"texture0\\\"\\n"
" texture: \\\"/assets/models/kenney_prototype-kit/Textures/colormap.png\\\"\\n"
" }\\n"
"}\\n"
"\"\n"
" position {\n"
" y: -0.05\n"
" }\n"
" rotation {\n"
" y: -0.70710677\n"
" w: 0.70710677\n"
" }\n"
"}\n"
""
}
embedded_instances {
id: "target2"
data: "embedded_components {\n"
" id: \"model\"\n"
" type: \"model\"\n"
" data: \"mesh: \\\"/assets/models/kenney_prototype-kit/target-a-round.glb\\\"\\n"
"name: \\\"{{NAME}}\\\"\\n"
"materials {\\n"
" name: \\\"colormap\\\"\\n"
" material: \\\"/examples/material/unlit/unlit.material\\\"\\n"
" textures {\\n"
" sampler: \\\"texture0\\\"\\n"
" texture: \\\"/assets/models/kenney_prototype-kit/Textures/colormap.png\\\"\\n"
" }\\n"
"}\\n"
"\"\n"
" position {\n"
" y: -0.25\n"
" }\n"
"}\n"
""
position {
x: 1.0
y: 1.0
z: -2.0
}
rotation {
x: 0.10821981
y: 0.488148
z: 0.1874422
w: 0.84549713
}
scale3 {
x: 2.0
}
}
embedded_instances {
id: "target3"
data: "embedded_components {\n"
" id: \"model\"\n"
" type: \"model\"\n"
" data: \"mesh: \\\"/assets/models/kenney_prototype-kit/target-a-round.glb\\\"\\n"
"name: \\\"{{NAME}}\\\"\\n"
"materials {\\n"
" name: \\\"colormap\\\"\\n"
" material: \\\"/examples/material/unlit/unlit.material\\\"\\n"
" textures {\\n"
" sampler: \\\"texture0\\\"\\n"
" texture: \\\"/assets/models/kenney_prototype-kit/Textures/colormap.png\\\"\\n"
" }\\n"
"}\\n"
"\"\n"
" position {\n"
" y: -0.25\n"
" }\n"
"}\n"
""
position {
x: -1.5
y: -0.5
z: -1.0
}
rotation {
x: -0.12094011
y: 0.9186313
z: -0.049097624
w: 0.37293348
}
scale3 {
x: 2.0
}
}
embedded_instances {
id: "target1"
data: "embedded_components {\n"
" id: \"model\"\n"
" type: \"model\"\n"
" data: \"mesh: \\\"/assets/models/kenney_prototype-kit/target-a-round.glb\\\"\\n"
"name: \\\"{{NAME}}\\\"\\n"
"materials {\\n"
" name: \\\"colormap\\\"\\n"
" material: \\\"/examples/material/unlit/unlit.material\\\"\\n"
" textures {\\n"
" sampler: \\\"texture0\\\"\\n"
" texture: \\\"/assets/models/kenney_prototype-kit/Textures/colormap.png\\\"\\n"
" }\\n"
"}\\n"
"\"\n"
" position {\n"
" y: -0.25\n"
" }\n"
"}\n"
""
position {
x: 1.0
y: -1.0
z: 1.0
}
rotation {
x: 0.1071506
y: -0.3398383
z: -0.28096747
w: 0.891115
}
scale3 {
x: 2.0
}
}
14 changes: 14 additions & 0 deletions examples/movement/look_rotation/look_rotation.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
name: Look rotation (3D)
title: Look rotation
brief: This example shows how to rotate a game object to look at the object in 3D space.
scripts: look_rotation.script
---

This example shows how to orient a game object to look at the target game object in 3D space. For this purpose, we created the function `quat_look_rotation` (also called `LookRotation` or `looking_at` in the industry). This function creates a rotation matrix from the forward and upwards vectors and then converts it to a quaternion. The function also handles the case where no upwards direction is specified, using the default (0, 1, 0) in that case.

Note: to properly apply the resulting rotation, you must remember that your game object must face backwards to the "z" axis, i.e. in Defold the "forward" direction is vector (0, 0, -1).

In this demo you can rotate the camera by holding down the mouse button. And also switch "targets" by pressing any key.

The models used in this example are from Kenney's [Prototype Kit](https://kenney.nl/assets/prototype-kit), licensed under CC0.
64 changes: 64 additions & 0 deletions examples/movement/look_rotation/look_rotation.script
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
--- Creates a rotation with the specified forward and upwards directions.
-- @param forward vector3 The forward direction.
-- @param upwards vector3|nil The upwards direction.
-- @return quat The rotation.
local function quat_look_rotation(forward, upwards)
-- If no upwards direction is specified, use the default (0, 1, 0)
upwards = upwards or vmath.vector3(0, 1, 0)

-- No zero vectors
if vmath.length_sqr(forward) < 0.0000000001 or vmath.length_sqr(upwards) < 0.0000000001 then
return vmath.quat()
end

-- Create a rotation matrix from the forward and upwards vectors
local matrix = vmath.matrix4_look_at(vmath.vector3(0), forward, upwards)

-- Convert the matrix to a quaternion and return it
return vmath.conj(vmath.quat_matrix4(matrix))
end

local function next_target(self)
self.target = (self.target or 0) + 1
if self.target > #self.targets then
self.target = 1
end

local target_id = self.targets[self.target]

local from = go.get_position("/sword")
local to = go.get_position(target_id)

self.target_rotation = quat_look_rotation(to - from)
end

function init(self)
-- Acquire input focus to receive input events
msg.post(".", "acquire_input_focus")

-- List of target objects
self.targets = {
"/target1",
"/target2",
"/target3"
}

-- Set the initial target
next_target(self)
end

function update(self, dt)
-- If a target rotation is set, smoothly rotate the sword to face the target
if self.target_rotation then
-- Important: we must use vmath.slerp to animate quaternions
local q = vmath.slerp(0.15, go.get_rotation("/sword"), self.target_rotation)
go.set_rotation(q, "/sword")
end
end

function on_input(self, action_id, action)
-- If the action is pressed (any key or mouse button), set the next target
if action.pressed then
next_target(self)
end
end

0 comments on commit c251282

Please sign in to comment.