Unity 角色控制和视角



零.参考资料

1.文章

第三人称视角 - 手动实现
第三人称视角 +鼠标滚轮缩放视野+视角拖拽

2.视频

角色移动方式汇总
第三人称视角+双轴移动 - 使用Cinemachine
第三人称视角+俯视视角+单/双轴移动+鼠标控制方向 - 使用Cinemachine
等距俯视视角+双轴移动


一.角色控制 - 不含视角控制

注: 单轴移动指在一个轴向(包含正反两个方向)上移动,在另一个轴向上进行旋转。双轴移动是指两个轴向均可控制角色移动。

1.单轴移动

1.1.直接改变位置

[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float rotateSpeed = 1f;

void Update()
{
    //获取输入
    var horizontalInput = Input.GetAxis("Horizontal");
    var verticalInput = Input.GetAxis("Vertical");
    //Position累加
    //transform.Translate(Vector3.forward * verticalInput * moveSpeed * Time.deltaTime, Space.Self);
    transform.position += transform.forward * verticalInput * moveSpeed * Time.deltaTime;
    //角色旋转
    transform.Rotate(Vector3.up, horizontalInput * rotateSpeed);
}

1.2.使用 Character Controller 组件

[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float rotateSpeed = 1f;
private CharacterController characterController;

private void Start()
{
    characterController = GetComponent<CharacterController>();
}

void Update()
{
    //获取输入
    var horizontalInput = Input.GetAxis("Horizontal");
    var verticalInput = Input.GetAxis("Vertical");
    //计算包含方向和速度的向量 
    var move = transform.forward * verticalInput * moveSpeed * Time.deltaTime;
    //移动角色
    characterController.Move(move);
    //角色旋转
    transform.Rotate(Vector3.up, horizontalInput * rotateSpeed);
}

1.x.效果


2.双轴移动

2.1.直接改变位置

[SerializeField] float moveSpeed = 5f;
[SerializeField] float smoothTime = 0.1f;//旋转平滑时间
private Vector3 input;

private void Update()
{
    //移动
    input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;
    if (input.magnitude == 0)
        return;
    transform.Translate(input * moveSpeed * Time.deltaTime, Space.World);
    //transform.position += input * moveSpeed * Time.deltaTime;
    //旋转
    Quaternion newQuaternion = Quaternion.LookRotation(input, transform.up);
    transform.rotation = Quaternion.Slerp(transform.rotation, newQuaternion, smoothTime);
}

2.2.使用 Character Controller 组件

[SerializeField] float moveSpeed = 5f;
[SerializeField] float smoothTime= 0.1f;//旋转平滑时间
private Vector3 input;
private CharacterController characterController;

private void Start()
{
    characterController = GetComponent<CharacterController>();
}

private void Update()
{
    //获取输入
	input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")).normalized;
	if (input.magnitude == 0)
    	return;
    var move = input * moveSpeed * Time.deltaTime;
    //移动角色
    characterController.Move(move);
    //旋转
    Quaternion newQuaternion = Quaternion.LookRotation(input, transform.up);
    transform.rotation = Quaternion.Slerp(transform.rotation,newQuaternion,smoothTime);
    }
}

2.x.效果


二.角色控制 - 含视角控制

注: 以下视角控制有些使用了Cinemachine插件。

1.第三人称视角

[SerializeField] private float moveSpeed = 5f;
[SerializeField] private Transform camera;
[SerializeField] private float rotateSpeed = 1f;
private CharacterController characterController;
private float turnSmoothVelocity;

void Start()
{
    characterController = GetComponent<CharacterController>();
}

void Update()
{
    //获取输入
    Vector3 input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;
    if (input.magnitude >= 0.1f)
    {
        float targetAngle = Mathf.Atan2(input.x, input.z) * Mathf.Rad2Deg + camera.eulerAngles.y;
        float angle = Mathf.SmoothDampAngle(transform.eulerAngles.y, targetAngle, ref turnSmoothVelocity, rotateSpeed);
        transform.rotation = Quaternion.Euler(0f, angle, 0f);
        Vector3 moveDir = Quaternion.Euler(0, targetAngle, 0f) * Vector3.forward;
        characterController.Move(moveDir.normalized * moveSpeed * Time.deltaTime);
    }
}

1.1.玩家层级结构

ThirdPersonPlayer:空物体,角色控制脚本以及CharacterController组件均挂载在该空物体上。
Player:玩家。
CM FreeLook1:虚拟相机(FreeLook Camera)。

1.2.虚拟相机参数设置

  • FollowLook At均设置为Player
  • 设置Orbits - Binding ModeWord Space
  • 调整上中下视角轨道(Orbits - TopRig/MiddleRig/BottomRig)的位置和大小。(根据需要设置)
  • 调整视角旋转速度(X/YAxis - Speed)或者鼠标是否反转(X/Y Axis - InputAxisValue - Invert)。(根据需要设置)

1.3.玩家控制脚本参数设置

注: Camera属性为Unity中的MainCamera,而不是虚拟相机。

1.x.效果


2.俯视角(鼠标控制方向)

[SerializeField] private float moveSpeed = 5f;
private CharacterController characterController;
void Start()
{
    characterController = GetComponent<CharacterController>();
}
void Update()
{
    //计算包含方向和速度的向量 
    var input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).normalized;
    var move = input * moveSpeed * Time.deltaTime;
    //移动角色
    characterController.Move(move);
    //转换玩家坐标系
    var playerScreenPoint = Camera.main.WorldToScreenPoint(transform.position);
    //计算旋转角度
    var point = Input.mousePosition - playerScreenPoint;
    var angle = Mathf.Atan2(point.x, point.y) * Mathf.Rad2Deg;
    transform.eulerAngles = new Vector3(transform.eulerAngles.x, angle, transform.eulerAngles.z);
}

2.1.玩家层级结构

Player:玩家,玩家控制脚本和CharacterController组件均挂载在此物体上。
CM vcam1:虚拟相机(Virtual Camera)。

2.2.虚拟相机参数设置

  • FollowLook At均设置为Player
  • 修改Body - Follow Offset属性和Aim - Tracked Object Offect属性,将相机视角设置为俯视视角。
  • 修改Body - Binding ModeLock To Target On Assign
  • 修改Aim后的属性为Do nothing
  • 修改Body - X/Y/ZDamping调整视角跟随延迟。(根据需要修改)

2.x.效果


3.等距俯视视角

3.1.玩家层级结构 / 设置相机视角

  • 红框部分为必须进行的设置,黄框部分根据实际需要进行调整。
  • Player:玩家。
  • IsoViewCamera:空物体,在该物体上设置相机的倾斜角度。
  • Main Camera:主相机。

3.2.编写辅助脚本旋转输入向量

public static class IsoViewPlayerControllerHelpers
{
    private static Matrix4x4 isoMatrix = Matrix4x4.Rotate(Quaternion.Euler(0, 45, 0));
    //给Vector3增加扩展方法
    public static Vector3 ToIso(this Vector3 input) => isoMatrix.MultiplyPoint3x4(input);
}

3.3.控制玩家移动

[SerializeField] private float moveSpeed = 5f;
[SerializeField] private float turnSpeed = 360;
private CharacterController characterController;

private void Start()
{
    characterController = GetComponent<CharacterController>();
}
private void Update()
{
    //获取输入向量并转换成等距视图向量(Isometry View,将输入向量倾斜45度),再将其归一化。
    Vector3 input = new Vector3(Input.GetAxisRaw("Horizontal"), 0, Input.GetAxisRaw("Vertical")).ToIso().normalized;
    if (input.magnitude > 0)
    {
        //通过输入向量获取一个方向仅指向玩家正前方,大小由输入控制的增向量。
        Vector3 move = transform.forward * input.magnitude * moveSpeed * Time.deltaTime;
        //移动玩家
        characterController.Move(move);
        //旋转玩家(有两种方式)
        Quaternion newQuaternion = Quaternion.LookRotation(input, transform.up);
        //transform.rotation = Quaternion.Slerp(transform.rotation, newQuaternion, 0.1f);
        transform.rotation = Quaternion.RotateTowards(transform.rotation, newQuaternion, turnSpeed * Time.deltaTime);
    }
}

注: 在以上代码中,控制玩家移动是采用玩家朝正前方移动 + 旋转的结果 = 自由移动。而不是玩家朝任意方向移动 + 旋转表现 = 自由移动旋转表现可有可无,即使玩家没有旋转,也不影响玩家自由移动。我觉得第一种方式比较真实,所以就采用这种方式移动角色。

3.x.效果

❀.使用 Character Controller组件时模拟重力、跳跃

注: Character Controller组件没有包含物理效果,如果想要重力效果则需要自己实现。

❀.1.模拟重力

[SerializeField] private Transform groundCheck;//用于与地面碰撞检测的物体(位置在玩家模型底部)
[SerializeField] private float checkRadius = 0.2f;//检测半径
[SerializeField] private LayerMask groundlayerMask;//检测的层
[SerializeField] private float gravity = -9.8f;//重力
private Vector3 velocity = Vector3.zero;//速度,重力(垂直方向)所影响的向量
private bool isGround;//是否接触地面

void Update()
{
    isGround = Physics.CheckSphere(groundCheck.position, checkRadius, groundlayerMask);
    if (isGround && velocity.y < 0)
        velocity.y = 0;
    velocity.y += gravity * Time.deltaTime;
    characterController.Move(velocity * Time.deltaTime);
}

❀.2.跳跃

[SerializeField] private Transform groundCheck;//用于与地面碰撞检测的物体(位置在玩家模型底部)
[SerializeField] private float checkRadius = 0.2f;//检测半径
[SerializeField] private LayerMask groundlayerMask;//检测的层
[SerializeField] private float gravity = -9.8f;//重力
private Vector3 velocity = Vector3.zero;//速度,重力(垂直方向)所影响的向量
private bool isGround;//是否接触地面

void Update()
{
    isGround = Physics.CheckSphere(groundCheck.position, checkRadius, groundlayerMask);
    if (isGround && Input.GetButtonDown("Jump"))
        velocity.y += Mathf.Sqrt(jumpHeight * -2 * gravity);
    velocity.y += gravity * Time.deltaTime;
    characterController.Move(velocity * Time.deltaTime);
}

☽.细节知识点

☽.1.使用Input.GetAxis()获取轴向上的向量时需要进行归一化

使用Input.GetAxis()获取到的值在-1~1之间,假如同时按下WD,获取到的水平和垂直轴的值均为1,根据勾股定理,斜向上方向量大小≈1.41,这样会导致斜向上的速度偏快。
由轴输入获取的向量要进行归一化

Vector3 input = new Vector3(Input.GetAxis("Horizontal"), 0, Input.GetAxis("Vertical")).normalized;

☽.2.游戏角色跳跃所需的垂直速度取决于重力和高度

跳跃所需要的垂直速度公式
g:重力(一般为-9.8f) h:跳跃高度

velocity.y += Mathf.Sqrt(-2f * gravity * jumpHeight);

  • 7
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Unity中实现手柄控制视角移动,需要先确保手柄已连接到计算机,并且已经设置好了Unity的输入管理器。 首先,在Unity的输入管理器中创建一个新的轴,用于控制视角的水平旋转。设置该轴的正向键为手柄的右摇杆向右,负向键为右摇杆向左。为了确保响应灵敏度,可以调整轴的灵敏度参数。 其次,创建另一个轴来控制视角的垂直旋转。设置该轴的正向键为手柄的右摇杆向上,负向键为右摇杆向下。同样地,也要根据需要调整轴的灵敏度。 然后,在脚本中获取手柄输入的数值。可以通过Input.GetAxis()函数来获取手柄轴的数值,然后将其乘以旋转速度系数,得到最终的旋转角度。 接下来,在相机的脚本中,将获取到的手柄输入数值用于旋转相机。可以使用Transform.Rotate()函数来实现相机的旋转,其中需要传入一个Vector3参数,表示旋转的欧拉角度。将手柄输入的水平旋转数值赋给欧拉角的y分量,垂直旋转数值赋给欧拉角的x或者z分量,即可实现相应的旋转效果。 最后,将相机的脚本绑定到相机对象上,确保相机对象能够接收到手柄输入,并进行相应的旋转。 需要注意的是,以上的实现示例是基于手柄的右摇杆来控制视角的旋转,如果需要使用其他手柄的按键或者轴来控制视角移动,可以参考Unity官方文档或其他相关教程进行配置和开发。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值