UPdate
This commit is contained in:
55
.idea/.idea.HALLUCINATE/.idea/workspace.xml
generated
55
.idea/.idea.HALLUCINATE/.idea/workspace.xml
generated
@@ -5,62 +5,9 @@
|
|||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="f9183c68-daf0-43b8-be4c-fad79983f91b" name="Changes" comment="">
|
<list default="true" id="f9183c68-daf0-43b8-be4c-fad79983f91b" name="Changes" comment="">
|
||||||
<change beforePath="$PROJECT_DIR$/.gemini-workspace-history/active-context.md" beforeDir="false" afterPath="$PROJECT_DIR$/.gemini-workspace-history/active-context.md" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/.idea.HALLUCINATE/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/Change - Fix Log.txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/Change - Fix Log.txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/Editor.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/Editor/RealToonShaderCache.cs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/Editor/RealToonShaderCache.cs.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/For VRoid-VRM users.txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/For VRoid-VRM users.txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/ReadMe - Important - Guide.txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/ReadMe - Important - Guide.txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon (User Guide).pdf" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon (User Guide).pdf.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples/Built-In RP [3D].meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples/Check.unity" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples/Check.unity.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples/Read Me First [About the Example - Demos].txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples/Read Me First [About the Example - Demos].txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples/SRP.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples/SRP/HDRP.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Examples/SRP/URP.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/Built-In RP [3D].meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP).meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/HDRP.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/HDRP/Please read before you unpack or import.txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/HDRP/Please read before you unpack or import.txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/HDRP/RealToon HDRP (Quick Guide).txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/HDRP/RealToon HDRP (Quick Guide).txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/HDRP/Unity 2023 and Below.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/HDRP/Unity 6.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/LWRP.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/LWRP/Please read before you unpack or import.txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/LWRP/Please read before you unpack or import.txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/URP.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/URP/Please read before you unpack or import.txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/URP/Please read before you unpack or import.txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/URP/Unity 2023 and Below.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Shader Packages/SRP (LWRP - URP - HDRP)/URP/Unity 6.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Tools.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Tools/PerspectiveAdjustmentController.cs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Tools/PerspectiveAdjustmentController.cs.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Tools/ShadowTSDFModeHelper.cs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Tools/ShadowTSDFModeHelper.cs.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Tools/SmearEffectHelper.cs" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/RealToon Tools/SmearEffectHelper.cs.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/What's New.txt" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/RealToon/What's New.txt.meta" beforeDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/Scove/UIScaleTest.unity" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scove/UIScaleTest.unity" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/SettingsController.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/SettingsController.cs" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/UIManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/UIManager.cs" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/Assets/Scripts/UI/UIManager.cs" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/Scripts/UI/UIManager.cs" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/UI/Global.uss" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/UI/Global.uss" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/Assets/UI/Global.uss" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/UI/Global.uss" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/UI/MainPanelSettings.asset" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/UI/MainPanelSettings.asset" afterDir="false" />
|
|
||||||
<change beforePath="$PROJECT_DIR$/Assets/UI/Settings.uxml" beforeDir="false" afterPath="$PROJECT_DIR$/Assets/UI/Settings.uxml" afterDir="false" />
|
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
||||||
@@ -203,7 +150,7 @@
|
|||||||
<workItem from="1777443280908" duration="5223000" />
|
<workItem from="1777443280908" duration="5223000" />
|
||||||
<workItem from="1777484328779" duration="32427000" />
|
<workItem from="1777484328779" duration="32427000" />
|
||||||
<workItem from="1777568077522" duration="8613000" />
|
<workItem from="1777568077522" duration="8613000" />
|
||||||
<workItem from="1777604072510" duration="6443000" />
|
<workItem from="1777604072510" duration="10566000" />
|
||||||
</task>
|
</task>
|
||||||
<servers />
|
<servers />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -37,12 +37,11 @@ namespace Hallucinate.UI
|
|||||||
[SerializeField] private Sprite cursorSprite;
|
[SerializeField] private Sprite cursorSprite;
|
||||||
[SerializeField] private Sprite cursorTrailSprite;
|
[SerializeField] private Sprite cursorTrailSprite;
|
||||||
[SerializeField, Range(10f, 150f)] private float cursorSize = 40f;
|
[SerializeField, Range(10f, 150f)] private float cursorSize = 40f;
|
||||||
[SerializeField, Range(5, 50)] private int trailLength = 20;
|
[SerializeField, Range(2, 50)] private float trailDistanceThreshold = 10f;
|
||||||
[SerializeField, Range(1, 10)] private int trailSpacing = 2;
|
|
||||||
[SerializeField] private bool enableRipples = true;
|
[SerializeField] private bool enableRipples = true;
|
||||||
[SerializeField] private Color rippleColor = new Color(1, 1, 1, 0.4f);
|
[SerializeField] private Color rippleColor = new Color(0, 1, 0.8f, 0.4f);
|
||||||
|
|
||||||
[Header("UI Templates")]
|
[Header("UI Templates & Global Styles")]
|
||||||
[SerializeField] private VisualTreeAsset loginTemplate;
|
[SerializeField] private VisualTreeAsset loginTemplate;
|
||||||
[SerializeField] private VisualTreeAsset mainMenuTemplate;
|
[SerializeField] private VisualTreeAsset mainMenuTemplate;
|
||||||
[SerializeField] private VisualTreeAsset lobbyTemplate;
|
[SerializeField] private VisualTreeAsset lobbyTemplate;
|
||||||
@@ -50,24 +49,24 @@ namespace Hallucinate.UI
|
|||||||
[SerializeField] private VisualTreeAsset profileTemplate;
|
[SerializeField] private VisualTreeAsset profileTemplate;
|
||||||
[SerializeField] private VisualTreeAsset settingsTemplate;
|
[SerializeField] private VisualTreeAsset settingsTemplate;
|
||||||
[SerializeField] private VisualTreeAsset hudTemplate;
|
[SerializeField] private VisualTreeAsset hudTemplate;
|
||||||
|
[SerializeField] private StyleSheet globalStyleSheet;
|
||||||
|
|
||||||
private LoginController _loginController;
|
private LoginController _loginController;
|
||||||
private MainMenuController _mainMenuController;
|
private MainMenuController _mainMenuController;
|
||||||
private LobbyController _lobbyController;
|
private LobbyController _lobbyController;
|
||||||
private SettingsController _settingsController;
|
private SettingsController _settingsController;
|
||||||
private List<VisualElement> _trailSegments = new List<VisualElement>();
|
|
||||||
private List<Vector2> _posHistory = new List<Vector2>();
|
|
||||||
|
|
||||||
private Vector2 _lastMousePos;
|
// Osu Trail Pooling
|
||||||
private float _trailOpacity = 1f;
|
private const int MAX_TRAIL_PARTICLES = 60;
|
||||||
|
private readonly List<VisualElement> _trailPool = new List<VisualElement>();
|
||||||
|
private int _currentTrailIndex = 0;
|
||||||
|
|
||||||
|
private Vector2 _lastTrailSpawnPos;
|
||||||
private bool _isSettingsOpen = false;
|
private bool _isSettingsOpen = false;
|
||||||
public bool IsSettingsOpen => _isSettingsOpen;
|
public bool IsSettingsOpen => _isSettingsOpen;
|
||||||
|
|
||||||
private const string UI_SCALE_KEY = "UIScale";
|
private const string UI_SCALE_KEY = "UIScale";
|
||||||
|
|
||||||
[Header("Development Settings")]
|
|
||||||
[SerializeField] private bool allowMultipleInstances = true;
|
|
||||||
|
|
||||||
#if UNITY_EDITOR
|
#if UNITY_EDITOR
|
||||||
private void OnValidate()
|
private void OnValidate()
|
||||||
{
|
{
|
||||||
@@ -85,11 +84,7 @@ namespace Hallucinate.UI
|
|||||||
|
|
||||||
private void Awake()
|
private void Awake()
|
||||||
{
|
{
|
||||||
if (Instance != null && Instance != this)
|
if (Instance != null && Instance != this) { Destroy(gameObject); return; }
|
||||||
{
|
|
||||||
Destroy(gameObject);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Instance = this;
|
Instance = this;
|
||||||
DontDestroyOnLoad(gameObject);
|
DontDestroyOnLoad(gameObject);
|
||||||
|
|
||||||
@@ -104,21 +99,23 @@ namespace Hallucinate.UI
|
|||||||
{
|
{
|
||||||
cursorSize = PlayerPrefs.GetFloat("CursorSize", 40f);
|
cursorSize = PlayerPrefs.GetFloat("CursorSize", 40f);
|
||||||
enableRipples = PlayerPrefs.GetInt("CursorRipples", 1) == 1;
|
enableRipples = PlayerPrefs.GetInt("CursorRipples", 1) == 1;
|
||||||
bool trailEnabled = PlayerPrefs.GetInt("CursorTrail", 1) == 1;
|
|
||||||
if (!trailEnabled) trailLength = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCursorSize(float size)
|
public void SetCursorSize(float size)
|
||||||
{
|
{
|
||||||
cursorSize = size;
|
cursorSize = size;
|
||||||
PlayerPrefs.SetFloat("CursorSize", size);
|
PlayerPrefs.SetFloat("CursorSize", size);
|
||||||
SetupVirtualCursor();
|
if (_mainCursor != null)
|
||||||
|
{
|
||||||
|
_mainCursor.style.width = cursorSize;
|
||||||
|
_mainCursor.style.height = cursorSize;
|
||||||
|
}
|
||||||
|
foreach(var p in _trailPool) { p.style.width = cursorSize; p.style.height = cursorSize; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCursorTrail(bool enabled)
|
public void SetCursorTrail(bool enabled)
|
||||||
{
|
{
|
||||||
PlayerPrefs.SetInt("CursorTrail", enabled ? 1 : 0);
|
PlayerPrefs.SetInt("CursorTrail", enabled ? 1 : 0);
|
||||||
SetupVirtualCursor();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SetCursorRipples(bool enabled)
|
public void SetCursorRipples(bool enabled)
|
||||||
@@ -155,20 +152,34 @@ namespace Hallucinate.UI
|
|||||||
float savedScale = PlayerPrefs.GetFloat(UI_SCALE_KEY, 1.0f);
|
float savedScale = PlayerPrefs.GetFloat(UI_SCALE_KEY, 1.0f);
|
||||||
SetUIScale(savedScale);
|
SetUIScale(savedScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
{
|
{
|
||||||
if (_uiDocument == null) _uiDocument = GetComponent<UIDocument>();
|
if (_uiDocument == null) _uiDocument = GetComponent<UIDocument>();
|
||||||
_rootElement = _uiDocument.rootVisualElement;
|
_rootElement = _uiDocument.rootVisualElement;
|
||||||
|
|
||||||
_cursorLayer = new VisualElement();
|
if (globalStyleSheet != null)
|
||||||
_cursorLayer.name = "CursorLayer";
|
_rootElement.panel.visualTree.styleSheets.Add(globalStyleSheet);
|
||||||
|
|
||||||
|
_cursorLayer = new VisualElement { name = "CursorLayer" };
|
||||||
_cursorLayer.style.position = Position.Absolute;
|
_cursorLayer.style.position = Position.Absolute;
|
||||||
_cursorLayer.style.width = Length.Percent(100);
|
_cursorLayer.style.width = Length.Percent(100);
|
||||||
_cursorLayer.style.height = Length.Percent(100);
|
_cursorLayer.style.height = Length.Percent(100);
|
||||||
_cursorLayer.pickingMode = PickingMode.Ignore;
|
_cursorLayer.pickingMode = PickingMode.Ignore;
|
||||||
_rootElement.Add(_cursorLayer);
|
_rootElement.Add(_cursorLayer);
|
||||||
|
|
||||||
SetupVirtualCursor();
|
InitializeTrailPool();
|
||||||
|
|
||||||
|
_mainCursor = new VisualElement { name = "MainCursor" };
|
||||||
|
_mainCursor.style.position = Position.Absolute;
|
||||||
|
_mainCursor.style.width = cursorSize;
|
||||||
|
_mainCursor.style.height = cursorSize;
|
||||||
|
_mainCursor.style.backgroundImage = new StyleBackground(Background.FromSprite(cursorSprite));
|
||||||
|
|
||||||
|
// Căn giữa sprite hình tròn bằng translate
|
||||||
|
_mainCursor.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
|
||||||
|
_mainCursor.pickingMode = PickingMode.Ignore;
|
||||||
|
_cursorLayer.Add(_mainCursor);
|
||||||
|
|
||||||
_rootElement.RegisterCallback<PointerDownEvent>(OnGlobalClick, TrickleDown.TrickleDown);
|
_rootElement.RegisterCallback<PointerDownEvent>(OnGlobalClick, TrickleDown.TrickleDown);
|
||||||
|
|
||||||
@@ -182,6 +193,24 @@ namespace Hallucinate.UI
|
|||||||
CheckLoginStatus();
|
CheckLoginStatus();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void InitializeTrailPool()
|
||||||
|
{
|
||||||
|
for (int i = 0; i < MAX_TRAIL_PARTICLES; i++)
|
||||||
|
{
|
||||||
|
var particle = new VisualElement();
|
||||||
|
particle.style.position = Position.Absolute;
|
||||||
|
particle.style.width = cursorSize;
|
||||||
|
particle.style.height = cursorSize;
|
||||||
|
particle.style.backgroundImage = new StyleBackground(Background.FromSprite(cursorTrailSprite));
|
||||||
|
particle.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
|
||||||
|
particle.style.opacity = 0;
|
||||||
|
particle.style.display = DisplayStyle.None;
|
||||||
|
particle.pickingMode = PickingMode.Ignore;
|
||||||
|
_cursorLayer.Add(particle);
|
||||||
|
_trailPool.Add(particle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void CheckLoginStatus()
|
private void CheckLoginStatus()
|
||||||
{
|
{
|
||||||
string savedName = PlayerPrefs.GetString("Username", "");
|
string savedName = PlayerPrefs.GetString("Username", "");
|
||||||
@@ -209,7 +238,7 @@ namespace Hallucinate.UI
|
|||||||
{
|
{
|
||||||
_isSettingsOpen = true;
|
_isSettingsOpen = true;
|
||||||
_settingsController.Root.BringToFront();
|
_settingsController.Root.BringToFront();
|
||||||
_cursorLayer.BringToFront();
|
if (_cursorLayer != null) _cursorLayer.BringToFront();
|
||||||
await _settingsController.PlayTransitionIn();
|
await _settingsController.PlayTransitionIn();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -222,47 +251,55 @@ namespace Hallucinate.UI
|
|||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
if (_history.Count > 0) _history.Peek().Update();
|
if (_history.Count > 0) _history.Peek().Update();
|
||||||
UpdateCursorAndTrail();
|
UpdateCursorInput();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SetupVirtualCursor()
|
private void UpdateCursorInput()
|
||||||
{
|
{
|
||||||
if (_cursorLayer == null) return;
|
if (!Application.isFocused || _cursorLayer == null) return;
|
||||||
_cursorLayer.Clear();
|
|
||||||
_trailSegments.Clear();
|
|
||||||
_posHistory.Clear();
|
|
||||||
|
|
||||||
if (cursorTrailSprite != null)
|
// Dùng cách tính tọa độ thủ công để tránh offset khi pivot ở giữa
|
||||||
|
Vector2 mousePos = Input.mousePosition;
|
||||||
|
float scale = GetCurrentScale();
|
||||||
|
Vector2 uiPos = new Vector2(mousePos.x / scale, (Screen.height - mousePos.y) / scale);
|
||||||
|
|
||||||
|
if (_mainCursor != null)
|
||||||
{
|
{
|
||||||
for (int i = 0; i < trailLength; i++)
|
_mainCursor.style.left = uiPos.x;
|
||||||
{
|
_mainCursor.style.top = uiPos.y;
|
||||||
var segment = new VisualElement();
|
|
||||||
segment.style.position = Position.Absolute;
|
|
||||||
segment.style.width = cursorSize;
|
|
||||||
segment.style.height = cursorSize;
|
|
||||||
segment.style.backgroundImage = new StyleBackground(Background.FromSprite(cursorTrailSprite));
|
|
||||||
float ratio = 1f - ((float)i / trailLength);
|
|
||||||
segment.style.opacity = 0f;
|
|
||||||
segment.style.scale = new StyleScale(new Scale(new Vector3(ratio, ratio, 1f)));
|
|
||||||
segment.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
|
|
||||||
segment.pickingMode = PickingMode.Ignore;
|
|
||||||
_cursorLayer.Add(segment);
|
|
||||||
_trailSegments.Add(segment);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_mainCursor = new VisualElement();
|
bool trailEnabled = PlayerPrefs.GetInt("CursorTrail", 1) == 1;
|
||||||
_mainCursor.style.position = Position.Absolute;
|
if (trailEnabled && cursorTrailSprite != null)
|
||||||
_mainCursor.style.width = cursorSize;
|
{
|
||||||
_mainCursor.style.height = cursorSize;
|
float dist = Vector2.Distance(uiPos, _lastTrailSpawnPos);
|
||||||
_mainCursor.style.backgroundImage = new StyleBackground(Background.FromSprite(cursorSprite != null ? cursorSprite : cursorTrailSprite));
|
if (dist > trailDistanceThreshold)
|
||||||
_mainCursor.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
|
{
|
||||||
_mainCursor.pickingMode = PickingMode.Ignore;
|
SpawnPooledTrail(uiPos);
|
||||||
_cursorLayer.Add(_mainCursor);
|
_lastTrailSpawnPos = uiPos;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Vector2 startPos = new Vector2(Input.mousePosition.x, Screen.height - Input.mousePosition.y);
|
private void SpawnPooledTrail(Vector2 pos)
|
||||||
_lastMousePos = startPos;
|
{
|
||||||
for (int i = 0; i < trailLength * trailSpacing + 1; i++) _posHistory.Add(startPos);
|
var particle = _trailPool[_currentTrailIndex];
|
||||||
|
_currentTrailIndex = (_currentTrailIndex + 1) % MAX_TRAIL_PARTICLES;
|
||||||
|
|
||||||
|
Tween.StopAll(particle);
|
||||||
|
particle.style.display = DisplayStyle.Flex;
|
||||||
|
particle.style.left = pos.x;
|
||||||
|
particle.style.top = pos.y;
|
||||||
|
particle.style.opacity = 0f;
|
||||||
|
particle.style.scale = Vector3.one;
|
||||||
|
|
||||||
|
Sequence.Create()
|
||||||
|
.Group(Tween.Custom(0f, 0.6f, duration: 0.05f, onValueChange: val => particle.style.opacity = val))
|
||||||
|
.Chain(Tween.Custom(0.6f, 0f, duration: 0.35f, onValueChange: val => particle.style.opacity = val))
|
||||||
|
.Group(Tween.Custom(1f, 0.2f, duration: 0.4f, onValueChange: val => {
|
||||||
|
particle.style.scale = new StyleScale(new Scale(new Vector3(val, val, 1f)));
|
||||||
|
}))
|
||||||
|
.OnComplete(() => particle.style.display = DisplayStyle.None);
|
||||||
}
|
}
|
||||||
|
|
||||||
private float GetCurrentScale() => (_uiDocument != null && _uiDocument.panelSettings != null) ? _uiDocument.panelSettings.scale : 1.0f;
|
private float GetCurrentScale() => (_uiDocument != null && _uiDocument.panelSettings != null) ? _uiDocument.panelSettings.scale : 1.0f;
|
||||||
@@ -270,57 +307,29 @@ namespace Hallucinate.UI
|
|||||||
private void OnGlobalClick(PointerDownEvent evt)
|
private void OnGlobalClick(PointerDownEvent evt)
|
||||||
{
|
{
|
||||||
if (!enableRipples || _cursorLayer == null) return;
|
if (!enableRipples || _cursorLayer == null) return;
|
||||||
|
|
||||||
var ripple = new VisualElement();
|
var ripple = new VisualElement();
|
||||||
ripple.style.position = Position.Absolute;
|
ripple.style.position = Position.Absolute;
|
||||||
ripple.style.width = cursorSize;
|
ripple.style.width = cursorSize;
|
||||||
ripple.style.height = cursorSize;
|
ripple.style.height = cursorSize;
|
||||||
ripple.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
|
ripple.style.translate = new StyleTranslate(new Translate(Length.Percent(-50), Length.Percent(-50)));
|
||||||
|
ripple.style.left = evt.localPosition.x;
|
||||||
|
ripple.style.top = evt.localPosition.y;
|
||||||
|
|
||||||
var radius = new StyleLength(new Length(50, LengthUnit.Percent));
|
var radius = new StyleLength(new Length(50, LengthUnit.Percent));
|
||||||
ripple.style.borderTopLeftRadius = radius; ripple.style.borderTopRightRadius = radius;
|
ripple.style.borderTopLeftRadius = radius; ripple.style.borderTopRightRadius = radius;
|
||||||
ripple.style.borderBottomLeftRadius = radius; ripple.style.borderBottomRightRadius = radius;
|
ripple.style.borderBottomLeftRadius = radius; ripple.style.borderBottomRightRadius = radius;
|
||||||
ripple.style.borderTopColor = rippleColor; ripple.style.borderBottomColor = rippleColor;
|
ripple.style.borderTopColor = rippleColor; ripple.style.borderBottomColor = rippleColor;
|
||||||
ripple.style.borderLeftColor = rippleColor; ripple.style.borderRightColor = rippleColor;
|
ripple.style.borderLeftColor = rippleColor; ripple.style.borderRightColor = rippleColor;
|
||||||
ripple.style.borderTopWidth = 2; ripple.style.borderBottomWidth = 2;
|
ripple.style.borderTopWidth = 2; ripple.style.borderBottomWidth = 2;
|
||||||
ripple.style.left = evt.localPosition.x; ripple.style.top = evt.localPosition.y;
|
|
||||||
ripple.pickingMode = PickingMode.Ignore;
|
ripple.pickingMode = PickingMode.Ignore;
|
||||||
|
|
||||||
_cursorLayer.Add(ripple);
|
_cursorLayer.Add(ripple);
|
||||||
|
|
||||||
Tween.Custom(Vector3.one, Vector3.one * 2.5f, duration: 0.4f, onValueChange: val => ripple.style.scale = new StyleScale(new Scale(val)), ease: Ease.OutQuad);
|
Tween.Custom(Vector3.one, Vector3.one * 2.5f, duration: 0.4f, onValueChange: val => ripple.style.scale = new StyleScale(new Scale(val)), ease: Ease.OutQuad);
|
||||||
Tween.Custom(1f, 0f, duration: 0.4f, onValueChange: val => ripple.style.opacity = val).OnComplete(() => ripple.RemoveFromHierarchy());
|
Tween.Custom(1f, 0f, duration: 0.4f, onValueChange: val => ripple.style.opacity = val).OnComplete(() => ripple.RemoveFromHierarchy());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateCursorAndTrail()
|
|
||||||
{
|
|
||||||
if (!Application.isFocused || _cursorLayer == null)
|
|
||||||
{
|
|
||||||
if (_cursorLayer != null) _cursorLayer.style.display = DisplayStyle.None;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
Vector3 mousePos = Input.mousePosition;
|
|
||||||
bool isMouseInWindow = mousePos.x >= 0 && mousePos.x <= Screen.width && mousePos.y >= 0 && mousePos.y <= Screen.height;
|
|
||||||
if (!isMouseInWindow) { _cursorLayer.style.display = DisplayStyle.None; return; }
|
|
||||||
_cursorLayer.style.display = DisplayStyle.Flex;
|
|
||||||
float scale = GetCurrentScale();
|
|
||||||
Vector2 uiPos = new Vector2(mousePos.x / scale, (Screen.height - mousePos.y) / scale);
|
|
||||||
float mouseSpeed = Vector2.Distance(uiPos, _lastMousePos);
|
|
||||||
_lastMousePos = uiPos;
|
|
||||||
if (mouseSpeed > 0.1f) _trailOpacity = Mathf.MoveTowards(_trailOpacity, 1f, Time.deltaTime * 5f);
|
|
||||||
else _trailOpacity = Mathf.MoveTowards(_trailOpacity, 0f, Time.deltaTime * 3f);
|
|
||||||
_posHistory.Insert(0, uiPos);
|
|
||||||
if (_posHistory.Count > trailLength * trailSpacing + 1) _posHistory.RemoveAt(_posHistory.Count - 1);
|
|
||||||
if (_mainCursor != null) { _mainCursor.style.left = uiPos.x; _mainCursor.style.top = uiPos.y; }
|
|
||||||
for (int i = 0; i < _trailSegments.Count; i++)
|
|
||||||
{
|
|
||||||
int historyIndex = (i + 1) * trailSpacing;
|
|
||||||
if (historyIndex < _posHistory.Count)
|
|
||||||
{
|
|
||||||
_trailSegments[i].style.left = _posHistory[historyIndex].x;
|
|
||||||
_trailSegments[i].style.top = _posHistory[historyIndex].y;
|
|
||||||
float baseRatio = 1f - ((float)i / trailLength);
|
|
||||||
_trailSegments[i].style.opacity = baseRatio * 0.5f * _trailOpacity;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeControllers()
|
private void InitializeControllers()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@@ -346,7 +355,7 @@ namespace Hallucinate.UI
|
|||||||
instance.style.width = Length.Percent(100); instance.style.height = Length.Percent(100);
|
instance.style.width = Length.Percent(100); instance.style.height = Length.Percent(100);
|
||||||
instance.style.display = DisplayStyle.None;
|
instance.style.display = DisplayStyle.None;
|
||||||
_rootElement.Add(instance);
|
_rootElement.Add(instance);
|
||||||
if (_cursorLayer != null) _cursorLayer.BringToFront(); // Giữ cursor layer trên cùng của root
|
if (_cursorLayer != null) _cursorLayer.BringToFront();
|
||||||
var controller = ScriptableObject.CreateInstance<T>();
|
var controller = ScriptableObject.CreateInstance<T>();
|
||||||
controller.Initialize(instance, this);
|
controller.Initialize(instance, this);
|
||||||
_controllers[typeof(T)] = controller;
|
_controllers[typeof(T)] = controller;
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
/* Global Styles for Hallucinate UI */
|
/* Global Styles for Hallucinate UI */
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
DESIGN TOKENS
|
DESIGN TOKENS & UNITY THEME OVERRIDES
|
||||||
============================================================ */
|
============================================================ */
|
||||||
:root {
|
:root {
|
||||||
--primary-color: #ffffff;
|
--primary-color: #ffffff;
|
||||||
@@ -14,6 +14,12 @@
|
|||||||
--radius-md: 12px;
|
--radius-md: 12px;
|
||||||
--radius-lg: 24px;
|
--radius-lg: 24px;
|
||||||
--radius-pill: 999px;
|
--radius-pill: 999px;
|
||||||
|
|
||||||
|
/* ÉP UNITY DÙNG MÀU CỦA GAME CHO CÁC THÀNH PHẦN NỘI BỘ (DROPDOWN POPUP) */
|
||||||
|
--unity-colors-surface-background: #0a0a0a;
|
||||||
|
--unity-colors-surface-border: #00ffcc;
|
||||||
|
--unity-colors-surface-text: #ffffff;
|
||||||
|
--unity-colors-highlight-background: rgba(0, 255, 204, 0.2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
@@ -143,18 +149,19 @@
|
|||||||
/* ============================================================
|
/* ============================================================
|
||||||
DROPDOWN & FIELDS (THE BIG FIX)
|
DROPDOWN & FIELDS (THE BIG FIX)
|
||||||
============================================================ */
|
============================================================ */
|
||||||
.unity-dropdown-field {
|
DropdownField, .unity-dropdown-field {
|
||||||
margin-bottom: 12px;
|
margin-bottom: 12px;
|
||||||
|
transition: 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unity-dropdown-field__label {
|
DropdownField .unity-dropdown-field__label {
|
||||||
width: 35%;
|
width: 35%;
|
||||||
color: #aaaaaa;
|
color: #aaaaaa;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
-unity-font-style: bold;
|
-unity-font-style: bold;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unity-dropdown-field__input {
|
DropdownField .unity-base-field__input {
|
||||||
background-color: rgba(255, 255, 255, 0.05);
|
background-color: rgba(255, 255, 255, 0.05);
|
||||||
border-radius: 10px;
|
border-radius: 10px;
|
||||||
border-width: 1px;
|
border-width: 1px;
|
||||||
@@ -165,50 +172,150 @@
|
|||||||
transition: 200ms;
|
transition: 200ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
.unity-dropdown-field__input:hover {
|
DropdownField:hover .unity-base-field__input {
|
||||||
background-color: rgba(255, 255, 255, 0.1);
|
background-color: rgba(255, 255, 255, 0.08);
|
||||||
border-color: #00ffcc;
|
border-color: #00ffcc;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* NHẮM VÀO CÁI MENU XỔ XUỐNG (POPUP) */
|
/* NHẮM VÀO CÁI MENU XỔ XUỐNG (POPUP) */
|
||||||
/* Cần selector cực kỳ mạnh để đè style mặc định của Unity */
|
/* Cần selector cực kỳ mạnh và ghi đè toàn bộ phân cấp */
|
||||||
|
|
||||||
|
/* Container chính của Popup - Lớp phủ toàn màn hình */
|
||||||
.unity-base-dropdown {
|
.unity-base-dropdown {
|
||||||
|
background-color: rgba(0, 0, 0, 0) !important; /* Phải để trong suốt để không tràn màn hình */
|
||||||
|
border-width: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Phần nền nội bộ của cái menu box thực tế */
|
||||||
|
.unity-base-dropdown__container-inner {
|
||||||
background-color: #0a0a0a !important;
|
background-color: #0a0a0a !important;
|
||||||
border-width: 2px !important;
|
border-width: 2px !important;
|
||||||
border-color: #00ffcc !important;
|
border-color: #00ffcc !important;
|
||||||
border-radius: 12px !important;
|
border-radius: 12px !important;
|
||||||
margin-top: 10px !important;
|
margin-top: 10px !important;
|
||||||
|
padding: 5px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Đè phân cấp nội bộ của Popup */
|
/* Từng dòng Item */
|
||||||
.unity-base-dropdown__container-inner {
|
|
||||||
background-color: #0a0a0a !important;
|
|
||||||
border-width: 0 !important;
|
|
||||||
}
|
|
||||||
|
|
||||||
.unity-base-dropdown__item {
|
.unity-base-dropdown__item {
|
||||||
padding: 12px 15px !important;
|
padding: 12px 15px !important;
|
||||||
background-color: transparent !important;
|
background-color: transparent !important;
|
||||||
color: #eeeeee !important;
|
color: #eeeeee !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Chữ trong Item */
|
||||||
|
.unity-base-dropdown__label {
|
||||||
|
color: #eeeeee !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Đè hiệu ứng hover mặc định */
|
/* Đè hiệu ứng hover mặc định */
|
||||||
.unity-base-dropdown__item:hover {
|
.unity-base-dropdown__item:hover {
|
||||||
background-color: rgba(0, 255, 204, 0.15) !important;
|
background-color: rgba(0, 255, 204, 0.15) !important;
|
||||||
color: #00ffcc !important;
|
color: #00ffcc !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.unity-base-dropdown__item:hover .unity-base-dropdown__label {
|
||||||
|
color: #00ffcc !important;
|
||||||
|
}
|
||||||
|
|
||||||
/* Item được chọn */
|
/* Item được chọn */
|
||||||
.unity-base-dropdown__item--selected {
|
.unity-base-dropdown__item--selected {
|
||||||
background-color: rgba(0, 255, 204, 0.1) !important;
|
background-color: rgba(0, 255, 204, 0.1) !important;
|
||||||
color: #00ffcc !important;
|
color: #00ffcc !important;
|
||||||
-unity-font-style: bold;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.unity-base-dropdown__checkmark {
|
.unity-base-dropdown__checkmark {
|
||||||
-unity-background-image-tint-color: #00ffcc !important;
|
-unity-background-image-tint-color: #00ffcc !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ============================================================
|
||||||
|
SMART SIDEBAR (OSU STYLE OVERLAY)
|
||||||
|
============================================================ */
|
||||||
|
.sidebar-tabs-container {
|
||||||
|
background-color: rgba(5, 5, 5, 0.95);
|
||||||
|
padding-top: 60px;
|
||||||
|
flex-shrink: 0;
|
||||||
|
border-right-width: 1px;
|
||||||
|
border-right-color: rgba(0, 255, 204, 0.1);
|
||||||
|
transition: width 0.3s ease-out-quad;
|
||||||
|
overflow: hidden;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-collapsed {
|
||||||
|
width: 80px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-expanded {
|
||||||
|
width: 240px;
|
||||||
|
position: absolute;
|
||||||
|
z-index: 100;
|
||||||
|
border-right-color: #00ffcc;
|
||||||
|
border-right-width: 2px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-tab {
|
||||||
|
height: 60px;
|
||||||
|
background-color: transparent;
|
||||||
|
border-width: 0;
|
||||||
|
padding: 0;
|
||||||
|
flex-direction: row;
|
||||||
|
align-items: center;
|
||||||
|
border-left-width: 4px;
|
||||||
|
border-left-color: transparent;
|
||||||
|
margin: 2px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-icon-box {
|
||||||
|
width: 80px;
|
||||||
|
height: 60px;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
flex-shrink: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-icon {
|
||||||
|
width: 32px;
|
||||||
|
height: 32px;
|
||||||
|
background-color: #ffffff; /* Placeholder color */
|
||||||
|
-unity-background-image-tint-color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
.active-tab .tab-icon {
|
||||||
|
-unity-background-image-tint-color: #00ffcc;
|
||||||
|
background-color: #00ffcc;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tab-label {
|
||||||
|
font-size: 16px;
|
||||||
|
-unity-font-style: bold;
|
||||||
|
color: #888888;
|
||||||
|
margin-left: 10px;
|
||||||
|
white-space: nowrap;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.sidebar-expanded .tab-label {
|
||||||
|
opacity: 1;
|
||||||
|
color: #ffffff;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* ICON-ONLY BACK BUTTON */
|
||||||
|
.btn-icon-only {
|
||||||
|
width: 44px;
|
||||||
|
height: 44px;
|
||||||
|
border-radius: 22px;
|
||||||
|
padding: 0;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-icon-only .tab-icon {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
}
|
||||||
|
|
||||||
/* ============================================================
|
/* ============================================================
|
||||||
PANELS
|
PANELS
|
||||||
============================================================ */
|
============================================================ */
|
||||||
|
|||||||
Reference in New Issue
Block a user