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
P#26510 2016-08-05 02:56 ( Edited 2016-08-08 18:48)

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)

P#26511 2016-08-05 03:35 ( Edited 2016-08-05 07:35)

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.

P#26518 2016-08-05 10:32 ( Edited 2016-08-05 14:32)

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.)

P#26522 2016-08-05 12:41 ( Edited 2016-08-05 16:41)

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.
P#26544 2016-08-05 17:04 ( Edited 2016-08-05 21:04)

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!

P#26671 2016-08-08 14:48 ( Edited 2016-08-08 18:48)

[Please log in to post a comment]