Austin Stanley
Austin Stanley

Reputation: 1

How to improve Pico-8 Collision?

Error: Attempt to index global 'W' (a nil value)

Hello! I am having trouble getting collision working with a different system that spawns sprites in from the map screen.

This is the collision tutorial I used: https://youtu.be/Recf5_RJbZI?si=Df6FbJ2FYfCN39Qx This is the sprite spawning tutorial I used: https://youtu.be/8jb8SHNS66c?si=233nn8z_S1R4R64n

I have watched TONS of tutorials on this and still can't wrap my head around it. A lot of tutorials create very basic collision that has issues, like only being able to work with certain speed values (1,2,4,8,16,etc.) or that don't let your character slide alongside a wall when holding a diagonal.

Can anyone help? I definitely want to use this spawning system in the future to spawn in different types of walls and enemies. I have a feeling that I am misunderstanding how to use the table variables properly, so any explanation would be appreciated!

-- game loop --

function _init()
    cls()
    walls={}
    make_player()
    make_walls()
    -- top-left and lower-right
    -- bounds of player area
    a1,b1=8,8
    a2,b2=112,112
end

function _update60()
    -- keep inside the play area
    move_player()
    p.x=mid(a1,p.x,a2)
    p.y=mid(b1,p.y,b2)
end

function _draw()
    cls()
    draw_map()
    draw_player()
    
    for w in all(walls) do
        spr(w.wsp,w.wx,w.wy)
    end 
end
-- map --

function draw_map()
    map(0,0,0,0,16,16)
end
-- player --

function make_player()
    p={
    x=40,
    y=40,
    w=8,
    h=8,
    speed=2,
    sprite=1,
    }
end

function move_player()
    --move player with buttons
    --interacts with wall collision
    if (btn(⬅️)) then
        for newx=p.x,p.x-p.speed,-1 
            do
                if not box_hit(newx,p.y,
                    p.w,p.h,
                    w.wx,w.wy,
                    w.ww,w.wh) 
                then
                    p.x=newx
            end
        end
    end
        
        if (btn(➡️)) then
        for newx=p.x,p.x+p.speed 
            do
                if not box_hit(newx,p.y,
                        p.w,p.h,
                        w.wx,w.wy,
                        w.ww,w.wh) 
                then
                    p.x=newx
            end
        end
    end
        
        if (btn(⬆️)) then
        for newy=p.y,p.y-p.speed,-1 
            do
                if not box_hit(p.x,newy,
                        p.w,p.h,
                        w.wx,w.wy,
                        w.ww,w.wh) 
                then
                    p.y=newy
            end
        end
    end
        
        if (btn(⬇️)) then
        for newy=p.y,p.y+p.speed 
            do
                if not box_hit(p.x,newy,
                        p.w,p.h,
                        w.wx,w.wy,
                        w.ww,w.wh) 
                then
                    p.y=newy
            end
        end
    end
end

--draw player
function draw_player()
    spr(p.sprite,p.x,p.y)
end
-- walls --

function make_walls()
    for x=0,15 do
        for y=0,15 do
            if mget(x,y)==65 then
                add(walls,{
                    wx=x*8,
                    wy=y*8,
                    ww=8,
                    wh=8,
                    wsp=66
                })
                mset(x,y,64)
            end
        end
    end
end

--wall collision calculations

function box_hit(x1,y1,
        w1,h1,
        x2,y2,
        w2,h2)

        local hit=false
        local xd=abs((x1+(w1/2))-(x2+w2/2))
        local xs=w1/2+w2/2
        local yd=abs((y1+(h1/2))-(y2+h2/2))
        local ys=h1/2+h2/2  
    
    if xd < xs and yd < ys then
        hit=true
    end
    
    return hit
    
end

Upvotes: 0

Views: 349

Answers (2)

Rasmus Dalhoff-Jensen
Rasmus Dalhoff-Jensen

Reputation: 51

In case you have not yet found a solution, it appears there is an error in your move_player() function.

box_hit(p.x,newy,
    p.w,p.h,
    w.wx,w.wy,
    w.ww,w.wh) 

You use the variable w, which I assume refers to a wall, but you never loop through the table of all the walls to assign the value to w. I think you are missing a for loop, like so:

for w in all(walls) do
    box_hit(p.x,newy,
        p.w,p.h,
        w.wx,w.wy,
        w.ww,w.wh) 
end 

Upvotes: 0

teddblue
teddblue

Reputation: 23

in many older games, a system called subpixels was used. theyd calculate collision on a scale smaller than the actual pixels (for example to 0.1 pixels instead of 1 pixel) and when drawing theyd simply use the floor of the x and y values. this allows way more precision and smoothness. this tutorial series has alot of great advice, though its for another platform i still go back to it for help: https://www.youtube.com/playlist?list=PLy4zsTUHwGJIc90UaTKd-wpIH12FCSoLh this article also seems very useful, though i havent read through it all: http://higherorderfun.com/blog/2012/05/20/the-guide-to-implementing-2d-platformers/

Upvotes: 1

Related Questions