Player jitters with camera movement

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
Before you make a thread asking for help, read this.
Post Reply
MistyM
Prole
Posts: 6
Joined: Sun Aug 25, 2019 11:49 am

Player jitters with camera movement

Post by MistyM »

Hi,

I'm creating a game where the player follows a set path upon pressing the up arrow. The map is created in Tiled and implemented using STI.
I'm not sure if it's an issue with how I have implemented the path following (most likely) or the camera movement.

The issue happens when the the up arrow is held down (and so the player automatically follows the set path) and is most obvious when the camera begins to follow the character (so the player's x value is half the width of the screen).

Please help!
This is what it looks like:
PLATFORMER-2019-08-25-13-02-55.gif
PLATFORMER-2019-08-25-13-02-55.gif (523.22 KiB) Viewed 3295 times
Below is the code for my followPath function. I have also attached my full code :)

Code: Select all

local followPath = function()
			-- Set closestObj to the closest path
			if xDistance < 0 then
				xDistance = -xDistance
			end
			if yDistance < 0 then
				yDistance = -yDistance
			end
			local xyDistance = xDistance + yDistance
			local index = 1
			for i = 1, #path do
				local xDistance = self.x - path[i].x
				if xDistance < 0 then
					xDistance = -xDistance
				end
				local yDistance = self.y - path[i].y
				if yDistance < 0 then
					yDistance = -yDistance
				end
				if xDistance + yDistance <= xyDistance and path[i].visited == false then
					xyDistance = xDistance + yDistance
					closestObj = path[i]
					index = i
				end
			end

			-- If we are on the next path square, set it to visited
			if self.x >= closestObj.x and self.y >= closestObj.y then
				closestObj.visited = true
				-- Fixes getting stuck at path[1] issue
				if index == 1 then
					closestObj = path[index + 1]
				end	
			end

			-- Move to next closest path square at speed pathVelocity
			local moveAlong = function(closestObject)
				-- local startX = self.x
				-- local startY = self.y
				-- local targetX = closestObject.x
				-- local targetY = closestObject.y
				-- local distance = (targetX - startX)^2 + (targetY - startY)^2
				-- tween = flux.to(self, distance/(self.pathVelocity*10), { x = closestObject.x, y = closestObject.y })
				-- dist2 - the distance to the closest object (in a straight line)
				local dist2= (closestObject.x - self.x)^2 + (closestObject.y - self.y)^2
				local obj_vx, obj_vy = 0,0
				local startPosX, startPosY = self.x,self.y
				local pv = self.pathVelocity
				-- Speed up for when falling - to look more realistic
				if closestObject.y > self.y then
					pv = self.pathVelocity - self.gravity * 5 * dt
				end
				if dist2 == 0 then
					-- avoid division by 0
				    obj_vx, obj_vy = 0, 0
				else
				    local dist = math.sqrt(dist2)
				    obj_vx = (closestObject.x - self.x) / dist * pv
				    obj_vy = (closestObject.y - self.y) / dist * pv
				end

		  		cols = self:movePlayer(self.x + obj_vx * dt, self.y + obj_vy * dt, dt)

		  		--Check collisions
		  		if #cols ~=0 then
		  			for i=1,#cols do
	  					local c = cols[i]
	  					if c.other.name == "enemy1" then
				  			local elayer = map.layers["EnemySprites"]
				  			-- if touch point is at top of enemy
				  			local x,y,w,h = world:getRect(c.other)				  			
					  		for i = 1, #elayer do
					  			local xx,yy = elayer[i].x,elayer[i].y
								if x == xx and y == yy then
									world:remove(c.other)
									table.remove(elayer,i)
									break
								end
							end
				  		end
	  				end
		  		end

		  		-- dist3 - distance from the start position to position now (in a straight line)
		  		local dist3 = (startPosX - self.x)^2 + (startPosY - self.y)^2
				if dist3 >= dist2 then
					print("3: ".. dist3)
					print("2: ".. dist2)
				-- Overshot - teleport to target instead.
				    self.x = closestObject.x
    				self.y = closestObject.y 
				    obj_vx = 0
				    obj_vy = 0
				end
			end
			-- print("closestObj: " .. closestObj.x,closestObj.y)
			-- print("self: ".. self.x,self.y)
			moveAlong(closestObj)
		end
pathfollow.zip
(208.47 KiB) Downloaded 148 times
User avatar
pgimeno
Party member
Posts: 3548
Joined: Sun Oct 18, 2015 2:58 pm

Re: Player jitters with camera movement

Post by pgimeno »

I think the reason for the jitter is that you don't handle transitions between waypoints correctly. When it overshoots, you simply place the player at the waypoint. So, say dt = 0.02 and obj_vx is 250. That's 5 pixels per frame. If the distance between waypoints is 32 and the player is at position 0, it advances 6 frames without problems, but the 7th frame it goes from position 30 to 35, and since it overshoots because the waypoint is at x=32, the position is corrected back to 32.

When it overshoots the waypoint, you need to calculate how much it takes for the player to reach the waypoint, advance the player to the waypoint and then, in the same frame, advance the player again in the direction of the next waypoint, using a new dt calculated as current dt minus the time to reach the waypoint. That's how it can go through angles in the path at a constant speed.

The time to reach the waypoint can be calculated by solving for t in v = s/t. You know the distance (s) from player to waypoint and the velocity (v) of the player.

You're also using different horizontal coordinates for the player in rectangle mode and in circle mode. That causes a jump at the very start of pressing the up key.
MistyM
Prole
Posts: 6
Joined: Sun Aug 25, 2019 11:49 am

Re: Player jitters with camera movement

Post by MistyM »

pgimeno wrote: Sun Aug 25, 2019 5:35 pm I think the reason for the jitter is that you don't handle transitions between waypoints correctly. When it overshoots, you simply place the player at the waypoint. So, say dt = 0.02 and obj_vx is 250. That's 5 pixels per frame. If the distance between waypoints is 32 and the player is at position 0, it advances 6 frames without problems, but the 7th frame it goes from position 30 to 35, and since it overshoots because the waypoint is at x=32, the position is corrected back to 32.

When it overshoots the waypoint, you need to calculate how much it takes for the player to reach the waypoint, advance the player to the waypoint and then, in the same frame, advance the player again in the direction of the next waypoint, using a new dt calculated as current dt minus the time to reach the waypoint. That's how it can go through angles in the path at a constant speed.

The time to reach the waypoint can be calculated by solving for t in v = s/t. You know the distance (s) from player to waypoint and the velocity (v) of the player.

You're also using different horizontal coordinates for the player in rectangle mode and in circle mode. That causes a jump at the very start of pressing the up key.
I managed to sort it out! Thanks so much for the detailed explanation :)
Post Reply

Who is online

Users browsing this forum: Bing [Bot] and 94 guests