这是我作为初学者学习出来的一个实现人物移动和镜头跟随的办法,那来看看我是怎么学习的
目录
一、镜头根据鼠标输入进行旋转
二、物体根据键盘输入进行移动
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勾上就可以啦。
接下来我们再新建一个空物体(Player)下面放一个胶囊体来代表我们的人物,然后我们创建一个C#脚本命名CharacterMovement,这个脚本主要是用来控制角色移动的,这个移动不仅可以给玩家用,可以可以给NPC用,接下来我们就来看看这个脚本吧
首先我们再开头写上[RequireComponent(typeof(Rigidbody))]
这个代表使用这个脚本必须拥有刚体,当你没有刚体的时候,系统会自动给你创建一个刚体。接下来我们创建一个刚体,并在Awake()里用GetComponent
因为是物理系统移动跟物理演算有关,所以我们选择在FixedUpdate()里进行移动。一般刚体的移动我们可以更改他的velocity,但是我们这个里用了一个MovePosition()的一个方法,这个方法怎么用呢,就是传入一个你要把物体移动的目标位置的参数,他还会计算移动到这个目标位置是否会发生碰撞,如果有碰撞是移动不过去的,所以很好用。这里我们的目标位置是什么呢,是自己的位置_rigidbody.position加上CurrentInput * MaxWalkSpeed * Time.fixedDeltaTime,加上的部分是路程,所以是(速度 * 时间)。因为我们还没有输入CurrentInput,所以默认值是0所以就不会移动。
然后我们就开始写输入的方法,这个方法中我们给CurrentInput加一个限制,因为他有可能传进来的数超过1,但我们希望他是0到1之间的向量,所以我们用Vector3.ClampMagnitude()来限制他的摩长,当超过1的时候会截断成1。(这里我觉得跟normalized很像的功能,简称归一化,这样不会出现斜着走比横着走快)
接下来我们来创建输入的脚本PlayerCharacter,为什么要分开写成两个脚本呢,这个是因为之后可以服务于NPC,因为NPC是用AI来控制人物移动的。好的我们在脚本里把CharacterMovement组件对象拿过来
然后写方法就是监听输入
好了,这样我们就实现了控制物体移动,但是现在这个移动是按照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游戏出来。当然啦,除了移动,人物还需要跳跃,攻击,射击等其他功能,所以我们下一个目标就是把这些做出来啦
最后,这些都是我作为初学者研究出来的,有什么错误的地方还希望大佬们指出开来,谢谢!