凭借一腔热情,想着大学做点什么事,就想着做个游戏出来。之前没有接触过unity等各类引擎,学习了一段时间发现有许多地方挺复杂的,开个专栏记录一下学到的东西。
基本目标是做一个RPG式的游戏,涉及的东西有很多:人物移动和镜头、战斗系统构建、UI构建等,先从基本的开始学起。
关于第三人称镜头和人物移动,我们的目标是实现一个玩家能够随意移动镜头观察环境,同时人物在静止时不会受到镜头方向影响,而移动时会受到影响的移动系统,就是比较常见的第三人称移动系统。
第一种实现方式,我主要模仿了油管主Brackeys的实现https://www.youtube.com/watch?v=j48LtUkZRjU&list=PLPV2KyIb3jR5QFsefuO2RlAgWEz6EvVi6
套用一个插件cinemachine,使用其中的FreeLook Camera可以比较轻松的去实现人物的跟随和Lookat
X和Y Axis对应unity的x和y轴,值得注意的是unity的y轴对应的是竖轴。按照我们一般玩家的习惯,Input Axis Name栏的Mouse X和Y就是对应我们鼠标的移动,所以不用去修改。需要强调的是,我们设置镜头后,镜头的旋转是和我们鼠标对应的,也就是说鼠标向上拖拽时是看向下,向左拖拽时是看向右边,因此我在Y Axis 勾选了invert反转,而X Axis取消了invert。
Orbits的TopRig MiddleRig BottomRig对应下图的三个环,代表游戏时拖拽鼠标上中下能够看到的范围
聚焦刚刚设置完的FreeLook Camera可以看到镜头的一个大概观察范围,蓝色十字中心便是镜头的中心(有时候会表示出黄点)。不同人物模型可能出现默认的聚焦中心不一样,如果觉得位置不符合我们的预期,可以在右边inspecter面板调出offset进行调整
通过以上的设置,我们基本完成了镜头的跟随和聚焦,利用插件实现十分方便。之后重头戏便是人物移动,这一点需要我们去编写脚本了。
创建一个ThirdPersonMovement脚本
利用Input.GetAxisRaw()函数去实现键盘映射(可在设置修改映射默认键位)
float horizontal = Input.GetAxisRaw("Horizontal");//对应键盘上的左右键,按下左或右时触发float vertical = Input.GetAxisRaw("Vertical");//对应键盘上的上下键,按下前或后时触发
建立映射后,将映射的方向保存在一个vector3变量中(normalized属性能够返回值为1的方向),之后引入if判断:如果该变量离原点大于0.01f 即有值映射入了direction,随后便可在if里实现移动
Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized;//建立一个矢量direction,其方向对应键盘输入的,各方向值为1if (direction.magnitude >= 0.01f)//magnitude返回矢量坐标到原点距离{}
这一段是具体实现,老实说我自己也不太懂,属于是照葫芦画瓢地写上去了,大致意思是建立targetAngle表示人物需要转动的角度(转到镜头正对的方位),利用Mathf库的SmoothDampAngle函数和quaternion四元数实现较为平滑的转动,最后用CharacterController对象的move方法实现移动,最后在移动时乘上速度和Time.deltaTime去模拟正常行动
(关于unity脚本中最常见的update函数和这里用到的Time.deltaTime可以看这个理解:
(7条消息) Unity增量时间Time.deltaTime详解_ChinarCSDN的博客-CSDN博客)
float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);transform.rotation = Quaternion.Euler(0f, angle, 0f);//函数第二个参数为转动的角度,上面一系列有关angle的代码是设置一个较为平滑的转动角度Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;controller.Move(moveDir.normalized * speed * Time.deltaTime);
最后实现的全部代码如下(有关于动画和速度调整的部分)
using UnityEngine;public class ThirdPlayerMovement : MonoBehaviour
{public CharacterController controller;//建立控制器对象public Transform cam;//建立摄像机的对象,数据类型是Transform类,对应主摄像机的转动public float walkSpeed=6f;//设置一个速度,浮点数类型public float runSpeed=10f;public float turnSmoothTime = 0.1f;public float turnSmoothVelocity;public Animator anim;private int isMove = Animator.StringToHash("isMove");private int isRunning = Animator.StringToHash("isRunning");private void Start(){//anim = this.GetComponent<Animator>();anim.SetBool(isMove, false);anim.SetBool(isRunning, false);}// Update is called once per framevoid Update(){anim.SetBool(isMove, false);anim.SetBool(isRunning, false);float speed = walkSpeed;float horizontal = Input.GetAxisRaw("Horizontal");//对应键盘上的左右键,按下左或右时触发float vertical = Input.GetAxisRaw("Vertical");//对应键盘上的上下键,按下前或后时触发Vector3 direction = new Vector3(horizontal, 0f, vertical).normalized;//建立一个矢量direction,其方向对应键盘输入的,各方向值为1if(Input.GetKey("left shift")){anim.SetBool(isRunning, true);speed = runSpeed;}if(Input.GetKey("w")||Input.GetKey("a")|| Input.GetKey("s")|| Input.GetKey("d")){anim.SetBool(isMove, true);}if (direction.magnitude >= 0.01f)//magnitude返回矢量坐标到原点距离{//anim.SetBool("isMove", true);float targetAngle = Mathf.Atan2(direction.x, direction.z) * Mathf.Rad2Deg + cam.eulerAngles.y;float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, turnSmoothTime);transform.rotation = Quaternion.Euler(0f, angle, 0f);//函数第二个参数为转动的角度,上面一系列有关angle的代码是设置一个较为平滑的转动角度Vector3 moveDir = Quaternion.Euler(0f, targetAngle, 0f) * Vector3.forward;controller.Move(moveDir.normalized * speed * Time.deltaTime);}//anim.SetBool("isMove", false);//if(Input.GetKey(KeyCode.))}
}
老实说我觉得这段代码在动画和速度控制上有点乱,整体结构也不是特别清晰,关于人物控制脚本的架构这一点我还需要学习一个
这段代码最后实现了一个和我们正常游玩较为相似的移动和镜头,但是我个人感觉依然有些别扭(一来镜头的移动有点不顺滑,二来镜头给我的感觉更像是电影镜头),本着学习的态度,我准备换一种方式去实现人物移动和镜头,到时对比哪个更合适。