// 27 Slicer
// Copyright 2021 Deftly Games
// https://slicer.deftly.games/
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using System.Text.RegularExpressions;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
namespace Slicer.Demo
{
///
/// The controller for the Demos UI.
///
[AddComponentMenu("Slicer/Demo/UI Controller")]
public class UIController : MonoBehaviour
{
public Text DecriptionText;
private string descriptionString;
public Text ToggleSlicingButtonText;
private string toggleSlicingString;
private bool toggleSlicingState = true;
public Text ToggleSlicingHintText;
private string toggleSlicingHintString;
private List trackedPhysicsObjects;
public Button NextViewButton;
private int currentCameraPosition = 0;
public List CameraPositionList;
private Camera mainCamera;
private const float scrollScale = 0.5f;
// Start is called before the first frame update
private void Awake()
{
mainCamera = Camera.main;
toggleSlicingString = ToggleSlicingButtonText.text;
if (ToggleSlicingHintText != null)
{
toggleSlicingHintString = ToggleSlicingHintText.text;
}
NextViewButton.gameObject.SetActive(CameraPositionList.Any());
descriptionString = DecriptionText.text;
SetDescription(CameraPositionList.FirstOrDefault());
trackedPhysicsObjects = FindObjectsOfType()
.Select(e => {
return new TrackedPhysicsObject
{
Rigidbody = e,
Position = e.position,
Rotation = e.rotation
};
}).ToList();
SetSlicingString();
}
private void Update()
{
var scroll = Input.mouseScrollDelta.y;
var transform = mainCamera.transform;
var cameraPos = transform.localPosition;
var translation = new Vector3(0, 0, scroll * scrollScale);
transform.localPosition = cameraPos + (transform.localRotation * translation);
}
private void SetDescription(CameraPositions cameraPosition)
{
if (cameraPosition != null)
{
DecriptionText.text = $"{descriptionString}\n\n{cameraPosition.Text}";
}
else
{
DecriptionText.text = descriptionString;
}
HighlightText(DecriptionText);
// Force refresh the vertical layout group
LayoutRebuilder.ForceRebuildLayoutImmediate(GetComponent());
}
public void NextViewButton_Click()
{
StartCoroutine(NextView());
}
public void ToggleSlicingButton_Click()
{
ToggleSlicing();
}
public void PrevSceneButton_Click(string sceneToload)
{
LoadSceneByName(sceneToload);
}
public void NextSceneButton_Click(string sceneToload)
{
LoadSceneByName(sceneToload);
}
private IEnumerator NextView()
{
NextViewButton.enabled = false;
currentCameraPosition = (currentCameraPosition + 1) % CameraPositionList.Count;
var cameraTransform = mainCamera.transform;
var cameraPosition = CameraPositionList[currentCameraPosition];
var endPositionTransform = cameraPosition.Transform;
var startPosition = cameraTransform.position;
var startRotation = cameraTransform.rotation;
SetDescription(cameraPosition);
float elapsed = 0;
float duration = 0.25f;
while (elapsed < duration)
{
elapsed += Time.deltaTime;
var elapsedFraction = elapsed / duration;
cameraTransform.position = Vector3.Lerp(startPosition, endPositionTransform.position, elapsedFraction);
cameraTransform.rotation = Quaternion.Lerp(startRotation, endPositionTransform.rotation, elapsedFraction);
yield return null;
}
cameraTransform.position = endPositionTransform.position;
cameraTransform.rotation = endPositionTransform.rotation;
NextViewButton.enabled = true;
}
private void ToggleSlicing()
{
toggleSlicingState = !toggleSlicingState;
var allSlicers = FindObjectsOfType();
foreach (var slicer in allSlicers)
{
if (toggleSlicingState)
{
slicer.EnableSlicing();
}
else
{
slicer.DisableSlicing();
}
slicer.RefreshSlice();
}
SetSlicingString();
ResetPhysicsObjects();
}
private void HighlightText(Text text)
{
var s = text.text;
var classes = AppDomain.CurrentDomain.GetAssemblies()
.First(e => e.FullName.StartsWith("27Slicer,"))
.GetTypes();
foreach (var c in classes)
{
s = Regex.Replace(s, $@"({c.Name}s?)", m =>
{
var name = Regex.Replace(m.Groups[1].Value, @"(\S)([A-Z])", m2 => $"{m2.Groups[1].Value} {m2.Groups[2].Value}");
return $"{name}";
});
}
text.text = s;
}
private void SetSlicingString()
{
string stateText;
string hintText;
if (toggleSlicingState)
{
stateText = "Disable";
hintText = "When the slicer is enabled you can see the effects the slicer has on Game Objects.";
}
else
{
stateText = "Enable";
hintText = "When the slicer is disabled you can see the Game Objects in their unsliced state.";
}
ToggleSlicingButtonText.text = string.Format(toggleSlicingString, stateText);
if (ToggleSlicingHintText)
{
ToggleSlicingHintText.text = string.Format(toggleSlicingHintString, ToggleSlicingButtonText.text, hintText);
}
}
private void LoadSceneByName(string sceneName)
{
if (string.IsNullOrEmpty(sceneName))
{
Debug.LogError($"{nameof(sceneName)} not supplied");
return;
}
var loadSceneParameters = new LoadSceneParameters(LoadSceneMode.Single);
#if UNITY_EDITOR
// Do this the long way to ensure that the correct scene is loaded
var foundAssetsGuids = UnityEditor.AssetDatabase.FindAssets($"t:scene {sceneName}");
var selectedAssetPath = foundAssetsGuids
.Select(e => UnityEditor.AssetDatabase.GUIDToAssetPath(e))
.FirstOrDefault(e => e.Contains("/27 Slicer/Demos/"));
if (string.IsNullOrEmpty(selectedAssetPath))
{
Debug.LogError($"Could not find scene '{sceneName}'");
return;
}
UnityEditor.SceneManagement.EditorSceneManager.LoadSceneInPlayMode(selectedAssetPath, loadSceneParameters);
#else
SceneManager.LoadScene(sceneName, loadSceneParameters);
#endif
}
private void ResetPhysicsObjects()
{
foreach (var trackedPhysicsObject in trackedPhysicsObjects)
{
if (trackedPhysicsObject.Rigidbody == null)
{
continue;
}
trackedPhysicsObject.Reset();
}
}
private class TrackedPhysicsObject
{
public Rigidbody Rigidbody;
public Vector3 Position;
public Quaternion Rotation;
public void Reset()
{
Rigidbody.linearVelocity = Vector3.zero;
Rigidbody.angularVelocity = Vector3.zero;
Rigidbody.position = Position;
Rigidbody.rotation = Rotation;
}
}
[Serializable]
public class CameraPositions
{
public Transform Transform;
[TextArea(2, 10)]
public string Text;
}
}
}