using UnityEngine; using System.Collections; using UnityEngine.EventSystems; using System.Collections.Generic; public class CameraController :MonoBehaviour { public bool m_isScale = true; #region fpp /// /// 转到第一人称视角 /// public bool m_fpp; /// /// 第一人称视角偏差 /// public Vector3 m_fppOffset; /// /// 跟随老师 /// public bool FollowTeacher; private bool m_followTeacher; #endregion public Transform Target; public float distance = 8.0f; public float xSpeed = 70.0f; public float ySpeed = 50.0f; public float yMinLimit = 0f; public float yMaxLimit = 90f; public float distanceMin = 8f; public float distanceMax = 15f; public float zoomSpeed = 0.5f; private float x = 0.0f; private float y = 0.0f; private float fx = 0f; private float fy = 0f; private float fDistance = 0; int m_fingerId = -1; // 当摇杆移动,控制镜头的手指 bool m_isClickUi = false; Dictionary m_dicTouch = new Dictionary(); //key 为fingerid ,value为是否接触到UI Transform m_trans; float t = 0.2f; public float m_minDis = 1.0f; public bool m_isNear = false; [Header("God Mode")] public bool God; //上帝模式 public float GodSpeed = 10; public float Sprint = 1.5f; public Vector3 MinClamp = new Vector3(0,12,0); public Vector3 MaxClamp = new Vector3(160,20,160); public Vector2 RollClamp = new Vector2(-45, 90); public Rigidbody _rigidbody; // Use this for initialization void Start() { _rigidbody = GetComponent(); m_trans = this.transform; Vector3 angles = transform.eulerAngles; x = angles.y; y = angles.x; fx = x; fy = y; UpdateRotaAndPos(); fDistance = distance; } void Update() { if (Input.touchCount == 0)//当前没有手指,全部初始化 { m_fingerId = -1; m_dicTouch.Clear(); } if (Input.touchCount == 1) { List deleteFinger = new List(); foreach (var item in m_dicTouch) { if (item.Key != Input.GetTouch(0).fingerId) { deleteFinger.Add(item.Key); } } //删除m_dicTouch非当前单指的item项目--》得到结果就是m_dicTouch只有当前单指或者啥也没有 for (int i = 0; i < deleteFinger.Count; i++) { //Debug.Log("单指:删除:" + deleteFinger[i]); m_dicTouch.Remove(deleteFinger[i]); } switch (Input.GetTouch(0).phase) { case TouchPhase.Began: if (EventSystem.current.IsPointerOverGameObject(Input.GetTouch(0).fingerId)) { //Debug.Log("单指:增加true:" + Input.GetTouch(0).fingerId); m_dicTouch[Input.GetTouch(0).fingerId] = true; //如果按在ui上为true } else { //Debug.Log("单指:增加false:" + Input.GetTouch(0).fingerId); m_dicTouch[Input.GetTouch(0).fingerId] = false; } break; case TouchPhase.Moved: break; case TouchPhase.Stationary: break; case TouchPhase.Ended: break; case TouchPhase.Canceled: break; default: break; } } if (Input.touchCount == 2) { List deleteFinger = new List(); foreach (var item in m_dicTouch) { bool isDelete = true; for (int i = 0; i < Input.touchCount; i++) { if (item.Key == Input.touches[i].fingerId) { isDelete = false; break; } } if (isDelete == true) { deleteFinger.Add(item.Key); } } //删除m_dicTouch里面非现在按下的两个手指--》得到的结果:m_dicTouch里有一个现在按下手指中的0-2个 for (int i = 0; i < deleteFinger.Count; i++) { //Debug.Log("双指:删除:" + deleteFinger[i]); m_dicTouch.Remove(deleteFinger[i]); } for (int i = 0; i < Input.touchCount; i++) { switch (Input.touches[i].phase) { case TouchPhase.Began: if (EventSystem.current.IsPointerOverGameObject(Input.touches[i].fingerId)) { //Debug.Log("双指:增加true:" + Input.touches[i].fingerId); m_dicTouch[Input.touches[i].fingerId] = true; } else { //Debug.Log("双指:增加false:" + Input.touches[i].fingerId); m_dicTouch[Input.touches[i].fingerId] = false; } break; case TouchPhase.Moved: break; case TouchPhase.Stationary: break; case TouchPhase.Ended: break; case TouchPhase.Canceled: break; default: break; } } if (IsCanScale() == true && m_isScale == true) { Touch touchZero = Input.GetTouch(0); Touch touchOne = Input.GetTouch(1); // 上一帧每个点位置 Vector2 touchZeroPrevPos = touchZero.position - touchZero.deltaPosition; Vector2 touchOnePrevPos = touchOne.position - touchOne.deltaPosition; //上一帧两点距离的平方,不要做平方根运算,消耗大 float prevTouchDeltaMag = (touchZeroPrevPos - touchOnePrevPos).magnitude; //这一帧两点距离的平方 float touchDeltaMag = (touchZero.position - touchOne.position).magnitude; // Find the difference in the distances between each frame. float deltaMagnitudeDiff = prevTouchDeltaMag - touchDeltaMag; fDistance = Mathf.Clamp(distance + deltaMagnitudeDiff * zoomSpeed, distanceMin, distanceMax); } } if (Application.isMobilePlatform == false && m_isScale == true) { if (Input.GetAxis("Mouse ScrollWheel") > 0) { fDistance = Mathf.Clamp(distance - zoomSpeed, distanceMin, distanceMax); } else if (Input.GetAxis("Mouse ScrollWheel") < 0) { fDistance = Mathf.Clamp(distance + zoomSpeed, distanceMin, distanceMax); } } distance = Mathf.Lerp(distance, fDistance, 0.25f); } private void FixedUpdate() { Move(); } private void Move() { if (Application.isMobilePlatform) { if (/*Input.GetMouseButton(1) &&*/ IsCanRotate()) { Touch input = new Touch(); for (int i = 0; i < Input.touchCount; i++) { if (Input.touches[i].fingerId == m_fingerId) { input = Input.touches[i];//找到控制镜头移动的手指 } } if (God) { if (Target) { if (Input.touchCount > 0 && input.phase == TouchPhase.Moved) { float dx = input.deltaPosition.x; float dy = input.deltaPosition.y; x -= dx * xSpeed * Time.deltaTime; y += dy * ySpeed * Time.deltaTime; y = ClampAngle(y, RollClamp.x, RollClamp.y); } } } else { if (Input.touchCount > 0 && input.phase == TouchPhase.Moved) { float dx = input.deltaPosition.x; float dy = input.deltaPosition.y; x -= dx * xSpeed * Time.deltaTime; y += dy * ySpeed * Time.deltaTime; y = ClampAngle(y, yMinLimit, yMaxLimit); } } } } else { if (Input.GetMouseButtonDown(1)) { if (EventSystem.current.IsPointerOverGameObject()) { m_isClickUi = true; } } if (Input.GetMouseButtonUp(0)) { m_isClickUi = false; } if (m_isClickUi == false && Input.GetMouseButton(1)) { if (God) { if (Target) { float dx = Input.GetAxis("Mouse X"); float dy = Input.GetAxis("Mouse Y"); x += dx * xSpeed * 20 * Time.deltaTime;//*distance y -= dy * ySpeed * 20 * Time.deltaTime; y = ClampAngle(y, RollClamp.x, RollClamp.y); } } else { float dx = Input.GetAxis("Mouse X"); float dy = Input.GetAxis("Mouse Y"); x += dx * xSpeed * 20 * Time.deltaTime;//*distance y -= dy * ySpeed * 20 * Time.deltaTime; y = ClampAngle(y, yMinLimit, yMaxLimit); } } } fx = Mathf.Lerp(fx, x, 0.2f); fy = Mathf.Lerp(fy, y, 0.2f); UpdateRotaAndPos(); } void UpdateRotaAndPos() { if (God) { float godspeed = (UtilitiesInput.Sprint ? GodSpeed * Sprint : GodSpeed) * Time.deltaTime; //transform.Translate(Vector3.forward * UtilitiesInput.Vertical * godspeed, Space.Self); //transform.Translate(Vector3.right * UtilitiesInput.Horizontal * godspeed, Space.Self); Vector3 dir = transform.forward * UtilitiesInput.Vertical + transform.right * UtilitiesInput.Horizontal; GodMoveCamera(dir, godspeed); if (UtilitiesInput.Down) transform.Translate(Vector3.down * godspeed, Space.World); if (UtilitiesInput.Up) transform.Translate(Vector3.up * godspeed, Space.World); Vector3 trans = transform.position; transform.position = new Vector3(Mathf.Clamp(trans.x, MinClamp.x, MaxClamp.x), Mathf.Clamp(trans.y, MinClamp.y, MaxClamp.y), Mathf.Clamp(trans.z, MinClamp.z, MaxClamp.z)); Quaternion rotation = Quaternion.Euler(fy, fx, 0); Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance); Vector3 position = rotation * negDistance + Target.position; //摄像头的位置为 移动后角度*距离 + 目标位置 transform.rotation = rotation; } else { if (Target) { bool isCurHit = false; Quaternion rotation = Quaternion.Euler(fy, fx, 0); Vector3 negDistance = new Vector3(0.0f, 0.0f, -distance); Vector3 position = rotation * negDistance + Target.position; //摄像头的位置为 移动后角度*距离 + 目标位置 Vector3 canSetPos = position; //m_trans.position = position; //Debug.DrawLine(target.position, m_trans.position, Color.red); //主角朝着这个方向发射射线 RaycastHit hit; if (Physics.Linecast(Target.position, position, out hit)) { //Debug.Log("摄像机碰到:" + hit.collider.gameObject); bool adjust = true; Renderer renderer = hit.transform.GetComponent(); if (renderer == null) adjust = false; if (renderer != null && !renderer.enabled) adjust = false; if (adjust) { //当碰撞的不是摄像机也不是地形 那么直接移动摄像机的坐标 Vector3 posHit = hit.point; Vector3 dir = posHit - Target.position; //Vector3 posEnd = posHit - dir * 0.5f; canSetPos = posHit - dir * 0.5f; isCurHit = true; //m_trans.position = posEnd; //m_trans.position = position; } } //摄像机与地面的检测,不要穿过地 if (canSetPos.y < Target.parent.position.y) { //Debug.Log("摄像机碰到了地"); canSetPos.y = Target.parent.position.y; Vector3 relativePos = Target.position - canSetPos; rotation = Quaternion.LookRotation(relativePos); isCurHit = true; } //float oldDis = (m_trans.position - target.position).sqrMagnitude; //float newDis = (canSetPos - target.position).sqrMagnitude; //if ((isCurHit == false && m_isLastHit == false) || (isCurHit == true && m_isLastHit == false) || (isCurHit == true && m_isLastHit == true)) //拉进是突进 //{ // m_trans.position = canSetPos; //} //else if (m_isLastHit == true && isCurHit == false) //{ // Debug.Log("镜头远离墙体"); // Vector3 mainCamPos = m_trans.position; // Vector3 newPos = Vector3.Lerp(mainCamPos, canSetPos, getCurrentDeltaTime() * movementLerpSpeed); // m_trans.position = newPos; //} m_trans.position = m_fpp ? Target.position + m_fppOffset : canSetPos; m_trans.rotation = rotation; } } } public virtual void GodMoveCamera(Vector3 _direction,float speed) { if (!God) return; _direction.y = 0; _direction.x = Mathf.Clamp(_direction.x, -1f, 1f); _direction.z = Mathf.Clamp(_direction.z, -1f, 1f); // limit the input if (_direction.magnitude > 1f) _direction.Normalize(); Vector3 targetPosition = _rigidbody.position + _direction * speed; Vector3 targetVelocity = (targetPosition - transform.position) / Time.deltaTime; bool useVerticalVelocity = true; if (useVerticalVelocity) targetVelocity.y = _rigidbody.velocity.y; _rigidbody.velocity = targetVelocity; } public static float ClampAngle(float angle, float min, float max) { if (angle < -360F) angle += 360F; if (angle > 360F) angle -= 360F; return Mathf.Clamp(angle, min, max); } /// /// 是否可以旋转 /// /// bool IsCanRotate() { bool ret = false; if (m_dicTouch.Count == 1) //只有一个手指按下,并且没按在UI上 { foreach (var item in m_dicTouch) { if (item.Value == false) { ret = true; m_fingerId = item.Key; } } } else { //当有两个手指按下,一个手指在UI(包含在UI摇杆)上,一个手指没在,可以移动镜头 int inUI = 0; int outUI = 0; foreach (var item in m_dicTouch) { if (item.Value == true) { inUI++; } else { outUI++; m_fingerId = item.Key; } } if (inUI == 1 && outUI == 1) { ret = true; } } return ret; } //何时才能双指控制缩放-->两个手指都没按在UI上 bool IsCanScale() { bool ret = true; if (m_dicTouch.Count == 2) { foreach (var item in m_dicTouch) { if (item.Value == true) { ret = false; break; } } } return ret; } }