0
\$\begingroup\$

I'm using touch inputs in my game to control the character. I would like to know how to disable my character from jumping again in the air.

if (FingerTouchy.phase == TouchPhase.Ended)
                {
       charcter.transform.Translate(Vector2.up * speed * Time.deltaTime);
       float jumpForce = 250;
                        charcter.GetComponent<Rigidbody2D>().AddForce(new Vector2(0, jumpForce));

                    }

Update

Im using Collision Detection

void OnCollisionEnter (Collision col)
    {
        if(col.gameObject.tag == "Ground")
        {
            grounded = true;

        }
    }

And checking if charcter is grounded

if(FingerTouchy.phase == TouchPhase.Ended)
            {

                    float jumpForce=250;
                    if (grounded)
                        continue;
                    charcter.transform.Translate(Vector2.up * speed * Time.deltaTime);
                    charcter.GetComponent<Rigidbody2D>().AddForce(new Vector2(0,jumpForce));
                        grounded=false;

                }

using collision/collision2d doesn't work too.

\$\endgroup\$
1
\$\begingroup\$

I've handling ground status with raycast.

I declare a global grounded variable and use it to check if my character can jump.

In the fixed update of my character controller, i call my groundedUpdater().

void GroundedUpdater ()
{
    grounded = false; //Set to false every frame by default
    RaycastHit2D[] hit;
    hit = Physics2D.RaycastAll (transform.position, Vector2.down, 0.6f);
    // you can increase RaycastLength and adjust direction for your case
    foreach (var hited  in hit) {
        if (hited.collider.gameObject == gameObject) //Ignore my character
            continue;
        // Don't forget to add tag to your ground
        if (hited.collider.gameObject.tag == "Ground") { //Change it to match ground tag
            grounded = true;
        }
    }
}

And where i handle inputs i do this

if (Input.GetKeyDown (KeyCode.UpArrow)) {
        if (grounded) { // can jump
            rig.AddForce (Vector3.up * jumpPower, ForceMode2D.Impulse);
            grounded = false; //Avoid direct double jump
        }
    }
\$\endgroup\$
  • 1
    \$\begingroup\$ While the code presented here is the one that I feel best suits the asker, there are some minor changes we can make for better efficiency. We can drop the if(hited.collider.gameobject = gameobject) statement entirely if we assign a layer mask to our ground objects that is used only for things we can stand on, and then raycast against only that layer. \$\endgroup\$ – Draco18s Dec 21 '15 at 16:33
  • \$\begingroup\$ @Draco18s did it work for you? \$\endgroup\$ – user75648 Dec 21 '15 at 17:18
  • \$\begingroup\$ @user75648 eh? I didn't pull any of these answers into Unity myself, I was just reading them. I happen to use the Standard Assets character controller which handles this on its own (also, I work in 3D, not 2D, so I do not know if a similar standard asset exists). \$\endgroup\$ – Draco18s Dec 21 '15 at 17:25
  • \$\begingroup\$ grounded bool is returning false \$\endgroup\$ – user75648 Dec 21 '15 at 17:36
  • \$\begingroup\$ @user75648 try to increase raycast length or change raycast vector angle in my case it's for 2D platform game. You can use ondrawgizmos to debug the raycast \$\endgroup\$ – Sata Dec 21 '15 at 17:50
0
\$\begingroup\$

Checking the game object's velocity in y axis.

if (FingerTouchy.phase == TouchPhase.Ended && charcter.GetComponent<Rigidbody2D>().velocity.y==0)
                {
       charcter.transform.Translate(Vector2.up * speed * Time.deltaTime);
       float jumpForce = 250;
    charcter.GetComponent<Rigidbody2D>().AddForce(new Vector2(0, jumpForce));

                    }

This just works fine.

Let me know if this has any drawbacks.

\$\endgroup\$
  • \$\begingroup\$ This will not work 100% accurate, as if ground has some bumpiness, or even not, moving rigidbody having Y velocity exactly zero is difficult any how. Second thing, during jump and falling of character, at one point Y velocity would must pass through 0, which is a glitch. This speech is only for information sharing. Hope you understand, at least little bit. :) \$\endgroup\$ – Hamza Hasan Dec 19 '15 at 14:48
0
\$\begingroup\$
if (FingerTouchy.phase == TouchPhase.Ended)
    {
        float jumpForce = 250;
        if (playerIsGrounded)
            charcter.transform.Translate(Vector2.up * speed * Time.deltaTime);
            charcter.GetComponent<Rigidbody2D>().AddForce(new Vector2(0, jumpForce));

    }

In the grounded check code :

void OnTriggerEnter(coll Collider)
{
    if (coll.tag == "Ground")
        playerIsGrounded = true;
}

void OnTriggerLeave(coll Collider)
{
    if(coll.tag == "Ground")
        playerIsGrounded = false;
}

Haven't used unity in a while but I think it's something like this?

\$\endgroup\$
  • \$\begingroup\$ @user75648 When the OnTriggerEnter(coll Collider) is called it will set the variable to true (since the player is on the ground) and the force (jump) is only called when this variable is set to true. And since its set to false when the player stops colliding with the ground, the player won't jump when he is in the air. \$\endgroup\$ – BiiX Dec 21 '15 at 16:04
  • \$\begingroup\$ on checking playerIsGrounded=true , I'm still able to jump more than once and on playerIsGrounded=false , the AddForce line is ignored. \$\endgroup\$ – user75648 Dec 21 '15 at 16:55
  • \$\begingroup\$ @user75648 I edited the answer, maybe this will work? \$\endgroup\$ – BiiX Dec 21 '15 at 17:01
  • \$\begingroup\$ playerIsGrounded is now returning false and I'm still able to jump more than once. \$\endgroup\$ – user75648 Dec 21 '15 at 17:06
  • \$\begingroup\$ @user75648 The transform and addForce lines should be ignored when the player is in the air, unless I'm being really dumb. Is it still running those 2 lines when you are not touching the ground? \$\endgroup\$ – BiiX Dec 21 '15 at 17:09
0
\$\begingroup\$

To do that, make a script name Ground. Attach Rigidbody2D to Ground and mark it as Kinematic. Assuming that your character has "Player" tag. Now time to use some delegate stuff.

A simple definition of delegate that delegate is use to notify other class on an event, even if that other class don't have any instance of first class. In other words, delegate does broadcast a message, then all other classes whichever wants to receive that broadcast, just set a listener in it.

For example, class A has an specific event. class B and class C wants to get notify when that specific even occurs in class A without having an instance of class A.

So similarly you can use delegate keeping a good structure of code.

using UnityEngine;
using System.Collections;

public class Ground : MonoBehaviour
{
    public delegate void OnCharacterLandedDelegate();
    public static event OnCharacterLandedDelegate OnCharacterLandedListener;
    // Use this for initialization
    void Start ()
    {

    }

    // Update is called once per frame
    void Update ()
    {

    }

    void OnCollisionEnter2D(Collision2D col)
    {
        if (col.gameObject.tag == "Player")
        {
            if (OnCharacterLandedListener != null)
                OnCharacterLandedListener();
        }
    }
}

Now in the script where you are handling touch. Add these lines of code.

bool _shouldJump = true;
void OnEnable()
{
    Ground.OnCharacterLandedListener += EnableJump;
}

void OnDisable()
{
    Ground.OnCharacterLandedListener -= EnableJump;
}

void EnableJump()
{
    _shouldJump = true;
}

Somewhere in your code,

if(FingerTouchy.phase == TouchPhase.Ended)
{
    //charcter.transform.Translate(Vector2.up * speed * Time.deltaTime);
    Jump();
}

void Jump()
{
    if (!_shouldJump)
        return;
    _shouldJump = false;
    float jumpForce=250;
    charcter.GetComponent<Rigidbody2D>().AddForce(new Vector2(0,jumpForce));
}
\$\endgroup\$
  • \$\begingroup\$ Made some edit, have a look \$\endgroup\$ – Hamza Hasan Dec 18 '15 at 15:12
  • 2
    \$\begingroup\$ Using delegates seems like overkill to me in this situation, since you call it with a single if-check in Update. you could just call EnableJump directly, or even you could just do _shouldJump = true; \$\endgroup\$ – S. Tarık Çetin Dec 18 '15 at 16:53
  • \$\begingroup\$ Update is my last resort \$\endgroup\$ – Hamza Hasan Dec 18 '15 at 17:48
  • \$\begingroup\$ In a more complex code, this structure would definetely be the first choice of me; but for short scripts, I try to keep code as simple as possible to not to get confused while reading it later. But it is a matter of preferance, actually. \$\endgroup\$ – S. Tarık Çetin Dec 18 '15 at 17:52
  • \$\begingroup\$ Actually even in this scenario how you can achieve 100% accuracy using Update? You will get glitch somehow. Second thing I avoid using update as much as possible \$\endgroup\$ – Hamza Hasan Dec 18 '15 at 18:16
-1
\$\begingroup\$

The easiest way is to use the Boolean variable. Make it true if the character on the ground else make it false. If it is true then only add the force to the character.

Ex:

First check the player is on the ground.

This code snippet goes on ground GameObject.

void OnCollisionEnter2D(Collision2D col)
    {
        if (col.gameObject.tag == "Player")
        {
            if (OnCharacterLandedListener != null)
                OnCharacterLandedListener();
               new PlayerScript().canJump=true;// if player on the ground
        }
    }

Your input action

This code snippet goes to the Player gameobject.

   [HideInspector]   //Don't show  this field in the inspector.
    public bool canJump=false;  

        if(FingerTouchy.phase == TouchPhase.Ended)
        {
            //charcter.transform.Translate(Vector2.up * speed * Time.deltaTime);
            if(canJump)
                Jump();
        }

        void Jump()
        {
            if (!_shouldJump)
                return;
             _shouldJump = false;
             float jumpForce=250;
             charcter.GetComponent<Rigidbody2D>().AddForce(new Vector2(0,jumpForce));
             canJump=false; // if not on the ground
        }
\$\endgroup\$
  • \$\begingroup\$ Please understand the needs, code given by asker and then give your input. Your answer completely confuse the person who asked. He is a beginner. According to your answer, you are enabling in OnCollisionEnter which is attached to the ground, and with the delegate call and accessing that flag in another script that is controlling the character. MAN!!! Gimme a break. You are creating flag here and accessing it there and even didn't understand the implemented functionality. Well, this speech is just for information sharing, nothing personal., hope you understand. \$\endgroup\$ – Hamza Hasan Dec 19 '15 at 14:57
  • \$\begingroup\$ @HamzaHasan Sorry for that mistake. I hope now it's alright \$\endgroup\$ – Albertkaruna Dec 21 '15 at 6:23
  • 1
    \$\begingroup\$ Again, you are creating new instance of PlayerScript having no relation with the one attached to Player GameObject :) \$\endgroup\$ – Hamza Hasan Dec 21 '15 at 7:02
-2
\$\begingroup\$

Since I mis understood, I would use a part of @HamzaHasan 's answer, but I would not use AddForce.

I advice to not use Addforce to let a character jump/move because this is not ment for character movement, this is more or less used for explosion that give a "force" to your body, or space ships floating movement. I would advice using transform.Translate(Vector3.up * speed * Time.deltaTime, Space.World);. Where vector.3 defines the direction this could be;

  • Vector3.left
  • Vector3.right
  • Vector3.up
  • Vector3.down
\$\endgroup\$
  • 1
    \$\begingroup\$ The asker wants to prevent double jumping. That is, if the character has already jumped (or is falling) he doesn't want to let the player jump again. \$\endgroup\$ – Draco18s Dec 18 '15 at 14:57
  • \$\begingroup\$ Ah, I misread there, i read "How do I prevent my player from jumping in the air". OP could have written "how to prevent player from double jump" \$\endgroup\$ – Dakpan Dec 18 '15 at 15:00
  • \$\begingroup\$ @JpHouten why would i use Vector3? \$\endgroup\$ – user75648 Dec 18 '15 at 15:05
  • \$\begingroup\$ @user75648 you can also use Vector2, it depends on your game, if you have a 2D game you should use Vector2. \$\endgroup\$ – Dakpan Dec 18 '15 at 15:19

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.