Untitled diff

Created Diff never expires
16 removals
280 lines
13 additions
275 lines
using System.Collections;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine;
using KinematicCharacterController;
using KinematicCharacterController;
using System;
using System;


namespace KinematicCharacterController.Walkthrough.WallJumping
namespace LezCharacterController
{
{
public struct PlayerCharacterInputs
public struct PlayerCharacterInputs
{
{
public float horizontal;
public float horizontal;
public bool JumpDown;
public bool JumpDown;
}
}


public class MyCharacterController : BaseCharacterController
public class KinematicCharacter : BaseCharacterController
{
{
[Header("Stable Movement")]
[Header("Movement")]
public float MaxStableMoveSpeed = 10f;
public float MaxStableMoveSpeed = 10f;
public float StableMovementSharpness = 15;
public float StableMovementSharpness = 15;
public float rotateSpeed = 10;
public float rotateSpeed = 10;


[Header("Air Movement")]
[Header("Air Movement")]
public float MaxAirMoveSpeed = 10f;
public float MaxAirMoveSpeed = 10f;
public float AirAccelerationSpeed = 5f;
public float AirAccelerationSpeed = 5f;
public float Drag = 0.1f;
public float Drag = 0.1f;


[Header("Jumping")]
[Header("Jumping")]
public bool AllowJumpingWhenSliding = false;
public bool AllowJumpingWhenSliding = false;
public bool AllowDoubleJump = false;
public bool AllowDoubleJump = false;
public bool AllowWallJump = false;
public bool AllowWallJump = false;
public float JumpSpeed = 10f;
public float JumpSpeed = 10f;
public float JumpPreGroundingGraceTime = 0f;
public float JumpPreGroundingGraceTime = 0f;
public float JumpPostGroundingGraceTime = 0f;
public float JumpPostGroundingGraceTime = 0f;


[Header("Misc")]
[Header("Misc")]
public bool RotationObstruction;
public Vector3 Gravity = new Vector3(0, -30f, 0);
public Vector3 Gravity = new Vector3(0, -30f, 0);
public Transform MeshRoot;
public Transform MeshRoot;

private Vector3 moveDirection;
private float Angle;
private float inputAmount;
private bool _jumpRequested = false;
private bool _jumpRequested = false;
private bool _jumpConsumed = false;
private bool _jumpConsumed = false;
private bool _jumpedThisFrame = false;
private bool _jumpedThisFrame = false;
private float _timeSinceJumpRequested = Mathf.Infinity;
private float _timeSinceJumpRequested = Mathf.Infinity;
private float _timeSinceLastAbleToJump = 0f;
private float _timeSinceLastAbleToJump = 0f;
private bool _doubleJumpConsumed = false;
private bool _doubleJumpConsumed = false;
private bool _canWallJump = false;
private bool _canWallJump = false;
private Vector3 _wallJumpNormal;
private Vector3 _wallJumpNormal;


float inputAmount, Angle;
public Transform DirectionReference;
Vector3 moveDirection;
Transform DirectionReference;


private void Start()
private void Start()
{
{
DirectionReference = new GameObject("Player's Direction Reference").transform;
DirectionReference = new GameObject("Player's Direction Reference").transform;
}
}


/// <summary>
/// <summary>
/// This is called every frame by MyPlayer in order to tell the character what its inputs are
/// This is called every frame by MyPlayer in order to tell the character what its inputs are
/// </summary>
/// </summary>
public void SetInputs(ref PlayerCharacterInputs inputs)
public void SetInputs(ref PlayerCharacterInputs inputs)
{
{
// Clamp input
// Clamp input
float inputMagnitude = Mathf.Abs(inputs.horizontal);
float inputMagnitude = Mathf.Abs(inputs.horizontal);
inputAmount = Mathf.Clamp01(inputMagnitude);
inputAmount = Mathf.Clamp01(inputMagnitude);


// base movement on direction reference
// base movement on direction reference
Vector3 correctedHorizontal = inputs.horizontal * DirectionReference.transform.right;
Vector3 correctedHorizontal = inputs.horizontal * DirectionReference.transform.right;
moveDirection = new Vector3((correctedHorizontal).normalized.x, 0, (correctedHorizontal).normalized.z);
moveDirection = new Vector3((correctedHorizontal).normalized.x, 0, (correctedHorizontal).normalized.z);


// Jumping input
// Jumping input
if (inputs.JumpDown)
if (inputs.JumpDown)
{
{
_timeSinceJumpRequested = 0f;
_timeSinceJumpRequested = 0f;
_jumpRequested = true;
_jumpRequested = true;
}
}
}
}


/// <summary>
/// (Called by KinematicCharacterMotor during its update cycle)
/// This is called before the character begins its movement update
/// </summary>
public override void BeforeCharacterUpdate(float deltaTime)
public override void BeforeCharacterUpdate(float deltaTime)
{
{
}
}


/// <summary>
/// <summary>
/// (Called by KinematicCharacterMotor during its update cycle)
/// (Called by KinematicCharacterMotor during its update cycle)
/// This is where you tell your character what its rotation should be right now.
/// This is where you tell your character what its rotation should be right now.
/// This is the ONLY place where you should set the character's rotation
/// This is the ONLY place where you should set the character's rotation
/// </summary>
/// </summary>
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
public override void UpdateRotation(ref Quaternion currentRotation, float deltaTime)
{
{
// rotate player to movement direction
// rotate player to movement direction
if (moveDirection != Vector3.zero)
if (moveDirection != Vector3.zero)
{
{
Angle = Vector3.Angle(transform.forward, DirectionReference.right);
Angle = Vector3.Angle(transform.forward, DirectionReference.right);
Quaternion rot = Quaternion.LookRotation(moveDirection);
Quaternion rot = Quaternion.LookRotation(moveDirection);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * inputAmount * rotateSpeed);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * inputAmount * rotateSpeed);
currentRotation = targetRotation;
currentRotation = targetRotation;
}
}
else
else
{
{
if (Angle < 90)
if (Angle < 90)
{
{
Quaternion rot = Quaternion.LookRotation(DirectionReference.right);
Quaternion rot = Quaternion.LookRotation(DirectionReference.right);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed);
currentRotation = targetRotation;
currentRotation = targetRotation;
}
}
else
else
{
{
Quaternion rot = Quaternion.LookRotation(-DirectionReference.right);
Quaternion rot = Quaternion.LookRotation(-DirectionReference.right);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed);
Quaternion targetRotation = Quaternion.Slerp(transform.rotation, rot, deltaTime * rotateSpeed);
currentRotation = targetRotation;
currentRotation = targetRotation;
}
}
}
}
}
}


/// <summary>
/// <summary>
/// (Called by KinematicCharacterMotor during its update cycle)
/// (Called by KinematicCharacterMotor during its update cycle)
/// This is where you tell your character what its velocity should be right now.
/// This is where you tell your character what its velocity should be right now.
/// This is the ONLY place where you can set the character's velocity
/// This is the ONLY place where you can set the character's velocity
/// </summary>
/// </summary>
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
public override void UpdateVelocity(ref Vector3 currentVelocity, float deltaTime)
{
{
Vector3 targetMovementVelocity = Vector3.zero;
Vector3 targetMovementVelocity = Vector3.zero;
if (Motor.GroundingStatus.IsStableOnGround)
if (Motor.GroundingStatus.IsStableOnGround)
{
{
// Reorient velocity on slope
// Reorient velocity on slope
currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, Motor.GroundingStatus.GroundNormal) * currentVelocity.magnitude;
currentVelocity = Motor.GetDirectionTangentToSurface(currentVelocity, Motor.GroundingStatus.GroundNormal) * currentVelocity.magnitude;


// Calculate target velocity
// Calculate target velocity
Vector3 inputRight = Vector3.Cross(moveDirection, Motor.CharacterUp);
Vector3 inputRight = Vector3.Cross(moveDirection, Motor.CharacterUp);
Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * moveDirection.magnitude;
Vector3 reorientedInput = Vector3.Cross(Motor.GroundingStatus.GroundNormal, inputRight).normalized * moveDirection.magnitude;
targetMovementVelocity = reorientedInput * MaxStableMoveSpeed;
targetMovementVelocity = reorientedInput * MaxStableMoveSpeed;


// Smooth movement Velocity
// Smooth movement Velocity
currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime));
currentVelocity = Vector3.Lerp(currentVelocity, targetMovementVelocity, 1 - Mathf.Exp(-StableMovementSharpness * deltaTime));
}
}
else
else
{
{
// Add move input
// Add move input
if (moveDirection.sqrMagnitude > 0f)
if (moveDirection.sqrMagnitude > 0f)
{
{
targetMovementVelocity = moveDirection * MaxAirMoveSpeed;
targetMovementVelocity = moveDirection * MaxAirMoveSpeed;


// Prevent climbing on un-stable slopes with air movement
// Prevent climbing on un-stable slopes with air movement
if (Motor.GroundingStatus.FoundAnyGround)
if (Motor.GroundingStatus.FoundAnyGround)
{
{
Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
Vector3 perpenticularObstructionNormal = Vector3.Cross(Vector3.Cross(Motor.CharacterUp, Motor.GroundingStatus.GroundNormal), Motor.CharacterUp).normalized;
targetMovementVelocity = Vector3.ProjectOnPlane(targetMovementVelocity, perpenticularObstructionNormal);
targetMovementVelocity = Vector3.ProjectOnPlane(targetMovementVelocity, perpenticularObstructionNormal);
}
}


Vector3 velocityDiff = Vector3.ProjectOnPlane(targetMovementVelocity - currentVelocity, Gravity);
Vector3 velocityDiff = Vector3.ProjectOnPlane(targetMovementVelocity - currentVelocity, Gravity);
currentVelocity += velocityDiff * AirAccelerationSpeed * deltaTime;
currentVelocity += velocityDiff * AirAccelerationSpeed * deltaTime;
}
}


// Gravity
// Gravity
currentVelocity += Gravity * deltaTime;
currentVelocity += Gravity * deltaTime;


// Drag
// Drag
currentVelocity *= (1f / (1f + (Drag * deltaTime)));
currentVelocity *= (1f / (1f + (Drag * deltaTime)));
}
}


// Handle jumping
// Handle jumping
{
{
_jumpedThisFrame = false;
_jumpedThisFrame = false;
_timeSinceJumpRequested += deltaTime;
_timeSinceJumpRequested += deltaTime;
if (_jumpRequested)
if (_jumpRequested)
{
{
// Handle double jump
// Handle double jump
if (AllowDoubleJump)
if (AllowDoubleJump)
{
{
if (_jumpConsumed && !_doubleJumpConsumed && (AllowJumpingWhenSliding ? !Motor.GroundingStatus.FoundAnyGround : !Motor.GroundingStatus.IsStableOnGround))
if (_jumpConsumed && !_doubleJumpConsumed && (AllowJumpingWhenSliding ? !Motor.GroundingStatus.FoundAnyGround : !Motor.GroundingStatus.IsStableOnGround))
{
{
Motor.ForceUnground();
Motor.ForceUnground();


// Add to the return velocity and reset jump state
// Add to the return velocity and reset jump state
currentVelocity += (Motor.CharacterUp * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
currentVelocity += (Motor.CharacterUp * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
_jumpRequested = false;
_jumpRequested = false;
_doubleJumpConsumed = true;
_doubleJumpConsumed = true;
_jumpedThisFrame = true;
_jumpedThisFrame = true;
}
}
}
}


// See if we actually are allowed to jump
// See if we actually are allowed to jump
if (_canWallJump ||
if (_canWallJump ||
(!_jumpConsumed && ((AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) || _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime)))
(!_jumpConsumed && ((AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround) || _timeSinceLastAbleToJump <= JumpPostGroundingGraceTime)))
{
{
// Calculate jump direction before ungrounding
// Calculate jump direction before ungrounding
Vector3 jumpDirection = Motor.CharacterUp;
Vector3 jumpDirection = Motor.CharacterUp;
if (_canWallJump)
if (_canWallJump)
{
{
jumpDirection = _wallJumpNormal;
jumpDirection = _wallJumpNormal;
}
}
else if (Motor.GroundingStatus.FoundAnyGround && !Motor.GroundingStatus.IsStableOnGround)
else if (Motor.GroundingStatus.FoundAnyGround && !Motor.GroundingStatus.IsStableOnGround)
{
{
jumpDirection = Motor.GroundingStatus.GroundNormal;
jumpDirection = Motor.GroundingStatus.GroundNormal;
}
}


// Makes the character skip ground probing/snapping on its next update.
// Makes the character skip ground probing/snapping on its next update.
// If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see.
// If this line weren't here, the character would remain snapped to the ground when trying to jump. Try commenting this line out and see.
Motor.ForceUnground();
Motor.ForceUnground();


// Add to the return velocity and reset jump state
// Add to the return velocity and reset jump state
currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
currentVelocity += (jumpDirection * JumpSpeed) - Vector3.Project(currentVelocity, Motor.CharacterUp);
_jumpRequested = false;
_jumpRequested = false;
_jumpConsumed = true;
_jumpConsumed = true;
_jumpedThisFrame = true;
_jumpedThisFrame = true;
}
}
}
}


// Reset wall jump
// Reset wall jump
_canWallJump = false;
_canWallJump = false;
}
}
}
}


/// <summary>
/// <summary>
/// (Called by KinematicCharacterMotor during its update cycle)
/// (Called by KinematicCharacterMotor during its update cycle)
/// This is called after the character has finished its movement update
/// This is called after the character has finished its movement update
/// </summary>
/// </summary>
public override void AfterCharacterUpdate(float deltaTime)
public override void AfterCharacterUpdate(float deltaTime)
{
{
// Handle jump-related values
// Handle jump-related values
{
{
// Handle jumping pre-ground grace period
// Handle jumping pre-ground grace period
if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime)
if (_jumpRequested && _timeSinceJumpRequested > JumpPreGroundingGraceTime)
{
{
_jumpRequested = false;
_jumpRequested = false;
}
}


if (AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround)
if (AllowJumpingWhenSliding ? Motor.GroundingStatus.FoundAnyGround : Motor.GroundingStatus.IsStableOnGround)
{
{
// If we're on a ground surface, reset jumping values
// If we're on a ground surface, reset jumping values
if (!_jumpedThisFrame)
if (!_jumpedThisFrame)
{
{
_doubleJumpConsumed = false;
_doubleJumpConsumed = false;
_jumpConsumed = false;
_jumpConsumed = false;
}
}
_timeSinceLastAbleToJump = 0f;
_timeSinceLastAbleToJump = 0f;
}
}
else
else
{
{
// Keep track of time since we were last able to jump (for grace period)
// Keep track of time since we were last able to jump (for grace period)
_timeSinceLastAbleToJump += deltaTime;
_timeSinceLastAbleToJump += deltaTime;
}
}
}
}
}
}


public override bool IsColliderValidForCollisions(Collider coll)
public override bool IsColliderValidForCollisions(Collider coll)
{
{
return true;
return true;
}
}


public override void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
public override void OnGroundHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
{
{
}
}


public override void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
public override void OnMovementHit(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, ref HitStabilityReport hitStabilityReport)
{
{
// We can wall jump only if we are not stable on ground and are moving against an obstruction
// We can wall jump only if we are not stable on ground and are moving against an obstruction
if (AllowWallJump && !Motor.GroundingStatus.IsStableOnGround && !hitStabilityReport.IsStable)
if (AllowWallJump && !Motor.GroundingStatus.IsStableOnGround && !hitStabilityReport.IsStable)
{
{
_canWallJump = true;
_canWallJump = true;
_wallJumpNormal = hitNormal;
_wallJumpNormal = hitNormal;
}
}
}
}


public override void PostGroundingUpdate(float deltaTime)
public override void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
{
}

public void AddVelocity(Vector3 velocity)
{
{
}
}


public override void ProcessHitStabilityReport(Collider hitCollider, Vector3 hitNormal, Vector3 hitPoint, Vector3 atCharacterPosition, Quaternion atCharacterRotation, ref HitStabilityReport hitStabilityReport)
public override void PostGroundingUpdate(float deltaTime)
{
{
}
}
}
}
}
}