最新文章
Cocos2d-x游戏开发实例详解7:对象释放时机
03-25 13:59
Cocos2d-x游戏开发实例详解6:自动释放池
03-25 13:55
Cocos2d-x游戏开发实例详解5:神奇的自动释放
03-25 13:49
Cocos2d-x游戏开发实例详解4:游戏主循环
03-25 13:44
Cocos2d-x游戏开发实例详解3:无限滚动地图
03-25 13:37
Cocos2d-x游戏开发实例详解2:开始菜单续
03-25 13:32
unity 赛车相机跟随物体移动
在开发Unity项目时,相机跟随物体移动是一个常见需求。此前我做过人物相机跟随物体移动的实现,其原理与赛车相机跟随物体移动基本一致,下面我将详细分享相关经验。
人物移动Demo开发
1. 人物素材导入问题
在导入人物素材时,可能会遇到一些问题。
- 模型材质显示问题:导入后人物模型可能呈现白色,没有皮肤,即便贴上材质球也无济于事。这通常是因为模型的缩放比例过小,比如为0.01,而正常缩放比例应为0.5。缩放比例过小会导致两个问题:一是模型的材质贴图无法显示;二是将模型拖到场景视图中根本看不见。因此,需要修改缩放比例,即修改
Scale Factor。 - 动画类型问题:一开始导入的动画类型为
Generic,在角色中添加动画组件并在代码中编写播放动画的代码时,代码提示动画不存在。后来将模型和所有动画都改成Legacy类型,所有动画便自动倒入Animation组件中,并且在代码中也能识别了。这里有一篇关于Unity动画系统分析的文章,写得很不错,推荐学习:Unity动画系统分析。
2. 人物自动寻路设置
人物自动寻路的问题在赛车相机跟随物体移动中也可能出现,以下是详细步骤:
- 地板设置:对地板
plane属性面板的static选项打勾,然后Layer选择default。如果要使用特定代码,可将Layer选择为自定义层,例如第八层,并取名为abc。在寻路代码中加入射线的参数mask == 1 << 8,这里的8代表第八层。设置完成后,进行bake操作,会生成蓝色的地板,此时会提示保存场景,保存后地板设置完成。 - 添加寻路组件:给主角添加
NavMeshAgent寻路组件,至此整个寻路步骤完成。 - 常见问题解决:属性面板旁边的
Navigation选项卡可能会消失,只需在菜单栏的windows中选择Navigation即可重新显示。
3. 人物自动寻路代码
// playerControl.cs
using UnityEngine;
using System.Collections;
public class PlayerControl : MonoBehaviour
{
// 代表要寻路的主角
NavMeshAgent m_player;
// 主角的动作动画
Animation m_animation;
// 主角在跑时候的速度
public float speed;
// 照相机要跟上主角移动
Transform m_Camera;
public float m_MoveFactor = 4.0f;
public float m_RotateFactor = 10.0f;
Vector3 nowPosition;
void Start()
{
// 通过这个函数可以找到套在主角身上的所有组件,这次找的是寻路组件
m_player = GetComponent<NavMeshAgent>();
// 获取主角身上的动画数组
m_animation = animation;
// 获取照相机的位置,transform是位置信息,可以平移,缩放,旋转
m_Camera = Camera.main.transform;
// 为了获取主角当前位置所设
nowPosition = transform.position;
}
void Update()
{
nowPosition = transform.position;
// 有任何键盘按下的时候会中断当前的寻路,原理是把寻路目标换成主角当前的位置
if (Input.anyKeyDown)
{
m_player.SetDestination(nowPosition);
}
// 主角如果到了目的地,播放待机动作
if (m_player.remainingDistance == 0)
{
m_animation.CrossFade("idle");
}
else
{
// 否则,播放跑步动作
m_animation.CrossFade("run");
}
// 鼠标点击坐标是屏幕坐标,需要用射线做成空间坐标
// 左击鼠标开始移动
if (Input.GetMouseButtonDown(0))
{
Debug.Log(" clickLeftMouseButton! ");
Ray ray;
RaycastHit hit;
// 这个mask就是选择Layers改为第八层的原因
LayerMask mask = 1 << 8;
ray = Camera.main.ScreenPointToRay(Input.mousePosition);
if (Physics.Raycast(ray, out hit, Mathf.Infinity, mask))
{
Debug.DrawLine(ray.origin, hit.point, Color.red, 2);
m_player.SetDestination(hit.point);
}
}
}
}
相机功能实现
相机具备以下功能:
- 跟随主角移动。
- 按住鼠标右键拖动能够移动视图。
- 滚动鼠标滚轮能够放大缩小游戏视图。
- 使用代码时,需要将
target = GameObject.Find("nanzhujueSCJ");中的nanzhujueSCJ改成自己的角色名称。
相机功能代码
// c1.cs
using UnityEngine;
using System.Collections;
[AddComponentMenu("Camera-Control/Mouse Look")]
public class c1 : MonoBehaviour
{
public enum RotationAxes { MouseXAndY = 0, MouseX = 1, MouseY = 2 }
public RotationAxes axes = RotationAxes.MouseXAndY;
public float sensitivityX = 15F;
public float sensitivityY = 15F;
public float minimumX = -360F;
public float maximumX = 360F;
public float minimumY = -85F;
public float maximumY = 4F;
public float rotationY = 0F;
public GameObject target;
public float theDistance = -10f;
public float MaxDistance = -10f;
public float ScrollKeySpeed = 100.0f;
void Update()
{
// 这里的target要改成你主角的名字
target = GameObject.Find("nanzhujueSCJ");
// 滚轮设置相机与人物的距离
if (Input.GetAxis("Mouse ScrollWheel") != 0)
{
theDistance = theDistance + Input.GetAxis("Mouse ScrollWheel") * Time.deltaTime * ScrollKeySpeed;
}
// 鼠标中间滚动得到的值不确定,当大于0时设距离为0,小于MaxDistance就设置为MaxDistance
if (theDistance > 0)
{
theDistance = 0;
}
if (theDistance < MaxDistance)
{
theDistance = MaxDistance;
}
// 按下鼠标右键
if (Input.GetMouseButton(1))
{
transform.position = target.transform.position;
if (axes == RotationAxes.MouseXAndY)
{
float rotationX = transform.localEulerAngles.y + Input.GetAxis("Mouse X") * sensitivityX;
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationY = Mathf.Clamp(rotationY, minimumY, maximumY);
transform.localEulerAngles = new Vector3(-rotationY, rotationX, 0);
}
else if (axes == RotationAxes.MouseX)
{
transform.Rotate(0, Input.GetAxis("Mouse X") * sensitivityX, 0);
}
else
{
rotationY += Input.GetAxis("Mouse Y") * sensitivityY;
rotationY = Mathf.Clamp(rotationY, minimumY, maximumY);
transform.localEulerAngles = new Vector3(-rotationY, transform.localEulerAngles.y, 0);
}
SetDistance();
}
else
{
transform.position = target.transform.position;
SetDistance();
}
}
void Start()
{
if (rigidbody)
{
rigidbody.freezeRotation = true;
transform.position = target.transform.position;
}
}
// 设置相机与人物之间的距离
void SetDistance()
{
transform.Translate(Vector3.forward * theDistance);
}
}
人物方向键移动实现
这里对人物方向键移动进行了优化,同时兼容两个按键,旋转时过渡自然。
人物方向键移动代码
// playerKeyMove.cs
using UnityEngine;
using System.Collections;
public class playerKeyMove : MonoBehaviour
{
// 动画对象
Animation m_Animation;
// 移动的速度
public float speed;
// 平移对象(照相机)
Transform m_Camera;
// 移动大小
public float m_MoveFactor = 4.0f;
// 旋转大小
public float m_RotateFactor = 10.0f;
NavMeshAgent m_NavmeshAgent;
void Start()
{
// 获取装有寻路功能的对象
m_NavmeshAgent = GetComponent<NavMeshAgent>();
// 实例化animation动画
m_Animation = animation;
// 平移对象相机是主相机的平移
m_Camera = Camera.main.transform;
}
void Update()
{
// 这部分内容是主角键盘移动
// 如果WSAD键松开的时候是处于正常状态
if (Input.GetKeyUp(KeyCode.W) || Input.GetKeyUp(KeyCode.S) || Input.GetKeyUp(KeyCode.A) || Input.GetKeyUp(KeyCode.D))
{
m_Animation.CrossFade("idle");
}
// 当W键按下的时候,又有其他键按下的时候主角应该出现旋转
if (Input.GetKey(KeyCode.W))
{
// 按下左键的时候逆时针旋转45度
if (Input.GetKey(KeyCode.A))
{
Move(-45.0f);
}
else if (Input.GetKey(KeyCode.D))
{
Move(45.0f);
}
else
{
// 这个键值不旋转
Move(0.0f);
}
}
else if (Input.GetKey(KeyCode.S))
{
if (Input.GetKey(KeyCode.A))
{
Move(-135.0f);
}
else if (Input.GetKey(KeyCode.D))
{
Move(135.0f);
}
else
{
Move(-180.0f);
}
}
else if (Input.GetKey(KeyCode.A))
{
Move(-90.0f);
}
else if (Input.GetKey(KeyCode.D))
{
Move(90.0f);
}
else if (Input.GetKey(KeyCode.Space))
{
// m_Animation.CrossFade("attack01");
Debug.Log("攻击");
}
}
// 这个函数的功能是实现移动和旋转
void Move(float delta)
{
// Quaternion是四元数,先计算角度angle是主相机的欧拉角
// transform.eulerAngles(x,y,z)表示分别绕x,y,z旋转的角度
float angle = m_Camera.eulerAngles.y + delta;
Quaternion rotate = Quaternion.Euler(0, angle, 0);
// 主角开始移动,移动的距离是旋转角度rotate*3维向量向前Vector.forward*一秒Time.deltaTime*移动的速度m_MoveeFactor
m_NavmeshAgent.Move(rotate * Vector3.forward * Time.deltaTime * m_MoveFactor);
// 主角旋转transform.rotation=
// Quaternion.Lerp意思是四元数的插值
transform.rotation = Quaternion.Lerp(transform.rotation, rotate, Time.deltaTime * m_RotateFactor);
// 播放跑的动作
// Animation.CrossFade 淡入淡出动画
m_Animation.CrossFade("run");
}
}
以上就是关于Unity人物移动及相机跟随的详细实现过程,其原理对于赛车相机跟随物体移动同样适用,希望对大家有所帮助。