I’ve a platform game where I want to fix the camera so it doesn’t change when the ‘hero’ jump - so the player can still see the level beneath, or maybe just changes by a smaller amount. At the moment it’s locked to the hero sprite. Do I need to create it as it’s own object and track the hero in a different way?
Yes, if the camera shouldn’t be fully locked to the position of the player then you need to move the camera when the player object moves and also apply inertia or other limitations to your camera logic that you need.
Yes. Put the camera in a game object separate from the player. You then need to add code to do the camera movement you want. There are lots of ways of doing the movement; there are a number of camera movement assets, these will show you how to do the movement of the camera.
I’m afraid there is no example like this. I’m working on a camera handling module for 2D/2.5D games and such thing like this is possible, but I’m not yet ready for a release
Few tips:
I believe Defold built-in camera component is now perfect to use in 2/2.5D games
As mentioned earlier, I have a separate form my player game object (operator) with another nested game object (offset) with camera component:
Camera component has cool properties that you can set, e.g. you can use perspective (I’m using perspective for “free” parallax effect) or orthographic, explained the best in here:
My camera module is following all objects (or none) defined in actors table, as you can see I have separation of following on x and y axis:
The idea of not following when jumping is either by manually in your code changing these properties, so that it is not following hero, when jumping and following again, when landing, etc, but you also have to take into account some deadzone - when hero is outside of this deadzone, you should start following it anyway, in order not to allow it to escape the screen. Adjusting parameters might be difficult
Dead zone can be defined either around player’s position or camera’s position.
Finally with modifying the position of the offset game object you can “lean” the camera in the direction of movement, zoom in/out or shake it (translational and rotational)!
Everything is just plain code executed in update with all the data you need (actors positions, camera, operator and offet settings)
local input = require "modules.input"
local x_follow_threshold = 6
local look_down_duration_threshold = 1.0
local look_down_move_speed = 2
function init(self)
self.follow_player_x = true
self.follow_player_y = false
self.original_y = go.get_position().y
self.url = msg.url('/camera#camera')
self.look_down_timer = 0
end
local function is_position_on_camera(self, position)
local projection = camera.get_projection(self.url)
local view = camera.get_view(self.url)
local view_projection = projection * view
local ndc_position = view_projection * vmath.vector4(position.x, position.y, position.z or 0, 1)
-- Normalize to NDC space
ndc_position.x = ndc_position.x / ndc_position.w
ndc_position.y = ndc_position.y / ndc_position.w
ndc_position.z = ndc_position.z / ndc_position.w
-- Check relative position to camera bounds
local result = {
on_screen = ndc_position.x >= -1 and ndc_position.x <= 1 and
ndc_position.y >= -1 and ndc_position.y <= 1 and
ndc_position.z >= 0 and ndc_position.z <= 1,
above = ndc_position.y > 1,
below = ndc_position.y < -1,
left = ndc_position.x < -1,
right = ndc_position.x > 1,
}
return result
end
local function lerp(a, b, t)
return a + (b - a) * t
end
function update(self, dt)
local camera_position = go.get_position()
local player_position = go.get_position("/player")
-- Check if the player is not above the screen
local camera_status = is_position_on_camera(self, player_position)
if camera_status.below or (not camera_status.on_screen and not camera_status.above) then
-- Move the camera to center on the player without lerp
camera_position.x = player_position.x
if self.follow_player_y then
camera_position.y = player_position.y
end
else
-- Apply smooth following when the player is now below camera
local x_diff = math.abs(camera_position.x - player_position.x)
if self.follow_player_x and x_diff > x_follow_threshold then
camera_position.x = lerp(camera_position.x, player_position.x, dt * 10)
end
if self.follow_player_y then
camera_position.y = lerp(camera_position.y, player_position.y, dt * 10)
end
end
if input.key_state.crouch then
self.look_down_timer = self.look_down_timer + dt
if self.look_down_timer >= look_down_duration_threshold and camera_status.on_screen then
camera_position.y = camera_position.y - look_down_move_speed
end
else
self.look_down_timer = 0 -- Reset timer if crouch is released
end
-- Ensure the camera doesn't drop below the original Y
if player_position.y < self.original_y then
camera_position.y = self.original_y
end
-- Prevent player scrolling from going too low
if camera_position.y < self.original_y then
camera_position.y = self.original_y
end
go.set_position(camera_position)
end
function on_message(self, message_id, message, sender)
if message_id == hash("follow_player_x") then
self.follow_player_x = message.toggle
end
if message_id == hash("follow_player_y") then
self.follow_player_y = message.toggle
end
end