Hello, I’m having an issue where once the character stays on the roof while walking but the second i stop, it falls right through. I’m not sure how to go about to fix it. I have double check the layer of house and it should be colliding with my character.
Odd that you can walk on it at all, if it’s not blocking when you stop…
Let’s start with a review of PlayerFreeLookState.cs. If you’re using a parent Move method (like it’s in PlayerBaseState(), be sure to include that as well.
I’ll also need a look at your ForceReceiver.cs
public abstract class PlayerBaseState : State
{
[SerializeField] protected PlayerStateMachine stateMachine;
public PlayerBaseState(PlayerStateMachine stateMachine)
{
this.stateMachine = stateMachine;
}
protected void Move(Vector3 movement, float deltaTime)
{
stateMachine.Controller.Move((movement + stateMachine.ForceReceiver.Movement) * deltaTime);
}
protected void Move(float deltaTime)
{
Move(Vector3.zero, deltaTime);
}
protected void FaceTarget()
{
if (stateMachine.Targeter.CurrentTarget == null) return;
var lookDirection = stateMachine.Targeter.CurrentTarget.transform.position - stateMachine.transform.position;
lookDirection.y = 0f;
stateMachine.transform.rotation = Quaternion.LookRotation(lookDirection);
}
protected void HandleTargetEvent()
{
if (!stateMachine.Targeter.SelectTarget()) return;
stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
}
protected void ReturnToLocomotion()
{
if (stateMachine.Targeter.CurrentTarget != null)
{
stateMachine.SwitchState(new PlayerTargetingState(stateMachine));
}
else
{
stateMachine.SwitchState(new PlayerFreeLookState(stateMachine));
}
}
}
public class PlayerFreeLookState : PlayerBaseState
{
private bool shouldFade;
private readonly int WalkingBlendTreeHash = Animator.StringToHash("Walking");
private readonly int MovementXHash = Animator.StringToHash("MovementX");
private readonly int MovementZHash = Animator.StringToHash("MovementZ");
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(MovementXHash, 0f);
stateMachine.Animator.SetFloat(MovementZHash, 0f);
if (shouldFade)
stateMachine.Animator.CrossFadeInFixedTime(WalkingBlendTreeHash, CrossFadeDuration);
else
stateMachine.Animator.Play(WalkingBlendTreeHash);
}
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.SwitchState(new PlayerIdleState(stateMachine));
}
stateMachine.Animator.SetFloat(MovementXHash, stateMachine.InputReader.MovementValue.x, AnimatorDampTime, deltaTime);
stateMachine.Animator.SetFloat(MovementZHash, stateMachine.InputReader.MovementValue.y, AnimatorDampTime, deltaTime);
FaceMovementDirection(movement, deltaTime);
}
public override void Exit()
{
stateMachine.InputReader.TargetEvent -= OnTarget;
stateMachine.InputReader.JumpEvent -= OnJump;
}
private void OnTarget()
{
Debug.Log("OnTarget");
HandleTargetEvent();
}
private void OnJump()
{
stateMachine.SwitchState(new PlayerJumpingState(stateMachine));
}
private Vector3 CalculateMovement()
{
var forward = stateMachine.MainCameraTransform.forward;
var 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)
{
if (movement == Vector3.zero) return;
stateMachine.transform.rotation = Quaternion.Lerp(
stateMachine.transform.rotation,
Quaternion.LookRotation(movement),
deltaTime * stateMachine.RotationDamping);
}
}
public class ForceReceiver : MonoBehaviour
{
[SerializeField] private CharacterController controller;
[SerializeField] private NavMeshAgent agent;
[SerializeField] private float drag = 0.3f;
private Vector3 dampingVelocity;
private Vector3 impact;
private float verticalVelocity;
public Vector3 Movement => impact + Vector3.up * verticalVelocity;
private void Update()
{
if (verticalVelocity < 0f && controller.isGrounded)
{
verticalVelocity = Physics.gravity.y * Time.deltaTime;
}
else
{
verticalVelocity += Physics.gravity.y * Time.deltaTime;
}
impact = Vector3.SmoothDamp(impact, Vector3.zero, ref dampingVelocity, drag);
if (agent != null)
{
if (impact.sqrMagnitude < 0.2f * 0.2f)
{
impact = Vector3.zero;
agent.enabled = true;
}
}
}
public void Reset()
{
impact = Vector3.zero;
verticalVelocity = 0f;
}
public void AddForce(Vector3 force)
{
impact += force;
if (agent != null)
{
agent.enabled = false;
}
}
public void Jump(float jumpForce)
{
verticalVelocity += jumpForce;
}
}
I had a NavMeshAgent component on my character. After disabling, it fixed the issue.
Oh, that makes sense. The NavMeshAgent will try to bully the rest of the system. While we need it for the enemies, it shoudln’t be on the player.
This topic was automatically closed 24 hours after the last reply. New replies are no longer allowed.