1.场景搭建
主要包含相机、地形、代表玩家的方块,相机需要跟随该方块。
由于需要接收触屏事件,因此需要设置模拟器
将代表玩家的方块的Tag设置为Player,用于之后相机碰撞检测过滤。
2.编写脚本
新建脚本,命名为TPSCamera
首先编写常用的属性, 将其挂载到Main Camera上。
将Cube绑定到followTarget上,Main Camera绑定到controlCamera上
public class TPSCamera : MonoBehaviour
{
public Transform followTarget = null; // 相机拍摄的物体
public Vector2 rotate; // 相机的转动角度(绕着x轴和y轴)
public float rotateSpeed = 0.6f; // 相机的转向速度
public float moveSpeed = 10; // 相机的移动速度
public float maxY = 80; // 相机向下移动的最大角度
public float minY = -80; // 相机向下移动的最小角度
public float viewSize = 60; // 相机的视野
public float defaultAngle = -135; // 默认角度
public float radius = 5; // 相机与目标物体的距离
public float height = 0.8f; // 焦点与目标物体的高度差
private Camera controlCamara; // 目标相机
void Start()
{
controlCamara = this.GetComponent<Camera>();
Input.multiTouchEnabled = true;
}
}
实现触屏移动视角的代码,这里我们找到接触到右半边屏幕的手指,并记录它的位置。
private int lastfingerId = -1;
void FixedUpdate()
{
for (int i = 0; i < Input.touchCount; i++)
{
Touch touch = Input.GetTouch(i);
// 找到接触到右半边的手指
if (touch.position.x < UnityEngine.Screen.width / 2)
continue;
if (lastfingerId != touch.fingerId && lastfingerId != -1)
continue;
switch (touch.phase)
{
case TouchPhase.Began:
lastfingerId = touch.fingerId;
break;
case TouchPhase.Moved:
rotate.x += touch.deltaPosition.x * rotateSpeed;
rotate.y += touch.deltaPosition.y * rotateSpeed;
if (rotate.y < -60)
{
rotate.y = -60;
}
else if (rotate.y > 45)
{
rotate.y = 45;
}
break;
case TouchPhase.Ended:
lastfingerId = -1;
break;
}
break;
}
}
同步相机位置并实现相机的碰撞检测
void LateUpdate()
{
if (followTarget == null) return;
Transform self = controlCamera.transform;
Vector3 startPosition = self.position;
Vector3 endPosition;
Vector3 targetPos = followTarget.position;
targetPos.y += height;
Vector2 v1 = CalcAbsolutePoint(rotate.x, radius);
endPosition = targetPos + new Vector3(v1.x, 0, v1.y);
Vector2 v2 = CalcAbsolutePoint(rotate.x + defaultAngle, 1);
Vector3 viewPoint = new Vector3(v2.x, 0, v2.y) + targetPos;
float dist = Vector3.Distance(endPosition, viewPoint);
Vector2 v3 = CalcAbsolutePoint(rotate.y, dist);
endPosition += new Vector3(0, v3.y, 0);
RaycastHit hit;
if (Physics.Linecast(targetPos, endPosition, out hit))
{
string name = hit.collider.gameObject.tag;
// 将玩家的Tag设置为Player
if (!(name == "MainCamera" || name.StartsWith("Player")))
{
endPosition = hit.point - (endPosition - hit.point).normalized * 0.2f;
}
}
self.position = Vector3.Lerp(startPosition, endPosition, Time.deltaTime * moveSpeed);
Quaternion rotateQ = Quaternion.LookRotation(viewPoint - endPosition);
self.rotation = Quaternion.Slerp(transform.rotation, rotateQ, Time.deltaTime * moveSpeed);
}
public static Vector2 CalcAbsolutePoint(float angle, float dist)
{
float radian = -angle * (Mathf.PI / 180);
float x = dist * Mathf.Cos(radian);
float y = dist * Mathf.Sin(radian);
return new Vector2(x, y);
}