Jumping.

Aug 10, 2009 at 3:16 AM
I'm making a 2d platformer/shooter (still) and I've hit yet another
roadblock. Jumping. I decided to go with a completely physical method
(one built with moving physics pieces) for a number of reasons:

A) I couldn't figure out for the life of me a decent way to check if
the player is on the ground

B) I don't want jumping to be constrained to the ground. I want it
possible for say, one player to jump off another's head.

So, I made a small 10x10 "jumpbox" and attatched it to my player with
a pin joint. The jumpbox's x position is constantly changed to that of
the player torso. When the player clicks the left stick, the target
distance is added to a constant value, forcing the jumpbox down
quickly, launching the player skyward. When the distance between the
jumpbox and the torso exceeds the constant, the target is reset.

This works well in theory, but after a bit of toying with it, it
became increasingly apparent that it is somewhat unreliable. The
player sometimes jumps super high, and other times barely jumps at
all. It's just not a good system.

So I'm wondering, are there any tried and true methods for jumping and
such? (or does anybody have an idea as to fix this one?)
Aug 10, 2009 at 4:55 AM

I use a sensor geometry at the base of the player. Jumping is only allowed if that geometry is colliding. The actual jumping is done just by applying an impulse.

Works quite well.

Aug 10, 2009 at 5:07 AM
Alright. So I can put a sensor geometry down there, but how would go
about the actual checking for collision?
Aug 10, 2009 at 10:02 AM
Edited Aug 10, 2009 at 10:03 AM
SlimeQ wrote:
Alright. So I can put a sensor geometry down there, but how would go
about the actual checking for collision?

Instead of checking when it is colliding for allowing the player jump, what I do is to check if it's not colliding with anything to avoid him to jump. I use Yobiv's method:

http://farseerphysics.codeplex.com/Thread/View.aspx?ThreadId=56162

For jumping, I just apply impulse.

Aug 10, 2009 at 5:52 PM
pnikosis wrote:
SlimeQ wrote:
Alright. So I can put a sensor geometry down there, but how would go
about the actual checking for collision?

Instead of checking when it is colliding for allowing the player jump, what I do is to check if it's not colliding with anything to avoid him to jump.

I guess that would be more efficient if you are only using the collision information for jumping.

I use it for applying different drag and changing character animations, so I already need to check it every frame. I just set a flag in the collision event handler. Nice and simple.

Aug 10, 2009 at 7:06 PM
I'm terribly sorry for the noob question, but I've looked at that code
before and couldn't figure it out... Where does that go? How do I use
it? Does all that stuff go in my main class, or is it a new one? How
do I go about checking the collision of the object in relation to
everything without using an array? Do I have to put everything in an
array?
Aug 10, 2009 at 9:07 PM

@SlimeQ:

I guess you are asking for the yobiv's code :)

In the example code, the class MyObject should be your character (with its geometries and bodies... or maybe only one geometry and body, however you designed your character). Your character should have an Update method, called each frame, and the OnCollision and OnSeparation methods are for the geometry you want to check if it collides or not. For example you character has a small geometry for its feet, you should check if that geometry collides with something or not to know if the character is standed on the ground or not. Let's suppose that that geometry is called geomFeet, so when you load or initialize your character you should tell to the system that you need to add special code for the OnCollision (called each time the geometry collides with something) and for the OnSeparation (called each time a geometry stops colliding with something) methods. For that you need to add the following code:

geomFeet.OnCollision += OnCollision;

geomFeet.OnSeparation += OnSeparation;

Then you add the code for the OnCollision and OnSeparation methods as showed on yobiv's post, and that's it. When the HasCollision variable is set to false, means that the character is not touching ground :)

Aug 13, 2009 at 10:42 PM
Edited Aug 15, 2009 at 9:13 AM

 

<Code actually irrelevant>

i'm getting this error with that code. (oh and by the way i'm using this with the bullets here... (i'm a very ADD-ish coder...)) but seeing as i'm not really entirely sure what yobiv's code is doing, i'm clueless as to what the problem is here. what's it mean?

 

Aug 13, 2009 at 10:50 PM

The error "not all code paths return a value" means that the stated method

(in this case, Hyperinflation.Bullet.OnCollision) is not guaranteed to return a value.

The method signature states that it will return a bool, so you need to make sure

that any code path taken will end in either return true; or return false;

Aug 15, 2009 at 1:40 AM
pnikosis wrote:

Then you add the code for the OnCollision and OnSeparation methods as showed on yobiv's post, and that's it. When the HasCollision variable is set to false, means that the character is not touching ground :)

Yes, but there are some weird things that *could* happen (these may be rare, but probably worth noting). Say we were writing a Mario-like game and there was a block in mid-air. If you hit the block, there would be a collision, but you would also be in mid-air. Since there was a collision, if you hit the jump button on the collision, you could technically jump again according to this method (and you could perpetually jump as long as you collided with the block), right? How could you work around this? My first thought would be to use the contact points list and detect which edge you collided with.

Maybe I misunderstand the method, but that's what seems to happen to me.

Coordinator
Aug 15, 2009 at 1:48 AM
Edited Aug 15, 2009 at 1:49 AM

I've not read this thread, but you will have to have a geometry as the ground (or several geometries) and check if it is the ground you collide with in the OnCollision event. If your player collides with the ground, he is able to jump again.

The thing is that the OnCollision and also OnSeparation events fires whenever there is an collision, but since we use approximations of physics there is a small error involved that makes the whole physics world jitter (not normally seen by the user). To prevent this you can add a sensor geometry (an ordinary geometry with IsSensor = true) on the feet the player and update the position of the sensor to be the same place as the player. Whenever the sensor collides with the ground, he would be able to jump.

@SlimeQ: Could you add a newline to the long error like you posted? it makes the site very wide and breaks word wrapping.

Aug 15, 2009 at 9:40 AM

@genbox: apologies.

i feel like i'm doing something really stupid here. i'm still getting that "not all code paths return a value" thing,and i'm not quite sure why. i did what pnikosis said, and i put in yobiv's code verbatim, but... not sure what's going on here.

        public void Update(GameTime time)
        {
            ++Ticks;
        }

        private bool OnCollision(Geom g1, Geom g2, ContactList contactList)
        {
            TicksCollision = Ticks;
            HasCollision = true;
        }

        private void OnSeparation(Geom g1, Geom g2)
        {
            if (TicksCollision < Ticks)
            {
                HasCollision = false;
            }
        }

^^^ it looks like that.^^^

i'm fairly new to C# (and obviously farseer) so a lot of this more complex stuff is going right over my head. it'd be super cool if somebody could explain in the simplest terms what's happening here codewise.

Aug 15, 2009 at 10:19 AM
Edited Aug 15, 2009 at 10:53 AM

@SlimeQ:

OnCollision is a function of type Boolean, and yet you did not return anything.

simply add "Return true" after the HasCollision= true line.

 

@ZachTheRiah

You don't have to get into that, seeing how the sensor is in the player's feet. If the player's body (the top of the player) collides with anything, it wouldn't allow it

to jump again.

 

edit: I need some help of my own as well. I tried to set the geometry on the player's feet to a sensor, after getting some weird results from a non-sensor geometry.

However, when I set the geom to a sensor, the character will just hang in the air in its initial position, without being able to move.

am I supposed to create a different body for the sensor? otherwise it's impossible to set the geometry to the body's position every step, since geom.position is read only.

Coordinator
Aug 15, 2009 at 3:47 PM

Yes, the sensor geometry needs its own body for now. The IsSensor property set the body to be static and the geometry to not react to collisions. You set the body.position property each step.

Aug 15, 2009 at 5:07 PM

When I was figuring this out on my own, I didn't use a sensor geometry. I just had a second "foot" geometry below my character, and after associating it with the body of my character, I initialized it with this code:

foot.CollisionResponseEnabled = false;
foot.OnCollision = 
    (a, b, c) => 
    {
        this.IsStanding = true;
        return true;
    };
foot.OnSeparation =
    (a, b) =>
    {
        //TODO: Fix the standing check methods so that it properly handles 
        //recognizing standing on an object even if another object is separating
        this.IsStanding = false;
    };

Note the big TODO... yobiv's code is an example of how to fix that issue. This code is just an alternative to using a sensor.

Aug 15, 2009 at 8:23 PM
Edited Aug 15, 2009 at 8:24 PM
private bool OnCollision(Geom g1, Geom g2, ContactList contactList)
        {
            TicksCollision = Ticks;
            HasCollision = true;
            return true;
        }

okay. no more errors, but HasCollision does nothing because no geometry is specified here... how would one specify the geometry that is to be checked?

EDIT; do i need to somehow call this method for every geom in my game?

 

Coordinator
Aug 16, 2009 at 12:34 AM

The OnCollision method is just an ordinary method. You can call it whatever you like. - But you also need the physics engine to call that method, so you will have to provide the engine with the name of your method. Just like this:

//This is where you tell the geometry to call your method once it 
// collides with something. You do this inside the code where you 
// create the geometry.
myGeometry.OnCollision += MyCollisionMethod;

//Then you create the method that gets called:
public bool MyCollisionMethod(Geom geomA, Geom geomB, ContactList list)
{
    //Inside here geomA will be myGeometry. It is always the one you 
    // told to call the method.

    //geomB will be whatever geometry myGeometry collided with.
}

Aug 16, 2009 at 2:37 AM

That got me thinking... genbox, is OnCollision called anywhere other than in the Arbiter class? I've been assuming that no other part of the framework will call it, but I guess it's good to know for sure.

Coordinator
Aug 16, 2009 at 3:30 AM

Nope, it is the responsibility of the Arbiter to call the OnCollision delegate right before the physics response is calculated and applied. This makes it possible to cancel the collision response (by returning false in the OnCollision method)

Aug 17, 2009 at 11:52 PM
Alright, I couldn't quite get it to work, but I have a theory as to
why. My map is concave, so the bounding rectangles of the 'ground' are
always intersecting with the players feet, therefore not allowing the
OnSeparation method to fire. Therefor, the hascollision bool is always
true.

Could this be happening, or is something else at play here?

(btw the hascollision bool won't change to false)
Aug 19, 2009 at 12:36 PM

I'm not sure, but this may have some to do with what I observed when playing with collisions - OnSeparation triggered only when there is no contact with bounding box of geometry (and this will cause problems if you have concave geometry). But no one confirmed my observations. ( http://www.youtube.com/watch?v=-RX-Z76q0J0 )

Aug 21, 2009 at 4:30 AM
SlimeQ wrote:

@genbox: apologies.

i feel like i'm doing something really stupid here.

 

... the player's gun was intersecting with the feet. i fixed it. it was stupid.

however, i couldn't get the IsSensor property to work right. it just sorta refused to detect collisions. i changed the jumpbox to a normal geom with collision response turned off, but this isn't really ideal (i don't think). what would have been wrong with the sensor?

Coordinator
Aug 21, 2009 at 3:18 PM

Sorry, that is my fault. I forgot that your ground is probably static and thus a sensor geometry will not detect the geometry. A sensor geometry is defined static for performance reasons and static geometries  are not tested against other static geometries. A sensor is not supposed to be moved around - but if someone wants this functionality they can create a bug report to suggest this functionality. I have limited time, so I need to prioritize.

Aug 21, 2009 at 6:12 PM
It's not a huge deal. Disabling the CollisionResponseEnabled bool
works just fine (tho the debug view shows the geom sinking all the
time (tho the collision works fine))
Aug 23, 2009 at 7:41 PM

What do you mean it shows it sinking all the time? Is your foot geometry not just associated with the player body? That'll keep it moving around with your player and you won't have to reposition it manually every frame or anything.

Aug 24, 2009 at 2:08 AM
I mean quite literally, the geom is sinking the collision still works
fine tho. I think the jumpbox is just falling indefinitely so it goes
farther and farther down. A simple dynamics reset will fix that.

And I can't associate it to the body cuz it's rotating at high speeds.
Aug 24, 2009 at 10:29 PM

Hmmm, I'm not sure if I'm being overly simplistic, but my jumping logic is working great with a very basic rule, which is a variation on Yobiv.

Basically, just check for collisions with the player legs, but make sure the contact normal is facing up. If this is true, this means the legs have contacted a flat surface. This has stopped my character from jumping off vertical walls and other mischievous situations without adding additional geometries or sensors.

Maybe I'm missing something...

Sep 1, 2009 at 5:53 PM

Nope, that sounds perfectly reasonable, and if it's working exactly how you want it, there's no need to change it!