256 lines
8.7 KiB
C#
256 lines
8.7 KiB
C#
using Invector.vCharacterController;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using UnityEngine;
|
|
using System.Text;
|
|
using System;
|
|
|
|
public class PlayerMover : MonoBehaviour
|
|
{
|
|
public float speed = 3f;
|
|
[HideInInspector]
|
|
public Vector3 move;
|
|
public VariableJoystick variableJoystick;
|
|
[HideInInspector] public vThirdPersonController cc;
|
|
public UnityEngine.UI.Button JumpButton;
|
|
|
|
public bool Freeze;
|
|
|
|
private bool isGrounded;
|
|
|
|
void Start()
|
|
{
|
|
isGrounded = true;
|
|
|
|
Init();
|
|
|
|
JumpButton.onClick.AddListener(() =>
|
|
{
|
|
if (JumpConditions())
|
|
Jump();
|
|
});
|
|
}
|
|
void Update()
|
|
{
|
|
if (Freeze) return;
|
|
|
|
float x = Input.GetAxis("Horizontal");
|
|
float z = Input.GetAxis("Vertical");
|
|
move = new Vector3(x, 0, z);
|
|
x = x == 0 ? variableJoystick.Horizontal : x;
|
|
z = z == 0 ? variableJoystick.Vertical : z;
|
|
move = new Vector3(x, 0, z);
|
|
|
|
if (move != Vector3.zero)
|
|
{
|
|
move = Quaternion.Euler(0, Camera.main.transform.eulerAngles.y, 0) * move;
|
|
transform.position += move * speed * Time.deltaTime;
|
|
RotatePlayer();
|
|
}
|
|
UpdateAnim();
|
|
}
|
|
|
|
void FixedUpdate()
|
|
{
|
|
CheckGround();
|
|
ControlJumpBehaviour();
|
|
}
|
|
|
|
void UpdateAnim()
|
|
{
|
|
animator.SetFloat("InputMagnitude", move.magnitude);
|
|
}
|
|
private void RotatePlayer()
|
|
{
|
|
//向量v围绕y轴旋转cameraAngle.y度
|
|
Vector3 vec = Quaternion.Euler(0, 0, 0) * move;
|
|
Quaternion qua = Quaternion.LookRotation(vec);
|
|
transform.rotation = Quaternion.Lerp(transform.rotation, qua, Time.deltaTime * 100);
|
|
}
|
|
|
|
private void Jump()
|
|
{
|
|
// trigger jump behaviour
|
|
jumpCounter = jumpTimer;
|
|
isJumping = true;
|
|
|
|
// trigger jump animations
|
|
if (move.sqrMagnitude < 0.1f)
|
|
animator.CrossFadeInFixedTime("Jump", 0.1f);
|
|
else
|
|
animator.CrossFadeInFixedTime("JumpMove", .2f);
|
|
}
|
|
|
|
protected virtual void ControlJumpBehaviour()
|
|
{
|
|
if (!isJumping) return;
|
|
|
|
jumpCounter -= Time.deltaTime;
|
|
if (jumpCounter <= 0)
|
|
{
|
|
jumpCounter = 0;
|
|
isJumping = false;
|
|
}
|
|
// apply extra force to the jump height
|
|
var vel = _rigidbody.velocity;
|
|
vel.y = jumpHeight;
|
|
_rigidbody.velocity = vel;
|
|
}
|
|
|
|
protected bool JumpConditions()
|
|
{
|
|
return isGrounded && GroundAngle() < slopeLimit && !isJumping ;
|
|
}
|
|
|
|
public float GroundAngle()
|
|
{
|
|
var groundAngle = Vector3.Angle(groundHit.normal, Vector3.up);
|
|
return groundAngle;
|
|
}
|
|
|
|
public float jumpTimer = 0.3f;
|
|
public float jumpHeight = 4;
|
|
internal float jumpCounter;
|
|
private bool isJumping;
|
|
private Vector3 input;
|
|
|
|
[Tooltip("Layers that the character can walk on")]
|
|
public LayerMask groundLayer = 1 << 0;
|
|
[Tooltip("Distance to became not grounded")]
|
|
public float groundMinDistance = 0.25f;
|
|
public float groundMaxDistance = 0.5f;
|
|
[Tooltip("Max angle to walk")]
|
|
[Range(30, 80)] public float slopeLimit = 75f;
|
|
[Tooltip("Apply extra gravity when the character is not grounded")]
|
|
public float extraGravity = -10f;
|
|
|
|
internal float groundDistance; // used to know the distance from the ground
|
|
internal RaycastHit groundHit; // raycast to hit the ground
|
|
internal float heightReached; // max height that character reached in air;
|
|
internal float verticalVelocity; // set the vertical velocity of the rigidbody
|
|
internal Vector3 colliderCenter; // storage the center of the capsule collider info
|
|
internal float colliderRadius, colliderHeight; // storage capsule collider extra information
|
|
|
|
protected virtual void CheckGround()
|
|
{
|
|
CheckGroundDistance();
|
|
ControlMaterialPhysics();
|
|
|
|
if (groundDistance <= groundMinDistance)
|
|
{
|
|
isGrounded = true;
|
|
if (!isJumping && groundDistance > 0.05f)
|
|
_rigidbody.AddForce(transform.up * (extraGravity * 2 * Time.deltaTime), ForceMode.VelocityChange);
|
|
|
|
heightReached = transform.position.y;
|
|
}
|
|
else
|
|
{
|
|
if (groundDistance >= groundMaxDistance)
|
|
{
|
|
// set IsGrounded to false
|
|
isGrounded = false;
|
|
// check vertical velocity
|
|
verticalVelocity = _rigidbody.velocity.y;
|
|
// apply extra gravity when falling
|
|
if (!isJumping)
|
|
{
|
|
_rigidbody.AddForce(transform.up * extraGravity * Time.deltaTime, ForceMode.VelocityChange);
|
|
}
|
|
}
|
|
else if (!isJumping)
|
|
{
|
|
_rigidbody.AddForce(transform.up * (extraGravity * 2 * Time.deltaTime), ForceMode.VelocityChange);
|
|
}
|
|
}
|
|
}
|
|
|
|
protected virtual void ControlMaterialPhysics()
|
|
{
|
|
return;
|
|
//change the physics material to very slip when not grounded
|
|
_capsuleCollider.material = (isGrounded && GroundAngle() <= slopeLimit + 1) ? frictionPhysics : slippyPhysics;
|
|
|
|
if (isGrounded && move == Vector3.zero)
|
|
_capsuleCollider.material = maxFrictionPhysics;
|
|
else if (isGrounded && move != Vector3.zero)
|
|
_capsuleCollider.material = frictionPhysics;
|
|
else
|
|
_capsuleCollider.material = slippyPhysics;
|
|
}
|
|
|
|
protected virtual void CheckGroundDistance()
|
|
{
|
|
if (_capsuleCollider != null)
|
|
{
|
|
// radius of the SphereCast
|
|
float radius = _capsuleCollider.radius * 0.9f;
|
|
var dist = 10f;
|
|
// ray for RayCast
|
|
Ray ray2 = new Ray(transform.position + new Vector3(0, colliderHeight / 2, 0), Vector3.down);
|
|
// raycast for check the ground distance
|
|
if (Physics.Raycast(ray2, out groundHit, (colliderHeight / 2) + dist, groundLayer) && !groundHit.collider.isTrigger)
|
|
dist = transform.position.y - groundHit.point.y;
|
|
// sphere cast around the base of the capsule to check the ground distance
|
|
if (dist >= groundMinDistance)
|
|
{
|
|
Vector3 pos = transform.position + Vector3.up * (_capsuleCollider.radius);
|
|
Ray ray = new Ray(pos, -Vector3.up);
|
|
if (Physics.SphereCast(ray, radius, out groundHit, _capsuleCollider.radius + groundMaxDistance, groundLayer) && !groundHit.collider.isTrigger)
|
|
{
|
|
Physics.Linecast(groundHit.point + (Vector3.up * 0.1f), groundHit.point + Vector3.down * 0.15f, out groundHit, groundLayer);
|
|
float newDist = transform.position.y - groundHit.point.y;
|
|
if (dist > newDist) dist = newDist;
|
|
}
|
|
}
|
|
groundDistance = (float)System.Math.Round(dist, 2);
|
|
}
|
|
}
|
|
|
|
#region Components
|
|
internal Animator animator;
|
|
internal Rigidbody _rigidbody; // access the Rigidbody component
|
|
internal PhysicMaterial frictionPhysics, maxFrictionPhysics, slippyPhysics; // create PhysicMaterial for the Rigidbody
|
|
internal CapsuleCollider _capsuleCollider; // access CapsuleCollider information
|
|
#endregion
|
|
|
|
void Init()
|
|
{
|
|
animator = GetComponent<Animator>();
|
|
|
|
frictionPhysics = new PhysicMaterial();
|
|
frictionPhysics.name = "frictionPhysics";
|
|
frictionPhysics.staticFriction = .25f;
|
|
frictionPhysics.dynamicFriction = .25f;
|
|
frictionPhysics.frictionCombine = PhysicMaterialCombine.Multiply;
|
|
|
|
// prevents the collider from slipping on ramps
|
|
maxFrictionPhysics = new PhysicMaterial();
|
|
maxFrictionPhysics.name = "maxFrictionPhysics";
|
|
maxFrictionPhysics.staticFriction = 1f;
|
|
maxFrictionPhysics.dynamicFriction = 1f;
|
|
maxFrictionPhysics.frictionCombine = PhysicMaterialCombine.Maximum;
|
|
|
|
// air physics
|
|
slippyPhysics = new PhysicMaterial();
|
|
slippyPhysics.name = "slippyPhysics";
|
|
slippyPhysics.staticFriction = 0f;
|
|
slippyPhysics.dynamicFriction = 0f;
|
|
slippyPhysics.frictionCombine = PhysicMaterialCombine.Minimum;
|
|
|
|
// rigidbody info
|
|
_rigidbody = GetComponent<Rigidbody>();
|
|
|
|
// capsule collider info
|
|
_capsuleCollider = GetComponent<CapsuleCollider>();
|
|
|
|
// save your collider preferences
|
|
colliderCenter = GetComponent<CapsuleCollider>().center;
|
|
colliderRadius = GetComponent<CapsuleCollider>().radius;
|
|
colliderHeight = GetComponent<CapsuleCollider>().height;
|
|
|
|
isGrounded = true;
|
|
}
|
|
}
|
|
|