说明
按下鼠标左键并拖拽,可以让相机在上下和左右方向以角色为轴心旋转
鼠标滚轮可以调节视角的大小
实现方式
相机不绑定在角色身上
需要在角色的中心位置放置一个空对象作为视角中心
需要在面板指定视角中心
效果?
环绕相机控制脚本
挂载在相机上
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SurroundCamera : MonoBehaviour
{
//视角中心
public Transform CentreOfView;
//相对距离
public Vector3 Distance;
//鼠标滚轮灵敏度
public float mouseWheelSensitivity = 30;
void Start()
{
Distance = CentreOfView.position - transform.position;
}
void Update()
{
Follow();
DragToRotateView();
ScrollToScaleDistance();
}
void Follow()
{
transform.position = CentreOfView.position - Distance;
}
private Vector3 startPoint;
private Vector3 endPoint;
//旋转每度需要拖拽的距离
public int DragDistancePerAngle = 5;
//两点连线与水平方向的夹角
public float currentAngleY;
//最小水平夹角
public float MinimumDegree = 10;
//最大水平夹角
public float MaximumDegree = 35;
void DragToRotateView()
{
if (Input.GetMouseButtonDown(0))
{
startPoint = Input.mousePosition;
}
if (Input.GetMouseButton(0))
{
endPoint = Input.mousePosition;
float dx = endPoint.x - startPoint.x;
float dy = endPoint.y - startPoint.y;
//将鼠标在屏幕上拖拽的距离转化为角度
float anglex = dx / DragDistancePerAngle;
float angley = dy / DragDistancePerAngle;
//计算两点连线与水平方向的夹角
currentAngleY = 90 - Vector3.Angle(CentreOfView.position - transform.position, Vector3.down);
if (currentAngleY - angley > MaximumDegree || currentAngleY - angley < MinimumDegree)
angley = 0;
Vector3 linkVector = CentreOfView.position - transform.position;
Vector3 verticalRotateAxis = Vector3.Cross(linkVector, Vector3.up).normalized;
transform.RotateAround(CentreOfView.position, Vector3.up, anglex);
transform.RotateAround(CentreOfView.position, verticalRotateAxis, angley);
//如果没有这一句,摄像头转着转着就会歪
transform.LookAt(CentreOfView);
//更新距离
Distance = CentreOfView.position - transform.position;
startPoint = endPoint;
endPoint = Vector3.zero;
}
}
//调节视角
//方案一
public float MinFieldOfView = 20f;
public float MaxFieldOfView = 100f;
void ScrollToScaleView()
{
if (Input.GetAxis("Mouse ScrollWheel") == 0) return;
GetComponent<Camera>().fieldOfView = GetComponent<Camera>().fieldOfView - Input.GetAxis("Mouse ScrollWheel") * mouseWheelSensitivity;
GetComponent<Camera>().fieldOfView = Mathf.Clamp(GetComponent<Camera>().fieldOfView, MinFieldOfView, MaxFieldOfView);
}
//方案二
public float MinViewDistance = 1;
public float MaxViewDistance = 10;
void ScrollToScaleDistance()
{
transform.position = CentreOfView.transform.position - Distance;
if (Input.GetAxis("Mouse ScrollWheel") > 0)
{
if (Distance.magnitude <= MinViewDistance) return;
transform.Translate(Distance / mouseWheelSensitivity *10, Space.World);
Distance = CentreOfView.transform.position - transform.position;
}
else if (Input.GetAxis("Mouse ScrollWheel") < 0)
{
if (Distance.magnitude >= MaxViewDistance) return;
transform.Translate(-Distance / mouseWheelSensitivity *10, Space.World);
Distance = CentreOfView.transform.position - transform.position;
}
}
}
原理解释
跟随:
相机不绑定在角色身上,而是作为一个单独的对象时刻跟随着角色
拖拽以旋转:
通过记录鼠标点击的前一位置与后一位置,用其长度控制旋转的角度
环绕:
使用transform.RotateAround函数,让相机围绕着视角中心旋转
水平环绕:
以竖直向上的单位向量为轴环绕
面向角色竖直环绕:
以 角色与相机的连线 与 竖直向上的单位向量 所在的平面法向量为轴环绕
限定视角参数的范围:
使用Mathf.Clamp函数
角色控制脚本
挂载在角色上
WS 前进后退 AD 左右旋转 空格跳跃
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class PlayerControl : MonoBehaviour
{
//速度:每秒移动4个单位长度
public float moveSpeed = 4;
//角速度:每秒旋转60度
private float angularSpeed = 60;
//角色水平旋转灵敏度
public float horizontalRotateSensitivity = 2;
//跳跃参数
public float jumpForce = 200f;
//角色的刚体
private Rigidbody rigidbody;
//动画控制器
Animator anim;
//二段跳限制
private int jumpLimit = 2;
void Start()
{
rigidbody = GetComponent<Rigidbody>();
anim = GetComponent<Animator>();
}
void FixedUpdate()
{
Move();
Jump();
}
void Move()
{
//通过键盘获取竖直、水平轴的值,范围在-1到1
float v = Input.GetAxis("Vertical");
float h = Input.GetAxis("Horizontal");
//按下左边Shift键行走
if (Input.GetKey(KeyCode.LeftShift))
{
v *= 0.5f;
}
//传入动画所需要的参数
//SpeedX代表水平轴,SpeedY代表竖直轴
anim.SetFloat("SpeedX", h);
anim.SetFloat("SpeedY", v);
//前进后退
transform.Translate(Vector3.forward * v * Time.deltaTime * moveSpeed);
//水平旋转
transform.Rotate(Vector3.up * h * Time.deltaTime * angularSpeed * horizontalRotateSensitivity);
}
// 通过射线检测角色是在地面或者物体上(注意,角色的零点需要设置在脚底处)
bool IsGrounded()
{
return Physics.Raycast(transform.position, -Vector3.up, 0.1f);
}
void Jump()
{
//如果接触地面,则恢复可跳跃次数
if (IsGrounded())
{
jumpLimit = 2;
anim.SetBool("Jump", false);
}
if (Input.GetKeyDown(KeyCode.Space))
{
//限制最多二段跳
if (jumpLimit > 0)
{
rigidbody.AddForce(Vector3.up * jumpForce);
anim.SetBool("Jump", true);
jumpLimit--;
}
}
}
}
|