同样是先看需求:
整个地方最难的在于,相机被挤压时要怎么处理。
由于没玩过上面两款游戏,也不知道是怎么处理的,我自己的想法是让相机直接旋转180度。
首先贴一下人物控制脚本,别忘了给人物加上Charactor Controll组件
using UnityEngine; using System.Collections; public class move_controll : MonoBehaviour { Transform m_transform,m_camera; CharacterController controller; float MoveSpeed = 1.0f; string[] clipName={"idle","shamble"}; Animation m_animation; // Use this for initialization void Start () { m_transform = this.transform; m_camera = GameObject.FindGameObjectWithTag ("MainCamera").transform; controller=GetComponent(); m_animation = m_transform.GetComponent (); } // Update is called once per frame void Update () { if ((Input.GetKey (KeyCode.W)) || (Input.GetKey (KeyCode.S)) || (Input.GetKey (KeyCode.A)) || (Input.GetKey (KeyCode.D))) { m_animation.Play (clipName[1]); if (Input.GetKey (KeyCode.W)) { controller.transform.eulerAngles = new Vector3 (0, m_camera.transform.eulerAngles.y, 0);//the eulerAngles depend on camera's eulerAngles } if (Input.GetKey (KeyCode.S)) { controller.transform.eulerAngles = new Vector3 (0, m_camera.transform.eulerAngles.y+180f, 0); } if (Input.GetKey (KeyCode.A)) { controller.transform.eulerAngles = new Vector3 (0, m_camera.transform.eulerAngles.y+270f, 0); } if (Input.GetKey (KeyCode.D)) { controller.transform.eulerAngles = new Vector3 (0, m_camera.transform.eulerAngles.y+90f, 0); } controller.Move(m_transform.forward * Time.deltaTime * MoveSpeed); } else //idle m_animation.Play (clipName[0]); //gravity if (!controller.isGrounded) { controller.Move(new Vector3(0,-10f*Time.deltaTime,0)); } } }
随后是相机控制,这里提供两个版本,一个是用滚轮控制镜头远近的(我从别的地方抄的):
// ==================================================================================================================== // Simple rotation and tilt of camera around a pivot object // Created by Leslie Young // http://www.plyoung.com/ or http://plyoung.wordpress.com/ // ==================================================================================================================== using UnityEngine; public class CameraOrbit : MonoBehaviour { public Transform pivot; // the object being followed public Vector3 pivotOffset = Vector3.zero; // offset from target's pivot public Transform target; // like a selected object (used with checking if objects between cam and target) public float distance = 10.0f; // distance from target (used with zoom) public float minDistance = 2f; public float maxDistance = 15f; public float zoomSpeed = 1f; public float xSpeed = 250.0f; public float ySpeed = 120.0f; public bool allowYTilt = true; public float yMinLimit = 30f; public float yMaxLimit = 80f; private float x = 0.0f; private float y = 0.0f; private float targetX = 0f; private float targetY = 0f; private float targetDistance = 0f; private float xVelocity = 1f; private float yVelocity = 1f; private float zoomVelocity = 1f; void Start() { var angles = transform.eulerAngles; targetX = x = angles.x; targetY = y = ClampAngle(angles.y, yMinLimit, yMaxLimit); targetDistance = distance; } void LateUpdate() { if (pivot) { // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // scroll wheel used to zoom in/out float scroll = Input.GetAxis("Mouse ScrollWheel"); if (scroll > 0.0f) targetDistance -= zoomSpeed; else if (scroll < 0.0f) targetDistance += zoomSpeed; targetDistance = Mathf.Clamp(targetDistance, minDistance, maxDistance); // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // right mouse button must be held down to tilt/rotate cam // or player can use the left mouse button while holding Ctr if (Input.GetMouseButton(1) || (Input.GetMouseButton(0) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) )) { targetX += Input.GetAxis("Mouse X") * xSpeed * 0.02f; if (allowYTilt) { targetY -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f; targetY = ClampAngle(targetY, yMinLimit, yMaxLimit); } } x = Mathf.SmoothDampAngle(x, targetX, ref xVelocity, 0.3f); if (allowYTilt) y = Mathf.SmoothDampAngle(y, targetY, ref yVelocity, 0.3f); else y = targetY; Quaternion rotation = Quaternion.Euler(y, x, 0); distance = Mathf.SmoothDamp(distance, targetDistance, ref zoomVelocity, 0.5f); // -=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=- // apply Vector3 position = rotation * new Vector3(0.0f, 0.0f, -distance) + pivot.position + pivotOffset; transform.rotation = rotation; transform.position = position; } } private float ClampAngle(float angle, float min, float max) { if (angle < -360) angle += 360; if (angle > 360) angle -= 360; return Mathf.Clamp(angle, min, max); } // ==================================================================================================================== }
然后我以这个脚本为基础来该,首先是人物被遮挡时,相机要拉近:
采用射线的方式进行检测:
RaycastHit hit;//ues a ray to make camera not be blocked if (Physics.Linecast (position, pivot.position,out hit)) { string name = hit.collider.gameObject.tag; if (name =="Untagged") { targetDistance=(hit.point-pivot.position).magnitude;//if the hit object's tag is Untagged,change the distance } }
然后是相机被挤压导致距离极低时的旋转:
if (distance > distanceLimit) { position = rotation * new Vector3 (0.0f, 0.0f, -distance) + pivot.position + pivotOffset; } else { rotation = Quaternion.Euler(y, x+180f, 0); position = rotation * new Vector3 (0.0f, 0.0f, -m_distance) + pivot.position + pivotOffset; targetX = targetX + 180; x = x + 180; }
整个脚本:
using UnityEngine; using System.Collections; public class Camera_Controll : MonoBehaviour { public Transform pivot; public Vector3 pivotOffset = Vector3.zero; public float distance = 10.0f; // distance from target (used with zoom) public float distanceLimit=3f;//distance when camera change Angles for 180 public float zoomSpeed = 1f; public float xSpeed = 250.0f; public float ySpeed = 120.0f; public bool allowYTilt = true; public float yMinLimit = -60f; public float yMaxLimit = 60f; private float x = 0.0f; private float y = 0.0f; private float targetX = 0f; private float targetY = 0f; private float targetDistance = 0f; private float xVelocity = 1f; private float yVelocity = 1f; private float zoomVelocity = 1f; private float m_distance; // Use this for initialization void Start () { var angles = transform.eulerAngles; targetX = x = angles.x; targetY = y = ClampAngle(angles.y, yMinLimit, yMaxLimit); targetDistance = distance; m_distance = distance; } // Update is called once per frame void LateUpdate () { if (pivot) { targetDistance = m_distance; if (Input.GetMouseButton(1) || (Input.GetMouseButton(0) && (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) )) { targetX += Input.GetAxis("Mouse X") * xSpeed * 0.02f; if (allowYTilt) { targetY -= Input.GetAxis("Mouse Y") * ySpeed * 0.02f; targetY = ClampAngle(targetY, yMinLimit, yMaxLimit); } } x = Mathf.SmoothDampAngle(x, targetX, ref xVelocity, 0.3f); if (allowYTilt) y = Mathf.SmoothDampAngle(y, targetY, ref yVelocity, 0.3f); else y = targetY; Quaternion rotation = Quaternion.Euler(y, x, 0); Vector3 position = rotation * new Vector3(0.0f, 0.0f, -m_distance) + pivot.position;//calculate the true camera positon RaycastHit hit;//ues a ray to make camera not be blocked if (Physics.Linecast (position, pivot.position,out hit)) { string name = hit.collider.gameObject.tag; if (name =="Untagged") { targetDistance=(hit.point-pivot.position).magnitude;//if the hit object's tag is Untagged,change the distance } } distance = Mathf.SmoothDamp(distance, targetDistance, ref zoomVelocity, 0.5f); if (distance > distanceLimit) { position = rotation * new Vector3 (0.0f, 0.0f, -distance) + pivot.position + pivotOffset; } else { rotation = Quaternion.Euler(y, x+180f, 0); position = rotation * new Vector3 (0.0f, 0.0f, -m_distance) + pivot.position + pivotOffset; targetX = targetX + 180; x = x + 180; } transform.rotation = rotation; transform.position = position; } } private float ClampAngle(float angle, float min, float max) { if (angle < -360) angle += 360; if (angle > 360) angle -= 360; return Mathf.Clamp(angle, min, max); } }