Unity3D游戏开发之自由视角下的角色控制.docx
《Unity3D游戏开发之自由视角下的角色控制.docx》由会员分享,可在线阅读,更多相关《Unity3D游戏开发之自由视角下的角色控制.docx(17页珍藏版)》请在冰点文库上搜索。
![Unity3D游戏开发之自由视角下的角色控制.docx](https://file1.bingdoc.com/fileroot1/2023-5/28/85d480fd-b459-4310-b633-0e72f791e636/85d480fd-b459-4310-b633-0e72f791e6361.gif)
Unity3D游戏开发之自由视角下的角色控制
Unity3D游戏开发之自由视角下的角色控制
今天呢,继续来探讨Unity3D角色控制的内容,自由视角是指玩家可以按照自身坐标系向着四个不同的方向移动,当玩家按下鼠标右键时,可以绕Y轴按照一定的角度旋转摄像机,在旋转的过程中,角色将旋转相应的角度。
在移动的过程中,摄像机会保持与玩家间的一定距离,然后跟随角色进行移动。
好了,下面我们正式开始今天的内容吧!
在开始今天的内容前,首先让我们来学习下Unity3D中较为重要的一部分知识,理解这些知识是我们开始学习今天内容的基础。
1、Input.GetAxis():
该方法用于在Unity3D中根据坐标轴名称返回虚拟坐标系中的值,通常情况下,使用控制器和键盘输入时此值范围在-1到1之间。
这段话怎么理解呢?
我们来看下面这段脚本:
∙usingUnityEngine;
∙usingSystem.Collections;
∙
∙publicclassexample:
MonoBehaviour{
∙
∙ //水平速度
∙ publicfloatHorizontalSpeed=2.0F;
∙ //垂直速度
∙ publicfloatVerticalSpeed=2.0F;
∙
∙ voidUpdate()
∙ {
∙ //水平方向
∙ floath=HorizontalSpeed*Input.GetAxis("MouseX");
∙ //垂直方向
∙ floatv=VerticalSpeed*Input.GetAxis("MouseY");
∙ //旋转
∙ transform.Rotate(v,h,0);
∙ }
∙}
这段脚本呢是根据鼠标的位置来旋转物体从而实现对物体的观察,从这段脚本中我们可以看出,通过获取输入轴的办法,我们可以获得鼠标移动的方向进而实现对于物体的旋转控制。
在Unity3D中我们可以通过Edit->ProjectSetting->Input来查看项目中的坐标轴名称:
在后面,我们还将使用这种方式,大家可以对这个方法有进一步的了解。
2、欧拉角eulerAngles:
该值是Vector3类型的值,x、y、z分别代表绕x轴旋转x度,绕y轴旋转y度,绕z轴旋转z度。
因此,该值最为直观的形式是可以允许我们直接以一个三维向量的形式来修改一个物体的角度,例如下面的脚本:
[html] viewplaincopy
∙floatmY=5.0;
∙
∙voidUpdate()
∙{
∙ mY+=Input.GetAxis("Horizontal");
∙ transform.eulerAngles=newVector3(0,mY,0);
∙}
如果你已经理解了上面的话,那么不出意外的,这段脚本会如你所愿的,按照鼠标在水平方向上移动的方向绕Y轴旋转。
通常情况下,我们不会单独设置欧拉角其中一个轴,例如eulerAngles.x=10,因为这将导致偏移和不希望的旋转。
当设置它们一个新的值时,要同时设置全部。
好在我们可以通过Quaternion.Euler()方法将一个Vector3类型的值转化为一个四元数,进而通过修改Transform.Rotation来实现相同的目的。
3、插值:
所谓插值是指在离散数据的基础上补插连续函数,使得这条连续曲线通过全部给定的离散数据点。
插值是离散函数逼近的重要方法,利用它可通过函数在有限个点处的取值状况,估算出函数在其他点处的近似值。
在某些情况下,如果我们希望过程中处理得较为平滑,此时我们就可以使用插值的方法来实现对中间过程的模拟。
在Unity3D中我们可以使用两种插值方法,即线性插值Lerp,球形插值SLerp。
我们来看下面的脚本:
∙voidRotating(floathorizontal,floatvertical)
∙ {
∙ //Createanewvectorofthehorizontalandverticalinputs.
∙ Vector3targetDirection=newVector3(horizontal,0f,vertical);
∙
∙ //Createarotationbasedonthisnewvectorassumingthatupistheglobalyaxis.
∙ QuaterniontargetRotation=Quaternion.LookRotation(targetDirection,Vector3.up);
∙
∙ //Createarotationthatisanincrementclosertothetargetrotationfromtheplayer'srotation.
∙ QuaternionnewRotation=Quaternion.Lerp(rigidbody.rotation,targetRotation,turnSmoothing*Time.deltaTime);
∙
∙ //Changetheplayersrotationtothisnewrotation.
∙ rigidbody.MoveRotation(newRotation);
∙ }
插值的方法很简单,只要我们给出初始和结束的状态、时间就可以了,大家可以自己看API。
文章出处狗刨学习网
好了,有了这三部分的基础,我们就可以开始今天的内容了,今天的脚本分为两个部分,第一部分是角色控制的部分,主要负责的角色在场景中的移动、转身和动画处理。
第二部分是相机控制的部分,主要涉及相机旋转、相机缩放的相关内容。
下面,我们分别来讲这两个部分,场景依然是博主自己在做的小游戏:
第一部分,主要的是完成角色向各个方向的转身,这里博主定义四个方向(其实八个方向是一样的!
),脚本如下:
∙usingUnityEngine;
∙usingSystem.Collections;
∙
∙publicclassNoLockiVew_Player:
MonoBehaviour{
∙ //玩家的行走速度
∙ publicfloatWalkSpeed=1.5F;
∙ //重力
∙ publicfloatGravity=20;
∙
∙ //角色控制器
∙ privateCharacterControllermController;
∙ //动画组件
∙ privateAnimationmAnim;
∙ //玩家方向,默认向前
∙ privateDirectionTypemType=DirectionType.Direction_Forward;
∙
∙ [HideInInspector]
∙ //玩家状态,默认为Idle
∙ publicPlayerStateState=PlayerState.Idle;
∙
∙ //定义玩家的状态枚举
∙ publicenumPlayerState
∙ {
∙ Idle,
∙ Walk
∙ }
∙
∙ //定义四个方向的枚举值,按照逆时针方向计算
∙ protectedenumDirectionType
∙ {
∙ Direction_Forward=90,
∙ Direction_Backward=270,
∙ Direction_Left=180,
∙ Direction_Right=0
∙ }
∙
∙ voidStart()
∙ {
∙ //获取角色控制器
∙ mController=GetComponent();
∙ //获取动画组件
∙ mAnim=GetComponentInChildren();
∙ }
∙
∙
∙ voidUpdate()
∙ {
∙ MoveManager();
∙ //MouseEvent();
∙ }
∙
∙ //玩家移动控制
∙ voidMoveManager()
∙ {
∙ //移动方向
∙ Vector3mDir=Vector3.zero;
∙ if(mController.isGrounded)
∙ {
∙ //将角色旋转到对应的方向
∙ if(Input.GetAxis("Vertical")==1)
∙ {
∙ SetDirection(DirectionType.Direction_Forward);
∙ mDir=Vector3.forward*Time.deltaTime*WalkSpeed;
∙ mAnim.CrossFade("Walk",0.25F);
∙ State=PlayerState.Walk;
∙ }
∙ if(Input.GetAxis("Vertical")==-1)
∙ {
∙ SetDirection(DirectionType.Direction_Backward);
∙ mDir=Vector3.forward*Time.deltaTime*WalkSpeed;
∙ mAnim.CrossFade("Walk",0.25F);
∙ State=PlayerState.Walk;
∙ }
∙ if(Input.GetAxis("Horizontal")==-1)
∙ {
∙ SetDirection(DirectionType.Direction_Left);
∙ mDir=Vector3.forward*Time.deltaTime*WalkSpeed;
∙ mAnim.CrossFade("Walk",0.25F);
∙ State=PlayerState.Walk;
∙ }
∙ if(Input.GetAxis("Horizontal")==1)
∙ {
∙ SetDirection(DirectionType.Direction_Right);
∙ mDir=Vector3.forward*Time.deltaTime*WalkSpeed;
∙ mAnim.CrossFade("Walk",0.25F);
∙ State=PlayerState.Walk;
∙ }
∙ //角色的Idle动画
∙ if(Input.GetAxis("Vertical")==0&&Input.GetAxis("Horizontal")==0)
∙ {
∙ mAnim.CrossFade("Idle",0.25F);
∙ State=PlayerState.Idle;
∙ }
∙
∙ }
∙ //考虑重力因素
∙ mDir=transform.TransformDirection(mDir);
∙ floaty=mDir.y-Gravity*Time.deltaTime;
∙ mDir=newVector3(mDir.x,y,mDir.z);
∙ mController.Move(mDir);
∙ }
∙
∙ //设置角色的方向,有问题
∙ voidSetDirection(DirectionTypemDir)
∙ {
∙ if(mType!
=mDir)
∙ {
∙ transform.Rotate(Vector3.up*(mType-mDir));
∙ mType=mDir;
∙ }
∙ }
∙}
这里定义四个方向,是按照逆时针方向转的,相邻的两个方向间相差90度,所以我们只需要将当前的角度和目标角度相减就可以转到目标角度的方向(其实这是以前写的代码,现在回头再看,直接用欧拉角似乎更为简单啊,呵呵)。
这里主要的内容就是这样了。
下面我们来看相机控制部分的代码吧,这里的代码参考了MouseOrbit脚本,主要完成了鼠标右键旋转控制,博主在此基础上增加了相机缩放的代码。
提到相机缩放,其实就是根据鼠标滚轮滚动的方向和大小重新计算角色与相机的距离,与之类似地还有小地图的放缩,其实同样是通过修改距离来实现的。
我们一起来看脚本
文章出处狗刨学习网
∙usingUnityEngine;
∙usingSystem.Collections;
∙
∙publicclassNoLockView_Camera:
MonoBehaviour
∙{
∙ //观察目标
∙ publicTransformTarget;
∙ //观察距离
∙ publicfloatDistance=5F;
∙ //旋转速度
∙ privatefloatSpeedX=240;
∙ privatefloatSpeedY=120;
∙ //角度限制
∙ privatefloat MinLimitY=5;
∙ privatefloat MaxLimitY=180;
∙
∙ //旋转角度
∙ privatefloatmX=0.0F;
∙ privatefloatmY=0.0F;
∙
∙ //鼠标缩放距离最值
∙ privatefloatMaxDistance=10;
∙ privatefloatMinDistance=1.5F;
∙ //鼠标缩放速率
∙ privatefloatZoomSpeed=2F;
∙
∙ //是否启用差值
∙ publicboolisNeedDamping=true;
∙ //速度
∙ publicfloatDamping=2.5F;
∙
∙ voidStart()
∙ {
∙ //初始化旋转角度
∙ mX=transform.eulerAngles.x;
∙ mY=transform.eulerAngles.y;
∙ }
∙
∙ voidLateUpdate()
∙ {
∙ //鼠标右键旋转
∙ if(Target!
=null&&Input.GetMouseButton
(1))
∙ {
∙ //获取鼠标输入
∙ mX+=Input.GetAxis("MouseX")*SpeedX*0.02F;
∙ mY-=Input.GetAxis("MouseY")*SpeedY*0.02F;
∙ //范围限制
∙ mY=ClampAngle(mY,MinLimitY,MaxLimitY);
∙ }
∙
∙ //鼠标滚轮缩放
∙
∙ Distance-=Input.GetAxis("MouseScrollWheel")*ZoomSpeed;
∙ Distance=Mathf.Clamp(Distance,MinDistance,MaxDistance);
∙
∙ //重新计算位置和角度
∙ QuaternionmRotation=Quaternion.Euler(mY,mX,0);
∙ Vector3mPosition=mRotation*newVector3(0.0F,0.0F,-Distance)+Target.position;
∙
∙ //设置相机的角度和位置
∙ if(isNeedDamping){
∙ //球形插值
∙ transform.rotation=Quaternion.Lerp(transform.rotation,mRotation,Time.deltaTime*Damping);
∙ //线性插值
∙ transform.position=Vector3.Lerp(transform.position,mPosition,Time.deltaTime*Damping);
∙ }else{
∙ transform.rotation=mRotation;
∙ transform.position=mPosition;
∙ }
∙ //将玩家转到和相机对应的位置上
∙ if(Target.GetComponent().State==NoLockiVew_Player.PlayerState.Walk)
∙ {
∙ Target.eulerAngles=newVector3(0,mX,0);
∙ }
∙ }
∙
∙ privatefloat ClampAngle(floatangle,floatmin,floatmax)
∙ {
∙ if(angle<-360)angle+=360;
∙ if(angle> 360)angle-=360;
∙ returnMathf.Clamp(angle,min,max);
∙ }
∙
∙
∙
∙
∙}
这里很多朋友可能对我设置一个状态很不理解吧,这其实是为了让玩家有一个自由查看角色的机会,否则当玩家按下鼠标右键的话,角色就会转向相机正对着的位置,这样玩家就看不到角色的正面了。
当然,这里用到了插值,这样能使角色在转身的时候平滑一点,效果会更好。
效果演示(2M的限制让很多展示都无可奈何)
如果在测试的时候出现Bug。
Bug出现在如下位置:
[csharp] viewplaincopy
∙//设置玩家跟随角度
∙if(Target.GetComponent().State==NoLockiVew_Player.PlayerState.Walk)
∙{
∙ Target.rotation=Quaternion.Euler(newVector3(0,mX,0));
∙}
该方法主要的作用是当玩家同时按下方向控制键和鼠标右键,玩家可以随着鼠标旋转到对应的角度,这主要是为了满足玩家双手操作的需求,不过由于这行代码,导致玩家在向左、向右、向后三个方向上的转身失效,如果除去这行代码,则原来的方向控制没有任何问题,可是没有这行代码,玩家的操作感就会下降。
后来博主想到我们对角色的旋转实际上应该是放在鼠标右键事件里的,所以博主将代码修改如下,这样就解决了这个Bug:
[cs