Skip to content

Commit

Permalink
Added recoil
Browse files Browse the repository at this point in the history
  • Loading branch information
britzl committed Feb 17, 2018
1 parent a8a4721 commit 67fb7ca
Show file tree
Hide file tree
Showing 7 changed files with 96 additions and 48 deletions.
17 changes: 16 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -101,13 +101,23 @@ Shake the camera.
* ```direction``` (hash) - Direction of the shake. Possible values: ```both```, ```horizontal```, ```vertical```. Defaults to ```both```.
* ```cb``` (function) - Function to call when the shake has finished. Optional.

### camera.stop_shaing(camera_id)

### camera.stop_shaking(camera_id)
Stop shaking the camera.

**PARAMETERS**
* ```camera_id``` (hash|url)


### camera.recoil(camera_id, offset, [duration])
Apply a recoil effect to the camera. The recoil will decay using linear interpolation.

**PARAMETERS**
* ```camera_id``` (hash|url)
* ```offset``` (vector3) - Offset to apply to the camera. Defaults to 0.05
* ```duration``` (number) - Duration of the recoil, in seconds. Defaults to 0.5


### camera.get_zoom(camera_id)
Get the current zoom level of the camera.

Expand Down Expand Up @@ -269,6 +279,11 @@ Message equivalent to ```camera.stop_shaking()```.

msg.post("camera", "stop_shaking")

### recoil
Message equivalent to ```camera.recoil()```. Accepted message keys: ```offset``` and ```duration```.

msg.post("camera", "recoil", { offset = vmath.vector3(100, 100, 0), duration = 0.75 })

### shake_complete
Message sent back to the sender of a ```shake``` message when the shake has completed.

Expand Down
11 changes: 11 additions & 0 deletions example/camera_controls.gui_script
Original file line number Diff line number Diff line change
Expand Up @@ -32,25 +32,33 @@ function on_input(self, action_id, action)
if action_id == hash("touch") and action.released then
if gui.pick_node(gui.get_node("unfollow/button"), action.x, action.y) then
msg.post("camera", "unfollow")
return true
elseif gui.pick_node(gui.get_node("follow_basic/button"), action.x, action.y) then
msg.post("camera", "follow", { target = "player" })
return true
elseif gui.pick_node(gui.get_node("follow_lerp/button"), action.x, action.y) then
msg.post("camera", "follow", { target = "player", lerp = 0.1 })
return true
elseif gui.pick_node(gui.get_node("shake_both/button"), action.x, action.y) then
msg.post("camera", "shake", { intensity = 0.05, duration = 0.5, direction = hash("both") })
return true
elseif gui.pick_node(gui.get_node("shake_horizontal/button"), action.x, action.y) then
msg.post("camera", "shake", { intensity = 0.05, duration = 0.5, direction = hash("horizontal") })
return true
elseif gui.pick_node(gui.get_node("shake_vertical/button"), action.x, action.y) then
msg.post("camera", "shake", { intensity = 0.05, duration = 0.5, direction = hash("vertical") })
return true
elseif gui.pick_node(gui.get_node("stop_shaking/button"), action.x, action.y) then
msg.post("camera", "stop_shaking")
return true
elseif gui.pick_node(gui.get_node("bounds/button"), action.x, action.y) then
self.bounds_enabled = not self.bounds_enabled
if self.bounds_enabled then
msg.post("camera", "bounds", { left = 0, right = 1728, bottom = 0, top = 1280 })
else
msg.post("camera", "bounds", {})
end
return true
elseif gui.pick_node(gui.get_node("deadzone/button"), action.x, action.y) then
self.deadzone_enabled = not self.deadzone_enabled
local dz = gui.get_node("deadzone_visualizer")
Expand All @@ -61,14 +69,17 @@ function on_input(self, action_id, action)
else
msg.post("camera", "deadzone", {})
end
return true
elseif gui.pick_node(gui.get_node("zoomin/button"), action.x, action.y) then
self.zoomlevel = self.zoomlevel + 0.25
msg.post("camera", "zoom_to", { zoom = self.zoomlevel } )
gui.set_text(gui.get_node("zoomlevel"), tostring(self.zoomlevel))
return true
elseif gui.pick_node(gui.get_node("zoomout/button"), action.x, action.y) then
self.zoomlevel = math.max(0.25, self.zoomlevel - 0.25)
msg.post("camera", "zoom_to", { zoom = self.zoomlevel } )
gui.set_text(gui.get_node("zoomlevel"), tostring(self.zoomlevel))
return true
end
end
end
Expand Down
22 changes: 0 additions & 22 deletions example/crosshair.script

This file was deleted.

17 changes: 1 addition & 16 deletions example/example.collection
Original file line number Diff line number Diff line change
Expand Up @@ -125,22 +125,7 @@ embedded_instances {
}
embedded_instances {
id: "crosshair"
data: "components {\n"
" id: \"script\"\n"
" component: \"/example/crosshair.script\"\n"
" position {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" }\n"
" rotation {\n"
" x: 0.0\n"
" y: 0.0\n"
" z: 0.0\n"
" w: 1.0\n"
" }\n"
"}\n"
"embedded_components {\n"
data: "embedded_components {\n"
" id: \"sprite\"\n"
" type: \"sprite\"\n"
" data: \"tile_set: \\\"/example/assets/examples.atlas\\\"\\n"
Expand Down
19 changes: 19 additions & 0 deletions example/player.script
Original file line number Diff line number Diff line change
@@ -1,11 +1,19 @@
local camera = require "orthographic.camera"

local SPEED = 400

function init(self)
msg.post(".", "acquire_input_focus")
self.input = {}
self.crosshair = vmath.vector3()
end

function update(self, dt)
-- update crosshair based on mouse and camera position
local cursor_pos = camera.screen_to_world(go.get_id("camera"), self.crosshair)
go.set_position(vmath.lerp(0.5, go.get_position("crosshair"), cursor_pos), "crosshair")

-- update player position
local pos = go.get_position()
if self.input[hash("up")] then
pos.y = pos.y + SPEED * dt
Expand All @@ -21,11 +29,22 @@ function update(self, dt)
end

function on_input(self, action_id, action)
self.crosshair.x = action.x
self.crosshair.y = action.y

if action_id then
if action.pressed then
self.input[action_id] = true
elseif action.released then
self.input[action_id] = false
end

-- shoot and apply recoil
if action_id == hash("touch") and action.pressed then
local crosshair_pos = go.get_position("crosshair")
local player_pos = go.get_position()
local offset = (crosshair_pos - player_pos) * 0.1
camera.recoil(go.get_id("camera"), offset, 0.5)
end
end
end
55 changes: 46 additions & 9 deletions orthographic/camera.lua
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ local WINDOW_HEIGHT = DISPLAY_HEIGHT
-- center camera to middle of screen
local OFFSET = vmath.vector3(DISPLAY_WIDTH / 2, DISPLAY_HEIGHT / 2, 0)

local VECTOR3_ZERO = vmath.vector3(0)

local MATRIX4 = vmath.matrix4()

local v4_tmp = vmath.vector4()
Expand Down Expand Up @@ -230,17 +232,38 @@ function M.update(camera_id, dt)
if camera.shake.duration < 0 then
camera.shake.cb()
camera.shake = nil
return
else
if camera.shake.horizontal then
camera.shake.offset.x = (DISPLAY_WIDTH * camera.shake.intensity) * (math.random() - 0.5)
end
if camera.shake.vertical then
camera.shake.offset.y = (DISPLAY_WIDTH * camera.shake.intensity) * (math.random() - 0.5)
end
end
end

if camera.recoil then
camera.recoil.time_left = camera.recoil.time_left - dt
if camera.recoil.time_left < 0 then
camera.recoil = nil
else
local t = camera.recoil.time_left / camera.recoil.duration
camera.recoil.offset.x = vmath.lerp(t, 0, camera.recoil.offset.x)
camera.recoil.offset.y = vmath.lerp(t, 0, camera.recoil.offset.y)
end
if camera.shake.horizontal then
camera.shake.offset.x = (DISPLAY_WIDTH * camera.shake.intensity) * (math.random() - 0.5)
end

local offset
if camera.shake or camera.recoil then
offset = VECTOR3_ZERO
if camera.shake then
offset = offset + camera.shake.offset
end
if camera.shake.vertical then
camera.shake.offset.y = (DISPLAY_WIDTH * camera.shake.intensity) * (math.random() - 0.5)
if camera.recoil then
offset = offset + camera.recoil.offset
end
end

camera.view = calculate_view(camera_id, camera_world_pos, camera.shake and camera.shake.offset)
camera.view = calculate_view(camera_id, camera_world_pos, offset)
camera.projection = calculate_projection(camera_id)
end

Expand Down Expand Up @@ -324,8 +347,6 @@ function M.shake(camera_id, intensity, duration, direction, cb)
}
end



--- Stop shaking a camera
-- @param camera_id
function M.stop_shaking(camera_id)
Expand All @@ -334,6 +355,22 @@ function M.stop_shaking(camera_id)
end



--- Simulate a recoil effect
-- @param camera_id
-- @param offset Amount to offset the camera with
-- @param duration Duration of the recoil. Optional, default: 0.5s.
function M.recoil(camera_id, offset, duration)
assert(camera_id, "You must provide a strength id")
print("recoil", offset, duration)
cameras[camera_id].recoil = {
offset = offset,
duration = duration or 0.5,
time_left = duration or 0.5,
}
end


--- Set the zoom level of a camera
-- @param camera_id
-- @param zoom The zoom level of the camera
Expand Down
3 changes: 3 additions & 0 deletions orthographic/camera.script
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ local ENABLE = hash("enable")
local DISABLE = hash("disable")
local UNFOLLOW = hash("unfollow")
local FOLLOW = hash("follow")
local RECOIL = hash("recoil")
local SHAKE = hash("shake")
local STOP_SHAKING = hash("stop_shaking")
local DEADZONE = hash("deadzone")
Expand Down Expand Up @@ -63,6 +64,8 @@ function on_message(self, message_id, message, sender)
camera.shake(go.get_id(), message.intensity, message.duration, message.direction, function()
msg.post(sender, "shake_completed")
end)
elseif message_id == RECOIL then
camera.recoil(go.get_id(), message.offset, message.duration)
elseif message_id == STOP_SHAKING then
camera.stop_shaking(go.get_id())
elseif message_id == ZOOM_TO then
Expand Down

0 comments on commit 67fb7ca

Please sign in to comment.