[Solved] Collision Check in 2D Platformer

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
User avatar
nikneym
Citizen
Posts: 56
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

[Solved] Collision Check in 2D Platformer

Post by nikneym »

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
(740 Bytes) Downloaded 231 times
Last edited by nikneym on Fri Feb 08, 2019 9:55 pm, edited 1 time in total.
User avatar
AdrianN
Citizen
Posts: 73
Joined: Wed Mar 28, 2018 5:13 pm
Location: Lima

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

Post by AdrianN »

Hi, I'm checking your .love file.

I would recommend doing something like that

love.update(dt) : You put the logic
love.draw(): You draw your game

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)
	--first you move your player
	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.
User avatar
nikneym
Citizen
Posts: 56
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

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

Post by nikneym »

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 :D
karolek
Prole
Posts: 13
Joined: Sun Jul 16, 2017 8:36 pm

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

Post by karolek »

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 :)
User avatar
AdrianN
Citizen
Posts: 73
Joined: Wed Mar 28, 2018 5:13 pm
Location: Lima

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

Post by AdrianN »

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 ...)
User avatar
nikneym
Citizen
Posts: 56
Joined: Sat Mar 09, 2013 1:22 pm
Contact:

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

Post by nikneym »

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

Who is online

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