The camera should have the functions of translating, following, rotating and zooming the field of view. Previously, the camera was placed at the lower node of the character to follow as a sub object of the character, but it was written dead:
After checking the Internet, I found that it is very convenient to use the camera to process according to the target:
First, there must be a targeted role:
/// <summary> ///Target role /// </summary> public Transform target;
You must also limit the elevation of the camera:
/// <summary> ///Minimum elevation /// </summary> //public float minAngle = 35; /// <summary> ///Maximum elevation degree /// </summary> public float maxAngle = 85; /// <summary> ///Initialize angle /// </summary> private float initAngle;
Then there is the camera's angle of view scaling: there must also be a range: it cannot exceed or approach 0:
ps: please ignore minAngle. In the end, minZAngle was used as the minimum angle. I wanted to do a function, but I didn't do it in the end
/// <summary> ///Distance between nearest camera and character /// </summary> public float minZ = 5f; /// <summary> ///Farthest distance between camera and character /// </summary> public float maxZ = 20f; /// <summary> ///Angle of shortest distance /// </summary> public float minZAngle = 10; /// <summary> ///Current distance of camera /// </summary> public float CurCameraDis;
Then record the horizontal offset value and the current vertical angle:
///Current angle /// </summary> public float CurCameraAngle; public float CurCameraAngleH;
First initialize the camera coordinates: because I use the camera behind the character as the benchmark
transform.position = target.position - target.forward;
First, get the distance between the camera and the character:
private void ZoomCamera() { //The mobile terminal -- should be gesture zoom -- hasn't been written yet if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer) { } else { //The computer uses the built-in mouse as the zoom trigger if (Input.GetAxis("Mouse ScrollWheel") != 0) { zoomValue = Input.GetAxis("Mouse ScrollWheel"); targDis = CurCameraDis - zoomValue * zoomSpeed; } } //Add a difference calculation to smooth scaling - from the current distance to the target distance CurCameraDis = Mathf.Lerp(CurCameraDis, targDis, Time.deltaTime * 10); //Limit scope CurCameraDis = Mathf.Clamp(CurCameraDis, minZ, maxZ); }
Then the vertical and horizontal offset values and angles are obtained according to the sliding screen:
Record the coordinates before and after the movement, and then subtract to obtain the corresponding x and y, corresponding to the horizontal offset value and vertical angle: finally, limit the range (only the vertical range needs to be limited)
private void SwipeScreen() { CurCameraAngleH = 0; if (Input.GetMouseButtonDown(0)) { oldMousePos = Vector2.zero; isMousePress = true; } else if (Input.GetMouseButtonUp(0)) { mousePosOffset = Vector2.zero; isMousePress = false; } if (!isMousePress) return; newMousePos = Input.mousePosition; if (oldMousePos != Vector2.zero) { mousePosOffset = newMousePos - oldMousePos; //vertical CurCameraAngle -= mousePosOffset.y * v_speed; //level CurCameraAngleH = mousePosOffset.x* h_speed; } oldMousePos = newMousePos; CurCameraAngle = Mathf.Clamp(CurCameraAngle, minZAngle, maxAngle); }
With the data, you can calculate the coordinates of the camera:
private void FollowPlayer() { if (target == null) return; //Use target position. y. The camera height is always based on the character's height, so that the character jumps and the camera will follow Vector3 camPosY = new Vector3(transform.position.x, target.position.y, transform.position.z); Vector3 targPos2D = new Vector3(target.position.x, target.position.y, target.position.z); //Rebuild coordinate system Vector3 m_forwld = (camPosY - targPos2D).normalized; Vector3 m_up = target.up; m_right = Vector3.Cross(m_forwld, m_up); //First vector -- vertical angle: around m_right axis rotation angle Quaternion rot = Quaternion.AngleAxis(CurCameraAngle, m_right); Vector3 dir = camPosY - target.position; //Vector matrix times vector dir = rot * dir; //The second vector based on the first vector -- rotates around the character's up axis Quaternion rotH = Quaternion.AngleAxis(CurCameraAngleH, m_up); Vector3 dirH = rotH * dir; //Start point + vector = end point: camera coordinates transform.position = target.position + dirH; //Debug.Log(rot + "---" + rotH); }
Finally, let the camera look at the character: there was a bug in the character you wanted to look at directly, and then calculate it yourself.
Then add the distance parameter of the camera: start point + vector * length = end point
transform.rotation = rota; Rota in calculates the lookat rotation
private void RotateCamera() { if (target == null) return; //lookat rotation Vector3 m_forwld = (target.position - transform.position).normalized; Vector3 m_up = Vector3.Cross(m_forwld, m_right); //Debug.Log(target.position + "---------" + transform.position); Quaternion rota = Quaternion.LookRotation(m_forwld, m_up); Debug.DrawRay(transform.position, m_forwld * 10, Color.red); Debug.DrawRay(transform.position, m_up * 10, Color.green); transform.position = target.position + (transform.position - target.position).normalized * CurCameraDis; transform.rotation = rota; }
Complete code: the mobile terminal can be commented out first, because I haven't tested it on the mobile terminal, and I haven't found any problems on the computer terminal. That is, when the scene enters, initialize the camera and assign the target. You need to manually call InitCamera() to initialize the camera.
using System.Collections; using System.Collections.Generic; using UnityEngine; public class PlayerCamera : MonoBehaviour { /// <summary> ///Target role /// </summary> public Transform target; /// <summary> ///Minimum elevation /// </summary> //public float minAngle = 35; /// <summary> ///Maximum elevation degree /// </summary> public float maxAngle = 85; /// <summary> ///Initialize angle /// </summary> private float initAngle; /// <summary> ///Distance between nearest camera and character /// </summary> public float minZ = 5f; /// <summary> ///Farthest distance between camera and character /// </summary> public float maxZ = 20f; /// <summary> ///Angle of shortest distance /// </summary> public float minZAngle = 10; /// <summary> ///Current distance of camera /// </summary> public float CurCameraDis; /// <summary> ///Current angle /// </summary> public float CurCameraAngle; public float CurCameraAngleH; /// <summary> ///Camera offset value /// </summary> public Vector2 mousePosOffset; public float initDic = 10; void Start() { InitCamera(); } // Update is called once per frame void Update() { //Mobile terminal if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer) { if (Input.touches[0].phase == TouchPhase.Began) { isDown = App.Instance.chickInRect(Input.touches[0].position); } } else { if (Input.GetMouseButtonDown(0)) { isDown = App.Instance.chickInRect(Input.mousePosition); } } ZoomCamera(); if (!isDown || Input.touches.Length >= 2) { SwipeScreen(); } } bool isDown = false; private void LateUpdate() { FollowPlayer(); RotateCamera(); } /// <summary> ///Initialize camera /// </summary> public void InitCamera() { if (target == null) return; initAngle = 40; CurCameraAngle = initAngle; mousePosOffset = Vector2.zero; transform.position = target.position - target.forward; targDis = CurCameraDis; isDown = false; } bool isMousePress = false; Vector2 oldMousePos; Vector2 newMousePos; public float v_speed = 0.2f; public float h_speed = 0.1f; private void SwipeScreen() { CurCameraAngleH = 0; //Mobile terminal if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer) { if (Input.touches.Length == 1 && Input.touches[0].phase == TouchPhase.Began|| Input.touches.Length >= 2 && Input.touches[1].phase == TouchPhase.Began) { oldMousePos = Vector2.zero; isMousePress = true; } else if (Input.touches.Length == 1 && Input.touches[0].phase == TouchPhase.Ended|| Input.touches.Length >= 2 && Input.touches[1].phase == TouchPhase.Ended) { mousePosOffset = Vector2.zero; isMousePress = false; } if (!isMousePress) return; if (Input.touches.Length == 1) { newMousePos = Input.touches[0].position; } else { newMousePos = Input.touches[1].position; } } else { if (Input.GetMouseButtonDown(0)) { oldMousePos = Vector2.zero; isMousePress = true; } else if (Input.GetMouseButtonUp(0)) { mousePosOffset = Vector2.zero; isMousePress = false; } if (!isMousePress) return; newMousePos = Input.mousePosition; } if (oldMousePos != Vector2.zero) { mousePosOffset = newMousePos - oldMousePos; //vertical CurCameraAngle -= mousePosOffset.y * v_speed; //level CurCameraAngleH = mousePosOffset.x* h_speed; } oldMousePos = newMousePos; CurCameraAngle = Mathf.Clamp(CurCameraAngle, minZAngle, maxAngle); } private float zoomValue; public float zoomSpeed = 20; float targDis; private void ZoomCamera() { if (Application.platform == RuntimePlatform.Android || Application.platform == RuntimePlatform.IPhonePlayer) { } else { if (Input.GetAxis("Mouse ScrollWheel") != 0) { zoomValue = Input.GetAxis("Mouse ScrollWheel"); targDis = CurCameraDis - zoomValue * zoomSpeed; } } CurCameraDis = Mathf.Lerp(CurCameraDis, targDis, Time.deltaTime * 10); CurCameraDis = Mathf.Clamp(CurCameraDis, minZ, maxZ); } Vector3 m_right; public float v_sa; private void FollowPlayer() { if (target == null) return; Vector3 camPosY = new Vector3(transform.position.x, target.position.y, transform.position.z); Vector3 targPos2D = new Vector3(target.position.x, target.position.y, target.position.z); //Rebuild coordinate system Vector3 m_forwld = (camPosY - targPos2D).normalized; Vector3 m_up = target.up; m_right = Vector3.Cross(m_forwld, m_up); //First root vector Quaternion rot = Quaternion.AngleAxis(CurCameraAngle, m_right); Vector3 dir = camPosY - target.position; dir = rot * dir; //Second root vector based on the first root vector Quaternion rotH = Quaternion.AngleAxis(CurCameraAngleH, m_up); Vector3 dirH = rotH * dir; transform.position = target.position + dirH; //Debug.Log(rot + "---" + rotH); } private void RotateCamera() { if (target == null) return; //lookat rotation Vector3 m_forwld = (target.position - transform.position).normalized; Vector3 m_up = Vector3.Cross(m_forwld, m_right); //Debug.Log(target.position + "---------" + transform.position); Quaternion rota = Quaternion.LookRotation(m_forwld, m_up); Debug.DrawRay(transform.position, m_forwld * 10, Color.red); Debug.DrawRay(transform.position, m_up * 10, Color.green); //Distance measurement //if (transform.position == Vector3.zero && CurCameraAngle == 90) //{ // rota = Quaternion.LookRotation(-target.up, target.forward); // transform.position = target.position + target.up * CurCameraDis; //} //else //{ transform.position = target.position + (transform.position - target.position).normalized * CurCameraDis; //} transform.rotation = rota; } }
Reference: camera perspective operation in making large MMO projects
Learn a little QAQ every day and give me a praise. I will be very happy