旋转视角
基础旋转
相机环绕角色旋转,使用RotateAround函数
视角水平旋转,以角色为圆心,以竖直向上的方向向量为旋转轴
视角上下旋转,从角色正面旋转到角色头顶,以角色为圆心,以相机左侧的方向向量为旋转轴,这种旋转之后,相机可能会倾斜,所以最后要使用LookAt函数修正,让相机正确地朝向角色
transform.RotateAround(focus.position, Vector3.up, anglex);
transform.RotateAround(focus.position, -transform.right, angley);
transform.LookAt(focus);
限制转动视角
只需要限制视角的上下旋转。
设相机为C,角色为P,拿到一个待旋转角∠C'PC,计算 与 的夹角,也就是∠PCD,再间接计算出∠CPQ,最后再判断∠C'PC+∠CPQ是否超出限制的范围即可。
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree)
angley = 0;
通过鼠标拖拽速度来旋转视角
思路
按下鼠标左键时,每一帧都获取鼠标的位置,通过两帧之间的鼠标位置之差除以两帧之间的时间,即可求得两帧之间的鼠标速度。
将鼠标速度作为视角旋转的依据,将鼠标速度转换为视角旋转的角度,转化比率可自己设定。
代码
float mouseVelocityX;
float mouseVelocityY;
Vector3? point1;
//旋转每度,在一帧中需要的速度
int DragVelocityPerAngle = 170;
void DragToRotateView_Velocity()
{
if (Input.GetMouseButton(0)) //按下鼠标左键的每一帧都执行
{
var point2 = Input.mousePosition;
if (point1 != null)
{
mouseVelocityX = -(point1.Value.x - point2.x) / Time.deltaTime;
mouseVelocityY = -(point1.Value.y - point2.y) / Time.deltaTime;
}
point1 = point2;
float anglex = mouseVelocityX / DragVelocityPerAngle; //将鼠标在屏幕上拖拽的速度转化为角度
float angley = mouseVelocityY / DragVelocityPerAngle;
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree)
angley = 0;
transform.RotateAround(focus.position, Vector3.up, anglex);
transform.RotateAround(focus.position, -transform.right, angley);
transform.LookAt(focus); //如果没有这一句,摄像头转着转着就会歪
RelativePosition = transform.position - focus.position; //更新相对位置
}
if(Input.GetMouseButtonUp(0)) //脱手瞬间
{
point1 = null;
}
}
基于速度的惯性旋转
实现方式
将惯性运动的初速度设定为鼠标左键松开时的鼠标移动速度,随后用协程实现
获取惯性运动的初速度
if(Input.GetMouseButtonUp(0)) //脱手瞬间
{
point1 = null;
inertialRotation = true;
lastMouseVelocityX = mouseVelocityX;
lastMouseVelocityY = mouseVelocityY;
if (lastMouseVelocityX > maxlastMouseVelocityX) lastMouseVelocityX = maxlastMouseVelocityX;
else if (lastMouseVelocityX < -maxlastMouseVelocityX) lastMouseVelocityX = -maxlastMouseVelocityX;
if (lastMouseVelocityX > 0) isCounterClockwise = true;
else if (lastMouseVelocityX < 0) isCounterClockwise = false;
//print(lastMouseVelocityX);
}
if(inertialRotation==true)
StartCoroutine("InertialRotation"); //通过协程来实现视角的惯性旋转,调用协程只有写在Update里并且在每一帧都被调用时才会继续执行
通过协程实现视角的惯性旋转
bool inertialRotation = false; //是否需要视角的惯性旋转
float lastMouseVelocityX; //脱手瞬间鼠标速度
float lastMouseVelocityY;
float maxlastMouseVelocityX = 3000;
bool isCounterClockwise; //旋转方向
IEnumerator InertialRotation() //在旋转末尾补上一个逐渐减缓的惯性旋转
{
yield return null;
float anglex = lastMouseVelocityX / DragVelocityPerAngle; //将鼠标在屏幕上拖拽的速度转化为角度
float angley = lastMouseVelocityY / DragVelocityPerAngle;
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree + 10)
angley = 0;
lastMouseVelocityX -= lastMouseVelocityX * 0.08f;
lastMouseVelocityY -= lastMouseVelocityY * 0.08f;
if ((isCounterClockwise && (anglex < 1))||!isCounterClockwise && (anglex > -1))
{
StopCoroutine("InertialRotation");
inertialRotation = false;
}
transform.RotateAround(focus.position, Vector3.up, anglex/3);
transform.RotateAround(focus.position, -transform.right, Mathf.Abs(angley/25));
transform.LookAt(focus);
RelativePosition = transform.position - focus.position;
}
通过鼠标拖拽距离来旋转视角
思路
按下鼠标左键时,每一帧都获取鼠标的位置。
将两帧之间的鼠标拖拽距离作为视角旋转的依据,将距离转换为视角旋转的角度,转化比率可自己设定。
代码
Vector3 Point1;
Vector3 Point2;
//旋转每度,在一帧中需要拖拽的距离
int DragDistancePerAngle = 20;
void DragToRotateView_Distance()
{
if (Input.GetMouseButton(0)) //按下鼠标左键的每一帧都执行
{
Point2 = Input.mousePosition;
float dx = Point2.x - Point1.x;
float dy = Point2.y - Point1.y;
float anglex = dx / DragDistancePerAngle; //将鼠标在屏幕上拖拽的距离转化为角度
float angley = dy / DragDistancePerAngle;
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree)
angley = 0;
transform.RotateAround(focus.position, Vector3.up, anglex);
transform.RotateAround(focus.position, -transform.right, angley);
transform.LookAt(focus); //如果没有这一句,摄像头转着转着就会歪
RelativePosition = transform.position - focus.position; //更新相对位置
Point1 = Point2;
Point2 = Vector3.zero;
}
}
基于鼠标拖拽距离的惯性旋转
按下鼠标瞬间记录拖拽起点,松开鼠标瞬间记录拖拽终点
获取两帧之间的拖拽距离
if (Input.GetMouseButtonDown(0)) //按下鼠标左键的瞬间,记录起始位置
{
Point1 = Input.mousePosition;
StartPoint = Point1;
}
if(Input.GetMouseButtonUp(0))
{
EndPoint = Input.mousePosition;
if (Point1!=EndPoint) //鼠标无速度则不进行惯性旋转
inertialRotation = true;
dragX = EndPoint.x - StartPoint.x;
dragY = EndPoint.y - StartPoint.y;
if (dragX > maxdragX) dragX = maxdragX;
else if (dragX < -maxdragX) dragX = -maxdragX;
if (dragX > 0) isCounterClockwise = true;
else if (dragX < 0) isCounterClockwise = false;
print(dragX);
}
if (inertialRotation == true)
StartCoroutine("InertialRotation2");
通过协程实现视角的惯性旋转
Vector3 StartPoint; //拖拽起点
Vector3 EndPoint; //拖拽终点
float dragX; //水平拖拽距离
float dragY; //垂直拖拽距离
float maxdragX = 3000;
float sactor = 10; //惯性系数
IEnumerator InertialRotation2() //在旋转末尾补上一个逐渐减缓的惯性旋转
{
yield return null;
float anglex = dragX / DragDistancePerAngle / sactor; //将鼠标在屏幕上拖拽的距离转化为角度
float angley = dragY / DragDistancePerAngle / sactor;
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree + 10)
angley = 0;
dragX -= dragX * 0.05f;
dragY -= dragY * 0.05f;
print(dragX);
if ((isCounterClockwise && (anglex < 1)) || !isCounterClockwise && (anglex > -1))
{
StopCoroutine("InertialRotation2");
inertialRotation = false;
}
transform.RotateAround(focus.position, Vector3.up, anglex / 4);
transform.RotateAround(focus.position, -transform.right, Mathf.Abs(angley/4));
transform.LookAt(focus);
RelativePosition = transform.position - focus.position;
}
效果
完整代码
/*-----------------调整视角------------------*/
//相机旋转方案
public CameraRotateBy cameraRotateBy = CameraRotateBy.MouseVelocity;
public enum CameraRotateBy
{
MouseVelocity,
Distance,
}
//最小水平夹角
public float MinimumDegree = 0;
//最大水平夹角
public float MaximumDegree = 60;
//两点连线与水平方向的夹角
float currentAngleY;
/*
方案一
以两帧之间的鼠标移动速度为依据进行旋转
*/
float mouseVelocityX;
float mouseVelocityY;
Vector3? point1;
//旋转每度,在一帧中需要的速度
int DragVelocityPerAngle = 170;
//脱手瞬间鼠标速度
float lastMouseVelocityX;
float lastMouseVelocityY;
void DragToRotateView_Velocity()
{
if (Input.GetMouseButton(0)) //按下鼠标左键的每一帧都执行
{
var point2 = Input.mousePosition;
if (point1 != null)
{
mouseVelocityX = -(point1.Value.x - point2.x) / Time.deltaTime;
mouseVelocityY = -(point1.Value.y - point2.y) / Time.deltaTime;
}
point1 = point2;
float anglex = mouseVelocityX / DragVelocityPerAngle; //将鼠标在屏幕上拖拽的速度转化为角度
float angley = mouseVelocityY / DragVelocityPerAngle;
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree)
angley = 0;
transform.RotateAround(focus.position, Vector3.up, anglex);
transform.RotateAround(focus.position, -transform.right, angley);
transform.LookAt(focus); //如果没有这一句,摄像头转着转着就会歪
RelativePosition = transform.position - focus.position; //更新相对位置
}
if(Input.GetMouseButtonUp(0)) //脱手瞬间
{
point1 = null;
inertialRotation = true;
lastMouseVelocityX = mouseVelocityX;
lastMouseVelocityY = mouseVelocityY;
if (lastMouseVelocityX > maxlastMouseVelocityX) lastMouseVelocityX = maxlastMouseVelocityX;
else if (lastMouseVelocityX < -maxlastMouseVelocityX) lastMouseVelocityX = -maxlastMouseVelocityX;
if (lastMouseVelocityX > 0) isCounterClockwise = true;
else if (lastMouseVelocityX < 0) isCounterClockwise = false;
//print(lastMouseVelocityX);
}
if(inertialRotation==true)
StartCoroutine("InertialRotation"); //通过协程来实现视角的惯性旋转,调用协程只有写在Update里并且在每一帧都被调用时才会继续执行
}
bool inertialRotation = false; //是否需要视角的惯性旋转
float maxlastMouseVelocityX = 3000;
bool isCounterClockwise; //旋转方向
IEnumerator InertialRotation() //在旋转末尾补上一个逐渐减缓的惯性旋转
{
yield return null;
float anglex = lastMouseVelocityX / DragVelocityPerAngle; //将鼠标在屏幕上拖拽的速度转化为角度
float angley = lastMouseVelocityY / DragVelocityPerAngle;
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree + 10)
angley = 0;
lastMouseVelocityX -= lastMouseVelocityX * 0.08f;
lastMouseVelocityY -= lastMouseVelocityY * 0.08f;
//print(lastMouseVelocityX);
if ((isCounterClockwise && (anglex < 1))||!isCounterClockwise && (anglex > -1))
{
StopCoroutine("InertialRotation");
inertialRotation = false;
}
transform.RotateAround(focus.position, Vector3.up, anglex/3);
transform.RotateAround(focus.position, -transform.right, Mathf.Abs(angley/25));
transform.LookAt(focus);
RelativePosition = transform.position - focus.position;
}
/*
方案二
以两帧之间的鼠标移动距离为依据进行旋转
*/
Vector3 Point1;
Vector3 Point2;
//旋转每度,在一帧中需要拖拽的距离
int DragDistancePerAngle = 20;
void DragToRotateView_Distance()
{
float v = Input.GetAxis("Vertical");
float h = Input.GetAxis("Horizontal");
if (!(h==0&&v==0)) //不运动时的旋转灵敏度
{
DragDistancePerAngle = 17; //松手前拖拽灵敏度
sactor = 10; //松手后拖拽灵敏度
}
else //运动时的旋转灵敏度
{
DragDistancePerAngle = 8;
sactor = 4;
}
if (Input.GetMouseButtonDown(0)) //按下鼠标左键的瞬间,记录起始位置
{
Point1 = Input.mousePosition;
StartPoint = Point1;
}
if (Input.GetMouseButton(0)) //按下鼠标左键的每一帧都执行
{
Point2 = Input.mousePosition;
float dx = Point2.x - Point1.x;
float dy = Point2.y - Point1.y;
float anglex = dx / DragDistancePerAngle; //将鼠标在屏幕上拖拽的距离转化为角度
float angley = dy / DragDistancePerAngle;
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree)
angley = 0;
transform.RotateAround(focus.position, Vector3.up, anglex);
transform.RotateAround(focus.position, -transform.right, angley);
transform.LookAt(focus); //如果没有这一句,摄像头转着转着就会歪
RelativePosition = transform.position - focus.position; //更新相对位置
Point1 = Point2;
Point2 = Vector3.zero;
}
if(Input.GetMouseButtonUp(0))
{
EndPoint = Input.mousePosition;
if (Point1!=EndPoint) //鼠标无速度则不进行惯性旋转
inertialRotation = true;
dragX = EndPoint.x - StartPoint.x;
dragY = EndPoint.y - StartPoint.y;
if (dragX > maxdragX) dragX = maxdragX;
else if (dragX < -maxdragX) dragX = -maxdragX;
if (dragX > 0) isCounterClockwise = true;
else if (dragX < 0) isCounterClockwise = false;
print(dragX);
}
if (inertialRotation == true)
StartCoroutine("InertialRotation2");
}
Vector3 StartPoint; //拖拽起点
Vector3 EndPoint; //拖拽终点
float dragX; //水平拖拽距离
float dragY; //垂直拖拽距离
float maxdragX = 3000;
float sactor = 10; //惯性系数
IEnumerator InertialRotation2() //在旋转末尾补上一个逐渐减缓的惯性旋转
{
yield return null;
float anglex = dragX / DragDistancePerAngle / sactor; //将鼠标在屏幕上拖拽的距离转化为角度
float angley = dragY / DragDistancePerAngle / sactor;
currentAngleY = 90 - Vector3.Angle(-RelativePosition, Vector3.down); //计算两点连线与水平方向的夹角
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree + 10)
angley = 0;
dragX -= dragX * 0.05f;
dragY -= dragY * 0.05f;
print(dragX);
if ((isCounterClockwise && (anglex < 1)) || !isCounterClockwise && (anglex > -1))
{
StopCoroutine("InertialRotation2");
inertialRotation = false;
}
transform.RotateAround(focus.position, Vector3.up, anglex / 4);
transform.RotateAround(focus.position, -transform.right, Mathf.Abs(angley/4));
transform.LookAt(focus);
RelativePosition = transform.position - focus.position;
}