草庐IT

Unity实现人物移动和镜头跟随

我就是CC啊 2023-11-21 原文

这是我作为初学者学习出来的一个实现人物移动和镜头跟随的办法,那来看看我是怎么学习的 

目录

一、镜头根据鼠标输入进行旋转

二、物体根据键盘输入进行移动

1、创建移动物体脚本

 2、创建输入控制脚本

 3、确定物体移动的前进方向

三、摄像机跟随人物

四、摄像机的放大与缩小

五、物体自身的旋转

 六、总结


一、镜头根据鼠标输入进行旋转

首先我们在Unity中建一个空物体(Photographer)坐标就设为(0,0,0),然后将摄像机作为我们的空物体的子物体Transform改为(0,0,-10),这样代表摄像机的这个子物体的局部位移往后平移10个单位,这样之后我们在旋转空物体(Photographer)的时候就有一个摄像机围绕它旋转的效果。

 我们应该知道Unity的蓝色箭头是Z,绿色箭头是Y,红色箭头是X。

接下来就是给空物体(Photographer)新建一个脚本了C#命名为Photographer。

如果我们绕着X轴旋转,那么视角就是一个上下的效果。如果我们绕着Y轴旋转,那么视角就是一个左右的旋转。所以我们定义两个属性Pitch和Yaw分别代表X轴旋转和绕着Y轴旋转的旋转量是多少。

 然后我们的旋转是有灵敏度的,我们再定义一个mouseSensitivity来控制旋转的灵敏度,具体就是给它一直值去乘我们通过Input.GetAxis("Mouse X")获取的变化量,这里Mouse X本身就是个变化量,乘上一个数值就是用来扩大获缩小它变化本身的值。(这里如果是手柄输入的话就不是这样了,手柄是一个渐进的过程,有兴趣的小伙伴可以去研究一下)

 

接下来我们写一个方法UpdateRotation来实现旋转,然后我们人在左右时可以控制我们的身体旋转在得到360度的视角,而上下只能控制我们的头抬起或者俯看,不可能头能上下旋转360度吧,所以我们的在绕着X轴旋转也就是视角上下的时候是有角度限制的,我们用到了Mathf.Clamp()来限制上下的角度,最后将我们Pitch和Yaw设为欧拉角的X和Y,也就是Quaternion.Evler(Pitch,Yaw,0)赋值给transform.rotation。然后将函数放到Update里运行。

(+=我的理解是一个累加的过程。Yaw和Input.GetAxis("Mouse X")这里我都理解是一个数。Yaw累加了我们输入的每一个Input.GetAxis("Mouse X")的数)

 这样我们就实现了基本的上下左右视角啦。这里有可能上下的方向是反的,把Mouse X的invert勾上就可以啦。


二、物体根据键盘输入进行移动

1、创建移动物体脚本

接下来我们再新建一个空物体(Player)下面放一个胶囊体来代表我们的人物,然后我们创建一个C#脚本命名CharacterMovement,这个脚本主要是用来控制角色移动的,这个移动不仅可以给玩家用,可以可以给NPC用,接下来我们就来看看这个脚本吧

首先我们再开头写上[RequireComponent(typeof(Rigidbody))]

这个代表使用这个脚本必须拥有刚体,当你没有刚体的时候,系统会自动给你创建一个刚体。接下来我们创建一个刚体,并在Awake()里用GetComponent<Rigidbody>()去获取到刚体,然后我们开始写属性,先用Vector3定义一个向量属性CurrentInput来代表输入一个0到1向量,它有方向和大小,方向代表移动方向,大小代表移动的单位速度。0到1的过程是判断有没有到满速的过程,再定义一个速度MaxWalkSpeed来与它相乘,我们就可以在这个速度上输入数值来控制他的快慢了

因为是物理系统移动跟物理演算有关,所以我们选择在FixedUpdate()里进行移动。一般刚体的移动我们可以更改他的velocity,但是我们这个里用了一个MovePosition()的一个方法,这个方法怎么用呢,就是传入一个你要把物体移动的目标位置的参数,他还会计算移动到这个目标位置是否会发生碰撞,如果有碰撞是移动不过去的,所以很好用。这里我们的目标位置是什么呢,是自己的位置_rigidbody.position加上CurrentInput * MaxWalkSpeed * Time.fixedDeltaTime,加上的部分是路程,所以是(速度 * 时间)。因为我们还没有输入CurrentInput,所以默认值是0所以就不会移动。

 然后我们就开始写输入的方法,这个方法中我们给CurrentInput加一个限制,因为他有可能传进来的数超过1,但我们希望他是0到1之间的向量,所以我们用Vector3.ClampMagnitude()来限制他的摩长,当超过1的时候会截断成1。(这里我觉得跟normalized很像的功能,简称归一化,这样不会出现斜着走比横着走快)

 2、创建输入控制脚本

接下来我们来创建输入的脚本PlayerCharacter,为什么要分开写成两个脚本呢,这个是因为之后可以服务于NPC,因为NPC是用AI来控制人物移动的。好的我们在脚本里把CharacterMovement组件对象拿过来

 然后写方法就是监听输入

 3、确定物体移动的前进方向

好了,这样我们就实现了控制物体移动,但是现在这个移动是按照Z轴为前进方向固定来移动的,所以我们还得把我们镜头旋转的正方向设置成前进方向。那么我们开始来拿镜头的方向,老样子先把对象拿过来,这里可以忽略[SerializeField],它就是允许外界可以对私有的对象序列化。

 

 然后我们用一个四元数通过欧拉角来代表左右方向旋转量,用到了之前我们定义的Yaw来代表旋转量。然后用朝向前方Vector3.forward的向量乘上这个四元数,就代表向前的向量加上欧拉角旋转量后得到的新向量。拿着这个新的向量去乘我们输入的摩尔向量就得到一个又有方向又有大小的向量啦(这里可能稍微有点难理解,可以多看看代码,或者换代码看看人物的移动情况,这样可以帮助你理解)我们的代码会变成这样


三、摄像机跟随人物

 OK,确定完前进方向后,我们要做摄像机的跟随,跟随有一个简单简单粗暴的方法,就是把摄像机放到物体的子物体里就行了。当然这样可以实现简单的跟随,但是一般高级的游戏采用的都是水平跟随,而上下方向也就是竖直方向上带有一定的差值效果甚至不会跟随,只有人物到达新高度时候才会改变,那么怎么实现这个效果呢?

我们可以在Photographer上加一个Transform对象_target用来接收传入的目标位置,还有一个用来控制差值大小的变量cameraYSpeed然后初始化我们的摄像机。让_target等于我们传进来的target参数

实现镜头跟随的方法里我们用到Mathf.Lerp()方法来做差值的过度,用法就是传入参数(初始位置,目标位置,过度时间Time.deltaTime * cameraYSpeed) 然后把他赋值给float类型的newY,(我的理解是代表一个变的数),最后让镜头目标的transform.position的Y等于newY

,然后再Update()函数上加上 UpdatePosition();

这样我们的镜头垂直跟随就有差值啦


四、摄像机的放大与缩小

根据我们玩游戏的经验,当摄像机从上往下看会拉得远一点,当摄像机从下往上看的时候会拉得比较近一点(可以防止在地形下出现穿帮),接下来我们就来实现这个效果

先加入一个AnimationCurve曲线字段armLengthCurve,用来做摄像机臂长的曲线,这个曲线的横坐标我准备表示摄像机上下角度从多少度到多少度,纵坐标表示缩放的大小。在创建一个Transform的_camera,可以把相机获得的位置赋值给他。然后我们拿到这个相机组件,因为是子组件,我们直接在Awake()用_camera = transform.GetChild(0);获得

      

OK,我们开始写方法UpdateArmLength()

 这里-1是因为往上是要缩小刚好倒过来了,接下来我们就可以物体里打开曲线并编辑它了

这样我们就实现放大缩小的效果了


五、物体自身的旋转

因为我们在移动的时候,物体的正前方肯定是要朝向我们前进的方向的,所以我们给胶囊提改进一下,在他的Z轴方向上加上一个蓝色方块表示他的朝向,如图

我们在CharacterMovement脚本里加上旋转部分,首先我们用if语句判断一下是否监听到键盘输入,否则我们不会改变朝向。rotateSpeed旋转速度我们自己定义一个就可以了。然后我们要用到Quaternion的两个方法,一个是Quaternion.LookRotation()用来获得旋转量,Quaternion.Slerp()用来缓慢的旋转物体(Slerp和Lerp的区别:Slerp是弧形插值是平分角度而Lerp是线性插值,在两点之间进行插值计算。)具体用法看代码

注释掉的是Quaternion的另外一种方法,也可以实现。好了我们的旋转也完成了,那本章的所以内容就结束了。


 

 六、总结

在研究向量、旋转量这些的时候可能一开始会有的吃力,因为有些是矢量有些是数值,什么时候用乘什么时候用加有时搞不清楚,我现在对这些也是只知道大概,有必要学习一下四元数研究一下。

好了,当我们学这些后呢,我们就可以自己做出自己想要的视角效果了,第一人称也能轻松做出来,(其实就是改变镜头的初始位置,关闭缩放),如果加上一些导入的资源包,我们甚至可以做出一下简单的3D游戏出来。当然啦,除了移动,人物还需要跳跃,攻击,射击等其他功能,所以我们下一个目标就是把这些做出来啦

最后,这些都是我作为初学者研究出来的,有什么错误的地方还希望大佬们指出开来,谢谢!

有关Unity实现人物移动和镜头跟随的更多相关文章

  1. ruby - 多次弹出/移动 ruby​​ 数组 - 2

    我的代码目前看起来像这样numbers=[1,2,3,4,5]defpop_threepop=[]3.times{pop有没有办法在一行中完成pop_three方法中的内容?我基本上想做类似numbers.slice(0,3)的事情,但要删除切片中的数组项。嗯...嗯,我想我刚刚意识到我可以试试slice! 最佳答案 是numbers.pop(3)或者numbers.shift(3)如果你想要另一边。 关于ruby-多次弹出/移动ruby​​数组,我们在StackOverflow上找到一

  2. ruby - 如何根据特征实现 FactoryGirl 的条件行为 - 2

    我有一个用户工厂。我希望默认情况下确认用户。但是鉴于unconfirmed特征,我不希望它们被确认。虽然我有一个基于实现细节而不是抽象的工作实现,但我想知道如何正确地做到这一点。factory:userdoafter(:create)do|user,evaluator|#unwantedimplementationdetailshereunlessFactoryGirl.factories[:user].defined_traits.map(&:name).include?(:unconfirmed)user.confirm!endendtrait:unconfirmeddoenden

  3. ruby-on-rails - 如何重命名或移动 Rails 的 README_FOR_APP - 2

    当我在我的Rails应用程序根目录中运行rakedoc:app时,API文档是使用/doc/README_FOR_APP作为主页生成的。我想向该文件添加.rdoc扩展名,以便它在GitHub上正确呈现。更好的是,我想将它移动到应用程序根目录(/README.rdoc)。有没有办法通过修改包含的rake/rdoctask任务在我的Rakefile中执行此操作?是否有某个地方可以查找可以修改的主页文件的名称?还是我必须编写一个新的Rake任务?额外的问题:Rails应用程序的两个单独文件/README和/doc/README_FOR_APP背后的逻辑是什么?为什么不只有一个?

  4. 华为OD机试用Python实现 -【明明的随机数】 2023Q1A - 2

    华为OD机试题本篇题目:明明的随机数题目输入描述输出描述:示例1输入输出说明代码编写思路最近更新的博客华为od2023|什么是华为od,od薪资待遇,od机试题清单华为OD机试真题大全,用Python解华为机试题|机试宝典【华为OD机试】全流程解析+经验分享,题型分享,防作弊指南华为o

  5. Unity 热更新技术 | (三) Lua语言基本介绍及下载安装 - 2

    ?博客主页:https://xiaoy.blog.csdn.net?本文由呆呆敲代码的小Y原创,首发于CSDN??学习专栏推荐:Unity系统学习专栏?游戏制作专栏推荐:游戏制作?Unity实战100例专栏推荐:Unity实战100例教程?欢迎点赞?收藏⭐留言?如有错误敬请指正!?未来很长,值得我们全力奔赴更美好的生活✨------------------❤️分割线❤️-------------------------

  6. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  7. unity---接入Admob - 2

    目录1.AdmobSDK下载地址2.将下载好的unityPackagesdk导入到unity里​编辑 3.解析依赖到项目中

  8. Unity 3D 制作开关门动画,旋转门制作,推拉门制作,门把手动画制作 - 2

    Unity自动旋转动画1.开门需要门把手先动,门再动2.关门需要门先动,门把手再动3.中途播放过程中不可以再次进行操作觉得太复杂?查看我的文章开关门简易进阶版效果:如果这个门可以直接打开的话,就不需要放置"门把手"如果门把手还有钥匙需要旋转,那就可以把钥匙放在门把手的"门把手",理论上是可以无限套娃的可调整参数有:角度,反向,轴向,速度运行时点击Test进行测试自己写的代码比较垃圾,命名与结构比较拉,高手轻点喷,新手有类似的需求可以拿去做参考上代码usingSystem.Collections;usingSystem.Collections.Generic;usingUnityEngine;u

  9. 基于C#实现简易绘图工具【100010177】 - 2

    C#实现简易绘图工具一.引言实验目的:通过制作窗体应用程序(C#画图软件),熟悉基本的窗体设计过程以及控件设计,事件处理等,熟悉使用C#的winform窗体进行绘图的基本步骤,对于面向对象编程有更加深刻的体会.Tutorial任务设计一个具有基本功能的画图软件**·包括简单的新建文件,保存,重新绘图等功能**·实现一些基本图形的绘制,包括铅笔和基本形状等,学习橡皮工具的创建**·设计一个合理舒适的UI界面**注明:你可能需要先了解一些关于winform窗体应用程序绘图的基本知识,以及关于GDI+类和结构的知识二.实验环境Windows系统下的visualstudio2017C#窗体应用程序三.

  10. ruby-on-rails - rbenv:从 RVM 移动到 rbenv 后,在 Jenkins 执行 shell 中找不到命令 - 2

    我从Ubuntu服务器上的RVM转移到rbenv。当我使用RVM时,使用bundle没有问题。转移到rbenv后,我在Jenkins的执行shell中收到“找不到命令”错误。我内爆并删除了RVM,并从~/.bashrc'中删除了所有与RVM相关的行。使用后我仍然收到此错误:rvmimploderm~/.rvm-rfrm~/.rvmrcgeminstallbundlerecho'exportPATH="$HOME/.rbenv/bin:$PATH"'>>~/.bashrcecho'eval"$(rbenvinit-)"'>>~/.bashrc.~/.bashrcrbenvversions

随机推荐