Tap to jump problems

Problem

So I've released this game called Jumpol on the iOS and Android app stores and it works fine. The only problem is that the jumping mechanic is a bit funky. Sometimes when I and other players tap, my player sometimes jumps and other times doesn't jump. Also when you tap the screen near the sides, it sometimes doesn't jump. Does anyone have any suggestions?

Link to Game (If you want to see for yourself)

Android Link

iOS Link

C# Code

using UnityEngine;

public class Player : MonoBehaviour {

    Rigidbody rb;

    float speed = 640;              // Speed of player.
    float thrust = 40;              // Jump force.
    float gravity = -6.18f;         // Gravity force.

    bool isGrounded = false;        // If on ground or not.

    private void Start () {

        rb = GetComponent<Rigidbody> ();

    }

    private void Update () {

        if (Application.platform == RuntimePlatform.WindowsEditor) DesktopControls ();

        if (Application.platform == RuntimePlatform.IPhonePlayer ||
            Application.platform == RuntimePlatform.Android) MobileControls ();

    }

    private void FixedUpdate () {

        if (GameManager.Instance.started) {

            Move ();
            Gravity ();

        }

    }

    private void OnCollisionEnter (Collision collision) {

        if (collision.gameObject.tag == "Ground") {
            isGrounded = true;
        }

    }

    private void OnCollisionExit (Collision collision) {

        if (collision.gameObject.tag == "Ground") {
            isGrounded = false;
        }

    }

    /// <summary>
    /// Controls for mobile devices.
    /// </summary>
    private void MobileControls () {

        if (Input.touchCount > 0 && Input.GetTouch (0).phase == TouchPhase.Began) Jump ();

    }

    /// <summary>
    /// Controls for desktops.
    /// </summary>
    private void DesktopControls () {

        if (Input.GetMouseButtonDown (0)) Jump ();

    }

    /// <summary>
    /// Makes player jump.
    /// </summary>
    private void Jump () {

        if (instructions.activeSelf) {
            instructions.SetActive (false);
        }

        if (isGrounded) {
            rb.velocity += new Vector3 (0, thrust, 0);

            SoundManager.Instance.PlayOneShot (SoundManager.Instance.jump);
        }

    }

    /// <summary>
    /// Adds gravity.
    /// </summary>
    private void Gravity () {

        rb.velocity += new Vector3 (0, gravity, 0);

    }

    /// <summary>
    /// Moves player.
    /// </summary>
    private void Move () {

        rb.velocity = new Vector3 (rb.velocity.x, rb.velocity.y, speed * Time.deltaTime);

    }

}

1 answer

  • answered 2018-01-11 22:35 Roy

    Sometimes when I and other players tap, my player sometimes jumps and other times doesn't jump.

    Your code relies heavily on collision events to implement your isGrounded state. Which don't get me wrong, the Unity Physics system is a powerful and capable system, however, in the Unity physics engine, Rigidbody objects and collisions simulated at runtime can give imperfect results at times. It's more of an approximation in practice so these approximations aren't always exact.

        private void OnCollisionEnter (Collision collision) {
    
        if (collision.gameObject.tag == "Ground") {
            isGrounded = true;
        }
    
    }
    
    private void OnCollisionExit (Collision collision) {
    
        if (collision.gameObject.tag == "Ground") {
            isGrounded = false;
        }
    
    }
    

    I would suggest not having your isGrounded state changes in OnCollisionEnter and OnCollisionExit, but instead, do a short Raycast check. Your player rigidbody object can easily move from OnCollisionEnter and OnCollisionExit causing your isGround bool to move from true to false when moving along the ground tagged object when you expect it to consistently be grounded, causing your jump calls to be ignored thinking you are in airborne. I would suggest to implement a more reliable ground checking system.

    For an example of how you could implement a Raycast based platformer system here is an example from Unity themselves with video and code in the link and all:

    void Update () 
    {
        grounded = Physics2D.Linecast(transform.position, groundCheck.position, 1 << LayerMask.NameToLayer("Ground"));
    
        if (Input.GetButtonDown("Jump") && grounded)
        {
            jump = true;
        }
    }
    

    It was originally meant for 2D so there are Physics2D function calls, however, the logic would be the same and you would need to swap out the 2D calls to their 3D equivalent. (ex. Physics.Raycast instead of Physics2D.Linecast)

    Also when you tap the screen near the sides, it sometimes doesn't jump.

    As for this, I would say its related to the problem I addressed above. Looking at the screenshots on your iOS App product page, I didn't see any UI on the sides there that might be in the way that could specifically block touch input events.