Solved | Character slowly drifting away

My character is slowly drifting when Im not pressing anything.
It’s my first attempt making a smooth movement script, I couldn’t find any good examples online so any help is appreciated

Script
go.property("acceleration", 80)
go.property("maxspeed", 3)
go.property("friction", 20)

go.property("w", hash("w"))
go.property("a", hash("a"))
go.property("s", hash("s"))
go.property("d", hash("d"))

function init(self)
	msg.post(".", "acquire_input_focus")
	msg.post("@render:", "use_fixed_projection", { near = -1, far = 1, zoom = 1 })
	msg.post("/cam#camera", "acquire_camera_focus")

	self.delta = 0
	self.direction = vmath.vector3()
end


function update(self, dt)
	self.delta = dt

	local position = go.get_position() + (dt * self.acceleration) * self.direction
	
	go.set_position(position)
	
	if self.direction.x > 0 then
		self.direction.x = self.direction.x - self.friction * dt
	elseif self.direction.x < 0 then
		self.direction.x = self.direction.x + self.friction * dt
	end

	if self.direction.y > 0 then
		self.direction.y = self.direction.y - self.friction * dt
	elseif self.direction.y < 0 then
		self.direction.y = self.direction.y + self.friction * dt
	end
end


function on_input(self, action_id)

	if action_id == self.a then
		if self.direction.x > -self.maxspeed then
			self.direction.x = self.direction.x - self.acceleration * self.delta
		end

	elseif action_id == self.d then
		if self.direction.x < self.maxspeed then
			self.direction.x = self.direction.x + self.acceleration * self.delta
		end

	elseif action_id == self.w then
		if self.direction.y < self.maxspeed then
			self.direction.y = self.direction.y + self.acceleration * self.delta
		end

	elseif action_id == self.s then
		if self.direction.y > -self.maxspeed then
			self.direction.y = self.direction.y - self.acceleration * self.delta
		end

	end
end

You need an extra check after applying self.friction to self.direction. Rather than stopping at zero, the value ends up going the other side of zero which introduces that drift you’re seeing.

I wont write it all out but here’s what I mean:

if self.direction.x > 0 then
	self.direction.x = self.direction.x - self.friction * dt
	if self.direction.x < 0 then
		self.direction.x = 0 -- clamp to zero
	end
end
4 Likes

Thanks!
I’ll leave the full script here, maybe it’ll help someone in the future

movement.script
go.property("acceleration", 80)
go.property("maxspeed", 3)
go.property("friction", 15)

function init(self)
	msg.post(".", "acquire_input_focus")
	msg.post("@render:", "use_fixed_projection", { near = -1, far = 1, zoom = 1 })
	msg.post("/cam#camera", "acquire_camera_focus")

	self.w = hash("w")
	self.a = hash("a")
	self.s = hash("s")
	self.d = hash("d")

	self.delta = 0
	self.direction = vmath.vector3()
end


function update(self, dt)
	self.delta = dt

	local position = go.get_position() + (dt * self.acceleration) * self.direction
	
	go.set_position(position)
	
	if self.direction.x > 0 then
		self.direction.x = self.direction.x - self.friction * dt

		if self.direction.x < 0 then
			self.direction.x = 0
		end

	elseif self.direction.x < 0 then
		self.direction.x = self.direction.x + self.friction * dt

		if self.direction.x > 0 then
			self.direction.x = 0
		end
	end

	if self.direction.y > 0 then
		self.direction.y = self.direction.y - self.friction * dt

		if self.direction.y < 0 then
			self.direction.y = 0
		end

	elseif self.direction.y < 0 then
		self.direction.y = self.direction.y + self.friction * dt

		if self.direction.y > 0 then
			self.direction.y = 0
		end
	end
end


function on_input(self, action_id)

	if action_id == self.a then
		if self.direction.x > -self.maxspeed then
			self.direction.x = self.direction.x - self.acceleration * self.delta
		end

	elseif action_id == self.d then
		if self.direction.x < self.maxspeed then
			self.direction.x = self.direction.x + self.acceleration * self.delta
		end

	elseif action_id == self.w then
		if self.direction.y < self.maxspeed then
			self.direction.y = self.direction.y + self.acceleration * self.delta
		end

	elseif action_id == self.s then
		if self.direction.y > -self.maxspeed then
			self.direction.y = self.direction.y - self.acceleration * self.delta
		end

	end
end
2 Likes