Unity实现主角移动与摄像机跟随
在游戏开发中,主角需要通过跑地图来通关升级,本章主要介绍主角的移动和摄像跟随的操作。
主角移动
角色位移通过主角的骨骼动画控制(后续文章会详细介绍状态机的使用),这里只需要勾选Animator动画控制器下ApplyRootMotion让角色的移动受动画控制。
通过碰撞检测来判断哪些位置主角可以移动,哪些位置角色不能行走,这里需要两个组件Rigidbody刚体,和Collider碰撞组件
- Rigidbody:为游戏赋予物理属性,在游戏中只有添加了刚体的物体才能模拟物理属性,如重力等。
 
如上图所示,各参数含义如下:
Mass质量:单位任意。但是官方建议物体的质量差不要超过100倍
Drag阻力:物体移动时受到的空气阻力,0表示无阻力
AngularDrag角阻力:当受扭力时物体旋转时受到的空气阻力,同样0表示无阻力
UseGravity使用重力:表示该物体是否受重力影响
IsKinematic是否是运动学:游戏对象是否遵循运动学规律,如果激活不在受物理引擎驱动(动画控制移动,不勾选)
Interpolate插值:物体运动的插值模式
CollisionDetection碰撞检测:碰撞检测模式。用于避免高速物体穿过其它物体未发生碰撞
Constraint约束:对刚体运动的约束,可以锁定位置和旋转的x、y、z轴
- Collider:碰撞器有很多中,需要根据实际的需要选择不同的触发器,这里只是简单的介绍其基础功能
 
IsTrigger触发器:勾选该选项,碰撞用于触发事件OnTriggerEnter、OnTriggerExit、OnTriggerStay并被物理引擎所忽略
Input.GetAxis(args):获取移动方位。
floath=Input.GetAxis("Horizontal");//对应键盘的上下
floatv=Input.GetAxis("Vertical");//对应键盘的左右
通过插值运算,控制主角平滑的转向和移动:
voidUpdate()
{
role.SetBool(StealthConst.SNEAK,Input.GetKey(KeyCode.LeftShift));
floath=Input.GetAxis("Horizontal");
floatv=Input.GetAxis("Vertical");
if(Mathf.Abs(h)>0.1f||Mathf.Abs(v)>0.1f)
{
//5.6由动画控制器中的参数决定
floatcurrentSpeed=Mathf.Lerp(role.GetFloat(StealthConst.SPEED),5.6f,moveSpeed*Time.deltaTime);
role.SetFloat(StealthConst.SPEED,currentSpeed);//Animator通过速度控制移动的快慢
Vector3targetDir=newVector3(h,0,v);
//Vector3.up相当于(0,1,0)绕着Y轴,看向目标位置
QuaternionnewRotation=Quaternion.LookRotation(targetDir,Vector3.up);
transform.rotation=Quaternion.Lerp(transform.rotation,newRotation,rotateSpeed*Time.deltaTime);
}
else
{
role.SetFloat(StealthConst.SPEED,0);
}
}
摄像机跟随
摄像机跟随的原理十分简单,在场景设计中将相机和主角的相对位置保持固定,跟随主角移动即可。但是有种特殊情况,当主角移动到墙边,被遮挡后如果还是保持原来的相对位置,则视野中将观察不到主角,这时需要动态的调整摄像机的位置。
这里将采用射线碰撞的方式来检查,从相机的位置开始,到主角正上方截止,平均划分3个点,依次从五个点分别发射一条射线,当射线能直接碰到主角或者没有碰到说明主角在摄像的范围内,将摄像机平滑的移动到能够看到主角的位置即可。
usingSystem.Collections;
usingSystem.Collections.Generic;
usingUnityEngine;
publicclassFollowPlayer:MonoBehaviour
{
privateVector3offset;
publicTransformrole;
publicfloatmoveSpeed=3;
publicfloatrotateSpeed=3;
//Startiscalledbeforethefirstframeupdate
voidStart()
{
offset=transform.position-role.position;
offset=newVector3(0,offset.y,offset.z);
}
//Updateiscalledonceperframe
voidUpdate()
{
Vector3beginPos=role.position+offset;//摄像机正常偏移位置,起点
Vector3endPos=role.position+offset.magnitude*Vector3.up;//offset.magnitude向量的长度
///从起点到终点分别取3个点,通过射线判断摄像机是否有遮挡
Vector3[]posArr=newVector3[]{
beginPos,
Vector3.Lerp(beginPos,endPos,0.25f),
Vector3.Lerp(beginPos,endPos,0.5f),
Vector3.Lerp(beginPos,endPos,0.75f),
endPos
};
Vector3targetPos=posArr[0];
foreach(varposinposArr)
{
RaycastHithitInfo;
///第一个参数射线的起点,第二个参数射线的方向
if(Physics.Raycast(pos,role.position-pos,outhitInfo))
{
if(hitInfo.collider.tag==StealthConst.PLAYER)
{
targetPos=pos;
break;
}
else
{
continue;
}
}
else
{
targetPos=pos;
break;
}
}
this.transform.position=Vector3.Lerp(transform.position,targetPos,Time.deltaTime*moveSpeed);//通过插值平滑移动
QuaternionnowRotation=transform.rotation;
this.transform.LookAt(role.position);//摄像机转向目标
this.transform.rotation=Quaternion.Lerp(nowRotation,transform.rotation,Time.deltaTime*rotateSpeed);//通过插曲平滑旋转
}
}
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持毛票票。
声明:本文内容来源于网络,版权归原作者所有,内容由互联网用户自发贡献自行上传,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任。如果您发现有涉嫌版权的内容,欢迎发送邮件至:czq8825#qq.com(发邮件时,请将#更换为@)进行举报,并提供相关证据,一经查实,本站将立刻删除涉嫌侵权内容。