欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Unity | FPS 第一人称视角的人物控制

程序员文章站 2022-05-09 17:18:10
...

FPS movement in Unity (youtube)

Two ways to create Character
这里只介绍第一种,使用人物控制组件Character Controller 制作
Unity | FPS 第一人称视角的人物控制
做一个FPS需要注意的所有问题
Unity | FPS 第一人称视角的人物控制


创建Character Controller 组件

创建一个空对象 First Person Player,加入 Character Controller 组件,设置 radiusheight(胶囊的半径和高度)

设置相机,将 Main Camera 相机移动到 First Person Player

为了更好地看到效果,在空对象下挂载子对象cylinder,移动位置,让相机在物体内(这样视野中不会看到 cylinder

Unity | FPS 第一人称视角的人物控制
Unity | FPS 第一人称视角的人物控制
(灰色部分之后会用到,可以先不用管)


Camera 视角移动

首先分析一下鼠标的移动对于视角的影响

鼠标在屏幕的两个方向 X/Y 上移动
X 方向控制左右旋转,Y 方向控制上下旋转

*注意,上下的视角移动限制在一定角度内
使用 Mathf.Clamp 完成

Unity | FPS 第一人称视角的人物控制

获取鼠标的移动输入

在导航栏 edit -> project settings -> input 中查看鼠标左右移动对应的输入名称
Unity | FPS 第一人称视角的人物控制
First Person Player上创建脚本 MouseLook.cs

Camera 脚本设置

variables 变量设置

public float mouseSensitivity = 100f;
public Transform playerBody;
float xRotation = 0f;

获取鼠标的移动
float mouseX = Input.GetAxis("Mouse X")
float mouseY = Input.GetAxis("Mouse Y")

设置鼠标灵敏度
public float mouseSensitivity = 100f

获取 FirstPersonPlayertransform 组件(相机为子对象,跟随人物旋转视角 )

Unity | FPS 第一人称视角的人物控制

修改后:

float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

左右方向转动

变量设置
public Transform playerBody;
绑定为 First Person Player

*注意,不是Camera,相机为子对象,随人物移动,不需要再移动相机

playerBody.Rotate(Vector3.up * mouseX);

上下方向转动

设置基于 X 轴的转动(X对应左右,Y对应垂直,Z对应前后,需要在YOZ平面移动,所以对应X)
float xRotation = 0f ; //初始角度为0f

xRotation -= mouseY;
xRotation = Mathf.Clamp(xRotation, -90f, 90f);// limit the angle
transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);

设置鼠标锁定不可视的效果

void Start(){
	Cursor.lockState = CursorLockMode.Locked;
}

完整版

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class MouseLook : MonoBehaviour
{

    public float mouseSensitivity = 100f;

    public Transform playerBody;

    float xRotation = 0f;

    // Start is called before the first frame update
    void Start()
    {
        // lock and hide the cursor
        Cursor.lockState = CursorLockMode.Locked;
    }

    // Update is called once per frame
    void Update()
    {
        float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity * Time.deltaTime;
        float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity * Time.deltaTime;

        xRotation -= mouseY;
        xRotation = Mathf.Clamp(xRotation, -90f, 90f);// limit the angle

        // rotate the camera within Y axis
        transform.localRotation = Quaternion.Euler(xRotation, 0f, 0f);
        // rotate the player within X axis
        playerBody.Rotate(Vector3.up * mouseX);
    }
}

PlayerMovement 人物移动

首先,默认方向键对应的名称及数值如下,可以在 Edit -> Project Settings -> Input Manager 中查看
Unity | FPS 第一人称视角的人物控制
First Person Player 添加脚本 PlayerMovement.cs

public class PlayerMovement : MonoBehaviour
{
    public CharacterController controller;

    public float speed = 12f;
    // Update is called once per frame
    void Update()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");

        //Vector3 move = new Vector3(x, 0f, z);// × global movement, we dont want
        Vector3 move = transform.right * x + transform.forward * z;// move along the local coordinates right and forward

        controller.Move(move * speed * Time.deltaTime);
    }
}

*注意,移动需要沿着玩家当前的位置进行移动
所以需要获取当前物体的局部坐标系对应世界坐标的方向向量

常用的三个:

  • transform.right
  • transform.forward
  • transform.up
Vector3 move = transform.right * x + transform.forward * z;

stairs

调整 step offset,代表能踏上距离地面多高范围内的台阶

Unity | FPS 第一人称视角的人物控制


测试

Unity | FPS 第一人称视角的人物控制


Gravity 重力模拟

重力影响下的速度和位移的曲线图
Unity | FPS 第一人称视角的人物控制


variables 变量设置

public Transform groundCheck;
public float groundDistance = 0.4f;// radius
public LayerMask groundMask;

bool isGrounded;

重力对 y 方向上速度的影响

在地面上我们不希望有任何 y 方向的速度,所以在接触地面时要清空 y 方向上的速度


GroundCheck 用来监测地面的空对象

在人物的最下方,添加一个空对象,用来监测与地面距离
Unity | FPS 第一人称视角的人物控制


CheckSphere

Physics.CheckSphere 用来监测一定距离内是否有 collider

可以探测物体是否接触地面,这时候就要用到 GroundCheck


CheckSphere(position, radius, mask)

Returns true if there are any colliders overlapping the sphere defined by position and radius in world coordinates.


Ground Mask

添加一个层级蒙版变量,用来检测接触到的物体是否为地面而非其他物体


添加和修改层级

Unity | FPS 第一人称视角的人物控制
修改地面物体的层级,应用于所有子对象
Unity | FPS 第一人称视角的人物控制


设置脚本的 Ground MaskGround
Unity | FPS 第一人称视角的人物控制


Jump

最后加上跳跃的效果

跳跃高度与速度的物体公式为
v=2hg v = \sqrt{2hg}
由于设置了重力为负,所以修改为
v=2hg v = \sqrt{-2hg}

variables 设置变量

public float jumpHight = 2f;// 跳跃高度

脚本设置

jump

if(Input.GetButtonDown("Jump") && isGrounded)
{
    velocity.y = Mathf.Sqrt(-2f * jumpHight * gravity);
}

最后再检查一遍脚本的对象挂载
Unity | FPS 第一人称视角的人物控制


测试

Unity | FPS 第一人称视角的人物控制

完成!


提升

真实情况下,一般人物在空中是无法左右移动的,所以人物在空中时,加上对左右移动的限制效果

限制人物空中改变方向

Vector3 move 设置为类成员变量,只有接触到地面才能改变方向

float x = Input.GetAxis("Horizontal");
float z = Input.GetAxis("Vertical");

if(isGrounded)
{
    move = transform.right * x + transform.forward * z;
}
controller.Move(move * speed * Time.deltaTime);

测试

Unity | FPS 第一人称视角的人物控制


小结

使用 CharacterController 控制人物移动,需要划分 视角移动 以及 人物移动

视角移动

视角的上下旋转为相机的自我旋转,限定一个范围 [-90,90]
左右旋转为人物的旋转,相机随人物旋转

人物移动

人物方向移动依靠 HorizontalVertical 方向键控制
需要注意坐标轴为局部坐标轴 transform.right transform.forward

重力根据重力公式修改 velocity.y 的速度,需要检测地面,在人物底面添加 CheckGround 空对象来探测

跳跃根据公式模拟,修改物体速度即可