123 lines
3.7 KiB
C#
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 } |