建议阅读缩放比例:150%

前言

嘿!看到这里的你,请你现在回想一下,你在玩旷野之息、鬼泣、怪猎、战神、黑魂、巫师这些ARPG时,你是如何操作你的角色移动的,我没有在开玩笑啊,请你认真的回想一下。

如果你有 "不就是使用WASD就可以就可以操作,这有什么好想的" 这种想法时,恭喜你,你所玩的ARPG游戏的操作体验制作的非常好,在ARPG中的移动和常规的操作有一些不同,因为要考虑到摄像机位置的问题,我们要保证角色的移动始终都是参照摄像机的位置移动的,而不是角色自身的方向,不然你的操作手感会相当的奇怪。

如果你想要知道如何制作ARPG那种移动效果,希望我的这篇文章能够帮到你
(这个是我自研的方法,肯定不会是最好的方法,仅供思路参考)

需要解决的问题

制作ARPG的时候我用了Input System和Cinemachine,所以我的情况更复杂一些

  • 角色转向时的旋转问题
  • 角色移动时需要参考摄像机的位置移动
  • 摄像机所给出的角度需要垂直于地面
  • 当角色180°的大旋转时的急停过渡动画如何使用

方法参考

角色转向时的旋转问题

我的第一版制作的时候,人物的旋转是依靠动画的效果,但这样后面有些问题(出现的问题写在文章末尾了),所以最终的版本是让角色真正旋转。

人物移动的动画机逻辑
ARPG人物移动.png

真旋转版就很简单了(如上图所示),不需要使用动画树就可以实现,接下来需要考虑的就是代码需要控制的角色旋转效果,这个没什么难度,只需要参考摄像机的方向逐渐改变rotation就可以了。

transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Camera.main.transform.forward), 15f * Time.deltaTime);`

这个是转向前方向的代码,如果想转其他方向,
则修改Camera.main.transform.forward为你想要的方向即可

角色移动时需要参考摄像机的位置移动

这个是最简单的问题,移动的值直接使用摄像机的位置信息就好了
示例:transform.Translate(Camera.main.transform.forward)

摄像机所给出的角度需要垂直于地面

这个部分的难点在于,我的角色是没有RootMotion的移动效果的,所以我是用代码实现移动的,但要参照摄像机的位置给出的角度不会全都是平行于地面的,摄像机角度一旦倾斜,角色的移动角度也会发生变化,会出现人物只按照摄像机的角度移动,而不是在地面上移动。

所以,我们需要让向量在地面上做一个投影向量,使得无论镜头怎么旋转,人物都是沿着地面移动的,所以我们就需要用到Vector3下的ProjectOnPlane方法。

使用示例:Vector3.ProjectOnPlane(Camera.main.transform.forward, Vector3.up)
这样就使得摄像机的前方向的向量始终的平行于地面

当角色180°的大旋转时的急停过渡动画如何使用

目前还在测试阶段...(我的肝在哭啊啊啊!!)

代码部分

注:按键获取使用的是Input System的方法

private void move() //真旋转版
{
    if (isRotate)
    {
        Vector2 moveInput = action.Player.Move.ReadValue<Vector2>();
        //moveValue.x = Mathf.Lerp(moveValue.x, moveInput.x, 0.05f);
        //moveValue.z = Mathf.Lerp(moveValue.z, moveInput.y, 0.05f);
        if (keyboard.wKey.isPressed)
        {
            transform.Translate(Vector3.ProjectOnPlane(Camera.main.transform.forward, Vector3.up).normalized * Time.deltaTime * moveSpeed * moveInput.y, Space.World);
            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Camera.main.transform.forward), 15f * Time.deltaTime);
        }
        if (keyboard.sKey.isPressed)
        {              transform.Translate(Vector3.ProjectOnPlane(Camera.main.transform.forward, Vector3.up).normalized * Time.deltaTime * moveSpeed * moveInput.y, Space.World);
            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(-Camera.main.transform.forward), 15f * Time.deltaTime);
        }
        if (keyboard.aKey.isPressed)
        {         transform.Translate(Vector3.ProjectOnPlane(Camera.main.transform.right, Vector3.up).normalized * Time.deltaTime * moveSpeed * moveInput.x, Space.World);
            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(-Camera.main.transform.right), 10f * Time.deltaTime);
        }
        if (keyboard.dKey.isPressed)
        {
            transform.Translate(Vector3.ProjectOnPlane(Camera.main.transform.right, Vector3.up).normalized * Time.deltaTime * moveSpeed * moveInput.x, Space.World);
            transform.rotation = Quaternion.Lerp(transform.rotation, Quaternion.LookRotation(Camera.main.transform.right), 10f * Time.deltaTime);
        }
    }
}

一些无关紧要的话

做ARPG项目的整个流程,让我感觉最困难的部分反而是人物的移动效果,仅仅是这一个模块我就大改了三遍代码,耗费近一个月的时间,一开始就想到了旋转的问题,索性我就直接做成了动画树,让人物的转向变成动画效果,而不是人物真正的旋转,以为可以让人物的转向看起来更顺滑,我称之为“动画旋转版”,但这个但做起来看似简单方便,事实上后面改动起来更麻烦,因为我的动画没有root motion,最要命的是我的音效用的是Animation event实现同步的,使用动画树会导致稍微有一点融合进来的动画都会触发event,最后被迫无奈的我改为了旋转的方法。