Game Development Community

The dreaded "Jump Question"

by Herlan Rovelo · in Torque X 2D · 08/04/2009 (7:55 pm) · 14 replies

Hello fellow game makers! I'm happy to report that thanks to the help I received in my previous post (1st ever), it really helped me make headway with my first game...and for that I thank everyone that gave me help/input. That being said, I've hit a wall. That wall is called the seemingly dreaded "jump" action everyone posts about in the forums.

I've serached and searched and searched and there seem to be bits and pieces of information regarding how to make the jump work all across these forums, but I have not been able to formulate the information into 1 coherent tutorial I can follow to make my little guy jump...mainly (my fault) because I'm not a programmer and I don't completely understand (though I'm learning a bit at a time) the terminology some of you advanced users use.

So if anyone would be as so kind as to help me out with maybe the piece of their code that makes their character jump, I would IMMENSELY appreciate it. I know that might be asking a lot so even some direction (tutorial or sample code) would be great too!

My understanding is that there some sort of velocity and gravity variable required to make it work right. Just so everyone understands what I'm making; it's a classic beat 'em up in the spirit of Castle Crashers and I'm using the basic TX2D, not the platformer kit. Thanks in advance!!!

About the author

Recent Threads

  • Character won't punch

  • #1
    08/05/2009 (4:29 pm)
    How are you moving your character's left and right? Do you manually set the character's x velocity? I would imagine you could do this with the y velocity as well.

    As far as gravity I used the info in this post to apply gravity to grenades and other thrown objects in my game: http://www.garagegames.com/community/forums/viewthread/55166
    #2
    08/05/2009 (5:06 pm)
    Hi Sean. I'm using the AnimatedCharacterComponent from John Kanalakis's book. I just added input functions to make the character punch, kick, block, & jump. I think this is the section in the code you're referring to:

    #region Public methods

    public void PlayMyAnimation(T2DAnimationData animationData)
    {
    if (AnimatedSprite.AnimationData != animationData || !AnimatedSprite.IsAnimationPlaying)
    {
    AnimatedSprite.PlayAnimation(animationData);
    AnimatedSprite.PlayAnimation();
    }
    }

    public virtual void ProcessTick(Move move, float dt)
    {

    if (move != null && move.Buttons.Count > 0 && move.Sticks.Count > 0)
    {

    if ((move.Sticks[0].X > 0) && (move.Sticks[0].Y > 0))
    {
    PlayMyAnimation(_animNorthEast);
    }
    else if ((move.Sticks[0].X > 0) && (move.Sticks[0].Y < 0))
    {
    PlayMyAnimation(_animSouthEast);
    }
    else if ((move.Sticks[0].X < 0) && (move.Sticks[0].Y > 0))
    {
    PlayMyAnimation(_animNorthWest);
    }
    else if ((move.Sticks[0].X < 0) && (move.Sticks[0].Y < 0))
    {
    PlayMyAnimation(_animSouthWest);
    }
    else if (move.Sticks[0].X > 0)
    {
    PlayMyAnimation(_animEast);
    }
    else if (move.Sticks[0].X < 0)
    {
    PlayMyAnimation(_animWest);
    }
    else if (move.Sticks[0].Y > 0)
    {
    PlayMyAnimation(_animNorth);
    }
    else if (move.Sticks[0].Y < 0)
    {
    PlayMyAnimation(_animSouth);
    }
    else if (move != null)
    {
    PlayMyAnimation(_animIdleEast);
    }

    else
    {
    AnimatedSprite.SetAnimationFrame(0);//Or whatever frame is standing.
    AnimatedSprite.PauseAnimation();
    }


    // set our test object's Velocity based on stick/keyboard input
    _sceneObject.Physics.VelocityX = move.Sticks[0].X * 25.0f;
    _sceneObject.Physics.VelocityY = -move.Sticks[0].Y * 25.0f;

    if (move.Buttons[1].Pushed)
    PlayMyAnimation(_animPunchEast);
    else if (move.Buttons[2].Pushed)
    PlayMyAnimation(_animKickEast);
    else if (move.Buttons[3].Pushed)
    PlayMyAnimation(_animJumpEast);
    else if (move.Buttons[4].Pushed)
    PlayMyAnimation(_animBlockEast);
    }
    }

    public virtual void InterpolateTick(float k)
    {
    // todo: interpolate between ticks as needed here
    }

    public override void CopyTo(TorqueComponent obj)
    {
    base.CopyTo(obj);
    AnimatedCharacterComponent obj2 = obj as AnimatedCharacterComponent;
    obj2._animNorth = _animNorth;
    obj2._animNorthWest = _animNorthWest;
    obj2._animWest = _animWest;
    obj2._animSouthWest = _animSouthWest;
    obj2._animSouth = _animSouth;
    obj2._animSouthEast = _animSouthEast;
    obj2._animEast = _animEast;
    obj2._animNorthEast = _animNorthEast;
    obj2._animIdleWest = _animIdleWest;
    obj2._animIdleEast = _animIdleEast;
    obj2._animBlockWest = _animBlockWest;
    obj2._animBlockEast = _animBlockEast;
    obj2._animPunchWest = _animPunchWest;
    obj2._animPunchEast = _animPunchEast;
    obj2._animKickWest = _animKickWest;
    obj2._animKickEast = _animKickEast;
    obj2._animJumpWest = _animJumpWest;
    obj2._animJumpEast = _animJumpEast;
    obj2._animJumpWest = _animRunWest;
    obj2._animJumpEast = _animRunEast;
    }

    #endregion


    I'll take a look at the link posted in the meantime. Many thanks!


    #3
    08/05/2009 (5:08 pm)
    BTW - I've searched hi and low, but it appears most people used what was already provided with the Platformer Kit. Haven't found info on building the jump component/function from scratch without using the PK. I also found some straight C# tutorials on other XNA boards, but my understanding is that you need to code the components differently to expose them to the TorqueX engine and make them useable that way.

    So far, everything works (although not perfectly as the code needs some tweaking) except for the jump.
    #4
    08/05/2009 (8:58 pm)
    We are also working on a classic beat-em-up game. TorqueX is quite limited in doing complex animations like jumping. Our solution involved players and enemies being two separate sprites: the shadow and character. The vertical Z component was expressed as the distance between the two. When the player jumped, we would move the character sprite away from the shadow.

    It involved a lot of code and even some TorqueX engine modifications (we modified the engine to allow us to change a mounted object's offset without dismounting it.) I can't give code as our method is very much ingrained in the game we are creating and we haven't bothered to develop a single component solution to the problem. Hopefully you can work something out.
    #5
    08/05/2009 (9:12 pm)
    Thank you very much for your response William. Sounds like a pain to implement that jump code from scratch which explains why everyone has opted to just go with the platformer kit; best of luck with your game! In any case, I will keep everyone posted on the progress. I think I'll just skip the jump component for now and focus on the other parts of the game.
    #6
    08/08/2009 (11:25 am)
    With any luck, this will be comprehensive enough to link from TDN...
    I struggled a lot figuring out an efficient way to jump and have gravity in general, so here's what I've come up with. I'll try and present it in the best way possible, and I will ONLY present the bare minimum. Maybe if there's enough request (or this code is good enough to warrant it) I'll make a JumpComponent to put on TDN. I'm going to number the steps just so that it's easier to critique this and reference a particular step.

    (1) First, whatever scene object you attach this to MUST also have a T2DForcecomponent attached along with it. You do not need to add ANY forces to it, it can be a “blank” force component, as it were. This is very(!!!) important for step number 7 to work, as well as the entire thing to work.
    (2) Next, make the following private properties (and their corresponding public properties for each one):
    T2DAnimationData _animIdle;
    T2DAnimationData _animWalk;
    T2DAnimationData _animJump;

    (3) Now make the following private properties:
    float _jumpForce;
    float _gravityForce;
    float _totalJumpingForce;
    bool _onGround = false;
    And remember to edit the CopyTo method as needed.

    (4) Make these public properties:
    [TorqueXmlSchemaType(DefaultValue = "2.0")]
    public float JumpForce
    {
         get { return _jumpForce; }
         set { _jumpForce = value; }
    }
    [TorqueXmlSchemaType(DefaultValue = "20.0")]
    public float GravityForce
    {
         get { return _gravityForce; }
         set { _gravityForce = value; }
    }

    (5) Now make these two public properties:
    public static T2DTriggerComponentOnEnterDelegate OnGround
    {
         get { return Ground; }
    }
    public static T2DTriggerComponentOnLeaveDelegate InAir
    {
         get { return Air; }
    }
    These two T2DTriggerComponent delegates will allow us to specify when someone is on the ground. Let me jump to implementing this in TXB (even though we have to go through and make functions before we can implement it) just so it's all in the same place.
    #7
    08/08/2009 (11:26 am)
    (6) Open up TXB, and create a blank scene object that extends to be the top of the ground/platform that you want your characters to stand on.. Then, remove every component, and add the T2DTriggerComponent. Make the OnEnter be OnGround, and OnLeave be InAir. That way, while a scene object with this component intersects with the blank scene object, it will run the “Ground” function. Once it leaves and does not intersect the blank scene object, it will run the InAir function.
    http://img268.imageshack.us/img268/229/txbjumpingtutorial.png

    (7) Okay... in the OnRegister private method, add:
    //add gravity
    T2DForceComponent forceComp = Owner.Components.FindComponent<T2DForceComponent>();
    T2DForceComponent.MasslessForce forceOfGravity = new T2DForceComponent.MasslessForce();
    forceOfGravity.InitialStrength = _gravityForce;
    forceOfGravity.MinStrength = _gravityForce;
    forceOfGravity.MaxStrength = _gravityForce;
    forceOfGravity.ConstantDirection = 0;
    forceOfGravity.ConstantDirectionIsWorldSpace = true;
    forceComp.AddForce(forceOfGravity);
    This finds the force component you have added to your object, and adds the force of gravity you wanted. This is nice because in order to change the force of gravity, you won't have to change a force in the force component, as well as the jumping force. Speaking of which....

    (8) Let's jump! To do that, we first need to process what the triggercomponent is telling us:
    public static void Ground(T2DSceneObject ourObject, T2DSceneObject theirObject)
    {
         PlayerComponent movementcomp = theirObject.Components.FindComponent<PlayerComponent>();
         if (movementcomp != null)
              movementcomp._onGround = true;
    }
    public static void Air(T2DSceneObject ourObject, T2DSceneObject theirObject)
    {
         PlayerComponent movementcomp = theirObject.Components.FindComponent<PlayerComponent>();
         if (movementcomp != null)
              movementcomp._onGround = false;
    }
    A couple quick (important) notes: the code that this all is attached to, for me, is called “PlayerComponent.” Make sure you substitute your components name in appropriately. And I'm not sure exactly why this all is structured the way it is- obviously something to do with the trigger component. I can make guesses, but you'd have to ask someone who's been using TX more than a few months. Anyway, this just sets our bool _OnGround to be true or false.

    (9) Now, set a movemap binding to a Jump function. I did it with a button, like this:
    inputMap.BindCommand(gamepadId, (int)XGamePadDevice.GamePadObjects.A, Jump, null);
    Quick sidenote: “Jump” is the function called when the button is pressed, and “null” is the function called when the button is released.
    Now we need our jump function...all this work for just a few lines of a jump function!
    public void Jump()
    {
         if (_onGround == true)
         {
              _totalJumpingForce = _gravityForce + _jumpForce;
              _sceneObject.Physics.ApplyImpulse(new Vector2(0, _totalJumpingForce * -1));
         }
    }
    This is kinda nice, because if you want to change the gravity, you don't have to change three things: the gravity (referenced in this component), the gravity force in the force component, and the jumping force (which needs to be some small value, in addition to the gravity force- otherwise you won't have enough force to overcome gravity!)
    #8
    08/08/2009 (11:28 am)
    (10) I want to make a quick mention of animations, however I'm not going to post the code because I stole it from the (amazing) TX book and don't want to steal credit. What I do is set up a hierarchy of animations. So, in ProcessTick:
    First, flip the sprite if needed.
    Then, as a seperate if/switch funtion, set up the order that animations should be played
    if _onGround = false, play _animJump (this makes it so that anytime you're in the air- if you jump or fall off an edge- It will play the jump anim.)
    if isFiring = true, play _animFire (or punching, or whatever. I just put this in to demonstrate that I personally am not allowing firing while in the air, but this is easily switched around)
    if movesticks.x > 0, play _animwalk
    if movesticks.x < 0, play _animwalk
    if _onGround = true, play _animIdle and pause animation
    else pause animation
    So what this does is process a jumping animation as the priority, then combat, then horizontal movement, then if the player is standing still and _onGround is true, it plays the idle animation. If I wanted combat while in the air, I'd simply do jumping combat, jumping, ground combat, horizontal movement, then standing still as my priority tree.

    (11) You should be good to build and attach the component to a scene object in TXB. So open it up and add the PlayerComponent (or whatever you named it). Also, make sure the collision is set to Clamp with the ground. Now be sure to tweak the settings for jumpforce, gravityforce, and the animations to your liking.

    I think that's everything...phew! If you have any questions, I will be watching this thread and will do my best to answer them. I want to give credit where it's due, so this is cobbled together from the TX book by John, the official tutorials, as well as a LOT of googling around these forums.
    #9
    08/08/2009 (4:06 pm)
    Dude! Ian, I can't thank you enough, man! The information you've provided should be more than enough to get the jump working. I'm extremely grateful as I know you didn't have to provide all this detail/info and go through the trouble of explaining it step by step. Can't thank you enough for your help. I'll get working on this and keep you posted!
    #10
    08/08/2009 (6:45 pm)
    Hey Ian this thread is awesome thank you so much.
    Im trying to follow this and have run into a snag i think.
    I am at step 6 and step 7.
    I opened up my Torque and set up the blank scene object like you said and when I went to assign the proper OnEnter and OnLeave they are blank.

    I went back to my code and Built it thinking maybe it had to update Torque but I get an incomplete build stating:
    "The name Ground does not exist in the current context"
    and
    "The name Air does not exist in the current context"

    looking over the code it doesn't mention anything about creating a Ground or Air object.

    Am I missing something here?
    #11
    08/08/2009 (7:11 pm)
    ok nevermind I just saw something I missed haha
    Ill let you know if any other issues.
    #12
    08/08/2009 (7:40 pm)
    ok so Im back!
    I did all the steps and the good news is that it all builds and compiles no problem so freaking sweet!!!!!

    Now I have a issue. I noticed this is set up for XBox game pad but not for keyboard input.
    Im going to try and figure it out for keyboard but is there any extra code or anything that needs to be changed to make it work with Keyboard input??

    Thanks again for this I have been going nuts for weeks trying to figure out a real jump with Torque!
    #13
    08/08/2009 (8:30 pm)
    Last time ! ok it works about 90% lol the player moves up when I hit the J button now, but it doesnt come back down to its original position, plus it only goes up as long as i have the button pushed down, im sure that is something in my code thats affecting that.

    Is there a feature that im missing that allows it to return to its original position?
    #14
    08/08/2009 (11:30 pm)
    Herlan: No problem! Writing it up was fairly easy, and I think I will (eventually) make a full fledged tutorial or component resource for it.

    Hey Randell, sorry I haven't been watching this thread today- been out and about. For future reference for anyone, keyboard input should be set up as such:
    inputMap.BindCommand(keyboardId, (int)Keys.Space, Jump, null);
    Same kinda thing as gamepad.

    As for the jumping itself, a few things to check- I apologize if this comes off as patronizing. I'm not just writing this for you but for anyone who googles it in the future as I have. Try these steps:
    (a)Check to see if step 8 is finding the correct component. Remember, whatever component you're putting this code in (be it MovementComponent, PlayerComponent, JumpComponent, PlayerActorComponent, or whatever) is what the Components.FindComponent needs to find. In my case, my component is named playercomponent, so I put that in.

    (b) Make sure gravity itself is working. So, spawn your character in the air and make sure he's falling to the ground and colliding with it and clamping. If it's not, see step 7

    (c) One big problem I have found that I didn't want to make mention of is a key point of the trigger component. As it stands now, the trigger activates when the blank object intersects with the scene object, NOT the collision polygon! I'm a mathematician, so for those who may not have as much of an intuitive sense of intersections with different polygons:
    Look at http://img268.imageshack.us/img268/229/txbjumpingtutorial.png again. See how there are small gray and white vertical lines next to bowser? For various reasons, this is because his scene object is about 1.5 times as tall as he is, with him centered vertically. This means that when that blank space at the bottom of the image touches the blank scene object, technically bowser is _onGround. So try and visualize this- When I hit the jump button, bowser should get an initial push on his feet, and as soon as his feet leave the ground he will register _onGround as false and stop being pushed. However, when I hit the jump button (and leave it pressed), there is a push being applied to the bottom of the bowser scene object's border. So once that bowser border is past the border of the empty scene object, only then will it register _onGround as false, and stop pushing. Hopefully this is clear... I know that I can fix this, however it's not too easy to do (I think) and I'd rather spend my time learning Torque and helping the community, and simply make my scene objects more constrained.


    I'm not sure of what else to check... One thing I highly recommend is to get the animations working. As long as gravity works, even if your jumping or movement don't work, if you have your animations set up correctly you can kind of debug it. For example, if the problem you're having is that _onGround never becomes false, with my animation hierarchy you will never see your _animJump being played, and thus be able to pinpoint the problem!

    Also, this doesn't seem to be well documented, but you can check to see what values public properties have from the console. So, set up a public property for _onGround:
    public bool OnGround
    {
         get { return _onGround; }
    }
    This will make the property public, but not list it in TXB as an editable field. So, build and debug your game. Now hit ~ (tilde, next to the 1 key if you don't know) to bring up the console. Now, making sure you character has a name in the scripting rollout of TXB, type
    Bowser.Playercomponent.OnGround
    Obviously substituting in your name and component name, and you will see the value of _onGround. Very useful debugging tool.