Log In  


I'm adapting the physics from the Sonic Physics Guide on Sonic Retro into PICO-8 and it's going pretty alright but my character keeps sinking into platforms?

Here's the code:

--platformer stuff
--physics model taken from
--sonicretro.org/sonic_physics_guide

--todo!
--wall collisions

function sign(x)
	if(x<0) return -1
	if(x==0) return 0
	if(x>0) return 1
end

function floor()
	local v=mget(flr((x+4)/8),flr((y+8)/8))
	return fget(v,0)
end

function _init()
	--basic stuff
	x=58				--player x
	y=58				--player y
	d=false	--direction:f=r,t=l

	--physics stuff
	xsp=0			--horizontal speed
	ysp=0 		--vertical speed
	jsp=5			--jump speed
	acc=0.1 --accelerate
	dec=1 		--decelerate
	frc=0.2 --friction
	top=2.5	--top speed
	grv=0.5	--gravity
	cj=true	--can jump? (flag)
	j=false	--jumping? (flag)

	--camera stuff
	cx=58 		--camera x offset
	cy=78			--camera y offset
	dx=58			--default x offset
	dy=78			--default y offset
	csf=2			--camera speed while fall
	csl=4			--camera speed on landing
end

function _update()
	if floor() then
		--back on land
		ysp=0
		--pans the camera back up
		cy+=csl
		if(cy>dy) cy=dy
		cj=true
	else
		--in the air!
		ysp+=grv
		--pans the camera downward
		cy-=csf
		if(cy<20) cy=20
		cj=false
	end

	--if can jump,allow jump!!!!
	if cj then
		if btn(4) then
			ysp=-jsp
		end
	end

	--left and right movement
	if btn(0) then
		--left button
		if xsp>0 then
			xsp-=dec
		elseif xsp>-top then
			xsp-=acc
		end
		d=true
	elseif btn(1) then
		--right button
		if xsp<0 then
			xsp+=dec
		elseif xsp<top then
			xsp+=acc
		end
		d=false
	else
		xsp=xsp-min(abs(xsp),frc)*sign(xsp)
	end

	--adds restart button in pause
	--menu
	menuitem(1,"restart",function() _init() end)

	x%=128
	x+=xsp
	y+=ysp
end

function _draw()
	cls()
	map(0,0)
	--camera(x-cx,y-cy)
	spr(0,x,y,1,1,d)
end
1


From what I can tell your code just stops the jump when the detection point is detected as being on a floor tile and sets y speed to zero. So if one frame the detection point is just above the tile, then if it moves say 4 pixels (as y speed increases by 0.5 per tick) it will be within the tile next frame.

Try adding some code that moves the player back "up" to the top of the tile when it lands ( eg FLR(y/8) * 8)


I added what you suggested here:

if floor() then
	--back on land
	ysp=0
	--makes sure player stands
	--on top of tile instead of
	--inside of it
	y=flr(y/8)*8
	--pans the camera back up
	cy+=csl
	if(cy>dy) cy=dy
	cj=true
else
	--in the air!
	ysp+=grv
	--pans the camera downward
	cy-=csf
	if(cy<20) cy=20
	cj=false
end

but the player still sinks into the floor for 1 frame before being pushed back to the top of the tile.


Maybe you can reorganize the code so that in the cases you would notice ground after you're inside it, the position correction is applied before it's had a chance to get drawn.

Maybe when you're falling fast enough you look a frame ahead (temporarily add an extra dose of dy and recheck) and turn on a flag that activates alternative handling for high-speed floor collisions.

Sometimes I like talking through my code in verbose comment style to see if there are obvious things I'm doing out of order or not accounting for. (in this case I would step through the main update loop assuming that I've already reached a ridiculous fall speed. Heck, just a quick max dy cap might be an easy fix depending.)


A few things I can think of going on here:

  1. Your character seems to go up 8 px per frame until the peak of the jump, it goes 4 down ONCE on the way down, and then 8 px the entire rest of the jump. Remove the 4px frame and you're golden.

  2. It's possible that once you've hit the ground, it doesn't immediately turn gravity "off," but a frame/step later, so your character "falls 4px" once they collide with the ground.

  3. Have each frame check for ground collision before landing - if it does, check for 4 px and move the last 4px there.

HOLY CRAP I ACTUALLY SOLVED IT
I added x and y arguments to my FLOOR function and when I called it in _update I added the characters y speed to the y argument.

function floor(x,y)
  local v=mget(flr((x+4)/8),flr((y+8)/8))
  return fget(v,0)
end

...

function _update()
	if floor(x,(y+ysp)) then
		--back on land
		ysp=0
		cy+=csl
		if(cy>dy) cy=dy
		cj=true
	else
		--in the air!
		ysp+=grv
		--pans the camera downward
		cy-=csf
		if(cy<20) cy=20
		cj=false
	end

(it still causes the player to pause 2 pixels above the floor for like one frame but I at least solved the sinking in platforms thing)

thanks for the help guys!



[Please log in to post a comment]