1087 lines
38 KiB
C#
1087 lines
38 KiB
C#
|
/********************************************************************************
|
|||
|
* 文件名: CameraController.cs
|
|||
|
* 全路径: \Script\Player\CameraController.cs
|
|||
|
* 创建人: 李嘉
|
|||
|
* 创建时间:2013-11-05
|
|||
|
*
|
|||
|
* 功能说明: 摄像机控制类
|
|||
|
* 所有的摄像机逻辑都在其中
|
|||
|
* 修改记录:
|
|||
|
* 主要逻辑重构,现在摄像机按照距离和角度两个参数计算位置
|
|||
|
*********************************************************************************/
|
|||
|
|
|||
|
using Games.Events;
|
|||
|
using Games.GlobeDefine;
|
|||
|
using Games.LogicObj;
|
|||
|
using GCGame.Table;
|
|||
|
using Module.Log;
|
|||
|
using System.Collections.Generic;
|
|||
|
using Games.Scene;
|
|||
|
using UnityEngine;
|
|||
|
using UnityEngine.Events;
|
|||
|
public sealed class CameraController : MonoBehaviour
|
|||
|
{
|
|||
|
// ******** 基础参数 ********
|
|||
|
public const string cameraIgnoreLayer = "MainCameraIgnore";
|
|||
|
|
|||
|
public const string skyBoxLayer = "Skybox";
|
|||
|
public static readonly string[] hideFromCameraLayers = { "UICameraTexture", "UI","MapPoint", cameraIgnoreLayer };
|
|||
|
|
|||
|
public Camera MainCamera { get; private set; }
|
|||
|
public Camera OverrideCamera { get; private set; }
|
|||
|
private readonly List<MonoBehaviour> _cameraEffectList = new List<MonoBehaviour>();
|
|||
|
private Animation _animation;
|
|||
|
private string _shakeAnimName;
|
|||
|
|
|||
|
// 暂时使用掩码处理多重动态雾效关闭的条件
|
|||
|
private static int _forceNoFog;
|
|||
|
// 隐藏摄像机的多重掩码;0为EnableCamera,1为UiCopyCamera,2为SceneMovie,3为OverrideCamera, 4为过场动画
|
|||
|
private int _hideCamera;
|
|||
|
|
|||
|
public static bool UseDepthTexture
|
|||
|
{
|
|||
|
get { return _useDepthTexture; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (_useDepthTexture != value)
|
|||
|
{
|
|||
|
_useDepthTexture = value;
|
|||
|
if (SceneLogic.CameraController != null)
|
|||
|
SceneLogic.CameraController.ToggleDepthTexture();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private static bool _useDepthTexture = true;
|
|||
|
|
|||
|
private CameraLowRes _cameraLowRes;
|
|||
|
|
|||
|
private bool _fruntumDirty;
|
|||
|
private Plane[] _fruntumPlanes;
|
|||
|
|
|||
|
// ******** 基础移动参数 ********
|
|||
|
// 默认摄像机焦点偏移数值
|
|||
|
public static readonly Vector3 defaultOffset = Vector3.up * 0.9f;
|
|||
|
// 默认摄像机剔除距离
|
|||
|
public const float cameraCullDistance = 45f;
|
|||
|
|
|||
|
public const float skyBoxCullDistance = 1000f;
|
|||
|
|
|||
|
// 同当前锁定目标的距离
|
|||
|
public float Distance { get; set; }
|
|||
|
// 摄像机仰角和水平方向。不考虑
|
|||
|
public float Pitch { get; set; }
|
|||
|
public float Yaw { get; set; }
|
|||
|
// FieldOfView调整
|
|||
|
public float FoVMin { get; private set; }
|
|||
|
public float FoVMax { get; private set; }
|
|||
|
private float _fovScale;
|
|||
|
public float FoVScale
|
|||
|
{
|
|||
|
get { return _fovScale; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (_fovScale != value)
|
|||
|
{
|
|||
|
_fovScale = value;
|
|||
|
UpdateFoV();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
// 摄像机就不做多个Override的排序处理了
|
|||
|
private float _fovOverride = -1f;
|
|||
|
public float FoVOverride
|
|||
|
{
|
|||
|
get { return _fovOverride; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (_fovOverride != value)
|
|||
|
{
|
|||
|
_fovOverride = value;
|
|||
|
UpdateFoV();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private float _fovValue = -1f;
|
|||
|
|
|||
|
public float FoVValue
|
|||
|
{
|
|||
|
get { return _fovValue; }
|
|||
|
set
|
|||
|
{
|
|||
|
if (_fovValue != value)
|
|||
|
{
|
|||
|
_fovValue = value;
|
|||
|
UpdateFoV();
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private bool _noCullByDist;
|
|||
|
|
|||
|
private void UpdateFoV()
|
|||
|
{
|
|||
|
if (_fovValue > 0)
|
|||
|
{
|
|||
|
MainCamera.fieldOfView = _fovValue;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
var fovScale = _fovOverride < 0 ? _fovScale : _fovOverride;
|
|||
|
MainCamera.fieldOfView = Mathf.Lerp(FoVMin, FoVMax, fovScale);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// 当前锁定目标,为空时视为锁定在Vector3.zero位置
|
|||
|
private Transform FocusObj { get; set; }
|
|||
|
|
|||
|
// 当前目标丢失时,自动锁定到的目标GUID
|
|||
|
public ulong FocusObjGuid { get; private set; }
|
|||
|
// 当前锁定目标点偏移值
|
|||
|
public Vector3 FocusOffset { get; private set; }
|
|||
|
// 当前摄像同锁定目标高度偏移值,锁定目标丢失时,保持最后一次赋值
|
|||
|
public float CameraHeight { get; private set; }
|
|||
|
|
|||
|
// ******** 震屏参数 ********
|
|||
|
// 处于delay阶段的震屏表
|
|||
|
private readonly List<CameraShakeData> _delayShakeData = new List<CameraShakeData>();
|
|||
|
private readonly List<CameraShakeData> _activeShakeData = new List<CameraShakeData>();
|
|||
|
private CameraShakeData _currentShake;
|
|||
|
private readonly List<CameraShakeTableData> _cameraShakeData = new List<CameraShakeTableData>();
|
|||
|
|
|||
|
// ******** 运动覆盖参数 ********
|
|||
|
public CameraMovementOverrider MoveOverrider { get; private set; }
|
|||
|
|
|||
|
public void ChangeFocusObj(Obj obj)
|
|||
|
{
|
|||
|
if (obj == null)
|
|||
|
{
|
|||
|
FocusObj = null;
|
|||
|
FocusObjGuid = GlobeVar.INVALID_GUID;
|
|||
|
EventDispatcher.Instance.SendMessage(Games.Events.EventId.MainCameraFocusValid);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
FocusObj = obj.transform;
|
|||
|
FocusObjGuid = obj.GUID;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public bool IsCurrFocus(Obj obj)
|
|||
|
{
|
|||
|
if (FocusObj == null || obj == null)
|
|||
|
return false;
|
|||
|
else
|
|||
|
return obj.transform == FocusObj;
|
|||
|
}
|
|||
|
|
|||
|
public T AddCameraEffect<T>(UnityAction<T> createFunc = null) where T : MonoBehaviour
|
|||
|
{
|
|||
|
T result = null;
|
|||
|
for (var i = 0; i < _cameraEffectList.Count; i++)
|
|||
|
{
|
|||
|
var effect = _cameraEffectList[i] as T;
|
|||
|
if (effect != null)
|
|||
|
{
|
|||
|
result = effect;
|
|||
|
result.enabled = true;
|
|||
|
}
|
|||
|
else
|
|||
|
_cameraEffectList[i].enabled = false;
|
|||
|
}
|
|||
|
|
|||
|
if (result == null)
|
|||
|
{
|
|||
|
result = MainCamera.gameObject.EnsureComponent<T>();
|
|||
|
if (createFunc != null)
|
|||
|
createFunc.Invoke(result);
|
|||
|
_cameraEffectList.Add(result);
|
|||
|
}
|
|||
|
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
public void RemoveCameraEffect<T>() where T : MonoBehaviour
|
|||
|
{
|
|||
|
for (var i = 0; i < _cameraEffectList.Count; i++)
|
|||
|
if (_cameraEffectList[i] is T)
|
|||
|
{
|
|||
|
_cameraEffectList[i].enabled = false;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void ModifyFocusOffset(Vector3 offset)
|
|||
|
{
|
|||
|
FocusOffset = defaultOffset + offset;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 替换当前主摄像机
|
|||
|
/// </summary>
|
|||
|
public void SetOverrideCamera(Camera overrideCamera)
|
|||
|
{
|
|||
|
if (OverrideCamera != overrideCamera)
|
|||
|
{
|
|||
|
OverrideCamera = overrideCamera;
|
|||
|
_fruntumDirty = true;
|
|||
|
SetHideCamera(3, overrideCamera != null);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void SetCameraParameterListener(bool isOn)
|
|||
|
{
|
|||
|
if (ProcessInput.Instance != null && ProcessInput.Instance.inputModule != null &&
|
|||
|
ProcessInput.Instance.inputModule.processCamera != null)
|
|||
|
{
|
|||
|
var cameraInput = ProcessInput.Instance.inputModule.processCamera;
|
|||
|
cameraInput.onCameraAngle -= MoveCameraAngle;
|
|||
|
cameraInput.onCameraDistance -= MoveCameraDistance;
|
|||
|
if (isOn)
|
|||
|
{
|
|||
|
cameraInput.onCameraAngle += MoveCameraAngle;
|
|||
|
cameraInput.onCameraDistance += MoveCameraDistance;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void MoveCameraAngle(Vector2 delta)
|
|||
|
{
|
|||
|
Pitch = Mathf.Clamp(Pitch - delta.y * GlobeVar.pitchPerDpi, GlobeVar.minPitch, GlobeVar.maxPitch);
|
|||
|
Yaw = Yaw + delta.x * GlobeVar.yawPerDpi;
|
|||
|
}
|
|||
|
|
|||
|
private void MoveCameraDistance(float delta)
|
|||
|
{
|
|||
|
Distance = Mathf.Clamp(Distance - delta * GlobeVar.distancePerDpi, GlobeVar.minDistance, GlobeVar.maxDistance);
|
|||
|
}
|
|||
|
|
|||
|
public Plane[] GetFrustumPlanes()
|
|||
|
{
|
|||
|
if (_fruntumDirty)
|
|||
|
{
|
|||
|
_fruntumDirty = false;
|
|||
|
var currentCamera = OverrideCamera ? OverrideCamera : MainCamera;
|
|||
|
_fruntumPlanes = currentCamera == null || !currentCamera.isActiveAndEnabled ? null : GeometryUtility.CalculateFrustumPlanes(currentCamera);
|
|||
|
}
|
|||
|
|
|||
|
return _fruntumPlanes;
|
|||
|
}
|
|||
|
|
|||
|
public static void ForceNoFog(bool isNoFog, int mask)
|
|||
|
{
|
|||
|
var temp = _forceNoFog.ReplaceFlag(mask.ToFlag(), isNoFog);
|
|||
|
var update = _forceNoFog > 0 != temp > 0;
|
|||
|
_forceNoFog = temp;
|
|||
|
if (update)
|
|||
|
{
|
|||
|
if (SceneLogic.CameraController != null)
|
|||
|
SceneLogic.CameraController.OnFogSettingUpdate(null);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void ChangeFocusId(ulong guid)
|
|||
|
{
|
|||
|
if (guid != GlobeVar.INVALID_GUID)
|
|||
|
{
|
|||
|
FocusObjGuid = guid;
|
|||
|
FocusObj = null;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void Awake()
|
|||
|
{
|
|||
|
MainCamera = transform.GetComponentInChildren<Camera>();
|
|||
|
FocusObjGuid = GlobeVar.INVALID_GUID;
|
|||
|
_animation = MainCamera.gameObject.EnsureComponent<Animation>();
|
|||
|
ToggleDepthTexture();
|
|||
|
ResetLayerMask();
|
|||
|
EventDispatcher.Instance.Add(Games.Events.EventId.FogSettingUpdate, OnFogSettingUpdate);
|
|||
|
EventDispatcher.Instance.Add(Games.Events.EventId.CameraSpaceBlurMax, OnCameraSpaceBlurMax);
|
|||
|
EventDispatcher.Instance.Add(Games.Events.EventId.SceneMovie, OnSceneMovie);
|
|||
|
EventDispatcher.Instance.Add(Games.Events.EventId.UiCameraCopy, OnUiCameraCopy);
|
|||
|
EventDispatcher.Instance.Add(Games.Events.EventId.LowResolution, OnLowResToggle);
|
|||
|
GameManager.AddLateUpdate(UpdateCamera, GameManager.cameraControllerUpdateOrder);
|
|||
|
EnableSceneCamera(true);
|
|||
|
OnLowResToggle(null);
|
|||
|
}
|
|||
|
|
|||
|
private void Start()
|
|||
|
{
|
|||
|
SetCameraParameterListener(true);
|
|||
|
}
|
|||
|
|
|||
|
public void DestroyCamera()
|
|||
|
{
|
|||
|
Clean();
|
|||
|
EventDispatcher.Instance.Remove(Games.Events.EventId.FogSettingUpdate, OnFogSettingUpdate);
|
|||
|
EventDispatcher.Instance.Remove(Games.Events.EventId.CameraSpaceBlurMax, OnCameraSpaceBlurMax);
|
|||
|
EventDispatcher.Instance.Remove(Games.Events.EventId.SceneMovie, OnSceneMovie);
|
|||
|
EventDispatcher.Instance.Remove(Games.Events.EventId.UiCameraCopy, OnUiCameraCopy);
|
|||
|
EventDispatcher.Instance.Remove(Games.Events.EventId.LowResolution, OnLowResToggle);
|
|||
|
GameManager.RemoveLateUpdate(UpdateCamera, GameManager.cameraControllerUpdateOrder);
|
|||
|
Destroy(gameObject);
|
|||
|
}
|
|||
|
|
|||
|
private void OnLowResToggle(object args)
|
|||
|
{
|
|||
|
var lowResComponent = MainCamera.GetComponent<CameraLowRes>();
|
|||
|
if (PlayerPreferenceData.useLowResolution)
|
|||
|
{
|
|||
|
if (lowResComponent == null)
|
|||
|
lowResComponent = MainCamera.gameObject.AddComponent<CameraLowRes>();
|
|||
|
else
|
|||
|
lowResComponent.enabled = true;
|
|||
|
}
|
|||
|
else if (lowResComponent != null)
|
|||
|
lowResComponent.enabled = false;
|
|||
|
}
|
|||
|
|
|||
|
public void EnableSceneCamera(bool isEnable)
|
|||
|
{
|
|||
|
if (isEnable)
|
|||
|
{
|
|||
|
var sceneId = GameManager.gameManager.RunningScene;
|
|||
|
Tab_SceneCameraStartPos sceneData = null;
|
|||
|
var sceneDatas = TableManager.GetSceneCameraStartPosByID(sceneId);
|
|||
|
if (sceneDatas != null)
|
|||
|
for (var i = 0; i < sceneDatas.Count; i++)
|
|||
|
if (sceneData == null || sceneDatas[i].Force == GameManager.gameManager.PlayerDataPool.MainPlayerBaseAttr.Force)
|
|||
|
sceneData = sceneDatas[i];
|
|||
|
SetHideCamera(0, false);
|
|||
|
if (sceneData == null)
|
|||
|
LogModule.ErrorLog(string.Format("副本场景{0}在SceneCameraStartPos表中无法获得!", sceneId));
|
|||
|
else if (sceneData.Pitch != Pitch || sceneData.Yaw != Yaw || sceneData.Distance != Distance ||
|
|||
|
sceneData.ViewMax != FoVMax || sceneData.ViewMin != FoVMin)
|
|||
|
{
|
|||
|
SetCameraParameters(sceneData.Pitch, sceneData.Yaw, sceneData.Distance, sceneData.ViewMin,
|
|||
|
sceneData.ViewMax);
|
|||
|
}
|
|||
|
OnFogSettingUpdate(null);
|
|||
|
}
|
|||
|
else
|
|||
|
SetHideCamera(0, true);
|
|||
|
}
|
|||
|
|
|||
|
public void Clean()
|
|||
|
{
|
|||
|
MoveOverrider = null;
|
|||
|
_delayShakeData.Clear();
|
|||
|
_activeShakeData.Clear();
|
|||
|
FocusObj = null;
|
|||
|
FocusObjGuid = GlobeVar.INVALID_GUID;
|
|||
|
}
|
|||
|
|
|||
|
private void OnFogSettingUpdate(object args)
|
|||
|
{
|
|||
|
RenderSettings.fog = PlayerPreferenceData.SystemQualityFog && _forceNoFog <= 0;
|
|||
|
MainCamera.clearFlags = CameraClearFlags.SolidColor;
|
|||
|
MainCamera.backgroundColor = RenderSettings.fogColor;
|
|||
|
//// 注:主相机在有雾情况下,使用短距离Cull,然后SolidColor衔接雾效颜色
|
|||
|
//if (RenderSettings.fog)
|
|||
|
//{
|
|||
|
// MainCamera.clearFlags = CameraClearFlags.SolidColor;
|
|||
|
// MainCamera.backgroundColor = RenderSettings.fogColor;
|
|||
|
// cullDistance = Math.Max(cameraCullDistanceMin, RenderSettings.fogEndDistance);
|
|||
|
//}
|
|||
|
//// 主相机无雾效情况下,使用长距离Cull
|
|||
|
//// 计划使用不清空,但是在某些场景和某些PC上,会有保存上一帧Depth的问题,因此强制清空一次
|
|||
|
//else
|
|||
|
//{
|
|||
|
// MainCamera.clearFlags = CameraClearFlags.Depth;
|
|||
|
// cullDistance = cameraCullDistanceMax;
|
|||
|
//}
|
|||
|
SetCameraCull();
|
|||
|
}
|
|||
|
|
|||
|
public void SetNoCullByDist(bool isNoCull)
|
|||
|
{
|
|||
|
if (_noCullByDist != isNoCull)
|
|||
|
{
|
|||
|
_noCullByDist = isNoCull;
|
|||
|
SetCameraCull();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void SetCameraCull()
|
|||
|
{
|
|||
|
var skyBox = LayerMask.NameToLayer(skyBoxLayer);
|
|||
|
var cameraCullDistances = MainCamera.layerCullDistances;
|
|||
|
for (var i = 0; i < cameraCullDistances.Length; i++)
|
|||
|
cameraCullDistances[i] = skyBox == i || _noCullByDist ? skyBoxCullDistance : cameraCullDistance;
|
|||
|
MainCamera.layerCullDistances = cameraCullDistances;
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
private void ToggleDepthTexture()
|
|||
|
{
|
|||
|
if (MainCamera != null)
|
|||
|
MainCamera.depthTextureMode = UseDepthTexture ? DepthTextureMode.Depth : DepthTextureMode.None;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 从基本摄像机Layer配置中,移除部分Layer
|
|||
|
/// </summary>
|
|||
|
public void RemoveLayerMask(int layerMask)
|
|||
|
{
|
|||
|
if (MainCamera != null)
|
|||
|
{
|
|||
|
var cameraMask = MainCamera.cullingMask;
|
|||
|
cameraMask &= ~layerMask;
|
|||
|
MainCamera.cullingMask = cameraMask;
|
|||
|
}
|
|||
|
}
|
|||
|
/// <summary>
|
|||
|
/// 恢复摄像机到基本Layer
|
|||
|
/// </summary>
|
|||
|
public void ResetLayerMask()
|
|||
|
{
|
|||
|
if (MainCamera != null)
|
|||
|
{
|
|||
|
var cameraMask = int.MaxValue;
|
|||
|
cameraMask &= ~LayerMask.GetMask(hideFromCameraLayers);
|
|||
|
MainCamera.cullingMask = cameraMask;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void SetCameraParameters(float pitch, float yaw, float distance, float minFieldOfView, float maxFieldOfView)
|
|||
|
{
|
|||
|
Pitch = pitch;
|
|||
|
Yaw = yaw;
|
|||
|
Distance = distance;
|
|||
|
FoVMin = minFieldOfView;
|
|||
|
FoVMax = maxFieldOfView;
|
|||
|
FoVScale = 1f;
|
|||
|
// 2019.05.10 Hack:对应主角OnMountCreate和OnMountDestroy
|
|||
|
// 暂时不使用事件驱动这个过程
|
|||
|
var mainPlayer = ObjManager.Instance.MainPlayer;
|
|||
|
if (mainPlayer != null &&
|
|||
|
mainPlayer.mountModel.model != null)
|
|||
|
ModifyFocusOffset(Vector3.up * mainPlayer.mount_DeltaHeigh);
|
|||
|
else
|
|||
|
ModifyFocusOffset(Vector3.zero);
|
|||
|
}
|
|||
|
|
|||
|
//更新场景摄像机
|
|||
|
private void UpdateCamera()
|
|||
|
{
|
|||
|
if (!LoadingWindow._IsLoadingScene)
|
|||
|
{
|
|||
|
_fruntumDirty = true;
|
|||
|
if (OverrideCamera == null)
|
|||
|
CameraMove();
|
|||
|
// ******** 更新Post Camera Movement ********
|
|||
|
PostCameraMovement();
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
private void CameraMove()
|
|||
|
{
|
|||
|
// ******** 更新摄像机位置 ********
|
|||
|
// 检测是否使用重载方式执行移动
|
|||
|
if (MoveOverrider == null || !MoveOverrider.MoveByOverride(this))
|
|||
|
{
|
|||
|
if (FocusObj == null)
|
|||
|
{
|
|||
|
if (FocusObjGuid != GlobeVar.INVALID_GUID)
|
|||
|
{
|
|||
|
var player = Singleton<ObjManager>.Instance.FindOtherPlayerByGuid(FocusObjGuid);
|
|||
|
if (player != null && !player.IsDie())
|
|||
|
FocusObj = player.transform;
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
var mainPlayer = ObjManager.Instance.MainPlayer;
|
|||
|
if (mainPlayer != null)
|
|||
|
{
|
|||
|
FocusObj = mainPlayer.ObjTransform;
|
|||
|
FocusObjGuid = mainPlayer.GUID;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
if (FocusObj != null)
|
|||
|
{
|
|||
|
var focusPos = FocusObj.position + FocusOffset;
|
|||
|
var rotation = Quaternion.Euler(Pitch, Yaw, 0f);
|
|||
|
transform.position = focusPos + rotation * Vector3.back * Distance;
|
|||
|
transform.rotation = rotation;
|
|||
|
CameraHeight = transform.position.y - focusPos.y;
|
|||
|
}
|
|||
|
}
|
|||
|
// ******** 更新震屏 ********
|
|||
|
for (var i = _delayShakeData.Count - 1; i >= 0; i--)
|
|||
|
if (_delayShakeData[i].startTime + _delayShakeData[i].data.delayTime < Time.time)
|
|||
|
{
|
|||
|
WakeOneShakeData(_delayShakeData[i]);
|
|||
|
_delayShakeData.RemoveAt(i);
|
|||
|
}
|
|||
|
// 注:WakeOneShakeData已经保证了优先度排序,因此无需做更多检测
|
|||
|
CameraShakeData nextShake = null;
|
|||
|
for (var i = _activeShakeData.Count - 1; i >= 0; i--)
|
|||
|
{
|
|||
|
var currentShakeData = _activeShakeData[i];
|
|||
|
if (currentShakeData.startTime + currentShakeData.data.delayTime + currentShakeData.data.animLength < Time.time)
|
|||
|
_activeShakeData.RemoveAt(i);
|
|||
|
else
|
|||
|
{
|
|||
|
nextShake = currentShakeData;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (nextShake != _currentShake)
|
|||
|
{
|
|||
|
_currentShake = nextShake;
|
|||
|
var shakeAnimName = _currentShake == null ? string.Empty : _currentShake.data.animName;
|
|||
|
if (shakeAnimName != _shakeAnimName)
|
|||
|
{
|
|||
|
_shakeAnimName = shakeAnimName;
|
|||
|
if (string.IsNullOrEmpty(_shakeAnimName))
|
|||
|
_animation.Stop();
|
|||
|
else
|
|||
|
{
|
|||
|
var clip = _animation.GetClip(_shakeAnimName);
|
|||
|
if (clip == null)
|
|||
|
{
|
|||
|
var newClip = CommonUtility.LoadFromResources<AnimationClip>(_shakeAnimName);
|
|||
|
if (newClip != null)
|
|||
|
{
|
|||
|
_animation.AddClip(newClip, _shakeAnimName);
|
|||
|
_animation.Play(_shakeAnimName);
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
_animation.Play(_shakeAnimName);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if (_currentShake == null)
|
|||
|
{
|
|||
|
MainCamera.transform.localPosition = Vector3.zero;
|
|||
|
MainCamera.transform.localRotation = Quaternion.identity;
|
|||
|
}
|
|||
|
else if (string.IsNullOrEmpty(_currentShake.data.animName))
|
|||
|
{
|
|||
|
Vector3 shakeOffset;
|
|||
|
Quaternion shakeRotation;
|
|||
|
if (_currentShake.data.EvaluteCurve(Time.time - _currentShake.startTime, out shakeOffset,
|
|||
|
out shakeRotation))
|
|||
|
{
|
|||
|
MainCamera.transform.localPosition = shakeOffset;
|
|||
|
MainCamera.transform.localRotation = shakeRotation;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
public void StartCameraRock(int rockId, Obj starter, int priority)
|
|||
|
{
|
|||
|
// 检查Starter是否在摄像机范围内
|
|||
|
if (PlayerPreferenceData.SystemCameraShake && starter != null)
|
|||
|
{
|
|||
|
var objCollider = starter.GetComponent<Collider>();
|
|||
|
var bounds = objCollider == null ? new Bounds(starter.Position, Vector3.zero) : objCollider.bounds;
|
|||
|
var cameraPlanes = GetFrustumPlanes();
|
|||
|
if (GeometryUtility.TestPlanesAABB(cameraPlanes, bounds))
|
|||
|
{
|
|||
|
CameraShakeTableData data = null;
|
|||
|
for (var i = 0; i < _cameraShakeData.Count; i++)
|
|||
|
if (_cameraShakeData[i].id == rockId)
|
|||
|
{
|
|||
|
data = _cameraShakeData[i];
|
|||
|
break;
|
|||
|
}
|
|||
|
if (data == null)
|
|||
|
{
|
|||
|
var tableData = TableManager.GetCameraRockByID(rockId, 0);
|
|||
|
if (tableData == null)
|
|||
|
LogModule.ErrorLog("无法找到震屏配置{0}!", rockId);
|
|||
|
else
|
|||
|
{
|
|||
|
data = new CameraShakeTableData(tableData);
|
|||
|
_cameraShakeData.Add(data);
|
|||
|
}
|
|||
|
}
|
|||
|
if (data != null)
|
|||
|
{
|
|||
|
var shakeData = new CameraShakeData(data, starter.ServerID, priority);
|
|||
|
if (shakeData.data.delayTime > 0)
|
|||
|
_delayShakeData.Add(shakeData);
|
|||
|
else
|
|||
|
WakeOneShakeData(shakeData);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
private void WakeOneShakeData(CameraShakeData data)
|
|||
|
{
|
|||
|
// 按照优先程度排序,最高优先度排列最后
|
|||
|
var add = true;
|
|||
|
for (var i = _activeShakeData.Count - 1; i >= 0; i--)
|
|||
|
if (_activeShakeData[i].priority <= data.priority)
|
|||
|
{
|
|||
|
_activeShakeData.Insert(i + 1, data);
|
|||
|
add = false;
|
|||
|
break;
|
|||
|
}
|
|||
|
if (add)
|
|||
|
_activeShakeData.Insert(0, data);
|
|||
|
}
|
|||
|
|
|||
|
public void StopCameraRock(int rockId, int serverId)
|
|||
|
{
|
|||
|
RemoveRockFromList(_delayShakeData, rockId, serverId);
|
|||
|
RemoveRockFromList(_activeShakeData, rockId, serverId);
|
|||
|
}
|
|||
|
|
|||
|
private void RemoveRockFromList(IList<CameraShakeData> list, int rockId, int starter)
|
|||
|
{
|
|||
|
for (var i = 0; i < list.Count; i++)
|
|||
|
if (list[i].data.id == rockId && list[i].handle == starter)
|
|||
|
list.RemoveAt(i);
|
|||
|
}
|
|||
|
|
|||
|
//public void InitCameraTrack(Vector3 posStart, Vector3 posEnd, Vector3 offset)
|
|||
|
//{
|
|||
|
// MoveOverrider = new CameraTrackMovement(posStart, posEnd, offset);
|
|||
|
//}
|
|||
|
|
|||
|
public void SetCameraOverrider(CameraMovementOverrider overrider)
|
|||
|
{
|
|||
|
if (MoveOverrider != overrider)
|
|||
|
{
|
|||
|
ResetCameraToMainPlayer();
|
|||
|
MoveOverrider = overrider;
|
|||
|
if(MoveOverrider != null)
|
|||
|
MoveOverrider.Start(this);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//恢复到摄像机跟随主角状态
|
|||
|
public void ResetCameraToMainPlayer()
|
|||
|
{
|
|||
|
if (MoveOverrider != null)
|
|||
|
MoveOverrider.End(this);
|
|||
|
MoveOverrider = null;
|
|||
|
}
|
|||
|
// 在副本切换达到最大亮度时切换摄像机角度
|
|||
|
private void OnCameraSpaceBlurMax(object args)
|
|||
|
{
|
|||
|
EnableSceneCamera(true);
|
|||
|
}
|
|||
|
|
|||
|
private void OnUiCameraCopy(object args)
|
|||
|
{
|
|||
|
var start = (bool)args;
|
|||
|
_hideCamera = _hideCamera.ReplaceFlag(1.ToFlag(), start);
|
|||
|
SetHideCamera(1, start);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
private void OnSceneMovie(object args)
|
|||
|
{
|
|||
|
var start = (bool)args;
|
|||
|
SetHideCamera(2, start);
|
|||
|
}
|
|||
|
|
|||
|
private void SetHideCamera(int mask, bool isHide)
|
|||
|
{
|
|||
|
_hideCamera = _hideCamera.ReplaceFlag(mask.ToFlag(), isHide);
|
|||
|
if (MainCamera != null)
|
|||
|
MainCamera.enabled = _hideCamera <= 0;
|
|||
|
}
|
|||
|
|
|||
|
// // 暂时使用协程处理这个部分
|
|||
|
// IEnumerator LerpCameraParameters(float pitch, float yaw, float distance, float minFieldOfView, float maxFieldOfView, Tab_SceneCameraStartPos target)
|
|||
|
// {
|
|||
|
// const float lerpTime = 1f;
|
|||
|
// var startTime = Time.unscaledTime;
|
|||
|
// while (startTime + lerpTime > Time.unscaledTime)
|
|||
|
// {
|
|||
|
// var ratio = (Time.unscaledTime - startTime) / lerpTime;
|
|||
|
// SetCameraParameters(
|
|||
|
// Mathf.Lerp(pitch, target.Pitch, ratio),
|
|||
|
// Mathf.Lerp(yaw, target.Yaw, ratio),
|
|||
|
// Mathf.Lerp(distance, target.Distance, ratio),
|
|||
|
// Mathf.Lerp(minFieldOfView, target.ViewMin, ratio),
|
|||
|
// Mathf.Lerp(maxFieldOfView, target.ViewMax, ratio),
|
|||
|
// FocusOffset);
|
|||
|
// yield return null;
|
|||
|
// }
|
|||
|
// SetCameraParameters(target.Pitch, target.Yaw, target.Distance, target.ViewMin, target.ViewMax, FocusOffset);
|
|||
|
// }
|
|||
|
|
|||
|
//private void OnPinch(PinchGesture gesture)
|
|||
|
//{
|
|||
|
// if (JoyStickLogic.Instance() != null && JoyStickLogic.Instance().FingerID != -1)
|
|||
|
// return;
|
|||
|
// if (gesture.Phase == ContinuousGesturePhase.Started)
|
|||
|
// {
|
|||
|
// var mainPlayer = Singleton<ObjManager>.Instance.MainPlayer;
|
|||
|
// if (null != mainPlayer)
|
|||
|
// if (Singleton<ObjManager>.GetInstance().MainPlayer.IsCanOperate_Move())
|
|||
|
// Singleton<ObjManager>.GetInstance().MainPlayer.StopMove();
|
|||
|
// m_bPinching = true;
|
|||
|
// }
|
|||
|
// else if (gesture.Phase == ContinuousGesturePhase.Updated)
|
|||
|
// {
|
|||
|
// var absDelta = Mathf.Abs(gesture.Delta);
|
|||
|
// if (absDelta > m_PinchMax)
|
|||
|
// absDelta = m_PinchMax;
|
|||
|
// var curDelta = absDelta * gesture.Delta / Mathf.Abs(gesture.Delta);
|
|||
|
// m_Scale -= curDelta * (0.5f + 0.5f * m_Scale) / m_pinchSpeed;
|
|||
|
// if (m_Scale > 1.0f) m_Scale = 1.0f;
|
|||
|
// if (m_Scale < 0) m_Scale = 0;
|
|||
|
// }
|
|||
|
// else
|
|||
|
// {
|
|||
|
// m_bPinching = false;
|
|||
|
// }
|
|||
|
//}
|
|||
|
|
|||
|
//private void PlayShakeAnimation(string animationName)
|
|||
|
//{
|
|||
|
// var clip = _animation.GetClip(animationName);
|
|||
|
// if (clip == null)
|
|||
|
// {
|
|||
|
// var newClip = CommonUtility.LoadFromResources<AnimationClip>("CameraRockAnimation/" + animationName);
|
|||
|
// if (newClip != null)
|
|||
|
// {
|
|||
|
// _animation.AddClip(newClip, animationName);
|
|||
|
// _animation.Play(animationName);
|
|||
|
// }
|
|||
|
// }
|
|||
|
// else
|
|||
|
// {
|
|||
|
// _animation.Play(animationName);
|
|||
|
// }
|
|||
|
//}
|
|||
|
|
|||
|
// 统一摄像机移动的接口
|
|||
|
private void PostCameraMovement()
|
|||
|
{
|
|||
|
//UpdateWeatherPosition();
|
|||
|
EventDispatcher.Instance.Dispatch(Games.Events.EventId.PostMainCameraMove);
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 整合CameraRock表以及AnimationCurve表的数据结构
|
|||
|
/// </summary>
|
|||
|
private class CameraShakeTableData
|
|||
|
{
|
|||
|
public readonly int id;
|
|||
|
public readonly string animName;
|
|||
|
public readonly float delayTime;
|
|||
|
public readonly float animLength;
|
|||
|
private readonly bool _playWhileDead;
|
|||
|
private readonly AnimationCurve _localXCurve;
|
|||
|
private readonly AnimationCurve _localYCurve;
|
|||
|
private readonly AnimationCurve _localZCurve;
|
|||
|
private readonly AnimationCurve _localForwardXCurve;
|
|||
|
private readonly AnimationCurve _localForwardYCurve;
|
|||
|
private readonly AnimationCurve _localForwardZCurve;
|
|||
|
|
|||
|
public CameraShakeTableData(Tab_CameraRock tableData)
|
|||
|
{
|
|||
|
id = tableData.RockID;
|
|||
|
delayTime = tableData.DelayTime;
|
|||
|
animLength = tableData.NeedRockTime;
|
|||
|
_playWhileDead = tableData.IsContinueDie;
|
|||
|
if (tableData.IsAnimation > 0)
|
|||
|
animName = tableData.AnimationName;
|
|||
|
else
|
|||
|
{
|
|||
|
animName = string.Empty;
|
|||
|
_localXCurve = CommonUtility.GetAnimationCurveById(tableData.PosXAnimCurveId);
|
|||
|
_localYCurve = CommonUtility.GetAnimationCurveById(tableData.PosYAnimCurveId);
|
|||
|
_localZCurve = CommonUtility.GetAnimationCurveById(tableData.PosZAnimCurveId);
|
|||
|
_localForwardXCurve = CommonUtility.GetAnimationCurveById(tableData.RXAnimCurveId);
|
|||
|
_localForwardYCurve = CommonUtility.GetAnimationCurveById(tableData.RYAnimCurveId);
|
|||
|
_localForwardZCurve = CommonUtility.GetAnimationCurveById(tableData.RZAnimCurveId);
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 使用动画组件执行震屏效果
|
|||
|
/// </summary>
|
|||
|
public bool EvaluteAnim(float time)
|
|||
|
{
|
|||
|
time = time - delayTime;
|
|||
|
return time <= animLength;
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 计算震屏效果的位置偏移和旋转偏移
|
|||
|
/// </summary>
|
|||
|
/// <param name="time">时间,包括delay部分</param>
|
|||
|
/// <param name="position">位置偏移</param>
|
|||
|
/// <param name="rotation">旋转偏移</param>
|
|||
|
/// <returns>动画是否过期</returns>
|
|||
|
public bool EvaluteCurve(float time, out Vector3 position, out Quaternion rotation)
|
|||
|
{
|
|||
|
time = time - delayTime;
|
|||
|
var result = time <= animLength;
|
|||
|
if (result)
|
|||
|
{
|
|||
|
position.x = _localXCurve == null ? 0 : _localXCurve.Evaluate(time);
|
|||
|
position.y = _localYCurve == null ? 0 : _localYCurve.Evaluate(time);
|
|||
|
position.z = _localZCurve == null ? 0 : _localZCurve.Evaluate(time);
|
|||
|
var forward = new Vector3
|
|||
|
(
|
|||
|
_localForwardXCurve ==null ? 0 : _localForwardXCurve.Evaluate(time),
|
|||
|
_localForwardYCurve == null ? 0 : _localForwardYCurve.Evaluate(time),
|
|||
|
_localForwardZCurve == null ? 0 : _localForwardZCurve.Evaluate(time)
|
|||
|
);
|
|||
|
if (forward == Vector3.zero || Vector3.Cross(forward, Vector3.up) == Vector3.zero)
|
|||
|
rotation = Quaternion.identity;
|
|||
|
else
|
|||
|
rotation = Quaternion.LookRotation(forward, Vector3.up);
|
|||
|
}
|
|||
|
else
|
|||
|
{
|
|||
|
position = Vector3.zero;
|
|||
|
rotation = Quaternion.identity;
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
|
|||
|
// 现仅仅检视主角死亡,后续有其他特殊检视都加在这里
|
|||
|
public bool IsPlayable()
|
|||
|
{
|
|||
|
var result = true;
|
|||
|
if (!_playWhileDead)
|
|||
|
{
|
|||
|
var mainCharacter = Singleton<ObjManager>.Instance.MainPlayer;
|
|||
|
if (mainCharacter == null || mainCharacter.IsDie())
|
|||
|
result = false;
|
|||
|
}
|
|||
|
return result;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
/// <summary>
|
|||
|
/// 实际运行中的CameraShakeData
|
|||
|
/// </summary>
|
|||
|
private class CameraShakeData
|
|||
|
{
|
|||
|
public readonly CameraShakeTableData data;
|
|||
|
public readonly float startTime;
|
|||
|
public readonly int handle;
|
|||
|
public readonly int priority;
|
|||
|
public CameraShakeData(CameraShakeTableData data,int handle, int priority)
|
|||
|
{
|
|||
|
this.data = data;
|
|||
|
this.handle = handle;
|
|||
|
this.priority = priority;
|
|||
|
startTime = Time.time;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
#region 摄像机移动重载功能
|
|||
|
// 接口基类
|
|||
|
public abstract class CameraMovementOverrider
|
|||
|
{
|
|||
|
/// <summary>
|
|||
|
/// 使用Override方式移动,返回值表示是否继续Override
|
|||
|
/// </summary>
|
|||
|
public abstract bool MoveByOverride(CameraController controller);
|
|||
|
/// <summary>
|
|||
|
/// 开始执行移动覆盖
|
|||
|
/// </summary>
|
|||
|
public abstract void Start(CameraController controller);
|
|||
|
/// <summary>
|
|||
|
/// 结束移动覆盖
|
|||
|
/// </summary>
|
|||
|
public abstract void End(CameraController controller);
|
|||
|
}
|
|||
|
|
|||
|
//public class CameraTrackMovement : CameraMovementOverrider
|
|||
|
//{
|
|||
|
// public const float defaultTrackSpeed = 10f;
|
|||
|
// public readonly Vector3 posStart;
|
|||
|
// public readonly Vector3 posEnd;
|
|||
|
// public readonly Vector3 offset;
|
|||
|
// public readonly Quaternion rotation;
|
|||
|
// public readonly float duration;
|
|||
|
// public readonly float startTime;
|
|||
|
|
|||
|
// public CameraTrackMovement(Vector3 start, Vector3 end, Vector3 offset, float trackSpeed = defaultTrackSpeed)
|
|||
|
// {
|
|||
|
// this.posStart = start;
|
|||
|
// this.posEnd = end;
|
|||
|
// this.offset = offset;
|
|||
|
// var lookDir = -offset;
|
|||
|
// var lookX = Vector3.Cross(Vector3.up, lookDir);
|
|||
|
// // 仰角为90或者-90并且end = start的情况自然报错
|
|||
|
// rotation = lookX == Vector3.zero ? Quaternion.LookRotation(lookDir, end - start) : Quaternion.LookRotation(lookDir, Vector3.up);
|
|||
|
// this.startTime = Time.time;
|
|||
|
// this.duration = Vector3.Distance(posStart, posEnd) / trackSpeed;
|
|||
|
// }
|
|||
|
|
|||
|
// public override bool MoveByOverride(CameraController controller)
|
|||
|
// {
|
|||
|
// var result = false;
|
|||
|
// if (Time.time < startTime + duration)
|
|||
|
// {
|
|||
|
// var focusPoint = Vector3.Lerp(posStart, posEnd, (Time.time - startTime) / duration);
|
|||
|
// controller.transform.position = focusPoint + offset;
|
|||
|
// controller.transform.rotation = rotation;
|
|||
|
// result = true;
|
|||
|
// }
|
|||
|
// return result;
|
|||
|
// }
|
|||
|
//}
|
|||
|
#endregion
|
|||
|
|
|||
|
// #region 天气系统
|
|||
|
// private const string _conditionHash = "Condition";
|
|||
|
// private static readonly MyTuple<WeatherCondition, string>[] weatherPaths =
|
|||
|
// {
|
|||
|
// new MyTuple<WeatherCondition, string>(WeatherCondition.Rain, "weather_rain"),
|
|||
|
// new MyTuple<WeatherCondition, string>(WeatherCondition.Snow, "weather_snow")
|
|||
|
// };
|
|||
|
//
|
|||
|
// private readonly List<MyTuple<WeatherCondition, WeatherParticle>> effectList =
|
|||
|
// new List<MyTuple<WeatherCondition, WeatherParticle>>();
|
|||
|
//
|
|||
|
// public WeatherCondition currentWeather { get; private set; }
|
|||
|
// private WeatherParticle currentWeatherSfx;
|
|||
|
//
|
|||
|
// public void SetWeather(WeatherCondition condition)
|
|||
|
// {
|
|||
|
// MyTuple<WeatherCondition, string> weather = null;
|
|||
|
// if (condition != WeatherCondition.None)
|
|||
|
// {
|
|||
|
// weather = weatherPaths.Find(a => a.first == condition);
|
|||
|
// if (weather == null)
|
|||
|
// {
|
|||
|
// LogModule.ErrorLog(string.Format("未定义天气效果{0}", condition.ToString()));
|
|||
|
// condition = WeatherCondition.None;
|
|||
|
// }
|
|||
|
// }
|
|||
|
// if (condition != currentWeather)
|
|||
|
// {
|
|||
|
// if (currentWeatherSfx != null)
|
|||
|
// currentWeatherSfx.gameObject.SetActive(false);
|
|||
|
// ActiveEffect(weather);
|
|||
|
// }
|
|||
|
// }
|
|||
|
//
|
|||
|
// private void ActiveEffect(MyTuple<WeatherCondition, string> weather)
|
|||
|
// {
|
|||
|
// currentWeather = weather.first;
|
|||
|
// if (currentWeather != WeatherCondition.None)
|
|||
|
// {
|
|||
|
// var effect = effectList.Find(a => a.first == weather.first);
|
|||
|
// if (effect == null)
|
|||
|
// {
|
|||
|
// var hash = new Hashtable();
|
|||
|
// hash.Add(_conditionHash, currentWeather);
|
|||
|
// CommonUtility.LoadAssetInstance(LoadAssetBundle.BUNDLE_PATH_EFFECT + weather.second, weather.second,
|
|||
|
// OnWeatherBundleLoaded, hash);
|
|||
|
// }
|
|||
|
// else
|
|||
|
// {
|
|||
|
// currentWeatherSfx = effect.second;
|
|||
|
// currentWeatherSfx.gameObject.SetActive(true);
|
|||
|
// UpdateWeatherPosition();
|
|||
|
// }
|
|||
|
// }
|
|||
|
// }
|
|||
|
//
|
|||
|
// private void OnWeatherBundleLoaded(string modelName, GameObject resObj, Hashtable hashParam)
|
|||
|
// {
|
|||
|
// var condition = (WeatherCondition)hashParam[_conditionHash];
|
|||
|
// // 仅缓存当前天气效果,非当前天气效果不缓存
|
|||
|
// if (condition == currentWeather)
|
|||
|
// {
|
|||
|
// var effect = effectList.Find(a => a.first == condition);
|
|||
|
// // 在第一次回调前,发出第二次要求时;第二次回调时会已经处理过
|
|||
|
// if (effect == null)
|
|||
|
// {
|
|||
|
// var sfxObj = Instantiate(resObj);
|
|||
|
// currentWeatherSfx = sfxObj.GetComponent<WeatherParticle>();
|
|||
|
// currentWeatherSfx.transform.localRotation = Quaternion.identity;
|
|||
|
// currentWeatherSfx.transform.localScale = Vector3.one;
|
|||
|
// effect = new MyTuple<WeatherCondition, WeatherParticle>(condition, currentWeatherSfx);
|
|||
|
// effectList.Add(effect);
|
|||
|
// UpdateWeatherPosition();
|
|||
|
// }
|
|||
|
// }
|
|||
|
// }
|
|||
|
//
|
|||
|
// private void UpdateWeatherPosition()
|
|||
|
// {
|
|||
|
// if (currentWeatherSfx != null)
|
|||
|
// {
|
|||
|
// currentWeatherSfx.transform.position = MainCamera.transform.position;
|
|||
|
// // 面向摄像机前方
|
|||
|
// var x = Vector3.Cross(Vector3.up, MainCamera.transform.forward);
|
|||
|
// var z = x == Vector3.zero ? Vector3.forward : Vector3.Cross(x, Vector3.up);
|
|||
|
// currentWeatherSfx.transform.rotation = Quaternion.LookRotation(z, Vector3.up);
|
|||
|
// currentWeatherSfx.OnCameraUpdate(this);
|
|||
|
// }
|
|||
|
// }
|
|||
|
//
|
|||
|
// public enum WeatherCondition
|
|||
|
// {
|
|||
|
// None, // 常规气候
|
|||
|
// Rain, // 下雨
|
|||
|
// Snow // 下雪
|
|||
|
// }
|
|||
|
// #endregion
|
|||
|
|
|||
|
// #region 截屏相关 全屏截图
|
|||
|
//
|
|||
|
// public void CaptureAllScreen(string savePath = "", CaptureOver fun = null)
|
|||
|
// {
|
|||
|
// StartCoroutine(CaptureScreen1(MainCamera, savePath, fun));
|
|||
|
// }
|
|||
|
//
|
|||
|
// private IEnumerator CaptureScreen1(Camera came, string savePath, CaptureOver fun)
|
|||
|
// {
|
|||
|
// if (came == null)
|
|||
|
// came = MainCamera;
|
|||
|
// if (came == null)
|
|||
|
// yield break;
|
|||
|
// Rect r = new Rect(0, 0, Screen.width, Screen.height);
|
|||
|
// if (came.pixelRect.x != 1 || came.pixelRect.y != 1)
|
|||
|
// r = came.pixelRect;
|
|||
|
// RenderTexture rt = new RenderTexture((int)r.width, (int)r.height, 0);
|
|||
|
// CameraClearFlags Old = came.clearFlags;
|
|||
|
// came.clearFlags = CameraClearFlags.Depth;
|
|||
|
// came.targetTexture = rt;
|
|||
|
// came.Render();
|
|||
|
// RenderTexture.active = rt;
|
|||
|
// Texture2D screenShot = new Texture2D((int)r.width, (int)r.height, TextureFormat.ARGB32, false);
|
|||
|
//
|
|||
|
// yield return new WaitForEndOfFrame();
|
|||
|
//
|
|||
|
// screenShot.ReadPixels(r, 0, 0);
|
|||
|
// screenShot.Apply();
|
|||
|
// came.targetTexture = null;
|
|||
|
// RenderTexture.active = null;
|
|||
|
// came.clearFlags = Old;
|
|||
|
// GameObject.Destroy(rt);
|
|||
|
//
|
|||
|
// string path = Application.persistentDataPath + "/" + savePath;
|
|||
|
//#if UNITY_EDITOR
|
|||
|
// path = Application.dataPath + "/" + savePath;
|
|||
|
//#endif
|
|||
|
//
|
|||
|
// savePath = savePath.Replace("\\", "/");
|
|||
|
// int index = savePath.LastIndexOf("/");
|
|||
|
// string Direct = savePath.Substring(0, index);
|
|||
|
// if (System.IO.Directory.Exists(Direct))
|
|||
|
// {
|
|||
|
// byte[] bytes = screenShot.EncodeToPNG();
|
|||
|
// System.IO.File.WriteAllBytes(savePath, bytes);
|
|||
|
// }
|
|||
|
// if(fun!=null)
|
|||
|
// {
|
|||
|
// fun(screenShot, savePath);
|
|||
|
// }
|
|||
|
// }
|
|||
|
// #endregion
|
|||
|
}
|