I'm learning to use Unity Engine and I've been working on the basis for a 2D platformer, and having a problem with the player character being able to jump indefinitely.
I've created an UniversalMovementHandler
class for the handling all movement common to both the player and other characters in the game (which I still haven't implemented) and a PlayerControlls
script for checking for user input, both are attached to the Player prefab that is spawned by the checkpoint
UniversalMovementHandler.cs:
using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class UniversalMovementHandler: MonoBehaviour
{
public Rigidbody2D rb;
// Rigidbody setup
void Start ()
{
rb = transform.GetComponent <Rigidbody2D> ();
}
// Check if object is on the ground with a raycast
private bool IsGrounded ()
{
// Layermask setup
LayerMask MaskA = LayerMask.GetMask ("Character");
LayerMask MaskB = LayerMask.GetMask ("Ignore Raycast");
LayerMask Mask = MaskA | MaskB;
// Raycating
RaycastHit2D hit = Physics2D.Raycast (transform.position, Vector2.down, Mathf.Infinity, Mask);
if (hit.collider != null)
{
float Distance = Mathf.Abs (hit.point.y - transform.position.y);
Debug.Log ("Distance = " + Distance);
if (Distance < transform.localScale.y / 2 + 0.1)
{
return true;
}
else
{
return false;
}
}
else
{
return false;
}
}
// [...]
// Jump if grounded or can double jump
public void Jump (float JumpForce, bool CanAirJump = false)
{
if (CanAirJump || IsGrounded ())
{
rb.AddForce (Vector2.up * JumpForce);
}
}
}
PlayerControlls.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControlls : MonoBehaviour
{
[SerializeField] private UniversalMovementHandler MovementHandler;
[SerializeField] private float WalkSpeed = 3;
[SerializeField] private float WalkForce = 4;
[SerializeField] private float JumpForce = 4;
// UniversalMovementHandler setup
void Start ()
{
MovementHandler = GameObject.Find ("Player(Clone)").GetComponent <UniversalMovementHandler> ();
if (MovementHandler == null)
{
Debug.Log ("Failed to assign MovementHandler");
Debug.Break ();
}
}
// Controll handling
void Update ()
{
// [...]
if (Input.GetKeyDown (KeyCode.Space))
{
MovementHandler.Jump (JumpForce);
}
}
}
I've created three layers, 0: Default, for the ground and other colliders the player directly interacts with, 2: Ignore Raycast for checkpoints and other objects with trigger colliders and 3: Character for both the player character and NPCs. I expected the player not to be able to jump mid-air, being CanAirJump set to false, but this isn't the case, the player just flies in the air so long as you keep pressing the jump button.
Tried flipping the bits myself, setting int MaskA
and int MaskB
to 1 << 2
and 1 << 3
, but still get the same result, printing Distance
to the console returns 0, so the raycast isn't ignoring the Character layer.
I could set the player to be grounded until it jumps, but that would allow it to jump after running off the edge of a platform, also I would have other it have other movement abilities, some of which might get it off the ground.
I could check if it is in contact with a ground collider, but that would require me to setup multiple colliders for the sides of platforms to avoid jumping when in mid-air contact with the side of a platform, which seems to be overly complicated, still would this be the better option or should I try and fix the raycasting?