Unity中移动某个游戏对象有以下两种方式:
·更改Transform组件的Position属性;
·利用物理引擎(PhyX, Box2D)移动游戏对象。
首先我们试着通过调整Transform组件的属性实现游戏对象的移动。在Unity的左手坐标系中,+Z方向是前进,-Z方向就是后退。
Translate函数用于处理游戏对象移动,函数原型如下
void Translate(Vector3 direction, [Space relativeTo]);
Vector3(x, y, z)是unity提供的用于保存三维坐标值和向量数据的结构体。当我们将向量单位乘以速度(movespeed),游戏对象就会按照movespeed变量指定的速度移动。(这里应该有图片.jpg)
tr.Translate(移动方向 * 速度 * 前进/后退方向 * Time.deltaTime, 基准坐标系);
Time.deltaTime表示前一帧到当前帧或非的时间,需要注意的是,Update函数内,使用Transform组件 是游戏对象移动的逻辑必须乘以deltaTime,是游戏对象的移动速度不受帧率的影响,而根据某个固定的速度移动。打个比方,如果没有乘以Time.deltaTime,游戏对象将每帧1个单位的速度移动;如果乘以Time.deltaTime,游戏对象将以每秒1各单位的速度前进。除此之外,Translate函数的第二个参数能决定游戏对象是以全局坐标还是局部坐标移动。
可以看到,使用Translate函数,我们可以轻松地实现游戏对象的控制,但同时也发现,这样“直来直去”的移动方式并不能很好的匹配较为复杂的地形,所以需要重力和碰撞。
Character Controller
为此,我们可以添加Character Controller组件。Character Controller不会对施加给它的作用力做出反应,也不会作用于其他的刚体。如果想让Character Controller组件能够作用于其他的刚体对象,可以通过脚本[OnControllerColliderHit()函数]在与其相碰撞的对象上使用一个作用力。另外,如果想让Character Controller受物理效果影响,那最好用刚体来代替它。
以下代码通过Character Controller组件实现了WSAD和空格键的人物移动控制。
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityStandardAssets.Utility;
public class PlayerMove : MonoBehaviour
{
public GameObject anibody;
public float speed = 6.0F;//移动速度
public float jumpSpeed = 8.0F;//跳跃速度
public float gravity = 20.0F;//重力加速度
private Vector3 moveDirection = Vector3.zero;
CharacterController controller;
Quaternion ed;//四元数 方向
public Transform camPivot;
public Transform camDir;
public Transform forwardstep;
public Transform downstep;
private Transform tr;
private float h, v;
private Vector3 currPos = Vector3.zero;
private Quaternion currRot = Quaternion.identity;
void Awake()
{
ed = new Quaternion(0, 0, 0, 0);
tr = GetComponent();
currPos = tr.position;
currRot = tr.rotation;
}
void Update()
{
if (controller.isGrounded)//判断人物是否在地面
{
moveDirection = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical"));//获取操作方向
moveDirection = transform.TransformDirection(moveDirection);
moveDirection *= speed;
if (Input.GetKeyDown(KeyCode.Space))//跳跃
moveDirection.y = jumpSpeed;
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
else//跳跃状态
{
moveDirection = new Vector3(Input.GetAxis("Horizontal") * speed, moveDirection.y, Input.GetAxis("Vertical") * speed);
moveDirection = transform.TransformDirection(moveDirection);
moveDirection.y -= gravity * Time.deltaTime;
controller.Move(moveDirection * Time.deltaTime);
}
}
这时我们发现,游戏对象虽然可以移动,但其朝向始终不变而且没有动作,就像恐怖片里的场景(至少我觉得有点吓人....)。关于动作我们可以先甩锅美术,日后再说。但如果我希望角色在移动时,能始终面向前方,可以加上这样一段代码:
if (Input.anyKey)
{
camDir = Camera.main.transform;//获取摄像机位置信息
ed = camDir.rotation;//摄像机方向
ed.x = 0;
ed.z = 0;
transform.rotation = Quaternion.Slerp(transform.rotation, ed, Time.deltaTime * 5.0f);//这里用上了插值是为了使人物转向自然过度
}
这样,游戏对象的简单控制就完成了。嗯,看起来不错~
但使用Character Controller组件也会遇到一些小麻烦,比如说下坡的时候,isGrounded的判断可能会出错,这时我们可以用射线的方法检测人物脚底与地面的距离作为另一个判断条件,当然这个的实现就日后再说了。