最近在用unity 做一个mmorpg游戏
其中相机运动这一块策划提了很多需求
做了很多版 最终定下来一版 记录一下:
大致需求是这样的
当相机处于点A时,角色锁定目标相机从A点以角色为中心,圆周运动到B点
B点为角色到目标连线的反向延长线, 要求相机运动速度可控
代码为
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class test1 : MonoBehaviour {
/// <summary>
/// 角色
/// </summary>
public Transform target;
/// <summary>
/// 目标
/// </summary>
public Transform target2;
/// <summary>
/// 相机
/// </summary>
public Camera camera;
/// <summary>
/// 相机距离角色水平距离
/// </summary>
public float _radius;
/// <summary>
/// 相机看向角色正前方多少米处
/// </summary>
public float cameraLookDis;
/// <summary>
/// 相机距离角色竖直距离
/// </summary>
public float _camHeight;
/// <summary>
/// 相机旋转角速度变化曲线
/// </summary>
public AnimationCurve _cameraAngleSpeedCurve;
/// <summary>
/// 相机角速度
/// </summary>
public float cameraSpeed;
public bool reset;
// Start is called before the first frame update
void Start() {
}
// Update is called once per frame
void Update() {
if(reset) {
Vector3 pos = camera.transform.position;
//角色到目标的向量
Vector3 dir = target.position - target2.position;
dir.y = 0.0f;
//角色到相机的水平方向上的向量
Vector3 roted = dir.normalized * _radius;
//相机看向的位置
Vector3 lookat = target.position - dir.normalized * cameraLookDis;
//相机应该移动到平面上的位置
Vector3 endPos = lookat + roted;
//当前相机在校准和角色的水平距离后在平面上的位置
Vector3 disEndPos = GetDisPos(pos, lookat);
Vector3 curPos = endPos;
//当前位置和应到位置的的角度(+-180)
float angle = Angle_180(disEndPos - lookat, endPos - lookat);
//根据角度获取曲线上的速度倍率
float curSpeedRate = _cameraAngleSpeedCurve.Evaluate(Mathf.Abs(angle));
float curSpeed = cameraSpeed;
//根据角度调整旋转方向
if(angle > 0) curSpeed *= 1;
else if(angle < 0) curSpeed *= -1;
//根据角度调整位置
if(Mathf.Abs(angle) > Mathf.Abs(curSpeed * Time.deltaTime * curSpeedRate)) {
float rotAngle = curSpeed * Time.deltaTime * curSpeedRate;
//根据圆心角度半径求出旋转角度后应到的位置
curPos = GetCurPos(target.position, disEndPos, rotAngle);
}
//相机看向目标
camera.transform.LookAt(lookat);
//相机位置赋值
camera.transform.position = curPos + Vector3.up * (_camHeight + target.position.y);
}
}
/// <summary>
/// 获取当前角度标准距离后的位置
/// </summary>
/// <returns></returns>
private Vector3 GetDisPos(Vector3 pos,Vector3 _lookat) {
Vector3 view = _lookat - pos;
view.y = 0.0f;
view.Normalize();
Vector3 endPos = _lookat - view * _radius;
endPos.y = 0f;
return endPos;
}
private Vector3 GetCurPos(Vector3 center, Vector3 curPos, float angle) {
return RotateRound(curPos, center, Vector3.up, angle);
}
/// <summary>
/// 围绕某点旋转指定角度
/// </summary>
/// <param name="position">自身坐标</param>
/// <param name="center">旋转中心</param>
/// <param name="axis">围绕旋转轴</param>
/// <param name="angle">旋转角度</param>
/// <returns></returns>
private Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle) {
return Quaternion.AngleAxis(angle, axis) * (position - center) + center;
}
/// <summary>
/// 求出两个向量之间的夹角+-180
/// </summary>
/// <param name="from"></param>
/// <param name="to"></param>
/// <returns></returns>
public float Angle_180(Vector3 from, Vector3 to) {
from.y = 0; to.y = 0;
Vector3 v3 = Vector3.Cross(from, to);
if(v3.y > 0)
return Vector3.Angle(from, to);
else
return -Vector3.Angle(from, to);
}
}
当前代码的效果是这样的
当有锁定目标是 保证了相机能同时照射到角色和目标
保证了角色冲向目标 并且到了目标的后方 相机依旧能走出弧形曲线
不会突然翻过去 下的很突兀
参数可以调节相机绕角色运动是的角速度
可以通过贝塞尔曲线调节不同角度范围之间相机的角速度
可以调成类似插值的效果
当然这个只实用于我们当前的需求
仅仅发文记录一下自己的实现过程
|