creative-jam-20/Assets/Scripts/WorldSwitcher.cs
2022-05-14 16:09:09 -04:00

131 lines
4.0 KiB
C#

using System;
using System.Collections;
using UnityEngine;
public class WorldSwitcher : MonoBehaviour {
[Range(0, 5)]
[SerializeField] float transitionDuration;
[SerializeField] AnimationCurve transitionCurve;
[SerializeField] WorldInfo[] worldInfos;
[SerializeField] float quadOffset;
[Range(0, 1)]
[SerializeField] float tabWidth;
int lastWorldIndex;
int currentWorldIndex;
Coroutine transition;
static readonly int UVOffset = Shader.PropertyToID("_UVOffset");
void Start() {
if (worldInfos.Length != 3)
Debug.LogWarning("For now, WorldSwitcher should have 3 worlds.");
currentWorldIndex = 1;
lastWorldIndex = 0;
for (int i = 0; i < worldInfos.Length; i++) {
worldInfos[i].material = worldInfos[i].renderQuad.GetComponent<Renderer>().material;
worldInfos[i].GenerateRenderTexture();
}
ResetQuadPositions();
}
public void SwitchWorld(bool right) {
if (right ? currentWorldIndex == worldInfos.Length - 1 : currentWorldIndex == 0)
return;
//TODO Block window resize during transition?
foreach (WorldInfo worldInfo in worldInfos) {
if (Screen.width != worldInfo.texture.width || Screen.height != worldInfo.texture.height)
worldInfo.GenerateRenderTexture();
}
lastWorldIndex = currentWorldIndex;
if (right)
currentWorldIndex++;
else
currentWorldIndex--;
transition = StartCoroutine(TransitionCamera(right));
}
void OnGUI() {
if (GUILayout.Button("Left world"))
SwitchWorld(false);
if (GUILayout.Button("Right world"))
SwitchWorld(true);
}
IEnumerator TransitionCamera(bool fromRight) {
WorldInfo lastWorld = worldInfos[lastWorldIndex];
WorldInfo newWorld = worldInfos[currentWorldIndex];
float startTime = Time.time;
Camera lastCam = lastWorld.camera;
//float startX = currentWorldIndex - lastWorldIndex > 0 ? -newWorld.texture.width / 2f + tabWidth * Screen.width : newWorld.texture.width / 2f - tabWidth * Screen.width + Screen.width;
while (Time.time < startTime + transitionDuration) {
float t = transitionCurve.Evaluate((Time.time - startTime) / transitionDuration);
newWorld.renderQuad.position = GetQuadOffset(lastCam, newWorld, currentWorldIndex, fromRight, t);
newWorld.material.SetFloat(UVOffset, fromRight ? 1f - t - tabWidth : -1f + t + tabWidth);
yield return null;
}
ResetQuadPositions();
transition = null;
}
Vector3 GetQuadOffset(Camera cam, WorldInfo worldInfo, int index, bool fromRight, float t = 0f) {
float x = fromRight ? 1f - tabWidth * (worldInfos.Length - index) - t : tabWidth * (1 + index) + t;
Vector3 quadHalfWidthOffset = Vector3.right * (fromRight ? worldInfo.renderQuad.localScale.x / 2f : -worldInfo.renderQuad.localScale.x / 2f);
return cam.ViewportToWorldPoint(new Vector3(x, .5f, quadOffset)) + quadHalfWidthOffset;
}
void ResetQuadPositions() {
Camera currCam = worldInfos[currentWorldIndex].camera;
for (int i = 0; i < worldInfos.Length; ++i) {
bool usingRenderTexture = i != currentWorldIndex;
worldInfos[i].SetUsingRenderTexture(usingRenderTexture);
if (usingRenderTexture) {
bool fromRight = i - currentWorldIndex > 0;
worldInfos[i].renderQuad.position = GetQuadOffset(currCam, worldInfos[i], i, fromRight);
worldInfos[i].material.SetFloat(UVOffset, fromRight ? 1f - tabWidth : -1f + tabWidth);
}
}
}
}
[Serializable]
struct WorldInfo {
public Camera camera;
[HideInInspector] public RenderTexture texture;
public Transform renderQuad;
[HideInInspector] public Material material;
static readonly int CameraTexture = Shader.PropertyToID("_CameraTexture");
public void SetUsingRenderTexture(bool usingTexture) {
if (usingTexture) {
camera.targetTexture = texture;
renderQuad.gameObject.SetActive(true);
}else {
camera.targetTexture = null;
renderQuad.gameObject.SetActive(false);
}
}
public void GenerateRenderTexture() {
renderQuad.localScale = new Vector3(camera.aspect, 1f, 1f);
texture = new RenderTexture(Screen.width, Screen.height, 32);
material.SetTexture(CameraTexture, texture);
}
}