using System; using System.Collections.Generic; using Superlazy; using UnityEngine; public abstract class CameraOperation { public virtual Vector3 CenterDelta { get; } = Vector3.zero; public virtual Vector3 OffsetDelta { get; } = Vector3.zero; public virtual float DistDelta { get; } = 0; public virtual float LatitudeDelta { get; } = 0; public virtual float OffsetRotationDelta { get; } = 0; public abstract bool IsEnd { get; } public abstract void Play(); } public class CameraZoom : CameraOperation { private readonly float fadeTime; private readonly float fadeDelay; private readonly float targetDist; private float currentTime; private float currentZoom; private float zoomDelta; public CameraZoom(float targetDist, float fadeTime, float fadeDelay) { this.fadeTime = fadeTime; this.fadeDelay = fadeDelay; currentTime = 0.0f; targetDist = targetDist + SLGame.Session["CameraView"]["DestDistance"] - SLGame.Session["CameraView"]["DestDistance"]; this.targetDist = targetDist; SLGame.Session["CameraView"]["DestDistance"] += targetDist; } public override float DistDelta => zoomDelta; public override bool IsEnd => currentTime > fadeTime + fadeDelay; public override void Play() { currentTime += Time.smoothDeltaTime; if (currentTime - fadeDelay > 0 && currentTime - fadeDelay < fadeTime) { var t = Mathf.SmoothStep(0, 1, (currentTime - fadeDelay) / fadeTime); zoomDelta = t * targetDist - currentZoom; currentZoom = t * targetDist; } else if (currentTime - fadeDelay >= fadeTime) { zoomDelta = targetDist - currentZoom; currentZoom = targetDist; } } } public class CameraMove : CameraOperation { private readonly Vector3 direction; private readonly float fadeTime; private readonly float fadeDelay; private float currentTime; private Vector3 currentCenter; private Vector3 centerDelta; public CameraMove(Vector3 direction, float fadeTime, float fadeDelay) { this.fadeTime = fadeTime; this.fadeDelay = fadeDelay; currentTime = 0.0f; currentCenter = Vector3.zero; this.direction = direction; var cameraView = SLGame.Session["CameraView"]; var dest = cameraView["Dest"].ToVector3() + direction; dest.x = Mathf.Clamp(dest.x, cameraView["MinX"], cameraView["MaxX"]); dest.z = Mathf.Clamp(dest.z, cameraView["MinZ"], cameraView["MaxZ"]); SLGame.Session["CameraView"]["Dest"] = dest.ToEntity(); } public override Vector3 CenterDelta => centerDelta; public override bool IsEnd => currentTime > fadeTime + fadeDelay; public override void Play() { currentTime += Time.deltaTime; if (currentTime - fadeDelay > 0 && currentTime - fadeDelay < fadeTime) { var t = (currentTime - fadeDelay) / fadeTime; var newCenter = Vector3.Lerp(Vector3.zero, direction, t); centerDelta = newCenter - currentCenter; currentCenter = newCenter; } else if (currentTime - fadeDelay >= fadeTime) { centerDelta = direction - currentCenter; currentCenter = direction; } } } public class CameraOffset : CameraOperation { private readonly Vector3 direction; private readonly float fadeTime; private readonly float fadeDelay; private float currentTime; private Vector3 currentCenter; private Vector3 centerDelta; public CameraOffset(Vector3 direction, float fadeTime, float fadeDelay) { this.fadeTime = fadeTime; this.fadeDelay = fadeDelay; currentTime = 0.0f; currentCenter = Vector3.zero; this.direction = direction; var dest = SLGame.Session["CameraView"]["DestOffset"].ToVector3() + direction; SLGame.Session["CameraView"]["DestOffset"] = dest.ToEntity(); } public override Vector3 OffsetDelta => centerDelta; public override bool IsEnd => currentTime > fadeTime + fadeDelay; public override void Play() { currentTime += Time.smoothDeltaTime; if (currentTime - fadeDelay > 0 && currentTime - fadeDelay < fadeTime) { var t = (currentTime - fadeDelay) / fadeTime; var newCenter = Vector3.Slerp(Vector3.zero, direction, t); centerDelta = newCenter - currentCenter; currentCenter = newCenter; } else if (currentTime - fadeDelay >= fadeTime) { centerDelta = direction - currentCenter; currentCenter = direction; } } } public class CameraShake : CameraOperation { private readonly Vector3 direction; private readonly float fadeTime; private readonly float fadeDelay; private float currentTime; private Vector3 currentCenter; private Vector3 centerDelta; private readonly int count; public CameraShake(Vector3 direction, int count, float fadeTime, float fadeDelay) { this.fadeTime = fadeTime; this.fadeDelay = fadeDelay; this.count = count; currentTime = 0.0f; currentCenter = Vector3.zero; this.direction = direction; } public override Vector3 CenterDelta => centerDelta; public override bool IsEnd => currentTime > fadeTime + fadeDelay; public override void Play() { currentTime += Time.smoothDeltaTime; if (currentTime - fadeDelay > 0 && currentTime - fadeDelay < fadeTime) { var t = (currentTime - fadeDelay) / fadeTime * count; var shakeAmount = direction.magnitude * (count - t); var shakeDir = direction.normalized; var shakeValue = Mathf.Cos((1 - t) * 360 * 2) * shakeAmount * shakeDir; centerDelta = shakeValue - currentCenter; currentCenter = shakeValue; } else if (currentTime - fadeDelay >= fadeTime) { centerDelta = direction - currentCenter; currentCenter = direction; } } } public class CameraRotation : CameraOperation { private readonly float fadeTime; private readonly float fadeDelay; private float currentTime; private float current; private float currentDelta; private readonly float delta; public CameraRotation(float delta, float fadeTime, float fadeDelay) { this.fadeTime = fadeTime; this.fadeDelay = fadeDelay; currentTime = 0.0f; this.delta = delta; SLGame.Session["CameraView"]["DestOffsetRotation"] += delta; } public override float OffsetRotationDelta => current; public override bool IsEnd => currentTime > fadeTime + fadeDelay; public override void Play() { currentTime += Time.smoothDeltaTime; if (currentTime - fadeDelay > 0 && currentTime - fadeDelay < fadeTime) { var t = (currentTime - fadeDelay) / fadeTime; var tv = Mathf.Sin(t * Mathf.PI - Mathf.PI / 2) * 0.5f + 0.5f; if (t < 0.5f) { t = Mathf.Pow(tv, 3); } else { t = 1 - Mathf.Pow(1 - tv, 3); } current = t * delta - currentDelta; currentDelta = t * delta; } else if (currentTime - fadeDelay >= fadeTime) { current = delta - currentDelta; currentDelta = current; } } } public class CameraLatitude : CameraOperation { private readonly float latitude; private readonly float fadeTime; private readonly float fadeDelay; private readonly float targetLatitude; private float currentTime; private float currentLatitude; private float latitudeDelta; public CameraLatitude(float latitude, float fadeTime, float fadeDelay) { this.fadeTime = fadeTime; this.fadeDelay = fadeDelay; currentTime = 0.0f; targetLatitude = latitude; SLGame.Session["CameraView"]["DestLatitude"] += targetLatitude; } public override float LatitudeDelta => latitudeDelta; public override bool IsEnd => currentTime > fadeTime + fadeDelay; public override void Play() { currentTime += Time.smoothDeltaTime; if (currentTime - fadeDelay > 0 && currentTime - fadeDelay < fadeTime) { var t = Mathf.SmoothStep(0, 1, (currentTime - fadeDelay) / fadeTime); latitudeDelta = t * targetLatitude - currentLatitude; currentLatitude = t * targetLatitude; } else if (currentTime - fadeDelay >= fadeTime) { latitudeDelta = targetLatitude - currentLatitude; currentLatitude = targetLatitude; } } } public class SLCamera : MonoBehaviour { public static float minCameraDist = 0; public static float maxCameraDist = 900; public float latitude = 40; public int longtitude = 40; public float distance = 900; public Vector3 center = Vector3.zero; public Vector3 offset = Vector3.zero; public float offsetRotation = 0; private readonly List operations = new List(); private float cameraDist; private Camera[] cams; private readonly Transform background; private string positionBind = string.Empty; private int stopDist; private int moveDist; private Camera[] Cams { get { if (cams == null) { cams = GetComponentsInChildren(); cameraDist = cams[0].farClipPlane; } return cams; } } private void LateUpdate() { foreach (var op in operations) { op.Play(); center += op.CenterDelta; distance += op.DistDelta; latitude += op.LatitudeDelta; offset += op.OffsetDelta; offsetRotation += op.OffsetRotationDelta; } operations.RemoveAll(op => op.IsEnd); if (operations.Count == 0) { center = SLGame.Session["CameraView"]["Dest"].ToVector3(); distance = SLGame.Session["CameraView"]["DestDistance"]; latitude = SLGame.Session["CameraView"]["DestLatitude"]; offset = SLGame.Session["CameraView"]["DestOffset"].ToVector3(); offsetRotation = SLGame.Session["CameraView"]["DestOffsetRotation"]; } if (string.IsNullOrEmpty(positionBind) == false) { var destCenter = SLGame.SessionGet(positionBind).ToVector3(); var targetDist = moveDist; if (destCenter == center) targetDist = stopDist; center = destCenter; SLGame.Session["CameraView"]["Dest"] = destCenter.ToEntity(); } { var mainCam = Cams[0]; var dist = distance; if (mainCam.aspect < 1.77f/*16.0f/9.0f*/) { foreach (var cam in Cams) { cam.farClipPlane = 1.7777f / mainCam.aspect * cameraDist; } dist = dist * 1.7777f / mainCam.aspect; } else { foreach (var cam in Cams) { cam.farClipPlane = cameraDist; } } { var safeWidthtRate = Screen.width / Screen.safeArea.width; var safeHeightRate = Screen.height / Screen.safeArea.height; dist *= Mathf.Max(safeWidthtRate, safeHeightRate); } transform.SetPositionAndRotation(Quaternion.Euler(latitude, longtitude, 0) * Vector3.back * dist - transform.rotation * offset + center, Quaternion.Euler(latitude, longtitude + offsetRotation, 0)); SLGame.Session["CameraView"]["Center"] = center.ToEntity(); SLGame.Session["CameraView"]["Distance"] = distance; SLGame.Session["CameraView"]["Offset"] = offset.ToEntity(); SLGame.Session["CameraView"]["Latitude"] = latitude; SLGame.Session["CameraView"]["OffsetRotation"] = offsetRotation; } } public void Play(CameraOperation op) { operations.Add(op); } private void Clear() { operations.Clear(); } public void InitCamera(int latitude, int distance, Vector3 center, Vector3 offset) { Clear(); this.latitude = latitude; this.distance = distance; this.center = center; this.offset = offset; SLGame.Session["CameraView"]["Dest"] = this.center.ToEntity(); SLGame.Session["CameraView"]["Center"] = this.center.ToEntity(); SLGame.Session["CameraView"]["DestDistance"] = this.distance; SLGame.Session["CameraView"]["Distance"] = this.distance; SLGame.Session["CameraView"]["DestOffset"] = this.offset.ToEntity(); SLGame.Session["CameraView"]["Offset"] = this.offset.ToEntity(); SLGame.Session["CameraView"]["DestLatitude"] = this.latitude; SLGame.Session["CameraView"]["Latitude"] = this.latitude; SLGame.Session["CameraView"]["DestOffsetRotation"] = 0; SLGame.Session["CameraView"]["OffsetRotation"] = 0; SLGame.Session["CameraView"]["MinX"] = float.MinValue; SLGame.Session["CameraView"]["MinZ"] = float.MinValue; SLGame.Session["CameraView"]["MaxX"] = float.MaxValue; SLGame.Session["CameraView"]["MaxZ"] = float.MaxValue; } public void AnchorBind(string anchorPosition, int stopDist, int moveDist, float zoomSpeed) { if (string.IsNullOrEmpty(anchorPosition)) { positionBind = null; } else { positionBind = anchorPosition; this.stopDist = stopDist; this.moveDist = moveDist; } } public void SetBound(float minX, float minZ, float maxX, float maxZ) { SLGame.Session["CameraView"]["MinX"] = minX; SLGame.Session["CameraView"]["MinZ"] = minZ; SLGame.Session["CameraView"]["MaxX"] = maxX; SLGame.Session["CameraView"]["MaxZ"] = maxZ; } }