IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 游戏开发 -> Unity 第一人称实现 -> 正文阅读

[游戏开发]Unity 第一人称实现

Unity 第一人称视角实现

项目目标:

完成第一人称视角的相机

项目要求:

1.可以通过键盘对操作物品进行移动操作

2.可以通过鼠标来对屏幕进行移动,从而达到旋转视角的效果

3.鼠标可以被隐藏并且在移动时始终保持在界面中心

项目分析:

在对(1)进行完成时,可以使用虚拟轴来实现,也可以通过直接检测键盘的输入来进行移动,然后在通过相关的transform组件来完成对物体位置的移动。

在使用虚拟轴时,在输入键盘时,其并不是从0立刻变成1或者-1,它是慢慢的变成1和-1的(大约0.3s),因此我们获取到的是一个变化,每当我们按下键盘一次它就会变化一下,所以当我们需要移动时,我们需要去将这些值累加起来才能对position进行计算,及我们需要对position进行一个累加,如果只是对其单纯的赋值,那么物体就只能在原地移动后又再次回到原位,并且在移动时也会有一个范围的最大值。

在我们进行移动是,是使用Update()来进行的,及我们是每一帧移动一次,当帧数不同时,我们的移动速度也会不一样,这是我们不希望看见的,使用我们可以在对移动量进行计算时,在加以乘入Time.deltaTime,这样我们就可以以时间来进行移动,当帧数低时,Time.deltaTime也会变大,因此在乘上Time.deltaTime后,输入帧数会跳动变化,但是移动速度会保持基本不变

例如

//虚拟轴输入
	float hor = Input.GetAxis("Horizontal");
    float ver = Input.GetAxis("Vertical");
//检测输入
if(Input.GetKey(KeyCode.S)){
    	 transform.position += View.transform.forward * -1 * Time.deltaTime * Moverate;
}

当对(2)进行完成时,也可以有两种思想,但大体的不同在对旋转摄像机进行完成时有差异,一是可以通过欧拉角来进行完成旋转,二是可以通过四元数来进行旋转。我们这边使用四元数进行对摄像机的操作,虽然四元数比欧拉角更加难以理解,但是,四元数不会像欧拉角一样的万向锁的问题(在静态欧拉角时不会出现这种问题)

  • 静态:即绕世界坐标系三个轴的旋转,由于物体旋转过程中坐标轴保持静止,所以称为静态。
  • 动态:即绕物体坐标系三个轴的旋转,由于物体旋转过程中坐标轴随着物体做相同的转动,所以称为动态。

Quaternion Yaw = Quaternion.AngleAxis(RotationTo.x,upAxis);

Quaternion.AngleAxis用法
public static Quaternion AngleAxis(float angle, Vector3 axis);

既绕着以Vector3 axis旋转float angle为角度旋转

那么如何拿到需要旋转的角度呢

我们可以使用一个二维数来进行对鼠标移动的存储,在我们使用虚拟轴时,当我们移动鼠标时,都会记下鼠标的x,y的变化,我们可以通过**Input.GetAxis(“Mouse X”)来获取到鼠标的x的变化,再将其记录到变量例如rh中,但因为Input.GetAxis(“Mouse X”)**得到的是变化的指,所以我们还需要有一个二维数来存储鼠标的x,y的变化

rh = Input.GetAxis("Mouse X")*Time.deltaTime*RotationRate;
rv = Input.GetAxis("Mouse Y") * Time.deltaTime * RotationRate ;

//当鼠标不移动时,直接结束,使电脑的负担减少
if (rv == 0 && rh == 0) return;

RotationTo.x += rh;
RotationTo.y += rv

之后我们就可以通过角度和轴来进行对摄像机的旋转了。当鼠标左右移动时,x发生变化,在游戏中摄像机左右旋转,所以应该绕世界的y轴旋转,及绕重力轴旋转

Quaternion Yaw = Quaternion.AngleAxis(RotationTo.x,upAxis);

在Unity 中,时常会有在游戏运行时,出现鼠标移动相反的情况,这时候我们会需要一个Y轴翻转来抵消这个情况带来的影响。

public bool pitch;
Quaternion Pitch = 
Quaternion.AngleAxis(RotationTo.y * (pitch ? 1 : -1), pitcAxis);

这时我们就可以在Unity面板上选择是否要开启Y轴翻转

在之后是对(3)进行完成,在Unity中已经为我们准备好了这一功能,我们只需要调用即可

 public void MouseHide()
    {
     //当按下左Alt时,鼠标就会出现
        if (!Input.GetKey(KeyCode.LeftAlt))
        {
            Cursor.visible = false;
            Cursor.lockState = CursorLockMode.Locked;
        }
        else
        {
            Cursor.visible = true;
            Cursor.lockState = CursorLockMode.None;
        }
    }

项目代码:

对此因为对物体的输入有两种方式,当然在使用非虚拟轴来进行输入键盘时,就会出现无法改建的情况,只有在代码中修改相应的键盘输入,才可以修改相应的键位,但是当使用虚拟轴时,可以在Unity中的预算修改这些键位。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class FirstView : MonoBehaviour
{
    public float Moverate = 0.1f;
    public float RotationRate = 0.1f;
    public GameObject View;
    float rh;
    float rv;
    Vector3 dir;
    Vector3 upAxis;
    Vector3 pitcAxis;
    [Header("pitch反转")]
    public bool pitch;

    Vector2 RotationTo;
    // Start is called before the first frame update
    void Start()
    {
        //对两个选择轴进行初始化
        upAxis = -Physics.gravity.normalized;
        pitcAxis = Vector3.Cross(upAxis,Vector3.ProjectOnPlane(transform.forward,upAxis));
    }

    // Update is called once per frame
    void Update()
    {
        MouseHide();
        //实现移动
        float hor = Input.GetAxis("Horizontal");
        float ver = Input.GetAxis("Vertical");
     
        //对position进行更新,使其移动
        transform.position +=
            View.transform.right * Time.deltaTime * Moverate * hor + View.transform.forward * Time.deltaTime * Moverate * ver;
        //上升
        float jump = Input.GetAxis("Jump");
      
        transform.position +=
           View.transform.up * Time.deltaTime * Moverate * jump;
        
        //获得鼠标的位置变化
        rh = Input.GetAxis("Mouse X")*Time.deltaTime*RotationRate;
        rv = Input.GetAxis("Mouse Y") * Time.deltaTime * RotationRate ;
        
        //在不使用鼠标时节省性能
        //if (rv == 0 && rh == 0) return;
        
        //对选择的角度进行累加
        RotationTo.x += rh;
        RotationTo.y += rv;     
        
        Quaternion Yaw = Quaternion.AngleAxis(RotationTo.x,upAxis);
        Quaternion Pitch = 
            Quaternion.AngleAxis(RotationTo.y * (pitch ? 1 : -1), 						pitcAxis);
        //计算方向
        dir = Yaw * Pitch * Vector3.forward;
        Quaternion RotationAngle = Quaternion.LookRotation(dir);
		//对相机进行选择
        View.transform.rotation = RotationAngle;

        
        //下面是使用非虚拟轴的完成代码
        /*
        if (Input.GetKey(KeyCode.W)&&Input.GetKey(KeyCode.D))
        {
            //transform.position += new Vector3(1 * Moverate*Time.deltaTime, 0, -1 * Moverate * Time.deltaTime);
            transform.position += (View.transform.forward*Time.deltaTime * Moverate) +(View.transform.right * Time.deltaTime * Moverate);
        }
        else if (Input.GetKey(KeyCode.W)&&Input.GetKey(KeyCode.A))
        {
            //transform.position += new Vector3(-1 * Moverate * Time.deltaTime, 0, -1 * Moverate * Time.deltaTime);
            transform.position += (View.transform.forward * 1 * Time.deltaTime * Moverate) + (View.transform.right * -1*Time.deltaTime * Moverate);
        }
        else if (Input.GetKey(KeyCode.S)&&Input.GetKey(KeyCode.D))
        {
            //transform.position += new Vector3(1 * Moverate * Time.deltaTime, 0, -1 * Moverate * Time.deltaTime);
            transform.position += (View.transform.forward * -1 * Time.deltaTime * Moverate) + (View.transform.right * 1 * Time.deltaTime * Moverate);
        }
        else if (Input.GetKey(KeyCode.S)&&Input.GetKey(KeyCode.A))
        {
            //transform.position += new Vector3(-1 * Moverate * Time.deltaTime, 0, -1 * Moverate * Time.deltaTime);
            transform.position += (View.transform.forward * -1 * Time.deltaTime * Moverate) + (View.transform.right * -1 * Time.deltaTime * Moverate);
        }
        else if (Input.GetKey(KeyCode.W))
        {
            //transform.position += new Vector3(0, 0, 1 * Moverate * Time.deltaTime);
            transform.position += View.transform.forward*Time.deltaTime * Moverate;
        }else if (Input.GetKey(KeyCode.A))
        {
            //transform.position += new Vector3(-1* Moverate * Time.deltaTime, 0, 0);
            transform.position += View.transform.right*-1 * Time.deltaTime * Moverate;
        }
        else if (Input.GetKey(KeyCode.D))
        {
            //transform.position += new Vector3(1 * Moverate * Time.deltaTime, 0, 0);
            transform.position += View.transform.right * Time.deltaTime * Moverate;
        }
        else if (Input.GetKey(KeyCode.S))
        {
            //transform.position += new Vector3(0, 0, -1 * Moverate * Time.deltaTime);
            transform.position += View.transform.forward * -1 * Time.deltaTime * Moverate;
        }
        */
    }
    public void MouseHide()
    {
        if (!Input.GetKey(KeyCode.LeftAlt))
        {
            Cursor.visible = false;
            Cursor.lockState = CursorLockMode.Locked;
        }
        else
        {
            Cursor.visible = true;
            Cursor.lockState = CursorLockMode.None;
        }
    }
}

项目小结:

通过代码我们可以看到,使用虚拟轴比不使用虚拟轴的代码要精简许多。

在实现非虚拟轴的移动时,我们需要去输入所有需要的可能,并且在需要同时输入A和S或者其他情况时,需要将其放在 if 语句的较为前端,不然就会直接执行单个字母的输入,即便你输入了两个键值。

使用虚拟轴时,要对position和旋转角度进行累加

当前代码依然会有因为角度旋转超过了360度而出现的Bug,因此我们可以将代码中的角度进行修改从0度到360度改至从 -180度到180度,这样可以避免Bug的产生。

  游戏开发 最新文章
6、英飞凌-AURIX-TC3XX: PWM实验之使用 GT
泛型自动装箱
CubeMax添加Rtthread操作系统 组件STM32F10
python多线程编程:如何优雅地关闭线程
数据类型隐式转换导致的阻塞
WebAPi实现多文件上传,并附带参数
from origin ‘null‘ has been blocked by
UE4 蓝图调用C++函数(附带项目工程)
Unity学习笔记(一)结构体的简单理解与应用
【Memory As a Programming Concept in C a
上一篇文章      下一篇文章      查看所有文章
加:2021-11-27 10:14:05  更:2021-11-27 10:15:21 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/27 22:33:54-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码