瀏覽代碼

Add look rotation example (#55)

Artsiom Trubchyk 10 月之前
父節點
當前提交
c251282203

二進制
assets/models/kenney_prototype-kit/target-a-round.glb


二進制
assets/models/kenney_prototype-kit/weapon-sword.glb


+ 1 - 1
examples/_main/examples.lua

@@ -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"] = {

+ 6 - 0
examples/_main/loader.go

@@ -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 - 0
examples/movement/look_at/look_at.md

@@ -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 - 0
examples/movement/look_rotation/look_rotation.collection

@@ -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 - 0
examples/movement/look_rotation/look_rotation.md

@@ -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 - 0
examples/movement/look_rotation/look_rotation.script

@@ -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