RPG角色相机控制

using UnityEngine;
using System.Collections;

public class RPG_Camera : MonoBehaviour {

public static RPG_Camera instance;

public Transform cameraPivot;//相对人物的位置参考点,可以在任务头顶上
public float distance = 5f;
public float distanceMax = 30f;
public float mouseSpeed = 8f;
public float mouseScroll = 15f;
public float mouseSmoothingFactor = 0.08f;
public float camDistanceSpeed = 0.7f;
public float camBottomDistance = 1f;
public float firstPersonThreshold = 0.8f;
public float characterFadeThreshold = 1.8f;

private Vector3 desiredPosition;
private float desiredDistance;
private float lastDistance;
private float mouseX = 0f;
private float mouseXSmooth = 0f;
private float mouseXVel;
private float mouseY = 0f;
private float mouseYSmooth = 0f;
private float mouseYVel;
private float mouseYMin = -89.5f;
private float mouseYMax = 89.5f;
private float distanceVel;
private bool camBottom;
private bool constraint;

private static float halfFieldOfView;
private static float planeAspect;
private static float halfPlaneHeight;
private static float halfPlaneWidth;

 

void Awake() {
instance = this;
}


void Start() {
distance = Mathf.Clamp(distance, 0.05f, distanceMax);
desiredDistance = distance;

halfFieldOfView = (Camera.main.fieldOfView / 2) * Mathf.Deg2Rad;
planeAspect = Camera.main.aspect;
halfPlaneHeight = Camera.main.nearClipPlane * Mathf.Tan(halfFieldOfView);
halfPlaneWidth = halfPlaneHeight * planeAspect;

mouseX = 0f;
mouseY = 15f;
}


public static void CameraSetup() {
GameObject cameraUsed;
GameObject cameraPivot;
RPG_Camera cameraScript;

if (Camera.main != null)
cameraUsed = Camera.main.gameObject;
else {
cameraUsed = new GameObject("Main Camera");
cameraUsed.AddComponent<Camera>();
cameraUsed.tag = "MainCamera";
}

if (!cameraUsed.GetComponent("RPG_Camera"))
cameraUsed.AddComponent<RPG_Camera>();
cameraScript = cameraUsed.GetComponent("RPG_Camera") as RPG_Camera;

cameraPivot = GameObject.Find("cameraPivot") as GameObject;
cameraScript.cameraPivot = cameraPivot.transform;
}


void LateUpdate() {
if (cameraPivot == null) {
Debug.Log("Error: No cameraPivot found! Please read the manual for further instructions.");
return;
}

GetInput();

GetDesiredPosition();

PositionUpdate();

CharacterFade();
}


void GetInput() {

if (distance > 0.1) { // distance > 0.05 would be too close, so 0.1 is fine
Debug.DrawLine(transform.position, transform.position - Vector3.up * camBottomDistance, Color.green);
camBottom = Physics.Linecast(transform.position, transform.position - Vector3.up * camBottomDistance);
}

bool constrainMouseY = camBottom && transform.position.y - cameraPivot.transform.position.y <= 0;

if (Input.GetMouseButton(0) || Input.GetMouseButton(1)) {
Cursor.visible = false; // if you want the cursor behavior of the version 1.0, change this line to "Screen.lockCursor = true;"

mouseX += Input.GetAxis("Mouse X") * mouseSpeed;

if (constrainMouseY) {
if (Input.GetAxis("Mouse Y") < 0)
mouseY -= Input.GetAxis("Mouse Y") * mouseSpeed;
} else
mouseY -= Input.GetAxis("Mouse Y") * mouseSpeed;
} else
Cursor.visible = true; // if you want the cursor behavior of the version 1.0, change this line to "Screen.lockCursor = false;"

mouseY = ClampAngle(mouseY, -89.5f, 89.5f);
mouseXSmooth = Mathf.SmoothDamp(mouseXSmooth, mouseX, ref mouseXVel, mouseSmoothingFactor);
mouseYSmooth = Mathf.SmoothDamp(mouseYSmooth, mouseY, ref mouseYVel, mouseSmoothingFactor);

if (constrainMouseY)
mouseYMin = mouseY;
else
mouseYMin = -89.5f;

mouseYSmooth = ClampAngle(mouseYSmooth, mouseYMin, mouseYMax);


if (Input.GetMouseButton(1))
RPG_Controller.instance.transform.rotation = Quaternion.Euler(RPG_Controller.instance.transform.eulerAngles.x, Camera.main.transform.eulerAngles.y, RPG_Controller.instance.transform.eulerAngles.z);

desiredDistance = desiredDistance - Input.GetAxis("Mouse ScrollWheel") * mouseScroll;

if (desiredDistance > distanceMax)
desiredDistance = distanceMax;

if (desiredDistance < 0.05)
desiredDistance = 0.05f;
}


void GetDesiredPosition() {
distance = desiredDistance;
desiredPosition = GetCameraPosition(mouseYSmooth, mouseXSmooth, distance);

float closestDistance;
constraint = false;

closestDistance = CheckCameraClipPlane(cameraPivot.position, desiredPosition);

if (closestDistance != -1) {
distance = closestDistance;
desiredPosition = GetCameraPosition(mouseYSmooth, mouseXSmooth, distance);

constraint = true;
}


distance -= Camera.main.nearClipPlane;

if (lastDistance < distance || !constraint)
distance = Mathf.SmoothDamp(lastDistance, distance, ref distanceVel, camDistanceSpeed);

if (distance < 0.05)
distance = 0.05f;

lastDistance = distance;

desiredPosition = GetCameraPosition(mouseYSmooth, mouseXSmooth, distance); // if the camera view was blocked, then this is the new "forced" position
}


void PositionUpdate() {
transform.position = desiredPosition;

if (distance > 0.05)
transform.LookAt(cameraPivot);
}


void CharacterFade() {
if (RPG_Animation.instance == null)
return;

if (distance < firstPersonThreshold)
RPG_Animation.instance.GetComponent<Renderer>().enabled = false;

else if (distance < characterFadeThreshold) {
RPG_Animation.instance.GetComponent<Renderer>().enabled = true;

float characterAlpha = 1 - (characterFadeThreshold - distance) / (characterFadeThreshold - firstPersonThreshold);
if (RPG_Animation.instance.GetComponent<Renderer>().material.color.a != characterAlpha)
RPG_Animation.instance.GetComponent<Renderer>().material.color = new Color(RPG_Animation.instance.GetComponent<Renderer>().material.color.r, RPG_Animation.instance.GetComponent<Renderer>().material.color.g, RPG_Animation.instance.GetComponent<Renderer>().material.color.b, characterAlpha);

} else {

RPG_Animation.instance.GetComponent<Renderer>().enabled = true;

if (RPG_Animation.instance.GetComponent<Renderer>().material.color.a != 1)
RPG_Animation.instance.GetComponent<Renderer>().material.color = new Color(RPG_Animation.instance.GetComponent<Renderer>().material.color.r, RPG_Animation.instance.GetComponent<Renderer>().material.color.g, RPG_Animation.instance.GetComponent<Renderer>().material.color.b, 1);
}
}


Vector3 GetCameraPosition(float xAxis, float yAxis, float distance) {
Vector3 offset = new Vector3(0, 0, -distance);
Quaternion rotation = Quaternion.Euler(xAxis, yAxis, 0);
return cameraPivot.position + rotation * offset;
}


float CheckCameraClipPlane(Vector3 from, Vector3 to) {
var closestDistance = -1f;

RaycastHit hitInfo;

ClipPlaneVertexes clipPlane = GetClipPlaneAt(to);

Debug.DrawLine(clipPlane.UpperLeft, clipPlane.UpperRight);
Debug.DrawLine(clipPlane.UpperRight, clipPlane.LowerRight);
Debug.DrawLine(clipPlane.LowerRight, clipPlane.LowerLeft);
Debug.DrawLine(clipPlane.LowerLeft, clipPlane.UpperLeft);

Debug.DrawLine(from, to, Color.red);
Debug.DrawLine(from - transform.right * halfPlaneWidth + transform.up * halfPlaneHeight, clipPlane.UpperLeft, Color.cyan);
Debug.DrawLine(from + transform.right * halfPlaneWidth + transform.up * halfPlaneHeight, clipPlane.UpperRight, Color.cyan);
Debug.DrawLine(from - transform.right * halfPlaneWidth - transform.up * halfPlaneHeight, clipPlane.LowerLeft, Color.cyan);
Debug.DrawLine(from + transform.right * halfPlaneWidth - transform.up * halfPlaneHeight, clipPlane.LowerRight, Color.cyan);


if (Physics.Linecast(from, to, out hitInfo) && hitInfo.collider.tag != "Player")
closestDistance = hitInfo.distance - Camera.main.nearClipPlane;

if (Physics.Linecast(from - transform.right * halfPlaneWidth + transform.up * halfPlaneHeight, clipPlane.UpperLeft, out hitInfo) && hitInfo.collider.tag != "Player")
if (hitInfo.distance < closestDistance || closestDistance == -1)
closestDistance = Vector3.Distance(hitInfo.point + transform.right * halfPlaneWidth - transform.up * halfPlaneHeight, from);

if (Physics.Linecast(from + transform.right * halfPlaneWidth + transform.up * halfPlaneHeight, clipPlane.UpperRight, out hitInfo) && hitInfo.collider.tag != "Player")
if (hitInfo.distance < closestDistance || closestDistance == -1)
closestDistance = Vector3.Distance(hitInfo.point - transform.right * halfPlaneWidth - transform.up * halfPlaneHeight, from);

if (Physics.Linecast(from - transform.right * halfPlaneWidth - transform.up * halfPlaneHeight, clipPlane.LowerLeft, out hitInfo) && hitInfo.collider.tag != "Player")
if (hitInfo.distance < closestDistance || closestDistance == -1)
closestDistance = Vector3.Distance(hitInfo.point + transform.right * halfPlaneWidth + transform.up * halfPlaneHeight, from);

if (Physics.Linecast(from + transform.right * halfPlaneWidth - transform.up * halfPlaneHeight, clipPlane.LowerRight, out hitInfo) && hitInfo.collider.tag != "Player")
if (hitInfo.distance < closestDistance || closestDistance == -1)
closestDistance = Vector3.Distance(hitInfo.point - transform.right * halfPlaneWidth + transform.up * halfPlaneHeight, from);


return closestDistance;
}


float ClampAngle(float angle, float min, float max) {
while (angle < -360 || angle > 360) {
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
}

return Mathf.Clamp(angle, min, max);
}


public struct ClipPlaneVertexes {
public Vector3 UpperLeft;
public Vector3 UpperRight;
public Vector3 LowerLeft;
public Vector3 LowerRight;
}


public static ClipPlaneVertexes GetClipPlaneAt(Vector3 pos) {
var clipPlane = new ClipPlaneVertexes();

if (Camera.main == null)
return clipPlane;

Transform transform = Camera.main.transform;
float offset = Camera.main.nearClipPlane;

clipPlane.UpperLeft = pos - transform.right * halfPlaneWidth;
clipPlane.UpperLeft += transform.up * halfPlaneHeight;
clipPlane.UpperLeft += transform.forward * offset;

clipPlane.UpperRight = pos + transform.right * halfPlaneWidth;
clipPlane.UpperRight += transform.up * halfPlaneHeight;
clipPlane.UpperRight += transform.forward * offset;

clipPlane.LowerLeft = pos - transform.right * halfPlaneWidth;
clipPlane.LowerLeft -= transform.up * halfPlaneHeight;
clipPlane.LowerLeft += transform.forward * offset;

clipPlane.LowerRight = pos + transform.right * halfPlaneWidth;
clipPlane.LowerRight -= transform.up * halfPlaneHeight;
clipPlane.LowerRight += transform.forward * offset;


return clipPlane;
}


public void RotateWithCharacter() {
float rotation = Input.GetAxis("Horizontal") * RPG_Controller.instance.turnSpeed;
mouseX += rotation;
}
}

posted @ 2015-07-15 09:52  小歪歪Frank  阅读(403)  评论(0编辑  收藏  举报