[Solved] Collision Check in 2D Platformer

Questions about the LÖVE API, installing LÖVE and other support related questions go here.
Forum rules
nikneym
Prole
Posts: 41
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

[Solved] Collision Check in 2D Platformer

Hi all. I've been trying to understand basic platformer mechanics like jumping. Thanks to this post: https://love2d.org/wiki/Tutorial:Baseline_2D_Platformer i got the basics about it but there is a major problem.

I've tried to make platformer like this:

Code: Select all

--might be weird but...
lp=love.graphics;
lk=love.keyboard;

function love.update(dt)
heroUpdate(dt);
end

function love.draw()
mapDraw(10, 10);
heroDraw();
end

hero={
x=10,
y=20,
w=10,
h=10,

speed=75,

velocity=0,
jump=-50,
gravity=-70,
};

local map={
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0},
{1, 0, 0, 0, 0, 1},
{1, 1, 0, 0, 1, 1},
{1, 1, 1, 1, 1, 1},
};

local w=10;
local h=10;

function collision(x, y)
if hero.x < x+w and
hero.x+hero.w > x and
hero.y < y+h and
hero.y+hero.h > y then
return true;
else
return false;
end
end

function mapDraw(mapX, mapY)
for y=1, #map do
for x=1, #map[1] do
if map[y][x]==0 then
lp.setColor(30, 30, 30);
elseif map[y][x]==1 then
--collision happens
if collision(mapX+(w*x)-w, mapY+(y*h)-h) then
hero.velocity=0;
lp.setColor(255, 40, 255);
else
lp.setColor(255, 255, 40);
end
end

lp.rectangle("fill", mapX+(w*x)-w, mapY+(y*h)-h, w, h);
end
end
end

function heroUpdate(dt)
if lk.isDown("left") then
hero.x=hero.x-hero.speed*dt;
elseif lk.isDown("right") then
hero.x=hero.x+hero.speed*dt;
end

if lk.isDown("space") or lk.isDown("up") then
if hero.velocity==0 then
hero.velocity=hero.jump;
end
end

if hero.velocity~=0 then
hero.y=hero.y+hero.velocity*dt;
hero.velocity=hero.velocity-hero.gravity*dt;
end
end

function heroDraw()
lp.setColor(255, 40, 40);
lp.rectangle("fill", hero.x, hero.y, hero.w, hero.h);
end

According to this code, (which is full of bugs) player walks through boxes and after a jump, it hangs on the air on the same direction with the last box it collide. So,

How can i make it fall after it tries to walk on the same direction?
How can i make the boxes solid? (like when it hits it instantly stops.)

Thank you alot!
Attachments
tile-collision.love
Last edited by nikneym on Fri Feb 08, 2019 9:55 pm, edited 1 time in total.

Prole
Posts: 46
Joined: Wed Mar 28, 2018 5:13 pm
Location: Lima

Re: [Need help] Collision Check in 2D Platformer

Hi, I'm checking your .love file.

I would recommend doing something like that

love.update(dt) : You put the logic

You can use AABB function like :

Code: Select all

function CheckCollision(obj1, obj2)
return (obj1.x < obj2.x+ obj2.w and
obj2.x < obj1.x+obj1.w and
obj1.y < obj2.y+obj2.h and
obj2.y < obj1.y+obj1.h), (obj2.y < obj1.y+obj1.h)
end
When you collides with another box example:

Code: Select all

player={x=0,y=0,w=25,h=25,oldx=0,oldy=0,ground=false}
boxes={}
table.insert(boxes,{x=40,y=0,w=50,h=50})
...

function love.update(dt)
player_move()
--you check the collisions
collisions()
end

function CheckCollision(obj1, obj2)
return (obj1.x < obj2.x+ obj2.w and
obj2.x < obj1.x+obj1.w and
obj1.y < obj2.y+obj2.h and
obj2.y < obj1.y+obj1.h), (obj2.y < obj1.y+obj1.h)
end

function collisions()
for _,box in ipairs(boxes) do
local col,ground=CheckCollision(player,box)
if col then
--if collides move player to old position
player.x=player.oldx
player.y=player.oldy

player.ground=ground
end
end

function player_move()
if love.keyboard.isdown("a") then
player.x=player.x-50
elseif love.keyboard.isdown("d") then
player.x=player.x+50
end

if love.keyboard.isdown("w") then
player.ground =false
....
end

--save old position
player.oldx=player.x
player.oldy=player.y

if not player.ground then
--gravity
end
end

You need to use a bolean ground and disable gravity when you collides with box and ground is true.
I not tried the code, but the logic is the same like you need,I hope it helps.

Sorry I'm no a english speaker.

nikneym
Prole
Posts: 41
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

Re: [Need help] Collision Check in 2D Platformer

i still couldn't make it. i think i understand the logic but what's the difference between for ipairs() and single for loop? in order to create the map, do i have to write every boxes' x and y one by one?

by the way, i'm not an english speaker too

karolek
Prole
Posts: 13
Joined: Sun Jul 16, 2017 8:36 pm

Re: [Need help] Collision Check in 2D Platformer

There are several ways to deal with collisions if you have a tilemap. AdrianN just showed a way for boxes that are not tile-based.
Here is a nice tutorial (not in lua, but easily to implement) that looks further into topic: https://jonathanwhiting.com/tutorial/collision/

The problem with your code is that you check collision after movement and if there was one you only set speed to 0. What you should do instead is to respond to such collision, reverse the wrong movement somehow. Some types of response (or avoiding collision totally) are explained in above tut

Prole
Posts: 46
Joined: Wed Mar 28, 2018 5:13 pm
Location: Lima

Re: [Need help] Collision Check in 2D Platformer

nikneym wrote:
Wed Feb 06, 2019 9:16 am
i still couldn't make it. i think i understand the logic but what's the difference between for ipairs() and single for loop?
Ipairs is the same if you use for loop. Ipairs only check if table's value is null.

Code: Select all

--check null and stop
for _, obj in ipairs(table) do

end

--equal to for loop
for _, obj in pairs(table) do

end

for i=1,#table,1 do

end
nikneym wrote:
Wed Feb 06, 2019 9:16 am
in order to create the map, do i have to write every boxes' x and y one by one?
Sorry I forgot you tile map, thanks karolek.
You can use this logic:

Code: Select all

local tilewidth, tileheight=32,32
local map={
{0, 0, 0, 0, 0, 0},
{0, 0, 0, 1, 0, 0},
{1, 0, 0, 0, 0, 1},
{1, 1, 0, 0, 1, 1},
{1, 1, 1, 1, 1, 1},
};

...
function Issolid(v)
if v==1 then
return true
else
return false
end
end

function collisions()
for j=1,#map,1 do
for i=1,#map[j], 1  do
local t={}
t.x=(i-1)*tilewidth
t.w=tilewidth
t.y=(j-1)*tileheight
t.h=tileheight
local col,ground=CheckCollision(player,t)
if col and Issolid(map[j][i]) then
--if collides move player to old position
player.x=player.oldx
player.y=player.oldy

player.ground=ground
end
end
end
end


Transform map array position to x,y axis. You can change issolid value(1 is wall) and add more values with table and loop (2= water,3 = grass ...)

nikneym
Prole
Posts: 41
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

Re: [Need help] Collision Check in 2D Platformer

it works great now. also, thanks for the ipairs() mechanic man!

Who is online

Users browsing this forum: Bing [Bot], Exabot [Bot], PGUp and 4 guests