Unity例子——第一人称视角的角色控制器

news2024/10/6 1:47:37

本文是为了前文Unity四元组的举例示范,为了让读者更好地理解。


效果是实现一个可以由鼠标进行方向操作,键盘进行移动操作的任务。

此为效果视频:

1687597097844


下面进行教学:

一、搭建简单场景

  1. 新建一个场景,放置一个plane作为地板,尺寸自定
  2. 创建一个新的material挂在plane上
  3. 再地板上放置一些cube,主要是为了在测试时作为参照物

二、创建主角物体

  1. 创建一个capsule,代表一个角色
  2. 创建一个cube作为capsule的子物体,将立方体放在capsule的“脸”部。挂上材质
  3. 拖曳场景列表中的著摄像机,让著摄像机变成capsule的子物体
  4. 将著摄像机的位置归0,然后微调著摄像机的位置到角色的脸部

 三、编写控制脚本——移动部分

  1.  创建脚本FPSCharacter,将其挂载于capsule上
  2. 编写脚本内容。脚本内容是重点,下面分步介绍

 角色的控制分为两大块:角色移动和摄像机旋转

角色移动方面,玩家可以按方向键进行前后左右平移。问题是;玩家按上方向键时,对应哪个方向;玩家按右方向键时,又对应哪个方向。

一般玩家本身具有前方向量transform.forward和右方向量transform.right。右方向量与右方向的移动直接对应;前方向量比较麻烦,因为存在抬头,低头的情况。如果玩家在抬头看天时直接向前方走,就会得到向天上飞的结果。

解决方案是得到前方向量后,略加修改,去除前方向量的y轴分量,这样就让前方向量保持水平了。整段代码在文章末尾,计算移动的部分代码如下

 void Move()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        Vector3 fwd = transform.forward;
        Vector3 f = new Vector3(fwd.x, 0, fwd.z).normalized;
        Vector3 r = transform.right;
        Vector3 move = f * z + r * x;
        transform.position += move * speed * Time.deltaTime;
    }

四、编写控制脚本——旋转部分

接下来是旋转镜头部分。由于著摄像机已经挂在角色身上,因此直接旋转角色,镜头就会跟着旋转。其旋转的关键代码如下

 void MouseLook()
    {
        float mx = Input.GetAxis("Mouse X");
        float my = -Input.GetAxis("Mouse Y");
        Quaternion qx = Quaternion.Euler(0, mx, 0);
        Quaternion qy = Quaternion.Euler(my, 0, 0);
        transform.rotation = qx * transform.rotation;
        transform.rotation = transform.rotation*qy;
    }

鼠标移动旋转物体的思路并不简单,但是巧妙利用四元数之后,代码出乎意料的简短。首先,“Mouse X”和“Mouse Y”是两个特殊的输入轴,分别对应的是鼠标的横向移动和纵向移动(不是鼠标位置,而是鼠标位置的变化量)

鼠标横向移动对应的是镜头水平旋转,即沿y轴旋转;鼠标纵向移动对应的是镜头俯仰旋转。因此可以将鼠标的横向、纵向移动当作欧拉角,并转化成四元数,这样就得到了两个”小旋转“,分别叫做qx和qy。

之后只要用四元数乘法将小旋转应用于角色当前朝向,问题就解决了。难点在于,镜头水品那个旋转实际上是沿世界坐标系的y轴旋转,而镜头俯仰旋转则是围绕局部坐标系的x轴旋转。

最后,因为人们在低头、抬头动作时,不能超过90°看到自己的后面,所以要对俯仰角度作出限制,因此需要在MouseLook()函数尾部补上以下一段逻辑。

 float angle = transform.eulerAngles.x;
        if (angle > 180) { angle -= 360; }
        if (angle <- 180) { angle+= 360; }
        if(angle>80)
        {
            Debug.Log("A" + transform.eulerAngles.x);
            transform.eulerAngles = new Vector3(80, transform.eulerAngles.y, 0);
        }
        if (angle <-80)
        {
            Debug.Log("A" + transform.eulerAngles.x);
            transform.eulerAngles = new Vector3(-80, transform.eulerAngles.y, 0);
        }

五、隐藏并锁定鼠标指针

测试时,会发现鼠标指针会影响游戏体验,如果单击到Game窗口之外的区域,Game窗口就会失去焦点。解决方法是隐藏鼠标指针,并把鼠标指针锁定到屏幕中央,代码如下

void Start()
    {
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Locked;
    }

在Unity编译器中,只需要按下Esc键就会显示出鼠标指针了,而在实际游戏开发者能够,别忘了在合适的时机将鼠标指针崇信县属出来,并取消锁定。如原神中就是摁Alt键取消锁定的。

六、完整代码

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

public class FPSCharachter : MonoBehaviour
{
    public float speed = 5f;
    void Start()
    {
        Cursor.visible = false;
        Cursor.lockState = CursorLockMode.Locked;
    }
    void Update()
    {
        Move();
        MouseLook();
    }
   void Move()
    {
        float x = Input.GetAxis("Horizontal");
        float z = Input.GetAxis("Vertical");
        Vector3 fwd = transform.forward;
        Vector3 f = new Vector3(fwd.x, 0, fwd.z).normalized;
        Vector3 r = transform.right;
        Vector3 move = f * z + r * x;
        transform.position += move * speed * Time.deltaTime;
    }
    void MouseLook()
    {
        float mx = Input.GetAxis("Mouse X");
        float my = -Input.GetAxis("Mouse Y");
        Quaternion qx = Quaternion.Euler(0, mx, 0);
        Quaternion qy = Quaternion.Euler(my, 0, 0);
        transform.rotation = qx * transform.rotation;
        transform.rotation = transform.rotation * qy;
        float angle = transform.eulerAngles.x;
        if (angle > 180) { angle -= 360; }
        if (angle <- 180) { angle+= 360; }
        if(angle>80)
        {
            Debug.Log("A" + transform.eulerAngles.x);
            transform.eulerAngles = new Vector3(80, transform.eulerAngles.y, 0);
        }
        if (angle <-80)
        {
            Debug.Log("A" + transform.eulerAngles.x);
            transform.eulerAngles = new Vector3(-80, transform.eulerAngles.y, 0);
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/680319.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SonarQube(sonar-scanner)+GitLab(gitlab-runner)实现提交代码自动扫描项目代码

安装gitlab-runner 插件挂载目录 mkdir -p /data/gitlab-runner/configdocker run -d --name gitlab-runner \ -v /data/gitlab-runner/config:/etc/gitlab-runner \ -v /var/run/docker.sock:/var/run/docker.sock \ --restart always \ --privilegedtrue \ gitlab/gitlab-r…

【数据库必备知识】索引和事务

数据库系列文章 1. 零基础带你快速上手SQL语言2. 玩转表及其数据3. 上手表设计 4. 索引和事务 目录 &#x1f4d6;前言 1. 索引 1.1 索引的概念 1.2 索引的作用 1.3 索引的使用场景 1.4 索引的使用 1.5 索引背后的数据结构(B树) 2. 事务 2.1 事务的概念 2.2 数据库使…

Centos7安装Python3.10

Centos7用yum安装的Python3版本比较旧&#xff0c;想要安装最新版本的Python3需要自己动手编译安装。下面就来讲讲安装步骤&#xff0c;主要分为这么几个步骤&#xff0c;依赖→下载→编译→配置。另外所有操作都是在root用户下进行。 依赖 编译Python源码需要依赖许多库&…

spring.cache 随笔0 集成设计

0. 最近感觉 “困意驱动睡眠” 也有他的意义 spring cache学习&#xff08;一&#xff09;&#xff1a;spring cache注解简单了解 Java Caching JSR107介绍 同样&#xff0c;本章也会简单的集成redisson作为缓存服务 1. 从我们自己写的javaConfig开始吧 Configuration // 这…

Java——文件操作

文件操作 1、File类概述2、File类的常用APIFile类的判断文件类型、获取文件信息功能创建文件、删除文件功能遍历文件夹文件搜索 3、字符集常见字符集字符集的编码、解码操作 4、IO流分类5、字节流的使用文件字节输入流文件字节输出流文件拷贝 6、字符类的使用文件字符输入流文件…

“前端已死”

一、一些迹象 逛社区&#xff0c;偶然看到了这张图片&#xff1a; 嗯……我眉头一皱&#xff0c;久久不语&#xff0c;心想&#xff0c;有这么夸张吗&#xff0c;假的吧&#xff1f; 突然想到&#xff0c;最近我在社区发了个前端招聘的信息&#xff0c;结果简历漫天纷飞&…

【C++】auto_ptr为何被唾弃?以及其他智能指针的学习

搭配异常可以让异常的代码更简洁 文章目录 智能指针 内存泄漏的危害 1.auto_ptr(非常不建议使用) 2.unique_ptr 3.shared_ptr 4.weak_ptr总结 智能指针 C中为什么会需要智能指针呢&#xff1f;下面我们看一下样例&#xff1a; int div() {int a, b;cin >&g…

图表制作办公首选--实用图表工具Echars

实用图表工具Echars 前言 由于工作的需要&#xff0c;在写材料的时候需要使用到柱状图、饼状图、折线图等等展示数据&#xff0c;可以使用PPT等办公软件构建出图表&#xff0c;在这里可以使用更加方便、更加美观的工具Echars。 Echars图表使用 Echars官网&#xff1a;Ecahr…

二叉平衡树之红黑树

目录 1.概念 2.性质 3.节点的定义 4.插入 1.按照二叉搜索树规则插入结点 2.调整颜色 1.uncle存在且为红色 2.uncle不存在或者为黑 cur为 3.根节点改为黑色 5.验证 6.比较 7.应用 1.概念 红黑树&#xff0c;是一种二叉搜索树&#xff0c;但在每个结点上增加一个存…

【计算机网络】计算机网络期末自测题(一)

目录 一、 填空题&#xff1a;(20 分&#xff0c;每空 1 分) 二、 选择题(20 分&#xff0c;每小题 1 分) 三、不定项选择题 (10 分&#xff0c;每小题 1 分) 四、名词解释 (15 分&#xff0c;每小题 3 分) 五、简答题 (25 分) 得分 一、 填空题&#xff1a;(20 分&#xff…

【C++】STL——string类详解

&#x1f680; 作者简介&#xff1a;一名在后端领域学习&#xff0c;并渴望能够学有所成的追梦人。 &#x1f681; 个人主页&#xff1a;不 良 &#x1f525; 系列专栏&#xff1a;&#x1f6f8;C &#x1f6f9;Linux &#x1f4d5; 学习格言&#xff1a;博观而约取&#xff0…

混合策略改进的哈里斯鹰优化算法-附代码

混合策略改进的哈里斯鹰优化算法 文章目录 混合策略改进的哈里斯鹰优化算法1.哈里斯鹰优化算法2.改进哈里斯鹰优化算法2.1 初始化种群的改进2.1.1 初始种群多样化2.1.2 初始种群精英化 2.2 逃逸能量递减机制的改进2.4 拉普拉斯交叉算子策略 3.实验结果4.参考文献5.Matlab代码6.…

6.17 、Java初级:锁

1 同步锁 1.1 前言 经过前面多线程编程的学习,我们遇到了线程安全的相关问题,比如多线程售票情景下的超卖/重卖现象. 上节笔记点这里-进程与线程笔记 我们如何判断程序有没有可能出现线程安全问题,主要有以下三个条件: 在多线程程序中 有共享数据 多条语句操作共享数据 多…

移动web-渐变

渐变 使用场景&#xff1a;使用background-image属性实现渐变背景效果 代码&#xff1a;background-image: linear-gradient(参数1,参数2,参数3...); (默认的方位从上到下) 参数1 方位名词: to right, to left 角度deg: 直接写度数 参数2 颜色1 参数3 颜色2... 注意&#xff…

看完这篇 教你玩转渗透测试靶机vulnhub—Corrosion:1

Vulnhub靶机Corrosion:1渗透测试详解 Vulnhub靶机介绍&#xff1a;Vulnhub靶机下载&#xff1a;Vulnhub靶机安装&#xff1a;Vulnhub靶机漏洞详解&#xff1a;①&#xff1a;信息收集&#xff1a; Vulnhub靶机渗透总结&#xff1a; Vulnhub靶机介绍&#xff1a; vulnhub是个提…

canvas详解01-绘制基本图形

既然我们已经设置了 canvas 环境&#xff0c;我们可以深入了解如何在 canvas 上绘制。到本文的最后&#xff0c;你将学会如何绘制矩形&#xff0c;三角形&#xff0c;直线&#xff0c;圆弧和曲线&#xff0c;变得熟悉这些基本的形状。绘制物体到 Canvas 前&#xff0c;需掌握路…

软件工程——第5章总体设计知识点整理

本专栏是博主个人笔记&#xff0c;主要目的是利用碎片化的时间来记忆软工知识点&#xff0c;特此声明&#xff01; 文章目录 1.总体设计的基本目的&#xff1f; 2.总体设计的任务&#xff1f; 3.总体设计过程由哪两个阶段组成&#xff1f; 4.总体设计的步骤&#xff1f; 5…

【Linux从入门到精通】进程地址空间(虚拟地址 vs 物理地址)

本篇文章会围绕三个问题&#xff08;什么是地址空间&#xff1f;地址空间是如何设计的&#xff1f;为什么要有地址空间&#xff1f;&#xff09;进行展开讲述。其中主要是了解虚拟地址和物理地址的区别。希望本篇文章会对你有所帮助。 文章目录 一、什么是地址空间&#xff1f;…

《机器学习公式推导与代码实现》chapter6-k近邻算法

《机器学习公式推导与代码实现》学习笔记&#xff0c;记录一下自己的学习过程&#xff0c;详细的内容请大家购买作者的书籍查阅。 k近邻算法 k近邻(k-nearest neighbor, k-NN)算法是一种经典的分类算法。k近邻算法根据新的输入实例的k个最近邻实例的类别来决定其分类。所以k近…

rust abc(1): 最小环境搭建

文章目录 1. 目的2. 命令集合3. 安装或更新 rust3.1 命令3.2 运行结果 4. 包管理工具 Cargo5. 创建 Rust 的 Hello World 程序: 单个文件6. 创建 Rust 的 Hello World 工程&#xff1a; 基于 Cargo6.1 cargo new 创建工程6.2 cargo run6.3 完整输出6.4 解释 7. IDE/编辑器8. Re…