(1.这里写的移动系统包括角色的移动以及摄像机的移动 2.不包括动画部分 3.本人是根据b站“傅老师”的黑魂复刻视频写的这个移动系统,所以高度相似)
对于游戏中的角色,让它移动实际上是让它向着某个方向上的位置移动或者给它某个方向的速度。
那么这个方向是怎么来的呢,对于玩家来说,是通过你所设定的键位来操纵的。
public string keyUp = "w";
public string keyDown = "s";
public string keyLeft = "a";
public string keyRight = "d";
所以我们一开始就需要设置好游戏中的方向键位,那么在获得键位之后,我们就应该让被按下的键位信号转化为能够代表方向的数值。所以我们先定义如下两个float变量:
public float Dup;
public float Dright;
Dup为向正前方向的值(direction up),Dright则是向正右方向的值(direction right),我们在Update函数中给予这两个变量相应的值:
void Update()
{
Dup = (Input.GetKey(keyUp) ? 1.0f : 0) - (Input.GetKey(keyDown) ? 1.0f : 0);
Dright = (Input.GetKey(keyRight) ? 1.0f : 0) - (Input.GetKey(keyLeft) ? 1.0f : 0);
}
这样,在游戏中按下你所设定好的键位时,Dup和Dright就会在-1或1中变化了,那么看到这样的值,我们很容易就能想到一个东西——坐标系。
没错,Dup和Dright现在呈现出来的数值完全可以让我们建立一个以玩家为坐标原点的,以玩家面对方向为y轴,以玩家右方向为x轴的坐标系,那么我们的思路就出来了:把玩家能够输入的按键信号转化为坐标系中的点,而坐标系中的点我们都知道是可以表示方向的,也就是说我们能得到玩家想要的方向。
而在得到这个方向坐标系后,我们应该会想到,如果我们能得到坐标系里的点,那么让游戏中的角色朝着这个点前进,不就能移动了吗!
没错,通过这种方式,我们可以同时解决角色的朝向方向和移动两个问题。
但是目前还有一个漏洞,那就是我们现在的Dup和Dright值是处于突变的过程的,要么是1,要么是-1,这样我们在坐标系中得到的点最多就只有八个,我们的角色的转向和前进都将是特别大幅度的,这显然不是我们想要的,所以我们需要Dup和Dright的值能变成慢慢递增/减的,那么这里我们就需要引入“SmoothDamp”方法。
private float targetDup;
private float targetDright;
private float velocityDup;
private float velocityDright;
定义四组值,分别为前方向的目标数值、右方向的目标数值、前方向运算用的内存空间、右方向运算用的内存空间。
然后,我们需要更改刚刚的代码,突变的Dup和Dright不是我们想要的,它们只是最终的目标,所以把这个突变的值赋给targetDup和targetDright吧。
targetDup = (Input.GetKey(keyUp) ? 1.0f : 0) - (Input.GetKey(keyDown) ? 1.0f : 0);
targetDright = (Input.GetKey(keyRight) ? 1.0f : 0) - (Input.GetKey(keyLeft) ? 1.0f : 0);
而此时的Dup和Dright我们这样处理:
Dup = Mathf.SmoothDamp(Dup, targetDup, ref velocityDup, 1.0f);
Dright = Mathf.SmoothDamp(Dright, targetDright, ref velocityDright, 1.0f);
来解释一下吧,在SmoothDamp方法中使用四个参数,第一个参数为要调整的值,第二个参数为要调整到的最终目标(current Velocity,可理解为进度),第三个ref的值是它运算用的内存空间,它会自己传入参数,我们不必具体的了解,保证它为与参数同样的类型即可(SmoothDamp方法也用于float变量),第四个参数则是整个变化过程所用的时间。
这样运行游戏之后我们就能发现随着按键信号的输入Dup和Dright值就会开始缓动了,达到了我们的预期,另外我们可以调整SmoothDamp方法最后的所用时间参数来得到我们所需要的效果(我最终使用的为0.1f)。
至此输入输出模块已基本完成,我们可以开始写动作控制器了。(这里附上代码)
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerInput : MonoBehaviour
{
[Header("===== Key settings =====")]
public string keyUp = "w";
public string keyDown = "s";
public string keyLeft = "a";
public string keyRight = "d";
[Header("===== Output signals =====")]
public float Dup;
public float Dright;
[Header("===== Others =====")]
public bool inputEnabled = true;
private float targetDup;
private float targetDright;
private float velocityDup;
private float velocityDright;
// Start is called before the first frame update
void Start()
{
}
// Update is called once per frame
void Update()
{
targetDup = ((Input.GetKey(keyUp) ? 1.0f : 0) - (Input.GetKey(keyDown) ? 1.0f : 0));
targetDright = (Input.GetKey(keyRight) ? 1.0f : 0) - (Input.GetKey(keyLeft) ? 1.0f : 0);
if (inputEnabled == false)
{
targetDup = 0;
targetDright = 0;
}
Dup = Mathf.SmoothDamp(Dup, targetDup, ref velocityDup, 0.1f);
Dright = Mathf.SmoothDamp(Dright, targetDright, ref velocityDright, 0.1f);
}
}
如果要禁止玩家再移动,一般的做法是直接把移动的脚本SetActive关掉,可是这样的话再次打开脚本由于输入模块中数值仍可变化那么可能会导致数值的混乱,所以我们正确的关闭方法应该是使用把targetDup和targetDright清零这样的软开关:
public bool inputEnabled = true;
定义一个bool值:可移动开关,然后有两种方法。
一种是修改targetDup和targetDright的公式:
targetDup = ((Input.GetKey(keyUp) ? 1.0f : 0) - (Input.GetKey(keyDown) ? 1.0f : 0)) * (inputEnabled ? 1.0f : 0);
targetDright = (Input.GetKey(keyRight) ? 1.0f : 0) - (Input.GetKey(keyLeft) ? 1.0f : 0)* (inputEnabled ? 1.0f : 0);
如果觉得公式这样公式太过复杂,那也可以直接使用一条if来改变它们的值:
if (inputEnabled == false)
{
targetDup = 0;
targetDright = 0;
}