Help with Jumping

Hi.

I’m working on my charter jumps right now. And thanks to things in this forums or found on the web I have something that -mostly- works.

The goal is to make a Mario style jump that keeps going up as long as you keep the button pressed (within a certain height limit), and you can’t jump in the air.

Here is the ‘touch’ code:
[lua]–what happens on touch
function touched( event )
local vx, vy = (Player[1]):getLinearVelocity();
–touch on the left, jump
if( event.x < (_W/2) ) then
–make sure you’re in the ground
if ( event.phase == “began” and vy <= 0 ) then
–determine how high can we get
Player[1].jumpLimit = Player[1].y - _jumpPotency;
Player[1].jumpMode = true;
elseif ( event.phase == “ended” or event.phase == “canceled” ) then
Player[1].jumpMode = false;
else
print("THE VY = “…vy…” THE VX = "…vx);
end
end
–touch on the right, slide.
–not implemented yet…
end[/lua]

And this is the code that actually does the jumping (located in the updateHero function):
[lua]–apply jumping force
if Player[1].jumpMode then
if Player[1].y >= Player[1].jumpLimit then
–only apply force when below height limit
Player[1]:translate( 0, _jumpVelocity );
–Player[1]:applyForce( -0, _jumpVelocity*6, Player[1].x, Player[1].y );
–Player[1]:setLinearVelocity( 0, _jumpVelocity *10);
else
–when we are high enough, start falling
Player[1].jumpMode = false;
end
end [/lua]
(Note how I’m testing with translate, applyForce and setLinearVelocity to make the jump. So far translate just looks and feels better than the other two).

My problem is that I can’t find a sure-fire way to tell if I’m on the ground. I know the most used method is to check for collision with a floor object and set a flag like hero.onGround or something similar, this doesn’t work on my case, because my floor is in constant movement and there is a possibility that will collide from the sides and not the top (so you can be on contact with floor, but still falling).

What I’m doing right now is check for the y velocity ( local vx, vy = (Player[1]):getLinearVelocity(); ) under the logic that if the velocity is 0 it means that I’m not falling and on the ground. This however, only works some of the time, it’s not 100% accurate.

Suggestions on how to fix this? (comments on my current method are also welcome).
[import]uid: 136402 topic_id: 29248 reply_id: 329248[/import]

Hi cialval,

Is your floor completely horizontal? In that case, you could check both that the player is colliding with the floor and that the player’s y coordinate is the appropriate distance above the floor. (By “appropriate distance”, I just mean the distance that it should be if and when the player is actually standing on the floor.)

This won’t be as simple if the floor isn’t completely horizontal. But you could still apply the same idea. You would just need to know the y coordinate of the part of the floor directly below the player (which, depending on how you’ve defined your floor, you may know or be able to calculate).

Would that work?

  • Andrew [import]uid: 109711 topic_id: 29248 reply_id: 117627[/import]

Another option is to make your floor objects into two overlapping bodies… one the “solid” part, the other a sensor part that extends just barely above the solid ground. Then, using the numerical parameter of multi-body collisions, you’d know if your player was actually on the top surface of the floor (or not) to set your “onGround” flag.

Yet another option is to sense the player’s downward velocity after a very short delay following collision. If the player is falling, his velocity would indicate that he’s not on solid ground, thus you wouldn’t set your flag. EDIT: just noticed you’ve tried this, but without the short delay. The delay should make it more reliable, but if you need a 100% flawless method, something like the first idea might be better.

I can probably think of more options if these or Andrew’s don’t accomplish what you need.

Brent [import]uid: 9747 topic_id: 29248 reply_id: 117662[/import]

Thanks for both responses, I’ll try them as soon as I can and get back to you. I like that sensor idea. [import]uid: 136402 topic_id: 29248 reply_id: 117748[/import]

Ok, since I have floors that are not completely horizontal, I went with the sensor idea. It works pretty good but it fumbles sometimes when the jumps are made from a downwards slope (ie the jump does not get as high as it should). And I’m not completly sure why.

I create a sensor for each floor piece and keep it in the correct place (there is only 8 pieces active at any time, so I hope there is not performance issues).

Collision code looks like this:

--did something collide?  
local function floorCollision(event)  
 if event.other.name == "hero" and event.phase == "began" and event.other.onGround == false then  
 Player[1].onGround = true;  
 elseif event.other.name == "hero" and event.phase == "ended" and event.other.jumpMode == true then  
 Player[1].onGround = false;  
 end   
end  

And the new touch code:

function touched( event )  
 --touch on the left, jump  
 if( event.x \< (\_W/2) ) then  
 --make sure you're in the ground  
 if ( event.phase == "began" and Player[1].onGround == true ) then  
 --determine how high can we get  
 Player[1].jumpLimit = Player[1].y - \_jumpPotency;  
 Player[1].jumpMode = true;   
 Player[1].onGround = false;  
 elseif ( event.phase == "ended" or event.phase == "canceled" ) then  
 Player[1].jumpMode = false;  
 end  
 end  
 --touch on the right, slide.  
 --not implemented yet...  
end  

( the game looks like this http://img215.imageshack.us/img215/518/gamesshot.png ) [import]uid: 136402 topic_id: 29248 reply_id: 117955[/import]

Hi again,
Most of this looks pretty good! :slight_smile: When you say it “fumbles” a bit, is this only jumping from slopes? How are you doing the jump, by applying impulse? Do you have a screenshot that shows your character?

A few things I might change in addition:

  1. I don’t see a need for the “jumpMode” variable, unless you’re using it for something else not in this attached code. Can you explain its purpose?
  2. I would move the sensors much closer to the floors they “sense for”. Just a few pixels away, only enough so that your character senses it when he’s firmly sitting on the ground.

Brent [import]uid: 9747 topic_id: 29248 reply_id: 117962[/import]

Hi Brent.

Well, as stated in my first post, I wanted a mario/megaman style jump, meaning that the longer you held the button (or the touch in this case) then the higher your jump goes (within a limit, of course), this allows the user to make quicker, shorter jumps if they need to, simply by lightly tapping the screen.

Here is how I handle the jumping (in a UpdateHero function, running in every frame):
[lua]–apply jumping force
if Player[1].jumpMode then
if Player[1].y >= Player[1].jumpLimit then
–only apply force when below height limit
Player[1]:translate( 0, _jumpVelocity );
–Player[1]:applyForce( -0, _jumpVelocity*6, Player[1].x, Player[1].y );
–Player[1]:setLinearVelocity( 0, _jumpVelocity *10);
else
–when we are high enough, start falling
Player[1].jumpMode = false;
end
end [/lua]
The jumpMode variable is what controls when you go up and when you start falling. I don’t use Impulses because those are single jolts of force, and that wouldn’t work with what I want to achieve. jumpVelocity (wich may not be the proper physics term, but it sounds cool ;p) is how many pixels you move up per each update, until you reach the limit of the jump or the user releases the touch.
As you can see, I’m still using :translate to move, because :applyForce looks too “floaty” and :setLinearVelocity causes weird problems.

I’m still trying to debug to see what causes the problem when jumping from a downwards slope. [import]uid: 136402 topic_id: 29248 reply_id: 118061[/import]

What kind of weird problems occur with “setLinearVelocity”? Of all the options, this would be my first choice… in a diminishing amount based on how near to the max jump height the player is. Personally, I don’t like using “simulated physical movement” (translate) in a physical interaction like a jump, because I fear that it just won’t look quite right in the end. I’d rather try my best to get a physical interaction on that object and let the physics engine do its work.

Brent [import]uid: 9747 topic_id: 29248 reply_id: 118120[/import]

Well, my problem with SetLinearVelocity was that it would somehow screw up the gravity, causing the player to fall slowly, that was due to something else that I was doing wrong elsewhere.That is fixed now.

As far as my problem with the jump I solved it by nullifying all forces before triggering the jump, setting LinearVelocity to 0.

I also ran into trouble because of my use of onGround variable, because the player sprite was wide enough to be on 2 floor pieces at a time, causing the boolean value to be unreliable. To solve this, I used a number variable to keep track on how many sensor was I stepping on.

I have to run more tests, but it looks pretty good right now.

touch code looks like:
[lua]function touched( event )
–touch on the left, jump
if( event.x < (_W/2) ) then
–make sure you’re in the ground
if ( event.phase == “began” and Player[1].groundNum >= 1 ) then
–determine how high can we get
Player[1].jumpLimit = Player[1].y - _jumpPotency;
Player[1].jumpMode = true;
–defeat whatever velocity we’re at
Player[1]:setLinearVelocity(0,0);
elseif ( event.phase == “ended” or event.phase == “cancelled” ) then
Player[1].jumpMode = false;
end
end
–touch on the right, slide.
–not implemented yet…
end[/lua]

Collision code:
[lua]local function floorCollision(event)
if event.other.name == “hero” and event.phase == “began” then
Player[1].groundNum = Player[1].groundNum +1;
print("Collision began, num = "… Player[1].groundNum);
elseif event.other.name == “hero” and event.phase == “ended” then
Player[1].groundNum = Player[1].groundNum - 1;
print("Collision Ended, num = "… Player[1].groundNum);
end
end[/lua]

And jump code is like this (I’m still tweaking numbers to get a jump that satisfies me):
[lua]–apply jumping force
if Player[1].jumpMode then
if Player[1].y >= Player[1].jumpLimit then
–only apply force when below height limit
–Player[1]:translate( 0, _jumpVelocity );
–Player[1]:applyForce( -0, _jumpVelocity, Player[1].x, Player[1].y );
Player[1]:setLinearVelocity( 0, _jumpVelocity * _jumpFactor);
if (_jumpFactor >= 16) then
_jumpFactor = _jumpFactor - 0.40;
end
else
–when we are high enough, start falling
Player[1].jumpMode = false;
_jumpFactor = 24;
end
end[/lua]

[import]uid: 136402 topic_id: 29248 reply_id: 118266[/import]

Sounds like you’re really close now! I was going to suggest the “multiple sensors being tracked” issue next, but I wasn’t sure if your character would be touching 2 at any time. A widely misunderstood fact about sensors is that an object can actually be touching several sensors, and the proper solution is exactly what you did: keep track of an integer value of how many sensors are involved, adding and subtracting as the sensing object enters and exits various sensors.

Also, good idea about resetting the velocities to 0 before a jump begins. That was an oversight on my part that I should have remembered; thanks for reminding me.

Please post any further questions to this topic and hopefully I or other developers can help sort it out.

Brent
[import]uid: 9747 topic_id: 29248 reply_id: 118273[/import]