using UnityEngine;
using System.Collections;
//刚体角色驱动
public class CharacterMotor : MonoBehaviour
{
//输入控制
bool
canControl = true;
//物理更新
bool
useFixedUpdate = true;
//序列化 但是不显示在inspector层
[HideInInspector]
public
Vector3 inputMoveDirection = Vector3.zero;
[HideInInspector]
//起始不为跳跃
public bool
inputJump = false;
class
CharacterMotorMovement
{
//水平最大速度
public float maxForwardSpeed = 10.0f;
public float maxSidewaysSpeed = 10.0f;
public float maxBackwardsSpeed = 10.0f;
//可调节动画帧率
基于斜率的乘法速度曲线(负=向下)
public AnimationCurve slopeSpeedMultiplier = new AnimationCurve(new
Keyframe(-90, 1), new Keyframe(0, 1), new Keyframe(90, 0));
public float maxGroundAcceleration = 30.0f;
public float maxAirAcceleration = 20.0f;
//人物的引力
public float gravity = 10.0f;
public float maxFallSpeed = 20.0f;
[HideInInspector]
//判断是否接近地面
public CollisionFlags collisionFlags;
//跟踪角色的速度
[HideInInspector]
public Vector3 velocity;
[HideInInspector]
public Vector3 frameVelocity = Vector3.zero;
[HideInInspector]
public Vector3 hitPoint = Vector3.zero;
[HideInInspector]
public Vector3 lastHitPoint = new Vector3(Mathf.Infinity, 0,
0);
}
CharacterMotorMovement movement = new CharacterMotorMovement();
//设置状态
enum
MovementTransferOnJump
{
None, // 跳跃不受地面速度的影响
InitTransfer, //从地板上跳的初速度,然后逐渐停下来
PermaTransfer, // 得到初始速度跳跃从楼,和保持,直到着陆速度
PermaLocked // 跳跃是相对于移动的最后一个接触地板,并将与该地板一起移动。
}
//记录跳跃相关的所有变量
class
CharacterMotorJumping
{
//是否跳跃
public bool enabled = true;
//点击一次跳跃高度
public float baseHeight = 1.0f;
//按住跳跃高度
public float extraHeight = 4.1f;
//0 垂直的跳跃,1垂直的。平面跳跃
public float perpAmount = 0.0f;
//斗破跳跃
public float steepPerpAmount = 0.5f;
[HideInInspector]
//是否在跳跃进行时
public bool jumping = false;
//是否按住跳跃键
[HideInInspector]
public bool holdingJumpButton = false;
//起始跳跃时间
[HideInInspector]
public float lastStartTime = 0.0f;
[HideInInspector]
public float lastButtonDownTime = -100;
//跳跃方向
[HideInInspector]
public Vector3 jumpDir = Vector3.up;
}
//跳跃类
CharacterMotorJumping jumping = new CharacterMotorJumping();
class
CharacterMotorMovingPlatform
{
public bool enabled = true;
public MovementTransferOnJump movementTransfer =
MovementTransferOnJump.PermaTransfer;
[HideInInspector]
public Transform hitPlatform;
[HideInInspector]
public Transform activePlatform;
[HideInInspector]
public Vector3 activeLocalPoint;
[HideInInspector]
public Vector3 activeGlobalPoint;
[HideInInspector]
public Quaternion activeLocalRotation;
[HideInInspector]
public Quaternion activeGlobalRotation;
[HideInInspector]
public Matrix4x4 lastMatrix;
[HideInInspector]
public Vector3 platformVelocity;
[HideInInspector]
public bool newPlatform;
}
//移动平台
CharacterMotorMovingPlatform movingPlatform = new
CharacterMotorMovingPlatform();
class
CharacterMotorSliding
{
//是否在斗破移动
public bool enabled = true;
//陡坡移动速度
public float slidingSpeed = 15f;
//以一半的速度向下移动
public float sidewaysControl = 1.0f;
//滑动累加值
public float speedControl = 0.4f;
}
CharacterMotorSliding sliding = new CharacterMotorSliding();
[HideInInspector]
//地面
bool
grounded = true;
//平滑地面
[HideInInspector]
Vector3
groundNormal = Vector3.zero;
private
Vector3 lastGroundNormal = Vector3.zero;
private
Transform tr;
private
CharacterController controller;
public void
Awake()
{
//CharacterMotorObj = obj;
controller = GetComponent();
tr = transform;
}
//内部更新机制
private void
UpdateFunction()
{
//实际速度给一个临时变量
Vector3 velocity = movement.velocity;
//赋值新的速度
velocity = ApplyInputVelocityChange(velocity);
//赋值新的跳跃
velocity = ApplyGravityAndJumping(velocity);
//移动平台 距离
Vector3 moveDistance = Vector3.zero;
if (MoveWithPlatform())
{
Vector3 newGlobalPoint =
movingPlatform.activePlatform.TransformPoint(movingPlatform.activeLocalPoint);
moveDistance = (newGlobalPoint -
movingPlatform.activeGlobalPoint);
if (moveDistance != Vector3.zero)
{
controller.Move(moveDistance);
}
//移动平台旋转
Quaternion newGlobalRotation =
movingPlatform.activePlatform.rotation *
movingPlatform.activeLocalRotation;
Quaternion rotationDiff = newGlobalRotation *
Quaternion.Inverse(movingPlatform.activeGlobalRotation);
float yRotation = rotationDiff.eulerAngles.y;
if (yRotation != 0)
{
//防止局部向上向量的旋转
tr.Rotate(0, yRotation, 0);
}
}
//保存lastposition for速度计算。
Vector3 lastPosition = tr.position;
//当前移动确切时间
Vector3 currentMovementOffset = velocity * Time.deltaTime;
float pushDownOffset = Mathf.Max(controller.stepOffset, new
Vector3(currentMovementOffset.x, 0,
currentMovementOffset.z).magnitude);
if (grounded)
{
currentMovementOffset -= pushDownOffset * Vector3.up;
}
//将设置为冲突函数的重置变量
movingPlatform.hitPlatform = null;
groundNormal = Vector3.zero;
//移动角色
movement.collisionFlags =
controller.Move(currentMovementOffset);
movement.lastHitPoint = movement.hitPoint;
lastGroundNormal = groundNormal;
if (movingPlatform.enabled && movingPlatform.activePlatform
!= movingPlatform.hitPlatform)
{
if (movingPlatform.hitPlatform != null)
{
movingPlatform.activePlatform = movingPlatform.hitPlatform;
movingPlatform.lastMatrix =
movingPlatform.hitPlatform.localToWorldMatrix;
movingPlatform.newPlatform = true;
}
}
//基于当前和以前的位置计算速度
Vector3 oldHVelocity = new Vector3(velocity.x, 0,
velocity.z);
//碰撞的结果
movement.velocity = (tr.position - lastPosition) /
Time.deltaTime;
Vector3 newHVelocity = new Vector3(movement.velocity.x, 0,
movement.velocity.z);
if (oldHVelocity == Vector3.zero)//在不需要的方向碰撞时的时候
{
movement.velocity = new Vector3(0, movement.velocity.y, 0);
}
else //防止这种影响的记录速度
{
float projectedNewVelocity = Vector3.Dot(newHVelocity,
oldHVelocity) / oldHVelocity.sqrMagnitude;
movement.velocity = oldHVelocity *
Mathf.Clamp01(projectedNewVelocity) + movement.velocity.y *
Vector3.up;
}
if (movement.velocity.y < velocity.y - 0.001)
{
if (movement.velocity.y < 0)
{
movement.velocity.y = velocity.y;
}
else
{
jumping.holdingJumpButton = false;
}
}
//接触地面的时候
if (grounded && !IsGroundedTest())
{
grounded = false;
if (movingPlatform.enabled &&
(movingPlatform.movementTransfer ==
MovementTransferOnJump.InitTransfer ||
movingPlatform.movementTransfer ==
MovementTransferOnJump.PermaTransfer)
)
{
movement.frameVelocity = movingPlatform.platformVelocity;
movement.velocity += movingPlatform.platformVelocity;
}
SendMessage("OnFall", SendMessageOptions.DontRequireReceiver);
tr.position += pushDownOffset * Vector3.up;
}
//刚降落的时候
else if (!grounded && IsGroundedTest())
{
grounded = true;
jumping.jumping = false;
SubtractNewPlatformVelocity();
SendMessage("OnLand",
SendMessageOptions.DontRequireReceiver);
}
if (MoveWithPlatform())
{
//作为参考点的下半球形的中心点
movingPlatform.activeGlobalPoint = tr.position + Vector3.up *
(controller.center.y - controller.height * 0.5f +
controller.radius);
//当人物站在倾斜的平台上时,这一效果最好
movingPlatform.activeLocalPoint =
movingPlatform.activePlatform.InverseTransformPoint(movingPlatform.activeGlobalPoint);
//平台旋转
movingPlatform.activeGlobalRotation = tr.rotation;
movingPlatform.activeLocalRotation =
Quaternion.Inverse(movingPlatform.activePlatform.rotation) *
movingPlatform.activeGlobalRotation;
}
}
public
void FixedUpdate()
{
if (movingPlatform.enabled)
{
if (movingPlatform.activePlatform != null)
{
if (!movingPlatform.newPlatform)
{
Vector3 lastVelocity = movingPlatform.platformVelocity;
movingPlatform.platformVelocity = (
movingPlatform.activePlatform.localToWorldMatrix.MultiplyPoint3x4(movingPlatform.activeLocalPoint)
-
movingPlatform.lastMatrix.MultiplyPoint3x4(movingPlatform.activeLocalPoint))
/ Time.deltaTime;
}
movingPlatform.lastMatrix =
movingPlatform.activePlatform.localToWorldMatrix;
movingPlatform.newPlatform = false;
}
else
{
movingPlatform.platformVelocity = Vector3.zero;
}
}
if (useFixedUpdate)
{
UpdateFunction();
}
}
public
void Update()
{
if (!useFixedUpdate)
{
UpdateFunction();
}
}
private
Vector3 ApplyInputVelocityChange(Vector3 velocity)
{
if (!canControl)
{
inputMoveDirection = Vector3.zero;
}
//记录期望的速度
Vector3 desiredVelocity;
if (grounded && TooSteep())
{
//记录方向
desiredVelocity = new Vector3(groundNormal.x, 0,
groundNormal.z).normalized;
//输入运动方向投影到滑动方向上
Vector3 projectedMoveDir = Vector3.Project(inputMoveDirection,
desiredVelocity);
//添加滑动方向,速度控制,和横向控制向量
desiredVelocity = desiredVelocity + projectedMoveDir *
sliding.speedControl + (inputMoveDirection - projectedMoveDir) *
sliding.sidewaysControl;
//乘与滑动速度
desiredVelocity *= sliding.slidingSpeed;
}
else
{
desiredVelocity = GetDesiredHorizontalVelocity();
}
if (movingPlatform.enabled &&
movingPlatform.movementTransfer ==
MovementTransferOnJump.PermaTransfer)
{
desiredVelocity += movement.frameVelocity;
desiredVelocity.y = 0;
}
if (grounded)
{
desiredVelocity = AdjustGroundVelocityToNormal(desiredVelocity,
groundNormal);
}
else
{
velocity.y = 0;
}
//执行最大速度变化
float maxVelocityChange = GetMaxAcceleration(grounded) *
Time.deltaTime;
Vector3 velocityChangeVector = (desiredVelocity - velocity);
if (velocityChangeVector.sqrMagnitude > maxVelocityChange *
maxVelocityChange)
{
velocityChangeVector = velocityChangeVector.normalized *
maxVelocityChange;
}
if (grounded || canControl)//如果我们在空中,没有控制,不要用任何速度改变
{
velocity += velocityChangeVector;
}
if (grounded)
{
velocity.y = Mathf.Min(velocity.y, 0);
}
return velocity;
}
//应用重力
和 跳跃
private
Vector3 ApplyGravityAndJumping(Vector3 velocity)
{
if (!inputJump || !canControl)
{
jumping.holdingJumpButton = false;
jumping.lastButtonDownTime = -100;
}
if (inputJump && jumping.lastButtonDownTime < 0
&& canControl)
{
jumping.lastButtonDownTime = Time.time;
}
if (grounded)
{
velocity.y = Mathf.Min(0, velocity.y) - movement.gravity *
Time.deltaTime;
}
else
{
velocity.y = movement.velocity.y - movement.gravity *
Time.deltaTime;
if (jumping.jumping && jumping.holdingJumpButton)
{
if (Time.time < jumping.lastStartTime + jumping.extraHeight /
CalculateJumpVerticalSpeed(jumping.baseHeight))
{
velocity += jumping.jumpDir * movement.gravity *
Time.deltaTime;
}
}
//角色一个终端速度
velocity.y = Mathf.Max(velocity.y, -movement.maxFallSpeed);
}
if (grounded)
{
if (jumping.enabled && canControl && (Time.time -
jumping.lastButtonDownTime < 0.2))
{
grounded = false;
jumping.jumping = true;
jumping.lastStartTime = Time.time;
jumping.lastButtonDownTime = -100;
jumping.holdingJumpButton = true;
//计算跳跃方向
if (TooSteep())
{
jumping.jumpDir = Vector3.Slerp(Vector3.up, groundNormal,
jumping.steepPerpAmount);
}
else
{
jumping.jumpDir = Vector3.Slerp(Vector3.up, groundNormal,
jumping.perpAmount);
}
//应用跳跃力的速度。先取消任何垂直速度。
velocity.y = 0;
velocity += jumping.jumpDir *
CalculateJumpVerticalSpeed(jumping.baseHeight);
//应用惯性平台
if (movingPlatform.enabled &&
(movingPlatform.movementTransfer ==
MovementTransferOnJump.InitTransfer ||
movingPlatform.movementTransfer ==
MovementTransferOnJump.PermaTransfer))
{
movement.frameVelocity = movingPlatform.platformVelocity;
velocity += movingPlatform.platformVelocity;
}
SendMessage("OnJump",
SendMessageOptions.DontRequireReceiver);
}
else
{
jumping.holdingJumpButton = false;
}
}
return velocity;
}
void
OnControllerColliderHit(ControllerColliderHit hit)
{
if (hit.normal.y > 0 && hit.normal.y > groundNormal.y
&& hit.moveDirection.y < 0)
{
if ((hit.point - movement.lastHitPoint).sqrMagnitude > 0.001 ||
lastGroundNormal == Vector3.zero)
{
groundNormal = hit.normal;
}
else
{
groundNormal = lastGroundNormal;
}
movingPlatform.hitPlatform = hit.collider.transform;
movement.hitPoint = hit.point;
movement.frameVelocity = Vector3.zero;
}
}
private
IEnumerator SubtractNewPlatformVelocity()
{
if (movingPlatform.enabled &&
(movingPlatform.movementTransfer ==
MovementTransferOnJump.InitTransfer ||
movingPlatform.movementTransfer ==
MovementTransferOnJump.PermaTransfer))
{
if (movingPlatform.newPlatform)
{
Transform platform = movingPlatform.activePlatform;
yield return new WaitForFixedUpdate();
yield return new WaitForFixedUpdate();
if (grounded && platform ==
movingPlatform.activePlatform)
{
yield return 1;//协同等待一秒在继续执行
}
}
movement.velocity -= movingPlatform.platformVelocity;
}
}
private
bool MoveWithPlatform()
{
return (movingPlatform.enabled && (grounded ||
movingPlatform.movementTransfer ==
MovementTransferOnJump.PermaLocked) &&
movingPlatform.activePlatform != null);
}
private
Vector3 GetDesiredHorizontalVelocity()
{
//记录期望的速度
Vector3 desiredLocalDirection =
tr.InverseTransformDirection(inputMoveDirection);
float maxSpeed = MaxSpeedInDirection(desiredLocalDirection);
if (grounded)
{
//基于斜率速度乘子曲线的斜坡最大速度修正
var movementSlopeAngle = Mathf.Asin(movement.velocity.normalized.y)
* Mathf.Rad2Deg;
maxSpeed *=
movement.slopeSpeedMultiplier.Evaluate(movementSlopeAngle);
}
return tr.TransformDirection(desiredLocalDirection *
maxSpeed);
}
private
Vector3 AdjustGroundVelocityToNormal(Vector3 hVelocity, Vector3
groundNormal)
{
Vector3 sideways = Vector3.Cross(Vector3.up, hVelocity);
return Vector3.Cross(sideways, groundNormal).normalized *
hVelocity.magnitude;
}
private
bool IsGroundedTest()
{
return (groundNormal.y > 0.01f);
}
float
GetMaxAcceleration(bool grounded)
{
//地面和空中的最大加速度
float MaxAirSpeed = 0;
if (grounded)
{
MaxAirSpeed = movement.maxGroundAcceleration;
}
else
{
MaxAirSpeed = movement.maxAirAcceleration;
}
return MaxAirSpeed;
}
float
CalculateJumpVerticalSpeed(float targetJumpHeight)
{
//推断向上的速度
return Mathf.Sqrt(2 * targetJumpHeight * movement.gravity);
}
bool
IsJumping()
{
return jumping.jumping;
}
bool
IsSliding()
{
return (grounded && sliding.enabled &&
TooSteep());
}
bool
IsTouchingCeiling()
{
return (movement.collisionFlags & CollisionFlags.CollidedAbove)
!= 0;
}
bool
IsGrounded()
{
return grounded;
}
bool
TooSteep()
{
return (groundNormal.y <= Mathf.Cos(controller.slopeLimit *
Mathf.Deg2Rad));
}
Vector3
GetDirection()
{
return inputMoveDirection;
}
void
SetControllable(bool controllable)
{
canControl = controllable;
}
//返回所得到的向量的长度
float
MaxSpeedInDirection(Vector3 desiredMovementDirection)
{
if (desiredMovementDirection == Vector3.zero)
{
return 0;
}
else
{
float zAxisEllipseMultiplier = (desiredMovementDirection.z > 0 ?
movement.maxForwardSpeed : movement.maxBackwardsSpeed) /
movement.maxSidewaysSpeed;
Vector3 temp = new Vector3(desiredMovementDirection.x, 0,
desiredMovementDirection.z /
zAxisEllipseMultiplier).normalized;
float length = new Vector3(temp.x, 0, temp.z *
zAxisEllipseMultiplier).magnitude *
movement.maxSidewaysSpeed;
return length;
}
}
void
SetVelocity(Vector3 velocity)
{
grounded = false;
movement.velocity = velocity;
movement.frameVelocity = Vector3.zero;
SendMessage("OnExternalVelocity");
}
}
加载中,请稍候......