using UnityEngine;
public class PlayerController : MonoBehaviour
{
public Transform Itself;//自己本身
public GameObject Cam;//摄像机
public bool Gravity=true;//重力
public bool inAir=true;//空中
//方便移动和跳跃(外面只需要修改这里就可以移动跳跃旋转)
public bool ForwardMove = false;
public bool BackMove = false;
public bool RightMove = false;
public bool LeftMove = false;
public bool IsJump = false;
public Vector2 Rot = Vector2.zero;//旋转值
public bool IsTouchPadRot = false;
public float JumpSpeed=15f;//跳跃速度
public float MoveSpeed=8f;//速度
public float RotX_Speed=10f;//旋转x速度
public float RotY_Speed=10f;//旋转y速度
public Vector3 velocity = Vector3.zero;
public bool IsRot = true;//是否使用旋转
public bool IsPC_Rot = true;//旋转采用电脑或者其他设备
public float CapsuleR=0.5f;//胶囊半径
public float ShiftAcceleration=1.7f;//加速倍速度
public Vector3 CapsuleP1=Vector3.zero;//胶囊1负
public Vector3 CapsuleP2=Vector3.zero;//胶囊2正
public bool CameraSpace=true;//相机空间
public Vector3 ForceVelocity=Vector3.zero;//力速度
public float StepsPerSecond = 50;//步长秒
public float Acceleration = 50f;//加速
public bool UseLag = false;//使用滞后
public float LagTimeLeft;//剩余滞后时间
public float LagTime = 0.1f;//滞后时间
public float oldTime=0;//计时
public static readonly int[] SearchDirVert = { 1, -1, 0, 0, 1, 1, -1, -1 };//搜索方向垂直
public static readonly int[] SearchDirHor = { 0, 0, 1, -1, -1, 1, 1, -1 };//搜索方向水平
private void Update()
{
if (Cam == null) Cam = Camera.main.transform.gameObject;
//自身
if (Itself == null) Itself = transform;
//胶囊参数
CapsuleCollider capsuleCollider = Itself.GetComponent<CapsuleCollider>();
if (capsuleCollider != null)
{
CapsuleP1 = capsuleCollider.center + Vector3.up * (capsuleCollider.height / 2 - capsuleCollider.radius);
CapsuleP2 = capsuleCollider.center - Vector3.up * (capsuleCollider.height / 2 - capsuleCollider.radius);
CapsuleR = capsuleCollider.radius;
}
//模仿滞后
LagTimeLeft -= Time.deltaTime;
if (UseLag && LagTimeLeft > 0) return;
LagTimeLeft = LagTime;
//确定观看方向
Vector3 lookDir;
if (CameraSpace)
{
lookDir = new Vector3(Cam.transform.forward.x, Cam.transform.forward.y, Cam.transform.forward.z);
if (Gravity) lookDir.y = 0;
}
else lookDir = Itself.transform.forward;
lookDir = lookDir.normalized;
Vector3 strafeDir = Vector3.Cross(Vector3.up, lookDir);
//移动的
Vector3 direction = new Vector3(0, 0, 0);
if (Input.GetKeyDown(KeyCode.LeftShift)) { MoveSpeed *= ShiftAcceleration;}
if ( Input.GetKeyUp(KeyCode.LeftShift)) { MoveSpeed /= ShiftAcceleration;}
if (IsJump||Input.GetKey(KeyCode.Space) && !inAir) { velocity.y = JumpSpeed;IsJump = false; }
if (ForwardMove||Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow)) { direction += lookDir; }
if (BackMove||Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow)) { direction -= lookDir; }
if (RightMove||Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow)) { direction += strafeDir; }
if (LeftMove||Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow)) { direction -= strafeDir; }
if (IsRot)
{
if (IsPC_Rot)
{
Cam.transform.Rotate(new Vector3(-Input.GetAxis("Mouse Y"), 0, 0) * RotY_Speed * Time.deltaTime);
Itself.Rotate(new Vector3(0, Input.GetAxis("Mouse X"), 0) * Time.deltaTime * RotX_Speed);
}
else
{
if (IsTouchPadRot)
{
Cam.transform.Rotate(new Vector3(-Rot.y, 0, 0) * RotY_Speed * Time.deltaTime);
Itself.Rotate(new Vector3(0, Rot.x, 0) * Time.deltaTime * RotX_Speed);
//rot.x += Time.deltaTime * RotX_Speed * Rot.x;
// rot.y += Time.deltaTime * RotY_Speed * Rot.y;
//Cam.transform.rotation = Quaternion.Euler(-rot.y, 0, 0);
//Itself.rotation = Quaternion.Euler(0, rot.x, 0);
IsTouchPadRot = false;
}
}
}
direction *= MoveSpeed * 10;
float deltaTime = Time.deltaTime; if (UseLag) deltaTime = Time.realtimeSinceStartup - oldTime;
Itself.position = MovePlayer(Itself.position, direction, deltaTime); //不调试时使用增量时间
oldTime = Time.realtimeSinceStartup;
}
public Vector3 MovePlayer(Vector3 pos, Vector3 direction, float time) //方向是控制器发送电荷的地方,速度是旧的速度
{
//计算迭代次数
int numSteps = (int)(time * StepsPerSecond) + 1;
float stepTime = time / numSteps;
if (numSteps > StepsPerSecond / 10f) numSteps = (int)(StepsPerSecond / 10f); //如果fps太低,则断开速度
for (int i = 0; i < numSteps; i++)
{
Vector3 initialPos = pos; //防止卡住
//调节速度
if (direction.sqrMagnitude > 0.01f) //如果移动
{
velocity += direction.normalized * Acceleration * stepTime;
velocity = Vector3.ClampMagnitude(velocity, MoveSpeed);
}
else
{
Vector3 velocityModifier = velocity.normalized * Acceleration * stepTime;
if (velocity.sqrMagnitude > velocityModifier.sqrMagnitude) velocity -= velocityModifier; //如果还在移动
else velocity = Vector3.zero;
}
pos = TryMove(pos, velocity * stepTime);
//应用重力
if (Gravity)
{
ForceVelocity += Vector3.down * stepTime * 9.8f; //加速下降
if (ForceVelocity.y * stepTime > CapsuleR) ForceVelocity.y = CapsuleR / stepTime; //极限速度
Vector3 fallPos = pos + ForceVelocity * stepTime;
if (!Physics.CheckSphere(fallPos + CapsuleP2, CapsuleR) && !Physics.CheckSphere(fallPos + CapsuleP1, CapsuleR)) //也许胶囊1是不必要的
{ pos = fallPos; inAir = true; } //如果脚下什么都没有掉下来
else { ForceVelocity.y = 0; inAir = false; } //如果检测到地面,停止坠落
}
//检查卡住
if (Physics.CheckSphere(pos + CapsuleP1, CapsuleR) || Physics.CheckSphere(pos + CapsuleP2, CapsuleR) || Physics.Linecast(initialPos, pos))
{
Debug.Log("Controller stuck(碰撞器卡住)");
if (Physics.CheckSphere(pos + CapsuleP1, CapsuleR) || Physics.CheckSphere(pos + CapsuleP2, CapsuleR))
{
Debug.Log("CharController locked(碰撞器锁定)");pos = GetOutofStuck(pos);
}
pos = initialPos;velocity = new Vector3(0, velocity.y+ 0.1f, 0);
}
//else Debug.Log("notstuck");
}
return pos;
}
public Vector3 TryMove(Vector3 pos, Vector3 moveVector)
{
//检查char是否可以直走
if (!Physics.CheckSphere(pos + moveVector + CapsuleP1, CapsuleR) && !Physics.CheckSphere(pos + moveVector + CapsuleP2, CapsuleR))
{ return pos + moveVector; }
//准备载体
Vector3 perpHor = Vector3.Cross(moveVector, Vector3.up).normalized;
Vector3 perpVert = Vector3.Cross(moveVector, perpHor).normalized;
float moveDist = moveVector.magnitude;
//如果char不能直接找到替代位置
for (float i = 0.5f; i < 100f; i = i * 1.5f + 0.5f)
for (int dir = 0; dir < 8; dir++)
{
Vector3 possibleDir = (moveVector + perpHor * SearchDirHor[dir] * i * moveDist * 0.1f + perpVert * SearchDirVert[dir] * i * moveDist * 0.1f).normalized;
possibleDir *= Vector3.Dot(moveVector, possibleDir);
//possibleDir = possibleDir*0.5f + possibleDir.normalized*moveDist * 0.5f;
if (!Physics.CheckSphere(pos + possibleDir + CapsuleP1, CapsuleR) && !Physics.CheckSphere(pos + possibleDir +CapsuleP2, CapsuleR))
{ return pos + possibleDir; }
}
//如果找不到替代位置-返回原始位置
return pos;
}
public Vector3 GetOutofStuck(Vector3 pos)
{
for (float dist = 0.07f; dist < 3f; dist *= 1.5f)
for (int xi = 0; xi < 20; xi++)
for (int zi = 0; zi < 20; zi++)
{
int x = 0; int z = 0;
if (xi % 2 == 0) x = xi * xi; else x = -(xi + 1) * (xi + 1);
if (zi % 2 == 0) z = zi * zi; else z = -(zi + 1) * (zi + 1);
Vector3 dir = (new Vector3(x, 150, z)).normalized;
dir.y -= 0.5f;
dir = dir.normalized * dist;
if (!Physics.CheckSphere(pos + dir + CapsuleP1, CapsuleR) && !Physics.CheckSphere(pos + dir + CapsuleP2, CapsuleR))
return pos + dir;
}
return pos;
}
}