146 lines
5.6 KiB
C#
146 lines
5.6 KiB
C#
|
|
// ===============================================================================
|
||
|
|
// TimeLord - In-Scene Time Manipulation Tool
|
||
|
|
//
|
||
|
|
// Creator: Scove
|
||
|
|
// Last Updated: 2026-03-03
|
||
|
|
// Version: 2.0 (Sleek UI & Ergonomic Controls)
|
||
|
|
//
|
||
|
|
// Purpose:
|
||
|
|
// Provides a floating, interactive control panel inside the Scene View during
|
||
|
|
// Play Mode. Allows developers to easily manipulate game time (slow motion,
|
||
|
|
// fast forward, or pause) without constantly looking away from the action.
|
||
|
|
//
|
||
|
|
// Key Features:
|
||
|
|
// 1. Floating Dashboard: Clean, unobtrusive UI placed directly in the Scene View.
|
||
|
|
// 2. Dynamic Slider: Drag to fine-tune the time scale smoothly from 0x to 10x.
|
||
|
|
// 3. Smart Highlighting: Active speeds light up (Green), making it easy to read.
|
||
|
|
// 4. Auto-Resume: Clicking a speed preset while paused automatically resumes play.
|
||
|
|
// 5. Visual Pause State: Prominent pause button changes color when active.
|
||
|
|
//
|
||
|
|
// How to Use:
|
||
|
|
// 1. Place this script in an 'Editor' folder.
|
||
|
|
// 2. Hit PLAY in Unity.
|
||
|
|
// 3. Move your mouse to the Scene View and use the top-center Time Lord panel!
|
||
|
|
// ===============================================================================
|
||
|
|
|
||
|
|
using UnityEditor;
|
||
|
|
using UnityEngine;
|
||
|
|
|
||
|
|
namespace Editor
|
||
|
|
{
|
||
|
|
[InitializeOnLoad]
|
||
|
|
public class TimeLord
|
||
|
|
{
|
||
|
|
// Panel configuration
|
||
|
|
private const float PANEL_WIDTH = 340f;
|
||
|
|
private const float PANEL_HEIGHT = 105f;
|
||
|
|
|
||
|
|
static TimeLord()
|
||
|
|
{
|
||
|
|
// Unsubscribe first to prevent double-hooking upon script recompile
|
||
|
|
SceneView.duringSceneGui -= OnSceneGUI;
|
||
|
|
SceneView.duringSceneGui += OnSceneGUI;
|
||
|
|
}
|
||
|
|
|
||
|
|
private static void OnSceneGUI(SceneView sceneView)
|
||
|
|
{
|
||
|
|
// Only display the panel when the game is actually running
|
||
|
|
if (!Application.isPlaying) return;
|
||
|
|
|
||
|
|
Handles.BeginGUI();
|
||
|
|
|
||
|
|
// Calculate center-top position dynamically based on current Scene View size
|
||
|
|
float posX = (sceneView.position.width - PANEL_WIDTH) / 2f;
|
||
|
|
float posY = 15f;
|
||
|
|
Rect panelRect = new Rect(posX, posY, PANEL_WIDTH, PANEL_HEIGHT);
|
||
|
|
|
||
|
|
// Draw the main background box
|
||
|
|
GUI.Box(panelRect, GUIContent.none, EditorStyles.helpBox);
|
||
|
|
|
||
|
|
GUILayout.BeginArea(new Rect(posX + 10, posY + 10, PANEL_WIDTH - 20, PANEL_HEIGHT - 20));
|
||
|
|
|
||
|
|
// --- 1. HEADER (Title & Current Speed) ---
|
||
|
|
GUIStyle headerStyle = new GUIStyle(EditorStyles.boldLabel)
|
||
|
|
{
|
||
|
|
richText = true,
|
||
|
|
alignment = TextAnchor.MiddleCenter,
|
||
|
|
fontSize = 13
|
||
|
|
};
|
||
|
|
|
||
|
|
// Format the time scale to show 2 decimal places
|
||
|
|
string currentSpeedText = EditorApplication.isPaused ? "<color=#FF6B6B>PAUSED</color>" : $"<color=#4ECDC4>{Time.timeScale:F2}x</color>";
|
||
|
|
GUILayout.Label($"⏳ <b>TIME LORD</b> | Current: {currentSpeedText}", headerStyle);
|
||
|
|
GUILayout.Space(5);
|
||
|
|
|
||
|
|
// --- 2. TIME SLIDER (Fine-tune control) ---
|
||
|
|
EditorGUI.BeginChangeCheck();
|
||
|
|
float newTimeScale = GUILayout.HorizontalSlider(Time.timeScale, 0f, 10f);
|
||
|
|
if (EditorGUI.EndChangeCheck())
|
||
|
|
{
|
||
|
|
Time.timeScale = newTimeScale;
|
||
|
|
// Auto-resume if adjusting slider while paused
|
||
|
|
if (EditorApplication.isPaused && newTimeScale > 0f)
|
||
|
|
{
|
||
|
|
EditorApplication.isPaused = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
GUILayout.Space(5);
|
||
|
|
|
||
|
|
// --- 3. PRESET SPEED BUTTONS ---
|
||
|
|
GUILayout.BeginHorizontal();
|
||
|
|
DrawSpeedButton("0.1x", 0.1f);
|
||
|
|
DrawSpeedButton("0.5x", 0.5f);
|
||
|
|
DrawSpeedButton("1x", 1f);
|
||
|
|
DrawSpeedButton("2x", 2f);
|
||
|
|
DrawSpeedButton("5x", 5f);
|
||
|
|
GUILayout.EndHorizontal();
|
||
|
|
|
||
|
|
GUILayout.Space(5);
|
||
|
|
|
||
|
|
// --- 4. PAUSE / RESUME BUTTON ---
|
||
|
|
Color oldBgColor = GUI.backgroundColor;
|
||
|
|
GUI.backgroundColor = EditorApplication.isPaused ? new Color(1f, 0.4f, 0.4f) : new Color(0.9f, 0.9f, 0.9f);
|
||
|
|
|
||
|
|
string pauseLabel = EditorApplication.isPaused ? "▶ RESUME GAME" : "⏸ PAUSE GAME";
|
||
|
|
GUIStyle pauseStyle = new GUIStyle(GUI.skin.button) { fontStyle = FontStyle.Bold };
|
||
|
|
|
||
|
|
if (GUILayout.Button(pauseLabel, pauseStyle, GUILayout.Height(25)))
|
||
|
|
{
|
||
|
|
EditorApplication.isPaused = !EditorApplication.isPaused;
|
||
|
|
}
|
||
|
|
GUI.backgroundColor = oldBgColor;
|
||
|
|
|
||
|
|
GUILayout.EndArea();
|
||
|
|
Handles.EndGUI();
|
||
|
|
}
|
||
|
|
|
||
|
|
/// <summary>
|
||
|
|
/// Draws a preset button that automatically highlights green if it matches the current time scale.
|
||
|
|
/// </summary>
|
||
|
|
private static void DrawSpeedButton(string label, float targetSpeed)
|
||
|
|
{
|
||
|
|
Color oldBgColor = GUI.backgroundColor;
|
||
|
|
|
||
|
|
// Highlight green if this is the active speed AND the game is not paused
|
||
|
|
bool isActive = Mathf.Approximately(Time.timeScale, targetSpeed) && !EditorApplication.isPaused;
|
||
|
|
if (isActive)
|
||
|
|
{
|
||
|
|
GUI.backgroundColor = new Color(0.4f, 1f, 0.4f); // Light Green
|
||
|
|
}
|
||
|
|
|
||
|
|
if (GUILayout.Button(label, GUILayout.Height(22)))
|
||
|
|
{
|
||
|
|
Time.timeScale = targetSpeed;
|
||
|
|
|
||
|
|
// Auto-resume if the player clicked a speed while paused
|
||
|
|
if (EditorApplication.isPaused)
|
||
|
|
{
|
||
|
|
EditorApplication.isPaused = false;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
// Restore previous color
|
||
|
|
GUI.backgroundColor = oldBgColor;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|