|
|
|
// This code is part of the Fungus library (https://github.com/snozbot/fungus)
|
|
|
|
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
|
|
|
|
|
|
|
|
using UnityEngine;
|
|
|
|
using System;
|
|
|
|
using System.Collections;
|
|
|
|
using System.Collections.Generic;
|
|
|
|
using Fungus;
|
|
|
|
|
|
|
|
namespace Fungus
|
|
|
|
{
|
|
|
|
/// <summary>
|
|
|
|
/// Manager for main camera. Supports several types of camera transition including snap, pan & fade.
|
|
|
|
/// </summary>
|
|
|
|
public class CameraManager : MonoBehaviour
|
|
|
|
{
|
|
|
|
[Tooltip("Full screen texture used for screen fade effect.")]
|
|
|
|
[SerializeField] protected Texture2D screenFadeTexture;
|
|
|
|
|
|
|
|
[Tooltip("Icon to display when swipe pan mode is active.")]
|
|
|
|
[SerializeField] protected Texture2D swipePanIcon;
|
|
|
|
|
|
|
|
[Tooltip("Position of continue and swipe icons in normalized screen space coords. (0,0) = top left, (1,1) = bottom right")]
|
|
|
|
[SerializeField] protected Vector2 swipeIconPosition = new Vector2(1,0);
|
|
|
|
|
|
|
|
[Tooltip("Set the camera z coordinate to a fixed value every frame.")]
|
|
|
|
[SerializeField] protected bool setCameraZ = true;
|
|
|
|
|
|
|
|
[Tooltip("Fixed Z coordinate of main camera.")]
|
|
|
|
[SerializeField] protected float cameraZ = -10f;
|
|
|
|
|
|
|
|
[Tooltip("Camera to use when in swipe mode")]
|
|
|
|
[SerializeField] protected Camera swipeCamera;
|
|
|
|
|
|
|
|
protected float fadeAlpha = 0f;
|
|
|
|
|
|
|
|
// Swipe panning control
|
|
|
|
protected bool swipePanActive;
|
|
|
|
|
|
|
|
protected float swipeSpeedMultiplier = 1f;
|
|
|
|
protected View swipePanViewA;
|
|
|
|
protected View swipePanViewB;
|
|
|
|
protected Vector3 previousMousePos;
|
|
|
|
|
|
|
|
//Coroutine handles for panning and fading commands
|
|
|
|
protected LTDescr fadeTween, sizeTween, camPosTween, camRotTween;
|
|
|
|
|
|
|
|
protected class CameraView
|
|
|
|
{
|
|
|
|
public Vector3 cameraPos;
|
|
|
|
public Quaternion cameraRot;
|
|
|
|
public float cameraSize;
|
|
|
|
};
|
|
|
|
|
|
|
|
protected Dictionary<string, CameraView> storedViews = new Dictionary<string, CameraView>();
|
|
|
|
|
|
|
|
protected virtual void OnGUI()
|
|
|
|
{
|
|
|
|
if (swipePanActive)
|
|
|
|
{
|
|
|
|
// Draw the swipe panning icon
|
|
|
|
if (swipePanIcon)
|
|
|
|
{
|
|
|
|
float x = Screen.width * swipeIconPosition.x;
|
|
|
|
float y = Screen.height * swipeIconPosition.y;
|
|
|
|
float width = swipePanIcon.width;
|
|
|
|
float height = swipePanIcon.height;
|
|
|
|
|
|
|
|
x = Mathf.Max(x, 0);
|
|
|
|
y = Mathf.Max(y, 0);
|
|
|
|
x = Mathf.Min(x, Screen.width - width);
|
|
|
|
y = Mathf.Min(y, Screen.height - height);
|
|
|
|
|
|
|
|
Rect rect = new Rect(x, y, width, height);
|
|
|
|
GUI.DrawTexture(rect, swipePanIcon);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Draw full screen fade texture
|
|
|
|
if (fadeAlpha > 0f &&
|
|
|
|
screenFadeTexture != null)
|
|
|
|
{
|
|
|
|
// 1 = scene fully visible
|
|
|
|
// 0 = scene fully obscured
|
|
|
|
GUI.color = new Color(1,1,1, fadeAlpha);
|
|
|
|
GUI.depth = -1000;
|
|
|
|
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), screenFadeTexture);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected virtual void SetCameraZ(Camera camera)
|
|
|
|
{
|
|
|
|
if (!setCameraZ)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (camera == null)
|
|
|
|
{
|
|
|
|
Debug.LogWarning("Camera is null");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
camera.transform.position = new Vector3(camera.transform.position.x, camera.transform.position.y, cameraZ);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected virtual void Update()
|
|
|
|
{
|
|
|
|
if (!swipePanActive)
|
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (swipeCamera == null)
|
|
|
|
{
|
|
|
|
Debug.LogWarning("Camera is null");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 delta = Vector3.zero;
|
|
|
|
|
|
|
|
if (Input.touchCount > 0)
|
|
|
|
{
|
|
|
|
if (Input.GetTouch(0).phase == TouchPhase.Moved)
|
|
|
|
{
|
|
|
|
delta = Input.GetTouch(0).deltaPosition;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Input.GetMouseButtonDown(0))
|
|
|
|
{
|
|
|
|
previousMousePos = Input.mousePosition;
|
|
|
|
}
|
|
|
|
else if (Input.GetMouseButton(0))
|
|
|
|
{
|
|
|
|
delta = Input.mousePosition - previousMousePos;
|
|
|
|
previousMousePos = Input.mousePosition;
|
|
|
|
}
|
|
|
|
|
|
|
|
Vector3 cameraDelta = swipeCamera.ScreenToViewportPoint(delta);
|
|
|
|
cameraDelta.x *= -2f * swipeSpeedMultiplier;
|
|
|
|
cameraDelta.y *= -2f * swipeSpeedMultiplier;
|
|
|
|
cameraDelta.z = 0f;
|
|
|
|
|
|
|
|
Vector3 cameraPos = swipeCamera.transform.position;
|
|
|
|
|
|
|
|
cameraPos += cameraDelta;
|
|
|
|
|
|
|
|
swipeCamera.transform.position = CalcCameraPosition(cameraPos, swipePanViewA, swipePanViewB);
|
|
|
|
swipeCamera.orthographicSize = CalcCameraSize(cameraPos, swipePanViewA, swipePanViewB);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clamp camera position to region defined by the two views
|
|
|
|
protected virtual Vector3 CalcCameraPosition(Vector3 pos, View viewA, View viewB)
|
|
|
|
{
|
|
|
|
Vector3 safePos = pos;
|
|
|
|
|
|
|
|
// Clamp camera position to region defined by the two views
|
|
|
|
safePos.x = Mathf.Max(safePos.x, Mathf.Min(viewA.transform.position.x, viewB.transform.position.x));
|
|
|
|
safePos.x = Mathf.Min(safePos.x, Mathf.Max(viewA.transform.position.x, viewB.transform.position.x));
|
|
|
|
safePos.y = Mathf.Max(safePos.y, Mathf.Min(viewA.transform.position.y, viewB.transform.position.y));
|
|
|
|
safePos.y = Mathf.Min(safePos.y, Mathf.Max(viewA.transform.position.y, viewB.transform.position.y));
|
|
|
|
|
|
|
|
return safePos;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Smoothly interpolate camera orthographic size based on relative position to two views
|
|
|
|
protected virtual float CalcCameraSize(Vector3 pos, View viewA, View viewB)
|
|
|
|
{
|
|
|
|
// Get ray and point in same space
|
|
|
|
Vector3 toViewB = viewB.transform.position - viewA.transform.position;
|
|
|
|
Vector3 localPos = pos - viewA.transform.position;
|
|
|
|
|
|
|
|
// Normalize
|
|
|
|
float distance = toViewB.magnitude;
|
|
|
|
toViewB /= distance;
|
|
|
|
localPos /= distance;
|
|
|
|
|
|
|
|
// Project point onto ray
|
|
|
|
float t = Vector3.Dot(toViewB, localPos);
|
|
|
|
t = Mathf.Clamp01(t); // Not really necessary but no harm
|
|
|
|
|
|
|
|
float cameraSize = Mathf.Lerp(viewA.ViewSize, viewB.ViewSize, t);
|
|
|
|
|
|
|
|
return cameraSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
#region Public members
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Creates a flat colored texture.
|
|
|
|
/// </summary>
|
|
|
|
public static Texture2D CreateColorTexture(Color color, int width, int height)
|
|
|
|
{
|
|
|
|
Color[] pixels = new Color[width * height];
|
|
|
|
for (int i = 0; i < pixels.Length; i++)
|
|
|
|
{
|
|
|
|
pixels[i] = color;
|
|
|
|
}
|
|
|
|
Texture2D texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
|
|
|
|
texture.SetPixels(pixels);
|
|
|
|
texture.Apply();
|
|
|
|
|
|
|
|
return texture;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Full screen texture used for screen fade effect.
|
|
|
|
/// </summary>
|
|
|
|
/// <value>The screen fade texture.</value>
|
|
|
|
public Texture2D ScreenFadeTexture { set { screenFadeTexture = value; } }
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Perform a fullscreen fade over a duration.
|
|
|
|
/// </summary>
|
|
|
|
public virtual void Fade(float targetAlpha, float fadeDuration, Action fadeAction, LeanTweenType leanTweenType = LeanTweenType.easeInOutQuad)
|
|
|
|
{
|
|
|
|
StopFadeTween();
|
|
|
|
|
|
|
|
if (Mathf.Approximately(fadeDuration, 0))
|
|
|
|
{
|
|
|
|
fadeAlpha = targetAlpha;
|
|
|
|
if (fadeAction != null) fadeAction();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
fadeTween = LeanTween.value(fadeAlpha, targetAlpha, fadeDuration)
|
|
|
|
.setEase(leanTweenType)
|
|
|
|
.setOnUpdate((x) => fadeAlpha = x)
|
|
|
|
.setOnComplete(() =>
|
|
|
|
{
|
|
|
|
fadeAlpha = targetAlpha;
|
|
|
|
var tempFadeActin = fadeAction;
|
|
|
|
fadeAction = null;
|
|
|
|
if (tempFadeActin != null) tempFadeActin();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Fade out, move camera to view and then fade back in.
|
|
|
|
/// </summary>
|
|
|
|
public virtual void FadeToView(Camera camera, View view, float fadeDuration, bool fadeOut, Action fadeAction,
|
|
|
|
LeanTweenType fadeType = LeanTweenType.easeInOutQuad, LeanTweenType sizeTweenType = LeanTweenType.easeInOutQuad,
|
|
|
|
LeanTweenType posTweenType = LeanTweenType.easeInOutQuad, LeanTweenType rotTweenType = LeanTweenType.easeInOutQuad)
|
|
|
|
{
|
|
|
|
swipePanActive = false;
|
|
|
|
fadeAlpha = 0f;
|
|
|
|
|
|
|
|
float outDuration;
|
|
|
|
float inDuration;
|
|
|
|
|
|
|
|
if (fadeOut)
|
|
|
|
{
|
|
|
|
outDuration = fadeDuration / 2f;
|
|
|
|
inDuration = fadeDuration / 2f;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
outDuration = 0;
|
|
|
|
inDuration = fadeDuration;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fade out
|
|
|
|
Fade(1f, outDuration, delegate {
|
|
|
|
|
|
|
|
// Snap to new view
|
|
|
|
PanToPosition(camera, view.transform.position, view.transform.rotation, view.ViewSize, 0f, null, sizeTweenType, posTweenType, rotTweenType);
|
|
|
|
|
|
|
|
// Fade in
|
|
|
|
Fade(0f, inDuration, delegate {
|
|
|
|
if (fadeAction != null)
|
|
|
|
{
|
|
|
|
fadeAction();
|
|
|
|
}
|
|
|
|
}, fadeType);
|
|
|
|
}, fadeType);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Stop all camera tweening.
|
|
|
|
/// </summary>
|
|
|
|
public virtual void Stop()
|
|
|
|
{
|
|
|
|
StopFadeTween();
|
|
|
|
StopPosTweens();
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void StopFadeTween()
|
|
|
|
{
|
|
|
|
if (fadeTween != null)
|
|
|
|
{
|
|
|
|
LeanTween.cancel(fadeTween.id, true);
|
|
|
|
fadeTween = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void StopPosTweens()
|
|
|
|
{
|
|
|
|
if (sizeTween != null)
|
|
|
|
{
|
|
|
|
LeanTween.cancel(sizeTween.id, true);
|
|
|
|
sizeTween = null;
|
|
|
|
}
|
|
|
|
if (camPosTween != null)
|
|
|
|
{
|
|
|
|
LeanTween.cancel(camPosTween.id, true);
|
|
|
|
camPosTween = null;
|
|
|
|
}
|
|
|
|
if (camRotTween != null)
|
|
|
|
{
|
|
|
|
LeanTween.cancel(camRotTween.id, true);
|
|
|
|
camRotTween = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Moves camera from current position to a target position over a period of time.
|
|
|
|
/// </summary>
|
|
|
|
public virtual void PanToPosition(Camera camera, Vector3 targetPosition, Quaternion targetRotation, float targetSize, float duration, Action arriveAction,
|
|
|
|
LeanTweenType sizeTweenType = LeanTweenType.easeInOutQuad, LeanTweenType posTweenType = LeanTweenType.easeInOutQuad, LeanTweenType rotTweenType = LeanTweenType.easeInOutQuad)
|
|
|
|
{
|
|
|
|
if (camera == null)
|
|
|
|
{
|
|
|
|
Debug.LogWarning("Camera is null");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(setCameraZ)
|
|
|
|
{
|
|
|
|
targetPosition.z = camera.transform.position.z;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Stop any pan that is currently active
|
|
|
|
StopPosTweens();
|
|
|
|
swipePanActive = false;
|
|
|
|
|
|
|
|
if (Mathf.Approximately(duration, 0f))
|
|
|
|
{
|
|
|
|
// Move immediately
|
|
|
|
camera.orthographicSize = targetSize;
|
|
|
|
camera.transform.position = targetPosition;
|
|
|
|
camera.transform.rotation = targetRotation;
|
|
|
|
|
|
|
|
SetCameraZ(camera);
|
|
|
|
|
|
|
|
if (arriveAction != null)
|
|
|
|
{
|
|
|
|
arriveAction();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
sizeTween = LeanTween.value(camera.orthographicSize, targetSize, duration)
|
|
|
|
.setEase(sizeTweenType)
|
|
|
|
.setOnUpdate(x => camera.orthographicSize = x)
|
|
|
|
.setOnComplete(() =>
|
|
|
|
{
|
|
|
|
camera.orthographicSize = targetSize;
|
|
|
|
if (arriveAction != null) arriveAction();
|
|
|
|
sizeTween = null;
|
|
|
|
});
|
|
|
|
|
|
|
|
camPosTween = LeanTween.move(camera.gameObject, targetPosition, duration)
|
|
|
|
.setEase(posTweenType)
|
|
|
|
.setOnComplete(() =>
|
|
|
|
{
|
|
|
|
camera.transform.position = targetPosition;
|
|
|
|
camPosTween = null;
|
|
|
|
});
|
|
|
|
|
|
|
|
camRotTween = LeanTween.rotate(camera.gameObject, targetRotation.eulerAngles, duration)
|
|
|
|
.setEase(rotTweenType)
|
|
|
|
.setOnComplete(() =>
|
|
|
|
{
|
|
|
|
camera.transform.rotation = targetRotation;
|
|
|
|
camRotTween = null;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Activates swipe panning mode. The player can pan the camera within the area between viewA & viewB.
|
|
|
|
/// </summary>
|
|
|
|
public virtual void StartSwipePan(Camera camera, View viewA, View viewB, float duration, float speedMultiplier, Action arriveAction)
|
|
|
|
{
|
|
|
|
if (camera == null)
|
|
|
|
{
|
|
|
|
Debug.LogWarning("Camera is null");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
swipePanViewA = viewA;
|
|
|
|
swipePanViewB = viewB;
|
|
|
|
swipeSpeedMultiplier = speedMultiplier;
|
|
|
|
|
|
|
|
Vector3 cameraPos = camera.transform.position;
|
|
|
|
|
|
|
|
Vector3 targetPosition = CalcCameraPosition(cameraPos, swipePanViewA, swipePanViewB);
|
|
|
|
float targetSize = CalcCameraSize(cameraPos, swipePanViewA, swipePanViewB);
|
|
|
|
|
|
|
|
PanToPosition(camera, targetPosition, Quaternion.identity, targetSize, duration, delegate {
|
|
|
|
|
|
|
|
swipePanActive = true;
|
|
|
|
swipeCamera = camera;
|
|
|
|
|
|
|
|
if (arriveAction != null)
|
|
|
|
{
|
|
|
|
arriveAction();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
/// Deactivates swipe panning mode.
|
|
|
|
/// </summary>
|
|
|
|
public virtual void StopSwipePan()
|
|
|
|
{
|
|
|
|
swipePanActive = false;
|
|
|
|
swipePanViewA = null;
|
|
|
|
swipePanViewB = null;
|
|
|
|
swipeCamera = null;
|
|
|
|
}
|
|
|
|
|
|
|
|
#endregion
|
|
|
|
}
|
|
|
|
}
|