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

123 lines
3.7 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] Transform renderQuad;
[SerializeField] float quadOffset;
[SerializeField] float tabWidth;
int lastWorldIndex;
int currentWorldIndex;
Coroutine transition;
RenderTexture renderTexture;
Material renderMaterial;
void Awake() {
if (worldInfos.Length <= 1)
Debug.LogWarning("WorldSwitcher should have multiple cameras");
currentWorldIndex = 0;
lastWorldIndex = 0;
renderMaterial = renderQuad.GetComponent<Renderer>().material;
GenerateRenderTexture();
for (int i = 0; i < worldInfos.Length; i++) {
WorldInfo worldInfo = worldInfos[i];
worldInfo.camera.enabled = i == 0;
Vector3 tabPos = worldInfo.worldTab.position;
float tabX = worldInfo.side == TabSide.Left ? 0 : ((RectTransform)worldInfo.worldTab.parent).rect.width;
worldInfo.worldTab.position = new Vector3(tabX, tabPos.y, tabPos.z);
}
}
public void SwitchWorld(int index) {
if (index == currentWorldIndex)
return;
if (index < 0 || index >= worldInfos.Length)
throw new IndexOutOfRangeException($"{index} is not an available world.");
lastWorldIndex = currentWorldIndex;
currentWorldIndex = index;
Camera currCam = worldInfos[currentWorldIndex].camera;
currCam.enabled = true;
//TODO Block window resize during transition?
if (Screen.width != renderTexture.width || Screen.height != renderTexture.height)
GenerateRenderTexture();
currCam.targetTexture = renderTexture;
renderQuad.localScale = new Vector3(worldInfos[lastWorldIndex].camera.aspect, 1f, 1f);
Vector3 oldPos = worldInfos[lastWorldIndex].worldTab.position;
worldInfos[lastWorldIndex].worldTab.position = new Vector3(worldInfos[lastWorldIndex].TabBaseX, oldPos.y, oldPos.z);
transition = StartCoroutine(TransitionCamera());
}
void OnGUI() {
for (int i = 0; i < worldInfos.Length; ++i) {
if (i == currentWorldIndex)
continue;
if (GUILayout.Button($"World {i}"))
SwitchWorld(i);
}
}
IEnumerator TransitionCamera() {
WorldInfo lastWorld = worldInfos[lastWorldIndex];
WorldInfo newWorld = worldInfos[currentWorldIndex];
float startTime = Time.time;
Transform lastCam = lastWorld.camera.transform;
Vector3 tabStartPosition = newWorld.worldTab.position;
float tabParentWidth = newWorld.TabParentWidth;
while (Time.time < startTime + transitionDuration) {
float t = transitionCurve.Evaluate((Time.time - startTime) / transitionDuration);
t *= (tabParentWidth + tabWidth) / tabParentWidth;
renderQuad.position = lastCam.position + Vector3.forward * quadOffset + Vector3.right * (2f * Mathf.Clamp01(t) - 2f);
//float tabX = newWorld.side == TabSide.Left ? t * (tabParentWidth + tabWidth) : t * -(tabParentWidth + tabWidth) + tabParentWidth;
newWorld.worldTab.position = new Vector3(tabParentWidth * t, tabStartPosition.y, tabStartPosition.z);
yield return null;
}
newWorld.camera.targetTexture = null;
lastWorld.camera.enabled = false;
transition = null;
}
void GenerateRenderTexture() {
renderTexture = new RenderTexture(Screen.width, Screen.height, 32);
renderMaterial.mainTexture = renderTexture;
}
}
[Serializable]
struct WorldInfo {
public Camera camera;
public RectTransform worldTab;
public ushort indexFromSide;
public TabSide side;
public float TabParentWidth => ((RectTransform)worldTab.parent).rect.width;
public float TabBaseX => side == TabSide.Left ?
indexFromSide * 6.25f :
TabParentWidth - indexFromSide * 6.25f;
}
[Serializable]
enum TabSide { Left, Right }