前言
起初,是为了完成大四毕业设计而起的念头,也是为了完成自己的一个小小的私心。关于使用 Unity 引擎来完成这个小游戏(第三人称RPG
)的制作,也是看中 Unity 入门较其他游戏引擎(如虚幻引擎UE)来看简单些许,而且可用资源丰富,上手难度较低。毕业设计给的时间相对较少,本人也有较严重的拖延症…。综上,这是一个持续更新系列,记录博主对 Unity 引擎的学习,实践过程。
一、关于角色视角控制
在我的项目里,从新手的角度上看,我采用脚本控制摄像机(Camera)的方式来观察主角玩家(Player),贴上摄像机(Camera)代码:
public class CameraController : MonoBehaviour
{
public float sensitivityMouse = 2f;
// 绑定观察角色
public Transform target;
// 观察距离
public float Distance = 6f;
// 旋转角度
private float mX = 0f;
private float mY = 0f;
// 纵向Y轴 角度限制
private float MinLimitY = 5;
private float MaxLinitY = 30;
// 是否启用插值??:3D化,更加难受
public bool isNeedDamping = false;
// 观察插值
public float Damping = 2f;
void Update()
{
}
void LateUpdate()
{
// 获取鼠标位置输入
mX += Input.GetAxis("Mouse X") * sensitivityMouse * 0.8f;
mY -= Input.GetAxis("Mouse Y") * sensitivityMouse * 0.5f;
// 范围限制
mY = ClampAngle(mY, MinLimitY, MaxLinitY);
// 重新计算位置和角度
Quaternion mRotation = Quaternion.Euler(mY, mX, 0);
Vector3 mPosition = mRotation * new Vector3(0.0f, 2.0f, -Distance) + target.position;
// 设置相机的角度和位置
if (isNeedDamping)
{
// 球形插值
transform.rotation = Quaternion.Slerp(transform.rotation, mRotation, Time.deltaTime * Damping);
// 线性插值
transform.position = Vector3.Lerp(transform.position, mPosition, Time.deltaTime * Damping);
}
else
{
transform.rotation = mRotation;
transform.position = mPosition;
}
}
private float ClampAngle(float angle, float min, float max)
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
}
二、关于角色移动控制
既然是实现一个第三人称RPG(如黑神话-悟空)类型的小游戏,那么角色的流畅控制就很重要了,这里需要学习的地方主要有:脚本 + 动画。脚本的话,新手主要还是网上(百度 + 官网)借鉴别人的代码学习(避免闭门造车)。这里简单地贴上玩家角色(Player)的脚本代码:
public class PlayerController : MonoBehaviour
{
Animator anim;
[Header("角色")]
public CharacterController controller;
[Header("跟随摄像机")]
public Transform FollowedCamera;
[Header("移动速度")]
public float moveSpeed = 8f;
// 要到达目标位置的近似时间,实际到达目标时要快一些。
[Header("转身缓冲速度")]
public float trunSnoothTime = 0.1f;
// 当前速度,这个值在你访问这个函数的时候会被随时修改
[Header("当前速度")]
float trunSmoothVelocity;
// 动画状态组件
private AnimatorStateInfo animatorInfo;
void Start()
{
anim = GetComponent<Animator>();
controller = GetComponent<CharacterController>();
}
void Update()
{
// 角色移动
PlayerMovement();
}
void PlayerMovement()
{
// Player 的移动方向:初始化
Vector3 moveDir = Vector3.zero;
// 未添加:Player 的移动判断:方向转正再移动
float horizontal = Input.GetAxisRaw("Horizontal");
float vertical = Input.GetAxisRaw("Vertical");
// Player:随摄像头正前方,WASD移动
if (horizontal != 0 || vertical != 0)
{
anim.SetBool("Walk", true);
Vector3 P_direction = new Vector3(horizontal, 0, vertical).normalized;
if (P_direction.magnitude >= 0.1f)
{
// 根据按键【当前角度 ——(转向)——> 目标角度】
float N_targetAngle = Mathf.Atan2(P_direction.x, P_direction.z) * Mathf.Rad2Deg + FollowedCamera.eulerAngles.y;
// 平滑阻尼: Mathf.SmoothDamp(...)
float N_angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, N_targetAngle, ref trunSmoothVelocity, trunSnoothTime);
transform.rotation = Quaternion.Euler(0f, N_angle, 0f);
// 获取当前朝向角度并移动
Vector3 N_moveDir = Quaternion.Euler(0f, N_targetAngle, 0f) * Vector3.forward;
controller.Move(N_moveDir.normalized * moveSpeed * Time.deltaTime);
}
}
// 无任何操作,保持站立动画
else if (horizontal == 0 && vertical == 0)
{
anim.SetBool("Walk", false);
}
}
}