3D沙盒游戏开发日志3——饥荒风格的战斗第三人称控制器

日志

  好多天没写日志了,其实最近做了很多东西,只是一直懒得记录而已,所以这两天先把前面的日志补完再继续开发
好了,值得一提的是最近又找到了几款合适的资源,日子真是越来越有盼头了^_^

  之前在第一次的时候我们制作了一个探索风格的第三人称视角,但沙盒游戏中更多的时候是战斗,所以我们需要开发
一个一般状态的操控器,之前的那个可以留在一些特定的场合使用。在战斗方面我觉得饥荒给我的感觉最舒服,所以我
决定模仿饥荒的人物操控来制作。

我们依然是在之前的两个脚本LocomotionController和ViewController中做补充

人物移动

事实是这样的,如果你想让人物控制感到真实,那么左右按键应该是旋转人物无论是lerp还是瞬间调整rotation;如果你想让人物操作简单,可以去“走位”,那么左右按键应该直接让人物转到对应的角度并向对应方向移动,如果我长按左键我是希望人物向左移动而非向左转动,这一点至关重要
想让人物“向左移动”需要两个步骤,第一是转到“左”,第二是向“左”走。 这里的“左”指得是摄像机观察方向下的左,所以我们应该获取摄像机观察方向下的前后左右(viewEulerAngle和viewDirForward,viewDirRight)。注意第一部是转到左而不是向左转,我们摄像机不会随人物转动,它受到单独的控制,所以摄像机的“左”是固定的,不会因为人物的转动而改变
但你可能也注意到如果这样做的话我们人物将不能向360度的任意方向移动,事实也确实如此,一般在这种情况下都会声明两个变量forward和right,由他们来组合成8个方向(0,-1,1)(算上静止的话就是9个),最终和视角方向和速度一起构成人物的位移

void FixedUpdate()
{
    Vector3 viewEulerAngle = viewController.thirdPersonCam.transform.eulerAngles;
    Vector3 viewDirForward = viewController.thirdPersonCam.transform.forward;
    Vector3 viewDirRight = viewController.thirdPersonCam.transform.right;
    Vector3 lastPos = transform.position;
    
    float forward = 0, right = 0;
    if(Input.GetKey(KeyCode.A))
    {
        viewController.model.rotation = Quaternion.Euler(0, viewEulerAngle.y - 90, 0);
        right -= 1;
    }
    if(Input.GetKey(KeyCode.D))
    {
        viewController.model.rotation = Quaternion.Euler(0, viewEulerAngle.y + 90, 0);
        right += 1;
    }
    if(Input.GetKey(KeyCode.W))
    {
        viewController.model.rotation = Quaternion.Euler(0, viewEulerAngle.y, 0);
        forward += 1;
    }            
    if(Input.GetKey(KeyCode.S))
    {
        viewController.model.rotation = Quaternion.Euler(0, viewEulerAngle.y + 180, 0);
        forward -= 1;
    }
    Vector3 moveDir = viewDirForward * forward + viewDirRight * right;
    moveDir.y = 0;
    moveDir.Normalize();
    transform.position += moveDir * Time.deltaTime * runSpeed;
}

这里还会有一个老生常谈的问题:我该把相机作为人物的子物体还是单独的物体?
在第一篇中已经讲过,单独控制相机跟随人物移动是困难的,并且它很容易产生bug,所以我们应该尽可能的让相机作为子物体;但我们的要求是:相机能跟随人物移动,但不跟随人物转动。这可能吗?其实这个问题在养成一个好习惯后往往不会遇到,因为我们一般不会将脚本直接挂载在模型上,而是重新创造一个空物体,那么我们只需要“移动”这个空物体,而“转动”模型,摄像机和模型都是空物体的子物体,就实现了我们的要求。

第三人称视角

其实视角部分的最核心问题已经解决了,在将摄影机作为子物体后视角部分不需要处理复杂的移动了,只有简单的旋转视角,因为是按照饥荒的风格,所以视角是绕人物旋转的即RotateAround。顺便旋转模型也是按照饥荒的感觉来模仿的,这里可以*选择是否旋转或者旋转角度。

void FixedUpdate()
{
    if(Input.GetKeyDown(KeyCode.Q))
    {
        thirdPersonCam.transform.RotateAround(model.position, Vector3.up, 45);
        model.Rotate(0, 45, 0);
    }
    if(Input.GetKeyDown(KeyCode.E))
    {
        thirdPersonCam.transform.RotateAround(model.position, Vector3.up, -45);
        model.Rotate(0, -45, 0);
    }
}

总结

这次的代码看起来很简单,但实际上并不是,我至少来回玩了3次饥荒才比较好的复刻了这种手感,看似完全不合理的操控旋转方式产出了一个很丝滑的控制效果,将一个看到的效果转换为代码的过程真的会学到很多。

效果图

3D沙盒游戏开发日志3——饥荒风格的战斗第三人称控制器

上一篇:Delaunay三角剖分实现


下一篇:用Unity3D实现简单的牧师与魔鬼游戏