Unity 3rd Person: Combat & Traversal JUMPING BUG

Im having this weird bug that if I run and jump the player always goes to the hanging state in mid air. I have gone through all of the scripts but cant seem to find anything wrong in that department.

Can you post your scripts for the free look state and the hanging state?

Also, you might want to change the category for this. Skill Builder is a separate thing from the courses. Set it to Unity Courses and it will get more visibility with the correct TA.

The hanging state bug in your Unity 3rd person combat and traversal system could be caused by a few factors. Here are some potential issues to check:

  1. Jump Logic : Ensure that your jump logic is correctly implemented. The transition to the hanging state might be triggered by an unintended condition in your jump script.
  2. Gravity Settings : Check your Rigidbody component’s gravity settings. If gravity is too low or improperly configured, it may cause the player to float or hang in mid-air.
  3. Animation States : Verify the animation transitions in your Animator. If the jump animation is not transitioning back to the idle or running state properly, it might lead to a hanging effect.
  4. Collision Detection : Ensure that the player’s collider is set up correctly. If the player is not detecting the ground properly, it may incorrectly trigger the hanging state.
  5. Layer Mask and Ground Check : If you’re using raycasting to check for ground, ensure your layer masks are correctly set up and that the ground detection is functioning as expected.

Reviewing these areas should help you identify the source of the bug in your Unity project. If you’re pursuing ICT40120 , understanding game physics and scripting is vital for troubleshooting issues like this!

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerFreeLookState : PlayerBaseState
{
private bool shouldFade;

private readonly int FreeLookBlendTreeHash = Animator.StringToHash("FreeLookBlendTree");
private readonly int FreeLookSpeedHash = Animator.StringToHash("FreeLookSpeed");

private const float AnimatorDampTime = 0.1f;

private const float CrossFadeDuration = 0.1f;

public PlayerFreeLookState(PlayerStateMachine stateMachine, bool shouldFade = true) : base(stateMachine)
{
    this.shouldFade = shouldFade;
}

public override void Enter()
{
    stateMachine.InputReader.TargetEvent += OnTarget;
    stateMachine.InputReader.JumpEvent += OnJump;

    stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0f);

    if (shouldFade)
    {
        stateMachine.Animator.CrossFadeInFixedTime(FreeLookBlendTreeHash, CrossFadeDuration);
    }
    else
    {
        stateMachine.Animator.Play(FreeLookBlendTreeHash);
    }
}

public override void Tick(float deltaTime)
{
    if (stateMachine.InputReader.IsAttacking)
    {
        stateMachine.SwitchState(new PlayerAttackingState(stateMachine, 0));
        return;
    }

    Vector3 movement = CalculateMovement();

    Move(movement * stateMachine.FreeLookMovementSpeed, deltaTime);

    if (stateMachine.InputReader.MovementValue == Vector2.zero)
    {
        stateMachine.Animator.SetFloat(FreeLookSpeedHash, 0, AnimatorDampTime, deltaTime);
        return;
    }

    stateMachine.Animator.SetFloat(FreeLookSpeedHash, 1, AnimatorDampTime, deltaTime);

    FaceMovementDirection(movement, deltaTime);
}

public override void Exit()
{
    stateMachine.InputReader.TargetEvent -= OnTarget;
    stateMachine.InputReader.JumpEvent -= OnJump;
}

private void OnTarget()
{
    if (!stateMachine.Targeter.SelectTarget()) { return; }

    stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
}

private void OnJump()
{
    stateMachine.SwitchState(new PlayerJumpingState(stateMachine));
}

private Vector3 CalculateMovement()
{
    Vector3 forward = stateMachine.MainCameraTransform.forward;
    Vector3 right = stateMachine.MainCameraTransform.right;

    forward.y = 0f;
    right.y = 0f;

    forward.Normalize();
    right.Normalize();

    return forward * stateMachine.InputReader.MovementValue.y +
        right * stateMachine.InputReader.MovementValue.x;
}

private void FaceMovementDirection(Vector3 movement, float deltaTime)
{
    stateMachine.transform.rotation = Quaternion.Lerp(
        stateMachine.transform.rotation,
        Quaternion.LookRotation(movement),
        deltaTime * stateMachine.RotationDamping);
}

}

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerHangingState : PlayerBaseState
{
private Vector3 ledgeForward;
private Vector3 closestPoint;

private readonly int HangingHash = Animator.StringToHash("Hanging");

private const float CrossFadeDuration = 0.1f;

public PlayerHangingState(PlayerStateMachine stateMachine, Vector3 ledgeForward, Vector3 closestPoint) : base(stateMachine)
{
    this.ledgeForward = ledgeForward;
    this.closestPoint = closestPoint;
}

public override void Enter()
{
    stateMachine.transform.rotation = Quaternion.LookRotation(ledgeForward, Vector3.up);

    stateMachine.Controller.enabled = false;
    stateMachine.transform.position = closestPoint - (stateMachine.LedgeDetector.transform.position - stateMachine.transform.position);
    stateMachine.Controller.enabled = true;
    
    stateMachine.Animator.CrossFadeInFixedTime(HangingHash, CrossFadeDuration);
}

public override void Tick(float deltaTime)
{
    if (stateMachine.InputReader.MovementValue.y > 0f)
    {
        stateMachine.SwitchState(new PlayerPullUpState(stateMachine));
    }
    else if (stateMachine.InputReader.MovementValue.y < 0f)
    {
        stateMachine.Controller.Move(Vector3.zero);
        stateMachine.ForceReceiver.Reset();
        stateMachine.SwitchState(new PlayerFallingState(stateMachine));
    }
}

public override void Exit()
{

}

}

I forgot that jumping is a separate state. Can you post that one as well. I will look at this when I am home from work.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerJumpingState : PlayerBaseState
{
private readonly int JumpHash = Animator.StringToHash(“Jump”);

private Vector3 momentum;

private const float CrossFadeDuration = 0.1f;

public PlayerJumpingState(PlayerStateMachine stateMachine) : base(stateMachine) { }

public override void Enter()
{
    stateMachine.ForceReceiver.Jump(stateMachine.JumpForce);

    momentum = stateMachine.Controller.velocity;
    momentum.y = 0f;

    stateMachine.Animator.CrossFadeInFixedTime(JumpHash, CrossFadeDuration);

    stateMachine.LedgeDetector.OnLedgeDetect += HandleLedgeDetect;
}

public override void Tick(float deltaTime)
{
    Move(momentum, deltaTime);

    if (stateMachine.Controller.velocity.y <= 0)
    {
        stateMachine.SwitchState(new PlayerFallingState(stateMachine));
        return;
    }

    FaceTarget();
}

public override void Exit()
{
    stateMachine.LedgeDetector.OnLedgeDetect -= HandleLedgeDetect;
}

private void HandleLedgeDetect(Vector3 ledgeForward, Vector3 closestPoint)
{
    stateMachine.SwitchState(new PlayerHangingState(stateMachine, ledgeForward, closestPoint));
}

}

You’re amazing thank you for helping

I don’t see anything off in the code. Try checking the player to see if you accidently added a ledge collider to the player. Maybe a label got switched. Check the size and shape of the ledge detector. Maybe it is much larger than you need. If it is not one of those, post your LedgeDetector class. Sometimes the little goofs are the hardest to find.

My suspicion is the same as @edc237 that the issue is in the LedgeDetector, but it also could be in the PlayerFallingState. Let’s take a look at both, and we’ll see if we can spot it.

Privacy & Terms