Player's yvel is still accelerating on the "ground" [Bump]

General discussion about LÖVE, Lua, game development, puns, and unicorns.
Post Reply
User avatar
redsled
Prole
Posts: 38
Joined: Wed Jun 04, 2014 6:33 am

Player's yvel is still accelerating on the "ground" [Bump]

Post by redsled »

So I'm working on a very basic platformer and decided to use kikito's bump.lua. So far it was going well (it's actually really cool) with a practice block, but I have a simple problem with probably a simple answer. If you view the .love and go off the block, you can tell the player's yvel is still accelerating even though it has hit the "ground". How do you check a collision with the block so I can reset the yvel? Is the solution afterwards to even reset the yvel?
Attachments
tiles.love
(7.44 KiB) Downloaded 72 times
User avatar
s-ol
Party member
Posts: 1077
Joined: Mon Sep 15, 2014 7:41 pm
Location: Cologne, Germany
Contact:

Re: Player's yvel is still accelerating on the "ground" [Bum

Post by s-ol »

redsled wrote:So I'm working on a very basic platformer and decided to use kikito's bump.lua. So far it was going well (it's actually really cool) with a practice block, but I have a simple problem with probably a simple answer. If you view the .love and go off the block, you can tell the player's yvel is still accelerating even though it has hit the "ground". How do you check a collision with the block so I can reset the yvel? Is the solution afterwards to even reset the yvel?
You can use

Code: Select all

local items, len = world:queryRect(l,t,w,h, filter)
to query a 1px-high rectangle just below the feet. Whenever it touches the ground, reset velocity to 0 and don't increase it.

s-ol.nu /blog  -  p.s-ol.be /st8.lua  -  g.s-ol.be /gtglg /curcur

Code: Select all

print( type(love) )
if false then
  baby:hurt(me)
end
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Player's yvel is still accelerating on the "ground" [Bum

Post by kikito »

There's a simpler way to do that, without using queryRect.

The short version is this: on every frame, you use the cols attribute that you get from world:move to detect when the player is "on ground". You do so by checking the 'y' normal of each collision that you get. Then, if you are on ground, you reset the yvel to 0.

This is done in the bump demo's player code. Here's a step-by-step explanation:

UPDATE: there is a simpler solution than what I explain on this list. See explanation after EDIT 2 below:
As a bonus, self.onGround also serves as a check to see whether you can jump or not (self.onGround must be true to allow jumping).

EDIT: Now that I think about it, it's possible that the call to changeVelocityByCollisionNormal already takes care of resetting the yvel to 0 on ground collisions. It would be interesting to see if removing the call to changeVelocityByBeingOnGround to see if it changes anything (probably it won't).

EDIT 2: My suspicion was correct. changeVelocityByBeingOnGround was redundant. I have removed it from the repo. Updated explanation:
  • For every collision that you get, reset the velocities like so: if you are moving right and you collide with something that is to the right (col.normal.x is negative) then you reset the xvel to 0. And the same for the rest of velocities (right, up, down), including xvel. In player this is done in this call to changeVelocityByCollisionNormal,which is defined in the Entity class.
This alone will be enough to reset the velocity. It is however highly recommended that you set a onGround variable, to control things like "can I jump?" etc.
When I write def I mean function.
User avatar
redsled
Prole
Posts: 38
Joined: Wed Jun 04, 2014 6:33 am

Re: Player's yvel is still accelerating on the "ground" [Bum

Post by redsled »

I'm sorry, but I can't seem to follow with your code. Could you take a look at mine and show me vaguely how to do what you suggested?
User avatar
kikito
Inner party member
Posts: 3153
Joined: Sat Oct 03, 2009 5:22 pm
Location: Madrid, Spain
Contact:

Re: Player's yvel is still accelerating on the "ground" [Bum

Post by kikito »

The main problem is here:

Code: Select all

	-- collision?
	if player.xvel ~= 0 or player.yvel ~= 0 then
		player.x, player.y, _, col_len = world:move(player, player.x + dx, player.y + dy)
	end

	local cols, len = world:check(player, 0, 0)
	if len > 0 then
		player.yvel = 0
	end
World:move and world:check do very similar things; if you are using one, chances are that you don't need the other. In your case I think using move is more appropiate. That leaves us with this:

Code: Select all

if player.xvel ~= 0 or player.yvel ~= 0 then
  player.x, player.y, _, col_len = world:move(player, player.x + dx, player.y + dy)
end
world:move returns 4 parameters: actualX, actualY, cols & len. In lua, when a function f returns several values, you can assign them to variables by doing:

Code: Select all

var1, var2, var3, var4 = f()
If you are not going to use one of the values, the convention is naming that variable _ (a single underscore). For example, if you don't need var3 in the previous example, you can do this:

Code: Select all

var1, var2, _, var4 = f()
Now back to your code: Since you are using _ on the third variable, you are basically saying "I don't need cols". But you need it. cols is what will tell you what kind of collisions you are having. You can use that to change the velocity. So start by setting it to a variable:

Code: Select all

if player.xvel ~= 0 or player.yvel ~= 0 then
  local cols, len
  player.x, player.y, cols, len = world:move(player, player.x + dx, player.y + dy)
end
Now you can use cols and len to check every collision using a loop. Here I am going to print the normal of each collision in the terminal (you will have to launch love from the terminal to see them):

Code: Select all

if player.xvel ~= 0 or player.yvel ~= 0 then
  local cols, len
  player.x, player.y, cols, len = world:move(player, player.x + dx, player.y + dy)
  for i=1,len do
    print(cols[i].normal.x, cols[i].normal.y)
  end
end
cols.normal.x and cols.normal.y are two vectors which indicate "on which direction" the collision happened. For example, if the collision happened with an object "to the right", then normal.x is -1, and normal.y is 0.

Once you have the normals, you can set xvel and yvel to 0 when it corresponds. For example, if the player was moving to the right, and the collision happened with an object to the right, you can reset it like this:

Code: Select all

if player.xvel ~= 0 or player.yvel ~= 0 then
  local cols, len
  player.x, player.y, cols, len = world:move(player, player.x + dx, player.y + dy)
  for i=1,len do
    if cols[i].normal.x < 0 and player.xvel > 0 then player.xvel = 0 end 
  end
end
Add conditions for the other 3 directions (left, up and down), and that should be enough. If you have doubts about which values the normals have, print them on the console.

Let me know if you need more help.

EDIT: I have made some changes to the simpledemo so that it now shows collision info when in debug mode. That way it uses cols instead of ignoring it.
Screen Shot 2015-03-21 at 21.12.40 .png
Screen Shot 2015-03-21 at 21.12.40 .png (77.05 KiB) Viewed 1434 times
You can see the changes in bump's simpledemo branch.
When I write def I mean function.
Post Reply

Who is online

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