Camera movement is delayed

Hello everyone!
I managed to create a moving character and I want to have a camera that is focussing on him. I managed to do this with a simple camera script:

function init(self)
	
	-- initial camera position
	go.set_position(go.get_position("hero/hero"))
	
	msg.post("#camera", "acquire_camera_focus")
	
end

function update(self, dt)
	go.set_position(go.get_position("hero/hero"))
end

It works just fine except that there is a slight delay in the movement of the camera. My hero script basically uses the exact same script as in the platformer tutorial. But that shouldnt matter since the position of the camera should not be affected by the way my player is moving.

So where is the problem?

Greetings from germany
Luca

PS: The support in the forum is absolutely great! Really impressed by it!

2 Likes

Might be a wildshot, but have you tried moving the camera by sending a message with its new position, before you move your player?

You can add the camera as a child object to the hero game object. That should make it follow the hero whenever it update its position.

I wanted to prevent sending messages in the update loop in terms of performance. But I will try this.

I know but I want to have full control about the camera movement like having a delay on purpose.
But when I do it this way I will always have to compensate the player movement so I thought it would be a better way to have a script controlling the camera

1 Like

Would using multiple cameras with different behaviors and parenting work?

So I tried sending a message with the player position in the player script and it seems to work now. Although I still dont understand why there is this delay when setting the camera to the players position directly

I’m trying to reproduce this problem but I don’t see any camera lag. Can you post your code?

This is pretty much a shot in the dark (as I’m a noob in Defold) but try to put in each update function a debug print and see the order in which everything gets called and the values.

It might just be that the camera updates its position before the hero has updated his, in which case the camera would be one step behind the hero each time.

Edit: Unity advises on using LateUpdate for camera actions.

Ok, so here is the code for the camera movement:

function update(self, dt)
	
	self.pos = go.get_position("hero")
	
	self.pos.x = self.pos.x - self.window_width * 0.5 * self.upscale_factor
	self.pos.y = self.pos.y - self.window_height * 0.5 * self.upscale_factor + 50
	
	go.set_position(self.pos)
	
end

this is the player movement script:

local input_left = hash("move_left")
local input_right = hash("move_right")

-- max speed right/left
go.property("max_speed", 30)
-- the acceleration to move right/left
go.property("move_acceleration", 1000)

function init(self)
	
	msg.post(".", "acquire_input_focus")
	
	-- initial player velocity
	self.velocity = vmath.vector3(0, 0, 0)
	
	-- movement input in the range [-1,1]
	self.move_input = 0
	
end

function update(self, dt)
    
    -- determine the target speed based on input
    local target_speed = self.move_input * self.max_speed

    -- calculate the difference between our current speed and the target speed
    local speed_diff = target_speed - self.velocity.x
	
    -- the complete acceleration to integrate over this frame
    local acceleration = vmath.vector3(0, 0, 0)
	
	if speed_diff ~= 0 then
        -- set the acceleration to work in the direction of the difference
        if speed_diff < 0 then
        	acceleration.x = -self.move_acceleration
        else
        	acceleration.x = self.move_acceleration
        end
	end
	
	-- calculate the velocity change this frame (dv is short for delta-velocity)
    local dv = acceleration * dt
        	
	-- check if dv exceeds the intended speed difference, clamp it in that case
    if math.abs(dv.x) > math.abs(speed_diff) then
        dv.x = speed_diff
    end

    -- save the current velocity for later use
    -- (self.velocity, which right now is the velocity used the previous frame)
    local v0 = self.velocity 
    
    -- calculate the new velocity by adding the velocity change
    self.velocity = self.velocity + dv
    
    -- calculate the translation this frame by integrating the velocity
    self.dp = (v0 + self.velocity) * dt * 0.5
    
    go.set_position(go.get_position() + self.dp)
    
end

function on_input(self, action_id, action)

    if action_id == input_right then
    
    	self.move_input = action.value
    	
	elseif action_id == input_left then
    
    	self.move_input = -action.value

	end
end

function final(self)

	msg.post(".", "release_input_focus")

end
1 Like

Where do you update the player position?

sorry, I did change the code a second ago ^^

1 Like

Ok. Just tried that with 2 game objects, each with the corresponding script and a camera on one. Don’t see any lag at all…

Do you have a custom render script?

yes I do. By delay I mean that you can see the sprite acceleratring which should not be visible if the camera is fixed to the player right?

here is my custom render script:

function init(self)
    self.tile_pred = render.predicate({"tile"})
    self.gui_pred = render.predicate({"gui"})
    self.text_pred = render.predicate({"text"})
    self.particle_pred = render.predicate({"particle"})

    self.clear_color = vmath.vector4(0, 0, 0, 0)
    self.clear_color.x = sys.get_config("render.clear_color_red", 0)
    self.clear_color.y = sys.get_config("render.clear_color_green", 0)
    self.clear_color.z = sys.get_config("render.clear_color_blue", 0)
    self.clear_color.w = sys.get_config("render.clear_color_alpha", 0)

    self.view = vmath.matrix4()
    
    -- scales the game up by its reciprocal value
    self.upscale_factor = 0.25

end

function update(self)
    render.set_depth_mask(true)
    render.clear({[render.BUFFER_COLOR_BIT] = self.clear_color, [render.BUFFER_DEPTH_BIT] = 1, [render.BUFFER_STENCIL_BIT] = 0})

    render.set_viewport(0, 0, render.get_window_width(), render.get_window_height())
    render.set_view(self.view)

    render.set_depth_mask(false)
    render.disable_state(render.STATE_DEPTH_TEST)
    render.disable_state(render.STATE_STENCIL_TEST)
    render.enable_state(render.STATE_BLEND)
    render.set_blend_func(render.BLEND_SRC_ALPHA, render.BLEND_ONE_MINUS_SRC_ALPHA)
    render.disable_state(render.STATE_CULL_FACE)

    render.set_projection(vmath.matrix4_orthographic(0, render.get_width()*self.upscale_factor, 0, render.get_height()*self.upscale_factor, -1, 1))

    render.draw(self.tile_pred)
    render.draw(self.particle_pred)
    render.draw_debug3d()

    render.set_view(vmath.matrix4())
    render.set_projection(vmath.matrix4_orthographic(0, render.get_window_width(), 0, render.get_window_height(), -1, 1))

    render.enable_state(render.STATE_STENCIL_TEST)
    render.draw(self.gui_pred)
    render.draw(self.text_pred)
    render.disable_state(render.STATE_STENCIL_TEST)

    render.set_depth_mask(false)
    render.draw_debug2d()
end

function on_message(self, message_id, message, sender)
    if message_id == hash("clear_color") then
        self.clear_color = message.color
    elseif message_id == hash("set_view_projection") then
        self.view = message.view
    elseif message_id == hash("get_dimensions") then
    	msg.post(sender, "window_dimensions",  {width = render.get_width(), height = render.get_height()})
    elseif message_id == hash("get_upscale_factor") then
    	msg.post(sender, "upscale_factor", {factor = self.upscale_factor})
    end
end
1 Like

Thanks. I’m running with your render script. Still no movement. The camera is tack-on the “hero” object.

1 Like

hm that is strange.

Is there a way to give you access to my project?

And by the way, thank you really much for your patience. Its probably a pretty stupid mistake :smile:

1 Like

Sure. Head into the dashboard and add me to the project. My email is mikael@sicher.org

2 Likes

did it work? :slight_smile:
Could you see what I mean by delay?

You need to sync the project to push your edits to the server.

1 Like

sorry I didn’t know that.
I think I did sync it now :smile:

Thanks, got the project now. I’ll have a look soon.

1 Like