PlayerController(角色移动(不需要碰撞器和刚体的方法))

4 篇文章 0 订阅

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;
    }
}
 

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值