去年在一个项目中遇到摄像机的跟随问题,摄像机跟随方式有成千上百种,那么怎样让Camera始终能够看到玩家,而不被游戏中的场景遮挡住?
在网上看到很多例子,大部分使用了插值,有的是当遮挡物遮挡Canera以后拉近和玩家的距离,我个人感觉这对于Player模型细腻的游戏来说还好,但是如果是一些轻型的游戏来说,就会有点尴尬,因为当遮挡物距离玩家很近的话,摄像机会和player拉的很近,所以完全报漏了模型的粗糙程度.后来参考了Unity官方教程<<秘密行动>>里面的Camera跟随方案,今天把它摘出来分享一下,希望对大家伙有所帮助:
大体的原理:
不改变摄像机和Player距离,改变角度.在player的正上方和正后方四分之一圆的范围内进行插值.
当有遮挡物时候:摄像机会从事先从预设的点里面找到可以看到player的点,然后继续跟随player,如图,位置3是Camera的最佳位置
具体实现:
using UnityEngine;
using System.Collections;
public class CameraMovement : MonoBehaviour //将这个脚本附加到你的maincamera(或其他任何你想使用的相机)
{
//这个脚本使用Unity秘密教程中引入的一些概念。
public float smooth = 1.5f; //照相机能赶上的相对速度。
private Transform ball; // The ball's position.
private Vector3 relativeCameraPosition; // 摄像机相对于球得点
private float relativeCameraDistance; // 摄像机现对于球 的距离
private Vector3 newCameraPosition; // 新位置点是否能到达摄像机
void Start ()
{
// Set up the values that remain unchanged during the entire level
//设置在整个级别中保持不变的值。
ball = GameObject.FindGameObjectWithTag(Tags.ball).transform;
if (ball == null) {Debug.LogError ("<color=blue>Marble Kit error:</color>: There needs exactly one object with the tag 'Ball' in the scene");}
relativeCameraPosition = transform.position - ball.position;//摄像机的相对位置
relativeCameraDistance = relativeCameraPosition.magnitude - 0.5f; // to look (roughly) at the center of the ball (1m ball size)摄像机看向求得距离
}
void FixedUpdate ()
{
//摄影机在FixedUpdate(因为游戏物理将在FixedUpdate,球移动相机应该做的)
Vector3 standardPosition = ball.position + relativeCameraPosition; // 获得当前摄像机的目标位置
Vector3 topPosition = ball.position + Vector3.up * relativeCameraDistance; //直接在球顶上取得位置
// 在标准位置和顶部位置之间放置一组可能的摄像机位置。
//
//如果相机不能从标准位置看到玩家,它会尝试所有其他位置,直到它可以看到球员againn。
Vector3[] cameraPoints = new Vector3[5];
cameraPoints[0] = standardPosition;
cameraPoints[1] = Vector3.Lerp(standardPosition, topPosition, 0.25f); // Lerp is used here to interpolate
cameraPoints[2] = Vector3.Lerp(standardPosition, topPosition, 0.5f); // 0, 25, 50, 75, 100% the line between standard and top position
cameraPoints[3] = Vector3.Lerp(standardPosition, topPosition, 0.75f);
cameraPoints[4] = topPosition;
//检查所有相机点,直到摄像机看到球。
for(int i = 0; i < cameraPoints.Length; i++)
{
if(CameraSeesBall(cameraPoints[i]))
break;
}
// Smoothly transition to the new camera point over time平稳过渡到新相机点随着时间的推移
transform.position = Vector3.Lerp(transform.position, newCameraPosition, smooth * Time.deltaTime);
// Reposition camera to look at the ball
CameraLookAtBall();
}
bool CameraSeesBall (Vector3 checkPosition)
{
RaycastHit hit;
//Raycast from Camera to the ball and see if it finds it
if(Physics.Raycast(checkPosition, ball.position - checkPosition, out hit,relativeCameraDistance))
if(hit.transform != ball)
return false;
//this is the new position for the camera
newCameraPosition = checkPosition;
return true;
}
void CameraLookAtBall()
{
// 创建一个向量和旋转从相机向玩家。
Vector3 relativeBallPosition = ball.position - transform.position;
Quaternion lookAtRotation = Quaternion.LookRotation(relativeBallPosition, Vector3.up);
//平滑调整相机
transform.rotation = Quaternion.Lerp(transform.rotation, lookAtRotation, smooth * Time.deltaTime);
}
}
以上代码参考了官方案例"秘密行动"