创建场景及物体

可以使用Unity Asset Store中的免费Propotyping Pack,其中有一些已经做好的形状,我们不需要自己从头开始做模型。

玩家需要使用一把枪作为武器,同样使用免费的模型,链接为Guns

这是搭建好的场景,玩家先使用一个球体代替。

因为地图场景可以当成一个整体来看待,我们可以先创建一个Empty Object,将其命名为Environment,然后将地图中的场景拖拽进Environment中。

玩家模型也是同样的道理,因为游戏是第一人称视角,所以我们要将Camera放在玩家的内部。

Unity3D中的面是单向面,也就是说这个面从一个方向可以看到,但是从另一个方向就看不见,所以我们将Camera放在Sphere内部是可以从里面看到外面的,就像人的眼睛。

我们可以将玩家模型命名为Player,将Player模型的默认自带的Mesh Render、Sphere组件删除,此时Player模型会变成透明的,我们在其内部创建一个Sphere 3D对象,这样Player就又有形状和颜色了。

为Player模型添加RigidBody组件,这个组件时Unity3D自带的。我们先不使用它的Gravity(重力)属性,这样我们的Player就可以浮在空中,要不然Camera中的视角就太矮了。

RigidBody(刚体)可以用于模拟物体在物理世界中的运动和碰撞。

编写控制玩家移动的脚本

为Player模型创建PlayerControllerPlayerInput两个脚本,分别用于读取玩家的输入和处理玩家的移动、转向。

键盘控制水平方向移动

我们可以将读取玩家输入的逻辑编写在PlayerInput文件的Update()函数中。

//水平方向的移动
float xMov = Input.GetAxisRaw("Horizontal");
float yMov = Input.GetAxisRaw("Vertical");
//normalized是单位化,保证速度不会因为斜向移动而变快
Vector3 velocity = (transform.right * xMov + transform.forward * yMov).normalized * speed;

在Unity3D中,速度是一个向量,我们将transform.righttransform.forward表示相对于物体本地坐标系的右方向和前方向。

  1. transform.right 这表示物体本地坐标系中的右方向。在Unity中,右方向是物体向右的本地坐标轴。当你使用 transform.right 时,你获取的是物体在其本地坐标系中沿着右侧轴的向量。

  2. transform.forward 这表示物体本地坐标系中的前方向。在Unity中,前方向是物体朝向的本地坐标轴。使用 transform.forward 时,你获取的是物体在其本地坐标系中沿着前方轴的向量。

用他们分别乘以x轴和y轴的移动量,再进行标准化,最后再乘以速度。速度是我们自定义的一个变量。

[SerializeField]
private float speed = 5f;

在PlayerController中,我们要编写控制玩家移动的代码了。

玩家是一个刚体,我们要控制一个刚体做物理运动时,最好使用FixedUpdate()函数,它和Update()函数的区别是,FixedUpdate在一秒内会均匀的执行50次,而Update的执行可能是不均匀的。

核心代码

public class PlayerController : MonoBehaviour
{
	[SerializeField]
    private Rigidbody rb;
	private Vector3 velocity;
	public void Move(Vector3 _velocity)
	{
	    velocity = _velocity;
	}

	private void PerformMovement()
	{
	    if (velocity != Vector3.zero)
	    {
	        rb.MovePosition(rb.position + velocity * Time.fixedDeltaTime);
	    }
	}
}

记得要在Unity编辑器中将RigidBody对象拖到rb属性上。

玩家的运动公式是,下一秒的位置=上一秒的运动位置 + 速度 * 时间,也就是xt=xt-1 + v * t

鼠标控制玩家旋转

同样,Input类中的静态方法GetAxisRaw也可以获取鼠标X轴和Y轴的移动,取值为0~1的浮点数,X轴正方向为正值,负方向为负值。

我们可以发现鼠标水平方向移动,移动的是物体的Y轴,而鼠标垂直方向移动,移动的是X轴。

lookSensitivity是用于控制镜头转动的灵敏度的

float xMouse = Input.GetAxisRaw("Mouse X");
float yMouse = Input.GetAxisRaw("Mouse Y");

Vector3 xRot = new Vector3(yMouse, 0f, 0f) * lookSensitivity;
Vector3 yRot = new Vector3(0f, xMouse, 0f) * lookSensitivity;

核心代码

public class PlayerController : MonoBehaviour
{
	private Vector3 xRot;
    private Vector3 yRot;

    [SerializeField]
    private Camera cam;

	public void Rotate(Vector3 _xRot, Vector3 _yRot)
    {
        xRot = _xRot;
        yRot = _yRot;
    }
	private void PerformRotation()
    {
        if (xRot != Vector3.zero)
        {
            cam.transform.Rotate(-xRot);
        }
        if (yRot != Vector3.zero)
        {
            rb.transform.Rotate(yRot);
        }
    }
}

同样要记得在Unity编辑器中将Camera对象拖进cam属性。

在Unity中控制物体旋转有很多方法,一种是使用四元数(比较复杂),另一种是使用欧拉角。这里使用第二种。

使用欧拉角是一种表示旋转的方式,但它有一些限制和问题,尤其是在进行多次旋转时可能出现万向锁(Gimbal Lock)的问题,导致旋转不稳定。