From 04785b4fbe0b33bc85ef33fc764961fb896f1fcf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Ritzl?= Date: Thu, 6 Jun 2019 14:59:02 +0200 Subject: [PATCH] Added support for immediately following a target even when lerping Fixes #25 --- README.md | 10 +++++++--- example/camera_controls.gui_script | 26 ++++++++++++++++---------- example/example.collection | 15 +++++++++++++++ orthographic/camera.lua | 4 ++++ orthographic/camera.script | 15 +++++++++++++++ 5 files changed, 57 insertions(+), 13 deletions(-) diff --git a/README.md b/README.md index 8831446..8d26ea6 100644 --- a/README.md +++ b/README.md @@ -55,6 +55,9 @@ This controls if the camera should follow the target along the horizontal axis o #### follow_vertical (boolean) This controls if the camera should follow the target along the vertical axis or not. See `camera.follow()` for details. +### follow_immediately (boolean) +This controls if the camera should immediately position itself on the follow target when initialized or if it should apply lerp (see below). See `camera.follow()` for details. + #### follow_target (hash) Id of the game object to follow. See `camera.follow()` for details. @@ -235,7 +238,8 @@ Acceptable values for the `options` table: * `lerp` (number) - Lerp from current position to target position with `lerp` as t. * `offset` (vector3) - Camera offset from target position. * `horizontal` (boolean) - True if following the target along the horizontal axis. -* `vertical` (vector3) - True if following the target along the vertical axis. +* `vertical` (boolean) - True if following the target along the vertical axis. +* `immediate` (boolean) - True if the camera should be immediately positioned on the target even when lerping. ### camera.unfollow(camera_id) Stop following a game object. @@ -400,9 +404,9 @@ Message equivalent to `camera.recoil()`. Accepted message keys: `offset` and `du Message sent back to the sender of a `shake` message when the shake has completed. ### follow -Message equivalent to `camera.follow()`. Accepted message keys: `target`, `lerp`, `horizontal` and `vertical`. +Message equivalent to `camera.follow()`. Accepted message keys: `target`, `lerp`, `horizontal`, `vertical`, `immediate`. - msg.post("camera", "follow", { target = hash("player"), lerp = 0.7, horizontal = true, vertical = false }) + msg.post("camera", "follow", { target = hash("player"), lerp = 0.7, horizontal = true, vertical = false, immediate = true }) ### unfollow Message equivalent to `camera.unfollow()`. diff --git a/example/camera_controls.gui_script b/example/camera_controls.gui_script index c0b269d..c161bc1 100644 --- a/example/camera_controls.gui_script +++ b/example/camera_controls.gui_script @@ -16,7 +16,7 @@ function init(self) self.deadzone_enabled = false self.current_projection = 1 self.lerp = 0 - camera.use_projector(CAMERA_ID, PROJECTIONS[self.current_projection].id) + msg.post("#", "use_projector") end local function get_scaling_factor() @@ -51,16 +51,16 @@ function update(self, dt) gui.set_text(gui.get_node("top_right"), ("%d,%d"):format(bounds.z, bounds.y)) gui.set_text(gui.get_node("zoomlevel"), ("%.2f"):format(tostring(camera.get_zoom(CAMERA_ID)))) gui.set_text(gui.get_node("current_projection"), PROJECTIONS[self.current_projection].name) +end - if self.follow then - msg.post(CAMERA_ID, "follow", { - target = "/player", - lerp = self.lerp, - offset = self.camera_offset, - horizontal = self.follow_horizontal, - vertical = self.follow_vertical, - }) - end +local function post_follow_message(self) + msg.post(CAMERA_ID, "follow", { + target = "/player", + lerp = self.lerp, + offset = self.camera_offset, + horizontal = self.follow_horizontal, + vertical = self.follow_vertical, + }) end function on_input(self, action_id, action) @@ -76,24 +76,28 @@ function on_input(self, action_id, action) self.follow_horizontal = true self.follow_vertical = true self.lerp = 1 + post_follow_message(self) return true elseif gui.pick_node(gui.get_node("follow_lerp/button"), action.x, action.y) then self.follow = true self.follow_horizontal = true self.follow_vertical = true self.lerp = 0.1 + post_follow_message(self) return true elseif gui.pick_node(gui.get_node("follow_horizontal/button"), action.x, action.y) then self.follow = true self.follow_horizontal = true self.follow_vertical = false self.lerp = 0.1 + post_follow_message(self) return true elseif gui.pick_node(gui.get_node("follow_vertical/button"), action.x, action.y) then self.follow = true self.follow_horizontal = false self.follow_vertical = true self.lerp = 0.1 + post_follow_message(self) return true elseif gui.pick_node(gui.get_node("shake_both/button"), action.x, action.y) then msg.post(CAMERA_ID, "shake", { intensity = 0.05, duration = 0.5, direction = hash("both") }) @@ -142,6 +146,8 @@ function on_input(self, action_id, action) camera.use_projector(CAMERA_ID, PROJECTIONS[self.current_projection].id) return true end + elseif message_id == hash("use_projector") then + camera.use_projector(CAMERA_ID, PROJECTIONS[self.current_projection].id) end end diff --git a/example/example.collection b/example/example.collection index 4af438e..37f7e74 100644 --- a/example/example.collection +++ b/example/example.collection @@ -30,6 +30,21 @@ instances { value: "true" type: PROPERTY_TYPE_BOOLEAN } + properties { + id: "follow" + value: "true" + type: PROPERTY_TYPE_BOOLEAN + } + properties { + id: "follow_immediately" + value: "true" + type: PROPERTY_TYPE_BOOLEAN + } + properties { + id: "follow_target" + value: "/player" + type: PROPERTY_TYPE_HASH + } } scale3 { x: 1.0 diff --git a/orthographic/camera.lua b/orthographic/camera.lua index 14ae072..803b497 100644 --- a/orthographic/camera.lua +++ b/orthographic/camera.lua @@ -367,6 +367,7 @@ end -- offset - Offset from target position (default: nil) -- horizontal - true if following target along horizontal axis (default: true) -- vertical - true if following target along vertical axis (default: true) +-- immediate - true if camera should be immediately positioned on the target function M.follow(camera_id, target, options, __offset) assert(camera_id, "You must provide a camera id") assert(target, "You must provide a target") @@ -376,11 +377,13 @@ function M.follow(camera_id, target, options, __offset) local offset = nil local vertical = true local horizontal = true + local immediate = false if type(options) == "table" then lerp = options.lerp offset = options.offset horizontal = options.horizontal vertical = options.vertical + immediate = options.immediate else lerp = options offset = __offset @@ -392,6 +395,7 @@ function M.follow(camera_id, target, options, __offset) offset = offset, horizontal = horizontal, vertical = vertical, + immediate = immediate, }) end diff --git a/orthographic/camera.script b/orthographic/camera.script index 985bb5b..de91d40 100644 --- a/orthographic/camera.script +++ b/orthographic/camera.script @@ -9,6 +9,7 @@ go.property("offset_gui", false) go.property("follow", false) go.property("follow_horizontal", true) go.property("follow_vertical", true) +go.property("follow_immediately", false) go.property("follow_target", hash("")) go.property("follow_lerp", 0.5) go.property("follow_offset", vmath.vector3(0, 0, 0)) @@ -40,11 +41,21 @@ local UPDATE_CAMERA = hash("update_camera") local ZOOM_TO = hash("zoom_to") local USE_PROJECTION = hash("use_projection") +local function position_on_follow(self) + local target_position = go.get_position(self.follow_target) + local camera_position = go.get_position() + target_position.z = camera_position.z + go.set_position(target_position) +end + function init(self) camera.init(go.get_id(), msg.url(), { zoom = self.zoom }) if self.enabled then camera.update(go.get_id(), 0) camera.send_view_projection(go.get_id()) + if self.follow and self.follow_immediately then + position_on_follow(self) + end end end @@ -89,6 +100,10 @@ function on_message(self, message_id, message, sender) self.follow_target = type(message.target) == "string" and hash(message.target) or message.target self.follow_lerp = message.lerp or 1 self.follow_offset = message.offset or vmath.vector3() + self.follow_immediately = message.immediate + if self.follow and self.follow_immediately then + position_on_follow(self) + end elseif message_id == DEADZONE then self.deadzone_right = message.right or 0 self.deadzone_top = message.top or 0