用比较简易的方法制作可以绕物体旋转的且可以避开障碍的摄像机.
Unity 3D 简易制作摄像机围绕物体随鼠标旋转效果
梗概:
一. 摄像机围绕目标物体旋转, 即摄像机离目标物体有一定的距离且旋转轴心为该物体的位置.
二. 当目标物体被障碍物挡住后, 需要将摄像机移动到障碍物前方能看见目标物体的位置.
思路:
一. 摄像机绕轴心旋转, 可以在轴心处创建一个空物体, 将摄像机设为该轴心的子物体. 如图:
这样便可以简单地实现摄像机旋转轴心 (注意: 旋转时应旋转轴心而不是单独旋转摄像机) . 还应注意, 如果摄像机的目标物体可以移动的话, 就应每帧将轴心的坐标设为目标物体的坐标 (尽量不要直接将轴心设为目标物体的子物体! 除非有特别需要) .
二. 当目标物体被障碍物挡住后, 可以在目标物体处发射一条射线, 射线原点就是目标物体的坐标 (也就是轴心) , 射线方向就是从原点到摄像机的方向. 此时射线的碰撞点就是将要把摄像机调整到的位置.
三. 当将摄像机移动到后方没有障碍物的位置时, 就应将摄像机移回至原距离.
过程:
- 创建任意目标物体;
- 创建一个空物体并命名, 这个空物体就是轴心, 并将其 Tag 设为 "3rdCameraAxle":
- 或者将其 Tag 设为你喜欢的一个都可以;
- 创建摄像机, 将其 Tag 设为 "MainCamera", 并设为刚创建的轴心的子物体;
- 创建任意障碍物.
代码:
一. 此时绕物体旋转摄像机便可简化为直接旋转轴心, 代码也简化了许多:
- 定义鼠标灵敏度:
public float mouseSensitivity = 2;
- 定义目标物体的 Transform
public Transform targetTrans;
- 定义轴心 Transform
Transform thirdPCamAxle;
Vector3 thirdPCamEuler;
在 void
void Start () {
thirdPCamAxle = GameObject.FindGameObjectWithTag("3rdCameraAxle").transform; //括号里的引号中也可以写上你自己对轴心设的 Tag.
thirdPCamEuler = thirdPCamAxle.localEulerAngles; //推荐写 localEulerAngles, 要不之后处理起来会比较麻烦.
}
- 定义摄像机:
Camera thirdPCam;
在 void
void Start () {
thirdPCam = Camera.main;
}
- 定义并赋值摄像机离物体的最大距离, 摄像机离物体的当前距离:
float camForwardMaxDistance = 9;
float camForwardDistance;
float camBackDistance;
- 在 void
thirdPCamAxle.position = targetTrans.position; //将摄像机旋转轴心位置设为目标物体位置
//定义旋转量
float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;
thirdPCamEuler.y += mouseX; //控制摄像机左右旋转
//控制摄像机上下旋转, 并且上下旋转范围不能超过90°或-90°, 此方法适用于 localEulerAngles.
if (thirdPCamEuler.z < 90 && mouseY > 0) { thirdPCamEuler.z += mouseY; }
if (thirdPCamEuler.z > -90 && mouseY < 0) { thirdPCamEuler.z += mouseY; }
thirdPCamAxle.localEulerAngles = thirdPCamEuler; //将旋转量应用到摄像机上.
至此, 控制摄像机旋转完成. 此部分代码如下:
1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;
4
5 public class ThirdPCamC : MonoBehaviour {
6 public float mouseSensitivity = 2;
7 public Transform targetTrans;
8
9 Transform thirdPCamAxle;
10 Vector3 thirdPCamEuler;
11
12 Camera thirdPCam;
13 float camForwardMaxDistance = 9;
14 float camForwardDistance;
15 float camBackDistance;
16
17 void Start () {
18 thirdPCamAxle = GameObject.FindGameObjectWithTag("3rdCameraAxle").transform;
19 thirdPCamEuler = thirdPCamAxle.localEulerAngles;
20
21 thirdPCam = Camera.main;
22 }
23
24 void Update () {
25 thirdPCamAxle.position = targetTrans.position;
26
27 float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
28 float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;
29 thirdPCamEuler.y += mouseX;
30 if (thirdPCamEuler.z < 90 && mouseY > 0) { thirdPCamEuler.z += mouseY; }
31 if (thirdPCamEuler.z > -90 && mouseY < 0) { thirdPCamEuler.z += mouseY; }
32 thirdPCamAxle.localEulerAngles = thirdPCamEuler;
33 }
34 }
二. 摄像机避开障碍物, 并在后方没有障碍物时移回原距离 (原距离可通过设置对 camForwardMaxDistance 的赋值来改变):
在 void
Ray camForwardRay = new Ray(thirdPCam.transform.position, thirdPCam.transform.forward); //在摄像机处发射一条向前的射线, 用来检测摄像机当前离目标的距离 (此处不必担心射线碰撞处是障碍物的情况).
RaycastHit forwardRayHit; //定义射线碰撞.
if (Physics.Raycast(camForwardRay, out forwardRayHit)) //当射线有碰撞物时 (也就是目标物体),
{
camForwardDistance = Vector3.Distance(thirdPCam.transform.position, forwardRayHit.point); //计算从摄像机到碰撞点的距离 (碰撞点也可以改为目标物体的位置).
}
Vector3 dir = thirdPCam.transform.position - targetTrans.position; //定义从目标物体到摄像机的方向.
dir = dir.normalized; //将方向单位化.
Ray ray = new Ray(targetTrans.position, dir); //在目标物体处发射一条射线, 方向即为刚刚定义的向量.
RaycastHit hit; //定义射线碰撞.
if (Physics.Raycast(ray, out hit)) //当该射线有碰撞, 即目标物体被障碍物挡住时,
{
thirdPCam.transform.position = hit.point; //将摄像机位置设为碰撞点位置.
}
else //如果没有碰撞, 即目标物体没有被障碍物挡住,
{
if (camForwardDistance < camForwardMaxDistance) //并且当前距离没有超过最大距离时,
{
thirdPCam.transform.Translate(Vector3.back * Time.deltaTime * 5); //将摄像机缓慢后移至最大距离.
}
}
全部代码如下:
1 using System.Collections;
2 using System.Collections.Generic;
3 using UnityEngine;
4
5 public class ThirdPCamC : MonoBehaviour {
6 public float mouseSensitivity = 2;
7 public Transform targetTrans;
8
9 Transform thirdPCamAxle;
10 Vector3 thirdPCamEuler;
11
12 Camera thirdPCam;
13 float camForwardMaxDistance = 9;
14 float camForwardDistance;
15 float camBackDistance;
16
17 void Start () {
18 thirdPCamAxle = GameObject.FindGameObjectWithTag("3rdCameraAxle").transform;
19 thirdPCamEuler = thirdPCamAxle.localEulerAngles;
20
21 thirdPCam = Camera.main;
22 }
23
24 void Update () {
25 thirdPCamAxle.position = targetTrans.position;
26
27 float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity;
28 float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity;
29 thirdPCamEuler.y += mouseX;
30 if (thirdPCamEuler.z < 90 && mouseY > 0) { thirdPCamEuler.z += mouseY; }
31 if (thirdPCamEuler.z > -90 && mouseY < 0) { thirdPCamEuler.z += mouseY; }
32 thirdPCamAxle.localEulerAngles = thirdPCamEuler;
33
34 Ray camForwardRay = new Ray(thirdPCam.transform.position, thirdPCam.transform.forward);
35 RaycastHit forwardRayHit;
36 if (Physics.Raycast(camForwardRay, out forwardRayHit))
37 {
38 camForwardDistance = Vector3.Distance(thirdPCam.transform.position, forwardRayHit.point);
39 }
40
41 Vector3 dir = thirdPCam.transform.position - targetTrans.position;;
42 dir = dir.normalized;
43 Ray ray = new Ray(targetTrans.position, dir);
44 RaycastHit hit;
45 if (Physics.Raycast(ray, out hit))
46 {
47 Debug.DrawLine(ray.origin, hit.point, Color.green);
48 thirdPCam.transform.position = hit.point;
49 }
50 else
51 {
52 if (camForwardDistance < camForwardMaxDistance)
53 {
54 thirdPCam.transform.Translate(Vector3.back * Time.deltaTime * 5);
55 }
56 }
57 }
58 }
最终效果图:
希望本篇教程能够帮到大家!
源码: [GitHub](https://github.com/JadMax/Unity3D-Miscellaneous/blob/master/ThirdpersonCameraController.cs)