第一部分:人物功能实现——锁定与格挡

        实现一个小的锁定敌人功能:

在人物的后方创建一个子物体(Camera Holder),并创建 子物体Lock Camera(锁定状态的虚拟相机),锁定状态的相机脚本如下:提供了Init函数供我们进行初始化看向的敌人。

public class ThirdLockEnemyCamera : MonoBehaviour
{
    private CinemachineVirtualCamera cinemachine;

    private EnemyController lockedEnemy;

    private void Awake()
    {
        cinemachine = GetComponent<CinemachineVirtualCamera>();
    }

    public void Init(EnemyController currentEnemy)
    {
        lockedEnemy = currentEnemy;
        cinemachine.LookAt = lockedEnemy.transform;
    }


}

在人物控制部分:规定鼠标中键进行锁定敌人,并且调用相机的变化。

//第三人称切换锁定状态
    private void SwitchLockState(InputAction.CallbackContext obj)
    {
        if (CameraManager.Instance.currentCameraStyle == CameraStyle.FirstPerson) return;
        IsLock = !IsLock;
        if (IsLock)
        {
            //选择一个敌人进行锁定
            //curLockedEnemy = SelectLockEnemyByMousePos();
            curLockedEnemy = SelectLockEnemy();
            if (curLockedEnemy != null)
            {
                CameraManager.Instance.SwitchToThirdPersonLockEnemy(curLockedEnemy);
                GlobalEvent.CallEnterFocusOnEnemy(curLockedEnemy);
            }
            else IsLock = false;
        }
        else
        {
            curLockedEnemy = null;
            //取消聚焦点  相机转换
            GlobalEvent.CallExitFocusOnEnemy();
            CameraManager.Instance.SwitchCameraStyle(CameraStyle.ThirdPersonCombat);
        }
    }

选择敌人的函数:

        方法一:根据人物的朝向进行选择

    //在指定的集合中根据当前人物的朝向选择一个敌人
    private EnemyController SelectEnemyCloseToPlayer(HashSet<EnemyController> enemiese, float minDistance,float faceingAngle)
    {
        //具体要求:距离小于某个值 + 角度为人物的前方   (根据角度选择最佳的目标) 
        EnemyController currentEnemy = null;
        float minAngle = faceingAngle / Mathf.PI * 180;
        foreach (var enemy in enemiese)
        {
            if (Vector3.Distance(transform.position, enemy.transform.position) < minDistance)
            {
                //enemy满足要求 比较得到更好的敌人

                Vector3 targetPos = enemy.transform.position - transform.position;
                float curAngle = Vector3.Angle(transform.forward, targetPos);
                if (curAngle < minAngle)
                {
                    minAngle = curAngle;
                    currentEnemy = enemy;
                }
            }
        }
        return currentEnemy;
    }

        方法二:根据鼠标的位置进行选择

//screenPoint表示屏幕的位置,z轴坐标为摄像机到人物的距离(转换到人物所在的平面上)

//通过Camera.main.ScreenToWorldPoint(screenPoint) 得到屏幕点在世界坐标(z轴为人物)上的位置,通过这个位置进行判断锁定敌人。

最终方法:想复杂了,直接使用摄像机Transform的位置和摄像机的forward即可。

    private EnemyController SelectEnemyCloseToMouse(HashSet<EnemyController> enemiese, float minDistance, float faceingAngle)
    {
        //具体要求:距离小于某个值 + 角度为人物的前方   (根据角度选择最佳的目标) 
        EnemyController currentEnemy = null;
        //Vector3 screenPoint = new Vector3(Input.mousePosition.x, Input.mousePosition.y, Vector3.Distance(Camera.main.transform.position, transform.position));
        //Vector3 startPos = Camera.main.ScreenToWorldPoint(screenPoint);
        Transform startTransform = Camera.main.transform;
        float minAngle = faceingAngle / Mathf.PI * 180;
        foreach (var enemy in enemiese)
        {
            if (Vector3.Distance(transform.position, enemy.transform.position) < minDistance)
            {
                //enemy满足要求 比较得到更好的敌人
                Vector3 targetPos = enemy.transform.position - startTransform.position;
                float curAngle = Vector3.Angle(startTransform.forward, targetPos);
                if (curAngle < minAngle)
                {
                    minAngle = curAngle;
                    currentEnemy = enemy;
                }
            }
        }
        return currentEnemy;
    }

在敌人死亡的时候,要判断死亡的敌人是否就是死亡的敌人。如果是的话,则需要取消锁定。(可以利用敌人的死亡事件来实现,添加一个判定即可)

对于锁定状态下的移动和旋转,和第一人称的方式差不多。

移动:根据面朝方向和输入控制移动。

//第三人称 锁定视角 移动人物
    private void MovePlayerInThirdPersonLock()
    {
        if (playerAnimationInf.IsWalk == false) return;
        //人物的实际移动:同时根据人物的朝向 和 人物的WASD输入
        moveDirection = transform.forward * inputDirection.y + transform.right * inputDirection.x;
        moveDirection.y = 0;
        if (physicalCheck.haveBarrierInMoveDirectino(transform.position + transform.up * 0.5f, moveDirection, moveDirection.normalized.magnitude * curSpeed * Time.deltaTime * 2)) return;
        characterController.Move(moveDirection.normalized * curSpeed * Time.deltaTime);
    }

旋转:始终面朝敌人即可。

    //第三人称 锁定视角方式的旋转
    private void RotatePlayerInThirdPersonLockEnemy()
    {
        //人物的forward永远是敌人,人物的目标面向:敌人坐标 - 自己坐标
        moveDirection = new Vector3(curLockedEnemy.transform.position.x - transform.position.x,transform.forward.y, curLockedEnemy.transform.position.z - transform.position.z);
        transform.forward = Vector3.Slerp(transform.forward, moveDirection, rotationSpeed * Time.deltaTime);
    }

        实现格挡功能,并假定规则如下:

        (1)按E键开始格挡进入Enter Guard,按着不放会进入Loop Guard状态,松开退出。

        (2)与动画联动,在Enter Guard状态下受到攻击会触发完美格挡(不掉血,不掉体力),并且进入Perfect Parry状态,在Loop Guard状态下受到攻击会触发普通格挡(减少掉血,但消耗体力),并且进入 Normal Parry状态。

        在以上规则下,通过合理设置Enter Guard的退出时间达到预设的格挡效果。

按键绑定函数如下:暂定只要当前不在攻击(/翻滚等)状态,就可以进行防御。

    //进行格挡
    private void StartParry(InputAction.CallbackContext obj)
    {
        if (CanParry) 
        {
            playerAnimationInf.IsGuard = true;
            CancelRun();
        }
    }

    //取消格挡
    private void StopParry(InputAction.CallbackContext obj)
    {
        playerAnimationInf.IsGuard = false;
    }

对于完美格挡的判定函数:利用动画名字判断

    public bool IsPerfectParry()
    {
        return anim.GetCurrentAnimatorStateInfo(animatorCombatLayer).IsName("Enter Guard");
    }

格挡要与角色的TakeDamage函数联系,普通格挡和完美格挡分别造成不同的(自定义)影响。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值