using UnityEngine;
using System.Collections;
using UnityEngine.EventSystems;
using UnityEngine.UI;
using UnityEngine.PostProcessing;
using System.Collections.Generic;
using System;
using DTools;
public class PlayerCamera : MonoBehaviour
{
public Transform mTarget;
private GameObject m_goPivot;
public Camera m_camPlayer;
[Tooltip("x:最小;y:最大")]
public Vector2 mDistance = new Vector2(3f, 10f);
public float mf_HorizontalRotSpeed = 3.0f;
public float mf_VerticalRotSpeed = 2.0f;
/// <summary>
/// 垂直方向旋转限制
/// </summary>
[Tooltip("x:最小;y:最大")]
public Vector2 mVerticalRotLimit = new Vector2(-20f,80f);
/// <summary>
/// 移动延迟
/// </summary>
public float mMoveDelay =10.0f;
public bool isReset = false;
public static PlayerCamera m_instance;
public static PlayerCamera Instance
{
get
{
if (m_instance == null)
{
m_instance = new GameObject("PlayerCamera").AddComponent<PlayerCamera>();
m_instance.gameObject.AddComponent<DontDestroyOnLoadScript>();
m_instance.InitCamera();
m_instance.ResetPos();
}
return m_instance;
}
}
//ProtectCameraFromWallClip protectCamera;
public float clipMoveTime = 0.04f; // time taken to move when avoiding cliping (low value = fast, which it should be)
public float returnTime = 0.05f; // time taken to move back towards desired position, when not clipping (typically should be a higher value than clipMoveTime)
public float sphereCastRadius = 0.1f; // the radius of the sphere used to test for object between camera and target
public bool visualiseInEditor; // toggle for visualising the algorithm through lines for the raycast in the editor
public float closestDistance = 0.5f; // the closest distance the camera can be from the target
public bool protecting { get; private set; } // used for determining if there is an object between the target and the camera
public string dontClipTag = "Map"; // don't clip against objects with this tag (useful for not clipping against the targeted object)
private Transform m_Cam; // the transform of the camera
private Transform m_Pivot; // the point at which the camera pivots around
public float m_OriginalDist = 0.8f; // the original distance to the camera before any modification are made
private float m_MoveVelocity; // the velocity at which the camera moved
public float m_CurrentDist; // the current distance from the camera to the target
private Ray m_Ray = new Ray(); // the ray used in the lateupdate for casting between the camera and the target
private RaycastHit[] m_Hits; // the hits between the camera and the target
private RayHitComparer m_RayHitComparer; // variable to compare raycast hit distances
public float mRotMoveDelay = 4f;
/// <summary>
///摄像机 到目标点距离
/// </summary>
[Range(0f, 1f)]
public float mf_DistanceFromTarget = 0.8f;
/// <summary>
/// 摄像机距离限制
/// </summary>
public Vector2 mv2_Distance = new Vector2(1, 10);
#region MonoBehaviour
public void InitCamera()
{
m_goPivot = new GameObject("CameraPivot");
m_goPivot.transform.parent = transform ;
m_goPivot.transform.localEulerAngles = new Vector3(0, 180, 0);
if (Camera.main != null)
{
Destroy(Camera.main.gameObject);
}
m_camPlayer = new GameObject("Camera").AddComponent<Camera>();
m_camPlayer.tag = "MainCamera";
m_camPlayer.transform.parent =transform;
m_camPlayer.transform.localEulerAngles = new Vector3(0,0,0);
m_camPlayer.transform.localPosition = new Vector3(0,0, 5);
m_camPlayer.farClipPlane = 3800;
m_camPlayer.allowMSAA = false;
m_camPlayer.renderingPath = RenderingPath.Forward;
m_camPlayer.gameObject.AddComponent<FlareLayer>();
PostProcessingBehaviour posproBehaviour= m_camPlayer.gameObject.AddComponent<PostProcessingBehaviour>();
posproBehaviour.profile = (ResourceManager.Instance.LoadObject("CameraPrafeb/MainCameraPP", false) as PostProcessingProfile);
//初始化穿墙检测
// find the camera in the object hierarchy
m_Cam = m_camPlayer.transform;
m_Pivot = transform.Find("CameraPivot");
m_CurrentDist = m_OriginalDist;
// create a new RayHitComparer
m_RayHitComparer = new RayHitComparer();
//protectCamera = gameObject.AddComponent<ProtectCameraFromWallClip>();
DontDestroyOnLoad(gameObject);
}
public void ResetCameraTarget(Transform _target)
{
mTarget = _target;
}
Text mlogtext;
private void Start()
{
if (RunMode.Instance.bLogWangsy)
{
HRotSpeed = mf_HorizontalRotSpeed.ToString();
VRotSpeed = mf_VerticalRotSpeed.ToString();
//VRotLimitMin = mVerticalRotLimit.x.ToString();
//VRotLimitMax = mVerticalRotLimit.y.ToString();
cameraSpeed = mMoveDelay.ToString();
mlogtext = GameObject.Find("LogText").GetComponent<Text>();
mlogtext.text = "sdasdada";
//camDisLimitMin = protectCamera.mv2_Distance.x.ToString();
//camDisLimitMax = protectCamera.mv2_Distance.y.ToString();
}
}
string HRotSpeed;//水平旋转速度
string VRotSpeed;//垂直旋转速度
string VRotLimitMin;//垂直旋转最小限制
string VRotLimitMax;//垂直旋转最大限制
string cameraSpeed;//摄像机移动速度
string camDisLimitMin;//摄像机最小距离限制
string camDisLimitMax;//摄像机最大距离限制
private void OnGUI()
{
if (RunMode.Instance.bLogWangsy)
{
GUI.Label(new Rect(300, 50, 80, 50), "水平旋转速度");
HRotSpeed = GUI.TextField(new Rect(380, 50, 80, 50), HRotSpeed);
GUI.Label(new Rect(300, 110, 80, 50), "垂直旋转速度");
VRotSpeed = GUI.TextField(new Rect(380, 110, 80, 50), VRotSpeed);
// GUI.Label(new Rect(300, 170, 80, 50), "垂直旋转最小限制");
// VRotLimitMin= GUI.TextField(new Rect(380, 170, 80, 50), mVerticalRotLimit.x.ToString());
// GUI.Label(new Rect(300, 240, 80, 50), "垂直旋转最大限制");
// VRotLimitMax= GUI.TextField(new Rect(380, 240, 80, 50), VRotLimitMax);
GUI.Label(new Rect(500, 50, 80, 50), "摄像机移动速度");
cameraSpeed = GUI.TextField(new Rect(580, 50, 80, 50), cameraSpeed);
GUI.Label(new Rect(500, 50, 80, 50), "摄像机拉近速度");
clipMoveTime = float.Parse(GUI.TextField(new Rect(580, 170, 80, 50), clipMoveTime.ToString())) ;
// GUI.Label(new Rect(500, 170, 80, 50), "摄像机最小距离限制");
// camDisLimitMin= GUI.TextField(new Rect(580, 170, 80, 50), camDisLimitMin);
// GUI.Label(new Rect(500, 110, 80, 50), "摄像机最大距离限制");
// camDisLimitMax= GUI.TextField(new Rect(580, 110, 80, 50), camDisLimitMax);
// GUI.Label(new Rect(500, 240, 80, 50), "当前摄像机角度"+transform.eulerAngles);
// GUI.Label(new Rect(500, 320, 80, 50), "当前摄像机距离" + protectCamera.mf_DistanceFromTarget);
if (GUI.Button(new Rect(100, 100, 80, 80), "更改所有参数"))
{
//if (!string.IsNullOrEmpty(camDisLimitMin))
// protectCamera.mv2_Distance.x = float.Parse(camDisLimitMin);
//if (!string.IsNullOrEmpty(camDisLimitMax))
// protectCamera.mv2_Distance.y = float.Parse(camDisLimitMax);
if (!string.IsNullOrEmpty(HRotSpeed))
mf_HorizontalRotSpeed = float.Parse(HRotSpeed);
if (!string.IsNullOrEmpty(VRotSpeed))
mf_VerticalRotSpeed = float.Parse(VRotSpeed);
//if (!string.IsNullOrEmpty(VRotLimitMin))
// mVerticalRotLimit.x = float.Parse(VRotLimitMin);
//if (!string.IsNullOrEmpty(VRotLimitMax))
// mVerticalRotLimit.y = float.Parse(VRotLimitMax);
if (!string.IsNullOrEmpty(cameraSpeed))
mMoveDelay = float.Parse(cameraSpeed);
}
}
}
float mouseX = 0.0f;
float mouseY = 0.0f;
Quaternion toRotation=Quaternion.identity;
string msgStr="";
/// <summary>
/// 放大缩小 穿墙检测用
/// </summary>
Vector3 oldPosition1;
Vector3 oldPosition2;
float mNowDistanceFromTarget;
/// <summary>
/// 缓存手指位置
/// </summary>
List<Vector2> temppos;
/// <summary>
/// 缓存手指按下的Touch
/// </summary>
Touch[] touches;
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR
int unUICount;
class MyFinger
{
/// <summary>
/// 定义一个手指类
/// </summary>
public int id = -1;
public Touch touch;
}
static private List<MyFinger> fingers = new List<MyFinger>();
/// <summary>
/// 手指容器
/// </summary>
static List<MyFinger> Fingers
{
get
{
if (fingers.Count == 0)
{
for (int i = 0; i < 5; i++)
{
MyFinger mf = new MyFinger();
mf.id = -1;
fingers.Add(mf);
}
}
return fingers;
}
}
#endif
void Update()
{
#if UNITY_EDITOR || UNITY_STANDALONE || UNITY_WEBPLAYER
if (Input.GetMouseButton(0))
{
//Debug.Log("选中的UI名字" + EventSystem.current.currentSelectedGameObject.tag);
if (!EventSystem.current.IsPointerOverGameObject())
{
if (CtrlPlayer.bIsJoyCtrl)
{
if (Input.mousePosition.x > Screen.width / 2)
{
mouseX += Input.GetAxis("Mouse X") * mf_HorizontalRotSpeed;
mouseY -= Input.GetAxis("Mouse Y") * mf_VerticalRotSpeed;
}
}
else
{
mouseX += Input.GetAxis("Mouse X") * mf_HorizontalRotSpeed;
mouseY -= Input.GetAxis("Mouse Y") * mf_VerticalRotSpeed;
}
}
}
if (Input.GetAxis("Mouse ScrollWheel") != 0)
{
mf_DistanceFromTarget += Input.GetAxis("Mouse ScrollWheel") * 0.5f;
mf_DistanceFromTarget = Mathf.Clamp(mf_DistanceFromTarget, 0.1f, 1);
}
#elif UNITY_ANDROID||UNITY_IOS
touches = Input.touches;
// 遍历所有的已经记录的手指
// --掦除已经不存在的手指
foreach (MyFinger mf in Fingers)
{
if (mf.id == -1)
{
continue;
}
bool stillExit = false;
foreach (Touch t in touches)
{
if (mf.id == t.fingerId)
{
stillExit = true;
break;
}
}
// 掦除
if (stillExit == false)
{
mf.id = -1;
unUICount--;
}
}
// 遍历当前的touches
// --并检查它们在是否已经记录在AllFinger中
// --是的话更新对应手指的状态,不是的放放加进去
foreach (Touch t in touches)
{
bool still = false;
// 存在--更新对应的手指
foreach (MyFinger mf in Fingers)
{
if (t.fingerId == mf.id)
{
still = true;
mf.touch = t;
break;
}
}
// 不存在--添加新记录
if (!still &&t.phase== TouchPhase.Began && !EventSystem.current.IsPointerOverGameObject(t.fingerId))
{
foreach (MyFinger mf in Fingers)
{
if (mf.id == -1)
{
mf.id = t.fingerId;
mf.touch = t;
unUICount++;
break;
}
}
}
}
if (unUICount == 1)
{
// 记录完手指信息后,就是响应相应和状态记录了
foreach (var mf in Fingers)
{
if (mf.id != -1)
{
mouseX += mf.touch.deltaPosition.x * 0.05f * mf_HorizontalRotSpeed;
mouseY -= mf.touch.deltaPosition.y * 0.05f * mf_VerticalRotSpeed;
}
}
}
else if (unUICount > 1)
{
temppos = new List<Vector2>();
bool canMove = false;
foreach (var mf in Fingers)
{
if (mf.id != -1)
{
temppos.Add(mf.touch.position);
if (mf.touch.phase == TouchPhase.Moved)
{
canMove = true;
}
}
if (canMove && temppos.Count > 1)
{
var tempPosition1 = temppos[0];
var tempPosition2 = temppos[1];
if (isZoom(oldPosition1, oldPosition2, tempPosition1, tempPosition2))
{
if (mf_DistanceFromTarget > 0)
mf_DistanceFromTarget -= 0.05f;
}
else
{
if (mf_DistanceFromTarget < 1f)
mf_DistanceFromTarget += 0.05f;
}
oldPosition1 = tempPosition1;
oldPosition2 = tempPosition2;
break;
}
}
}
#endif
//摄像机旋转
if (mTarget != null)
{
m_goPivot.transform.position = mTarget.position;
mouseY = ClampAngle(mouseY, mVerticalRotLimit.x, mVerticalRotLimit.y);
toRotation = Quaternion.Euler(mouseY, mouseX, 0);
transform.rotation = Quaternion.Slerp(transform.rotation, toRotation, Time.deltaTime * mMoveDelay);
Vector3 toPosition = transform.rotation * new Vector3(0.0f, 0.0f, 0.0f) + mTarget.position;
Vector3 nowpos = Vector3.Lerp(transform.position, toPosition, 2f);
transform.position = nowpos;
}
else
{
GameLog.Wsy_Log("摄像机目标点不存在");
}
//摄像机撞墙检测
m_OriginalDist = GetCurrentDistance();
// initially set the target distance
float targetDist = m_OriginalDist;
m_Ray.origin = m_Pivot.position + m_Pivot.forward * sphereCastRadius;
m_Ray.direction = m_Pivot.forward;
// initial check to see if start of spherecast intersects anything
var cols = Physics.OverlapSphere(m_Ray.origin, sphereCastRadius);
bool initialIntersect = false;
bool hitSomething = false;
// loop through all the collisions to check if something we care about
for (int i = 0; i < cols.Length; i++)
{
if ((!cols[i].isTrigger) &&
cols[i].gameObject.CompareTag(dontClipTag))
{
initialIntersect = true;
break;
}
}
// if there is a collision
if (initialIntersect)
{
m_Ray.origin += m_Pivot.forward * sphereCastRadius;
// do a raycast and gather all the intersections
m_Hits = Physics.RaycastAll(m_Ray, m_OriginalDist - sphereCastRadius);
}
else
{
// if there was no collision do a sphere cast to see if there were any other collisions
m_Hits = Physics.SphereCastAll(m_Ray, sphereCastRadius, m_OriginalDist + sphereCastRadius);
}
// sort the collisions by distance
Array.Sort(m_Hits, m_RayHitComparer);
// set the variable used for storing the closest to be as far as possible
float nearest = Mathf.Infinity;
// loop through all the collisions
for (int i = 0; i < m_Hits.Length; i++)
{
// only deal with the collision if it was closer than the previous one, not a trigger, and not attached to a rigidbody tagged with the dontClipTag
if (m_Hits[i].distance < nearest && (!m_Hits[i].collider.isTrigger) && m_Hits[i].collider.gameObject.CompareTag(dontClipTag))
{
// change the nearest collision to latest
nearest = m_Hits[i].distance;
targetDist = m_Pivot.InverseTransformPoint(m_Hits[i].point).z;
hitSomething = true;
}
}
// visualise the cam clip effect in the editor
if (hitSomething)
{
Debug.DrawRay(m_Ray.origin, m_Pivot.forward * (targetDist + sphereCastRadius), Color.red);
//m_CurrentDist = targetDist;
}
else
{
m_CurrentDist = m_OriginalDist;
}
// hit something so move the camera to a better position
protecting = hitSomething;
m_CurrentDist = Mathf.SmoothDamp(m_CurrentDist, targetDist, ref m_MoveVelocity, m_CurrentDist < targetDist ? clipMoveTime : returnTime);
m_CurrentDist = Mathf.Clamp(m_CurrentDist, closestDistance, m_OriginalDist);
m_Cam.localPosition = -Vector3.forward * (m_CurrentDist - 0.5f);
}
#region Tools
/// <summary>
/// 放大/缩小
/// </summary>
/// <param name="oP1"></param>
/// <param name="oP2"></param>
/// <param name="nP1"></param>
/// <param name="nP2"></param>
/// <returns></returns>
bool isZoom(Vector2 oP1, Vector2 oP2, Vector2 nP1, Vector2 nP2)
{
float leng1 = Mathf.Sqrt((oP1.x - oP2.x) * (oP1.x - oP2.x) + (oP1.y - oP2.y) * (oP1.y - oP2.y));
float leng2 = Mathf.Sqrt((nP1.x - nP2.x) * (nP1.x - nP2.x) + (nP1.y - nP2.y) * (nP1.y - nP2.y));
if (leng1 < leng2)
return true;
else
return false;
}
float GetCurrentDistance()
{
mNowDistanceFromTarget = Mathf.Lerp(mNowDistanceFromTarget, mf_DistanceFromTarget, Time.deltaTime * mRotMoveDelay);
return mv2_Distance.x + (mv2_Distance.y - mv2_Distance.x) * mNowDistanceFromTarget;
}
#endregion
#endregion
public Vector3 GetForward()
{
return m_camPlayer.transform.forward;
}
Vector3 StartAngles = new Vector3(20,0,0);
public void ResetPos()
{
float rotY = 0;
if (MMgr.I.CtrlPlayer.m_PM != null)
{
rotY = MMgr.I.CtrlPlayer.m_PM.m_goPlayer.transform.localEulerAngles.y;
}
mouseX = StartAngles.y +rotY;
mouseY = StartAngles.x;
mf_DistanceFromTarget = 0.8f;
}
/// <summary>
/// 限制旋转最大/最小值
/// </summary>
/// <param name="angle">当前</param>
/// <param name="min">最小</param>
/// <param name="max">最大</param>
/// <returns></returns>
static float ClampAngle(float angle, float min, float max)
{
if (angle < -360)
angle += 360;
if (angle > 360)
angle -= 360;
return Mathf.Clamp(angle, min, max);
}
public class RayHitComparer : IComparer
{
public int Compare(object x, object y)
{
return ((RaycastHit)x).distance.CompareTo(((RaycastHit)y).distance);
}
}
}