feat: update song selection, score UI, and song creator features
- SongSelectManager/SongDetailPanel: 곡 선택 및 상세 패널 개선 - SongCreatorManager: 곡 생성 기능 추가 - FinalScoreLabel/ScoreManager: 결과 화면 점수 UI 업데이트 - MarqueeText: 마퀴 텍스트 컴포넌트 개선 - NoteData/SongController: 노트 데이터 및 컨트롤러 보완 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -412,7 +412,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 12.051, y: -28.918}
|
||||
m_AnchoredPosition: {x: 12.051, y: -30.052994}
|
||||
m_SizeDelta: {x: 130, y: 8}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &108468832
|
||||
@@ -725,7 +725,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0.00000033474, y: -40.969}
|
||||
m_AnchoredPosition: {x: 0.00000033474, y: -44.1}
|
||||
m_SizeDelta: {x: 168, y: 0.5}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &306375770
|
||||
@@ -920,7 +920,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -61.975, y: -36.665}
|
||||
m_AnchoredPosition: {x: -61.975, y: -37.8}
|
||||
m_SizeDelta: {x: 18, y: 7}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &354046698
|
||||
@@ -1670,7 +1670,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -13.772, y: -5.6772}
|
||||
m_AnchoredPosition: {x: -13.772, y: -5.2}
|
||||
m_SizeDelta: {x: 120, y: 9}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &528106932
|
||||
@@ -2131,7 +2131,7 @@ Transform:
|
||||
m_GameObject: {fileID: 633731941}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalPosition: {x: -0.5, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
@@ -2704,7 +2704,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -61.975, y: -28.918}
|
||||
m_AnchoredPosition: {x: -61.975, y: -30.052994}
|
||||
m_SizeDelta: {x: 18, y: 7}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &697160355
|
||||
@@ -3187,7 +3187,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 24.101, y: 8.095}
|
||||
m_AnchoredPosition: {x: -33.1, y: 8.095}
|
||||
m_SizeDelta: {x: 88, y: 9}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &885348079
|
||||
@@ -3324,7 +3324,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: -69}
|
||||
m_AnchoredPosition: {x: 0, y: -66}
|
||||
m_SizeDelta: {x: 170, y: 10}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!1 &927688130
|
||||
@@ -3361,7 +3361,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -61.975, y: -21.171}
|
||||
m_AnchoredPosition: {x: -61.975, y: -22.305994}
|
||||
m_SizeDelta: {x: 18, y: 7}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &927688132
|
||||
@@ -3637,7 +3637,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 12.051, y: -21.171}
|
||||
m_AnchoredPosition: {x: 12.051, y: -22.305994}
|
||||
m_SizeDelta: {x: 130, y: 8}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &961817605
|
||||
@@ -5126,7 +5126,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -20, y: -50.2}
|
||||
m_AnchoredPosition: {x: -20, y: -51.5}
|
||||
m_SizeDelta: {x: 98, y: 10}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1328124617
|
||||
@@ -5382,7 +5382,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0.00000033474, y: -9.9814}
|
||||
m_AnchoredPosition: {x: 0.00000033474, y: -11.4}
|
||||
m_SizeDelta: {x: 168, y: 0.5}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1401498817
|
||||
@@ -5953,7 +5953,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 65, y: -50.200005}
|
||||
m_AnchoredPosition: {x: 65, y: -51.500004}
|
||||
m_SizeDelta: {x: 36, y: 10}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1614055316
|
||||
@@ -7070,7 +7070,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -41.317, y: 8.095}
|
||||
m_AnchoredPosition: {x: 51.9, y: 8.095}
|
||||
m_SizeDelta: {x: 44, y: 9}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1795570113
|
||||
@@ -7191,7 +7191,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 12.051, y: -36.665}
|
||||
m_AnchoredPosition: {x: 12.051, y: -37.799995}
|
||||
m_SizeDelta: {x: 130, y: 8}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1799455459
|
||||
@@ -7866,7 +7866,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -57.671, y: -14.285}
|
||||
m_AnchoredPosition: {x: -57.671, y: -15.419995}
|
||||
m_SizeDelta: {x: 30, y: 6}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1924042092
|
||||
|
||||
@@ -5,12 +5,13 @@ using UnityEngine;
|
||||
[RequireComponent(typeof(TMP_Text))]
|
||||
public class MarqueeText : MonoBehaviour
|
||||
{
|
||||
public float speed = 35f;
|
||||
public float pauseStart = 1.5f;
|
||||
public float pauseEnd = 0.6f;
|
||||
public float speed = 14f;
|
||||
public float pauseStart = 1.8f;
|
||||
public float pauseEnd = 0.9f;
|
||||
|
||||
private TMP_Text _label;
|
||||
private RectTransform _rect;
|
||||
private Coroutine _scrollRoutine;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -20,7 +21,22 @@ public class MarqueeText : MonoBehaviour
|
||||
|
||||
private IEnumerator Start()
|
||||
{
|
||||
yield return null; // layout 완료 후 실행
|
||||
yield return null;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
StopScrolling();
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (!isActiveAndEnabled || _label == null || _rect == null || transform.parent == null)
|
||||
return;
|
||||
|
||||
StopScrolling();
|
||||
SetX(0f);
|
||||
|
||||
_label.ForceMeshUpdate();
|
||||
float textW = _label.preferredWidth;
|
||||
@@ -28,7 +44,7 @@ public class MarqueeText : MonoBehaviour
|
||||
float dist = textW - containerW;
|
||||
|
||||
if (dist > 1f)
|
||||
StartCoroutine(ScrollLoop(dist));
|
||||
_scrollRoutine = StartCoroutine(ScrollLoop(dist));
|
||||
}
|
||||
|
||||
private IEnumerator ScrollLoop(float dist)
|
||||
@@ -52,4 +68,13 @@ public class MarqueeText : MonoBehaviour
|
||||
|
||||
private void SetX(float x) =>
|
||||
_rect.anchoredPosition = new Vector2(x, _rect.anchoredPosition.y);
|
||||
|
||||
private void StopScrolling()
|
||||
{
|
||||
if (_scrollRoutine == null)
|
||||
return;
|
||||
|
||||
StopCoroutine(_scrollRoutine);
|
||||
_scrollRoutine = null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,19 @@ public class NoteData
|
||||
public class MapData
|
||||
{
|
||||
public List<NoteData> target;
|
||||
public ForcedResultData forcedResult;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ForcedResultData
|
||||
{
|
||||
public bool enabled;
|
||||
public int totalNotes;
|
||||
public int perfect;
|
||||
public int great;
|
||||
public int good;
|
||||
public int miss;
|
||||
public int maxCombo;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
|
||||
@@ -79,11 +79,35 @@ public class SongController : MonoBehaviour
|
||||
yield break;
|
||||
}
|
||||
MapData map = JsonUtility.FromJson<MapData>(File.ReadAllText(mapPath));
|
||||
if (map?.target == null)
|
||||
if (map == null)
|
||||
{
|
||||
Debug.LogError("[SongController] Map parse failed");
|
||||
yield break;
|
||||
}
|
||||
if (map.target == null)
|
||||
map.target = new List<NoteData>();
|
||||
|
||||
if (IsForcedResultMap(map))
|
||||
{
|
||||
_scoreManager?.SetTotalNotes(Mathf.Max(0, map.forcedResult.totalNotes));
|
||||
|
||||
yield return StartCoroutine(Countdown());
|
||||
|
||||
_audio.PlayClip(clip);
|
||||
yield return new WaitForSeconds(Mathf.Min(Mathf.Max(0.2f, _clipLength), 0.75f));
|
||||
|
||||
_scoreManager?.ApplyForcedResult(
|
||||
map.forcedResult.totalNotes,
|
||||
map.forcedResult.perfect,
|
||||
map.forcedResult.great,
|
||||
map.forcedResult.good,
|
||||
map.forcedResult.miss,
|
||||
map.forcedResult.maxCombo);
|
||||
_scoreManager?.CompleteSong();
|
||||
onLevelComplete?.Invoke();
|
||||
yield break;
|
||||
}
|
||||
|
||||
map.target.Sort(CompareNotes);
|
||||
if (_clipLength <= 0.0f)
|
||||
{
|
||||
@@ -165,6 +189,9 @@ public class SongController : MonoBehaviour
|
||||
return a.lineLayer.CompareTo(b.lineLayer);
|
||||
}
|
||||
|
||||
private static bool IsForcedResultMap(MapData map)
|
||||
=> map?.forcedResult != null && map.forcedResult.enabled;
|
||||
|
||||
private static float MapLaneX(int position)
|
||||
{
|
||||
int lane = Mathf.Clamp(position, 0, 3);
|
||||
|
||||
@@ -50,14 +50,27 @@ public class SongCreatorManager : MonoBehaviour
|
||||
[SerializeField] private BeatSageUploader beatSageUploader;
|
||||
[SerializeField] private NasPublisher nasPublisher;
|
||||
|
||||
private static readonly Color NeonBg = new Color(0.05f, 0.82f, 0.95f, 0.42f);
|
||||
private static readonly Color DarkButtonBg = new Color(0.09f, 0.22f, 0.27f, 0.66f);
|
||||
private static readonly Color DisabledBg = new Color(0.06f, 0.12f, 0.15f, 0.48f);
|
||||
private static readonly Color ButtonText = new Color(0.92f, 1.0f, 1.0f, 1.0f);
|
||||
private static readonly Color MutedText = new Color(0.66f, 0.80f, 0.84f, 0.76f);
|
||||
private static readonly Color NeonOutline = new Color(0.25f, 0.96f, 1.0f, 0.42f);
|
||||
|
||||
private static string InputPath =>
|
||||
Path.Combine(Application.persistentDataPath, "input");
|
||||
|
||||
private readonly List<string> audioFiles = new();
|
||||
private string _pendingFilePath;
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
ApplyButtonStyles();
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
ApplyButtonStyles();
|
||||
Directory.CreateDirectory(InputPath);
|
||||
|
||||
if (inputPathHint != null)
|
||||
@@ -258,6 +271,7 @@ public class SongCreatorManager : MonoBehaviour
|
||||
if (refreshBtn != null) refreshBtn.interactable = value;
|
||||
if (filePickerBtn != null) filePickerBtn.interactable = value;
|
||||
if (urlDownloadBtn != null) urlDownloadBtn.interactable = value;
|
||||
ApplyButtonStyles();
|
||||
}
|
||||
|
||||
private void OnFilePickerClicked()
|
||||
@@ -323,6 +337,7 @@ public class SongCreatorManager : MonoBehaviour
|
||||
{
|
||||
SetAddStatus("Downloading...");
|
||||
if (urlDownloadBtn != null) urlDownloadBtn.interactable = false;
|
||||
ApplyButtonStyles();
|
||||
|
||||
string fileName;
|
||||
try
|
||||
@@ -341,6 +356,7 @@ public class SongCreatorManager : MonoBehaviour
|
||||
yield return req.SendWebRequest();
|
||||
|
||||
if (urlDownloadBtn != null) urlDownloadBtn.interactable = true;
|
||||
ApplyButtonStyles();
|
||||
|
||||
if (req.result == UnityWebRequest.Result.Success)
|
||||
{
|
||||
@@ -358,4 +374,51 @@ public class SongCreatorManager : MonoBehaviour
|
||||
}
|
||||
|
||||
private void SetAddStatus(string msg) { if (addStatusText != null) addStatusText.text = msg; }
|
||||
|
||||
private void ApplyButtonStyles()
|
||||
{
|
||||
ApplyCreatorButtonStyle(generateButton, true);
|
||||
ApplyCreatorButtonStyle(urlDownloadBtn, true);
|
||||
ApplyCreatorButtonStyle(refreshBtn, false);
|
||||
ApplyCreatorButtonStyle(filePickerBtn, false);
|
||||
ApplyCreatorButtonStyle(backButton, false);
|
||||
}
|
||||
|
||||
private static void ApplyCreatorButtonStyle(Button btn, bool primary)
|
||||
{
|
||||
if (btn == null)
|
||||
return;
|
||||
|
||||
Color bg = btn.interactable ? (primary ? NeonBg : DarkButtonBg) : DisabledBg;
|
||||
if (btn.targetGraphic is Image img)
|
||||
{
|
||||
img.color = bg;
|
||||
img.raycastTarget = true;
|
||||
}
|
||||
|
||||
var colors = btn.colors;
|
||||
colors.normalColor = bg;
|
||||
colors.highlightedColor = btn.interactable
|
||||
? new Color(0.10f, 0.95f, 1.0f, primary ? 0.58f : 0.48f)
|
||||
: DisabledBg;
|
||||
colors.pressedColor = btn.interactable
|
||||
? new Color(0.02f, 0.58f, 0.72f, 0.80f)
|
||||
: DisabledBg;
|
||||
colors.selectedColor = colors.highlightedColor;
|
||||
colors.disabledColor = DisabledBg;
|
||||
colors.fadeDuration = 0.08f;
|
||||
btn.colors = colors;
|
||||
|
||||
TMP_Text label = btn.GetComponentInChildren<TMP_Text>(true);
|
||||
if (label != null)
|
||||
{
|
||||
label.color = btn.interactable ? ButtonText : MutedText;
|
||||
label.raycastTarget = false;
|
||||
}
|
||||
|
||||
Outline outline = btn.GetComponent<Outline>() ?? btn.gameObject.AddComponent<Outline>();
|
||||
outline.enabled = btn.interactable;
|
||||
outline.effectColor = NeonOutline;
|
||||
outline.effectDistance = new Vector2(0.0f, -0.28f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -33,13 +33,20 @@ public class SongDetailPanel : MonoBehaviour
|
||||
[Header("씬 이름")]
|
||||
[SerializeField] private string gameSceneName = "Game";
|
||||
|
||||
private static readonly Color SelectedColor = new Color(0.2f, 0.78f, 0.4f);
|
||||
private static readonly Color DeselectedImgColor = new Color(1f, 1f, 1f, 0.12f); // original button alpha
|
||||
private static readonly Color NeonBg = new Color(0.05f, 0.82f, 0.95f, 0.42f);
|
||||
private static readonly Color DarkButtonBg = new Color(0.09f, 0.22f, 0.27f, 0.66f);
|
||||
private static readonly Color DisabledBg = new Color(0.06f, 0.12f, 0.15f, 0.48f);
|
||||
private static readonly Color DangerBg = new Color(0.52f, 0.16f, 0.22f, 0.72f);
|
||||
private static readonly Color ButtonText = new Color(0.92f, 1.0f, 1.0f, 1.0f);
|
||||
private static readonly Color MutedText = new Color(0.66f, 0.80f, 0.84f, 0.76f);
|
||||
private static readonly Color NeonOutline = new Color(0.25f, 0.96f, 1.0f, 0.42f);
|
||||
|
||||
private SongInfo currentSong;
|
||||
private string selectedDifficulty;
|
||||
private DownloadManager downloadManager;
|
||||
private SongSelectManager selectManager;
|
||||
private MarqueeText titleMarquee;
|
||||
private MarqueeText artistMarquee;
|
||||
|
||||
private readonly (string key, Func<SongDetailPanel, Button> btn)[] diffSlots =
|
||||
{
|
||||
@@ -49,6 +56,22 @@ public class SongDetailPanel : MonoBehaviour
|
||||
("expertplus", p => p.btnExpertPlus),
|
||||
};
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
HideDifficultyLabel();
|
||||
titleMarquee = ConfigureMarqueeText(titleText, 5.0f, 7.2f);
|
||||
artistMarquee = ConfigureMarqueeText(artistText, 3.4f, 4.4f);
|
||||
ConfigureOneLineText(infoText, 3.2f, 4.2f, TextAlignmentOptions.MidlineLeft);
|
||||
ConfigureButtonText(btnNormal, 3.2f, 4.0f);
|
||||
ConfigureButtonText(btnHard, 3.2f, 4.0f);
|
||||
ConfigureButtonText(btnExpert, 3.2f, 4.0f);
|
||||
ConfigureButtonText(btnExpertPlus, 3.0f, 3.8f);
|
||||
ConfigureButtonText(downloadButton, 3.5f, 4.4f);
|
||||
ConfigureButtonText(deleteButton, 3.5f, 4.4f);
|
||||
ConfigureButtonText(playButton, 3.5f, 4.4f);
|
||||
ConfigureButtonText(closeButton, 5.2f, 6.4f);
|
||||
}
|
||||
|
||||
// ── Public API ───────────────────────────────────────────
|
||||
|
||||
public void Show(SongInfo song, DownloadManager dm, SongSelectManager sm)
|
||||
@@ -61,9 +84,11 @@ public class SongDetailPanel : MonoBehaviour
|
||||
titleText.text = song.title;
|
||||
artistText.text = song.artist;
|
||||
infoText.text = song.duration > 0
|
||||
? $"BPM {Mathf.RoundToInt(song.bpm)} | {FormatDuration(song.duration)}"
|
||||
? $"BPM {Mathf.RoundToInt(song.bpm)} {FormatDuration(song.duration)}"
|
||||
: $"BPM {Mathf.RoundToInt(song.bpm)}";
|
||||
|
||||
titleMarquee?.Refresh();
|
||||
artistMarquee?.Refresh();
|
||||
RefreshUI();
|
||||
}
|
||||
|
||||
@@ -92,8 +117,11 @@ public class SongDetailPanel : MonoBehaviour
|
||||
|
||||
downloadButton.gameObject.SetActive(!downloaded);
|
||||
deleteButton.gameObject.SetActive(downloaded);
|
||||
downloadButton.interactable = !downloaded;
|
||||
deleteButton.interactable = downloaded;
|
||||
playButton.interactable = downloaded && selectedDifficulty != null;
|
||||
progressGroup.SetActive(false);
|
||||
UpdateActionButtonStyles(downloaded);
|
||||
|
||||
downloadButton.onClick.RemoveAllListeners();
|
||||
downloadButton.onClick.AddListener(OnDownloadClicked);
|
||||
@@ -116,6 +144,7 @@ public class SongDetailPanel : MonoBehaviour
|
||||
selectedDifficulty = difficulty;
|
||||
playButton.interactable = true;
|
||||
UpdateDiffColors();
|
||||
UpdateActionButtonStyles(true);
|
||||
}
|
||||
|
||||
private void UpdateDiffColors()
|
||||
@@ -125,14 +154,7 @@ public class SongDetailPanel : MonoBehaviour
|
||||
Button btn = getBtn(this);
|
||||
bool selected = key == selectedDifficulty;
|
||||
|
||||
if (btn.targetGraphic is Image img)
|
||||
img.color = selected ? SelectedColor : DeselectedImgColor;
|
||||
|
||||
var cb = btn.colors;
|
||||
cb.normalColor = Color.white;
|
||||
cb.highlightedColor = selected ? new Color(0.3f, 0.95f, 0.55f) : new Color(1f, 1f, 1f, 0.25f);
|
||||
cb.pressedColor = selected ? new Color(0.15f, 0.6f, 0.3f) : new Color(1f, 1f, 1f, 0.35f);
|
||||
btn.colors = cb;
|
||||
ApplyButtonStyle(btn, selected ? NeonBg : DarkButtonBg, selected, btn.interactable, false);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -234,4 +256,129 @@ public class SongDetailPanel : MonoBehaviour
|
||||
|
||||
private static string FormatDuration(int seconds)
|
||||
=> $"{seconds / 60}:{seconds % 60:D2}";
|
||||
|
||||
private void HideDifficultyLabel()
|
||||
{
|
||||
Transform label = transform.Find("LblDifficulty");
|
||||
if (label != null)
|
||||
label.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private void UpdateActionButtonStyles(bool downloaded)
|
||||
{
|
||||
ApplyButtonStyle(downloadButton, NeonBg, true, !downloaded, false);
|
||||
ApplyButtonStyle(deleteButton, DangerBg, true, downloaded, true);
|
||||
ApplyButtonStyle(playButton, NeonBg, true, playButton.interactable, false);
|
||||
ApplyButtonStyle(closeButton, DarkButtonBg, false, true, false);
|
||||
}
|
||||
|
||||
private static void ApplyButtonStyle(Button btn, Color activeBg, bool outlined, bool enabled, bool danger)
|
||||
{
|
||||
if (btn == null)
|
||||
return;
|
||||
|
||||
Color bg = enabled ? activeBg : DisabledBg;
|
||||
if (btn.targetGraphic is Image img)
|
||||
img.color = bg;
|
||||
|
||||
var colors = btn.colors;
|
||||
colors.normalColor = bg;
|
||||
colors.highlightedColor = enabled
|
||||
? (danger ? new Color(0.72f, 0.23f, 0.30f, 0.86f) : new Color(0.10f, 0.95f, 1.0f, 0.58f))
|
||||
: DisabledBg;
|
||||
colors.pressedColor = enabled
|
||||
? (danger ? new Color(0.42f, 0.10f, 0.15f, 0.92f) : new Color(0.02f, 0.58f, 0.72f, 0.80f))
|
||||
: DisabledBg;
|
||||
colors.selectedColor = colors.highlightedColor;
|
||||
colors.disabledColor = DisabledBg;
|
||||
colors.fadeDuration = 0.08f;
|
||||
btn.colors = colors;
|
||||
|
||||
TMP_Text label = btn.GetComponentInChildren<TMP_Text>();
|
||||
if (label != null)
|
||||
label.color = enabled ? ButtonText : MutedText;
|
||||
|
||||
Outline outline = btn.GetComponent<Outline>() ?? btn.gameObject.AddComponent<Outline>();
|
||||
outline.enabled = outlined && enabled;
|
||||
outline.effectColor = danger ? new Color(1.0f, 0.35f, 0.42f, 0.34f) : NeonOutline;
|
||||
outline.effectDistance = new Vector2(0.0f, -0.28f);
|
||||
}
|
||||
|
||||
private static MarqueeText ConfigureMarqueeText(TMP_Text text, float minSize, float maxSize)
|
||||
{
|
||||
if (text == null)
|
||||
return null;
|
||||
|
||||
RectTransform textRect = text.rectTransform;
|
||||
Transform originalParent = textRect.parent;
|
||||
int siblingIndex = textRect.GetSiblingIndex();
|
||||
string maskName = $"{text.name}Mask";
|
||||
Transform existingMask = originalParent != null ? originalParent.Find(maskName) : null;
|
||||
RectTransform maskRect;
|
||||
|
||||
if (existingMask != null)
|
||||
{
|
||||
maskRect = existingMask as RectTransform;
|
||||
if (textRect.parent != existingMask)
|
||||
textRect.SetParent(existingMask, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
var mask = new GameObject(maskName);
|
||||
mask.transform.SetParent(originalParent, false);
|
||||
mask.transform.SetSiblingIndex(siblingIndex);
|
||||
maskRect = mask.AddComponent<RectTransform>();
|
||||
maskRect.anchorMin = textRect.anchorMin;
|
||||
maskRect.anchorMax = textRect.anchorMax;
|
||||
maskRect.pivot = textRect.pivot;
|
||||
maskRect.anchoredPosition = textRect.anchoredPosition;
|
||||
maskRect.sizeDelta = textRect.sizeDelta;
|
||||
maskRect.localRotation = textRect.localRotation;
|
||||
maskRect.localScale = textRect.localScale;
|
||||
mask.AddComponent<RectMask2D>();
|
||||
textRect.SetParent(mask.transform, false);
|
||||
}
|
||||
|
||||
textRect.anchorMin = new Vector2(0f, 0f);
|
||||
textRect.anchorMax = new Vector2(0f, 1f);
|
||||
textRect.pivot = new Vector2(0f, 0.5f);
|
||||
textRect.anchoredPosition = Vector2.zero;
|
||||
textRect.localRotation = Quaternion.identity;
|
||||
textRect.localScale = Vector3.one;
|
||||
textRect.sizeDelta = new Vector2(260.0f, 0f);
|
||||
|
||||
ConfigureOneLineText(text, minSize, maxSize, TextAlignmentOptions.MidlineLeft);
|
||||
text.overflowMode = TextOverflowModes.Overflow;
|
||||
text.raycastTarget = false;
|
||||
|
||||
MarqueeText marquee = text.GetComponent<MarqueeText>() ?? text.gameObject.AddComponent<MarqueeText>();
|
||||
marquee.speed = 9f;
|
||||
marquee.pauseStart = 1.25f;
|
||||
marquee.pauseEnd = 0.8f;
|
||||
return marquee;
|
||||
}
|
||||
|
||||
private static void ConfigureButtonText(Button btn, float minSize, float maxSize)
|
||||
{
|
||||
if (btn == null)
|
||||
return;
|
||||
|
||||
TMP_Text label = btn.GetComponentInChildren<TMP_Text>();
|
||||
ConfigureOneLineText(label, minSize, maxSize, TextAlignmentOptions.Center);
|
||||
if (label != null)
|
||||
label.raycastTarget = false;
|
||||
}
|
||||
|
||||
private static void ConfigureOneLineText(TMP_Text text, float minSize, float maxSize, TextAlignmentOptions alignment)
|
||||
{
|
||||
if (text == null)
|
||||
return;
|
||||
|
||||
text.enableAutoSizing = true;
|
||||
text.fontSizeMin = minSize;
|
||||
text.fontSizeMax = maxSize;
|
||||
text.alignment = alignment;
|
||||
text.overflowMode = TextOverflowModes.Ellipsis;
|
||||
text.textWrappingMode = TextWrappingModes.NoWrap;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,8 +16,11 @@ public class SongSelectManager : MonoBehaviour
|
||||
[SerializeField] private TMP_Text errorText;
|
||||
|
||||
|
||||
private static readonly Color TabActive = new Color(1f, 1f, 1f, 0.45f);
|
||||
private static readonly Color TabInactive = new Color(1f, 1f, 1f, 0.12f);
|
||||
private static readonly Color TabActiveBg = new Color(0.05f, 0.82f, 0.95f, 0.42f);
|
||||
private static readonly Color TabInactiveBg = new Color(0.09f, 0.22f, 0.27f, 0.66f);
|
||||
private static readonly Color TabActiveText = new Color(0.92f, 1.0f, 1.0f, 1.0f);
|
||||
private static readonly Color TabInactiveText = new Color(0.72f, 0.86f, 0.90f, 0.82f);
|
||||
private static readonly Color TabActiveOutline = new Color(0.25f, 0.96f, 1.0f, 0.55f);
|
||||
|
||||
private static string CachePath =>
|
||||
Path.Combine(Application.persistentDataPath, "songs_cache.json");
|
||||
@@ -49,17 +52,39 @@ public class SongSelectManager : MonoBehaviour
|
||||
|
||||
private void SetTabVisual(bool owned)
|
||||
{
|
||||
ApplyTabColor(tabAllBtn, owned ? TabInactive : TabActive);
|
||||
ApplyTabColor(tabOwnedBtn, owned ? TabActive : TabInactive);
|
||||
ApplyTabStyle(tabAllBtn, !owned);
|
||||
ApplyTabStyle(tabOwnedBtn, owned);
|
||||
}
|
||||
|
||||
private static void ApplyTabColor(Button btn, Color c)
|
||||
private static void ApplyTabStyle(Button btn, bool active)
|
||||
{
|
||||
if (btn == null)
|
||||
return;
|
||||
|
||||
Color bg = active ? TabActiveBg : TabInactiveBg;
|
||||
if (btn.targetGraphic is Image img)
|
||||
img.color = c;
|
||||
img.color = bg;
|
||||
|
||||
var colors = btn.colors;
|
||||
colors.normalColor = Color.white;
|
||||
colors.normalColor = bg;
|
||||
colors.highlightedColor = active
|
||||
? new Color(0.10f, 0.95f, 1.0f, 0.58f)
|
||||
: new Color(0.14f, 0.34f, 0.40f, 0.72f);
|
||||
colors.pressedColor = active
|
||||
? new Color(0.02f, 0.58f, 0.72f, 0.72f)
|
||||
: new Color(0.08f, 0.20f, 0.24f, 0.82f);
|
||||
colors.selectedColor = colors.highlightedColor;
|
||||
colors.disabledColor = new Color(0.05f, 0.10f, 0.12f, 0.45f);
|
||||
btn.colors = colors;
|
||||
|
||||
TMP_Text label = btn.GetComponentInChildren<TMP_Text>();
|
||||
if (label != null)
|
||||
label.color = active ? TabActiveText : TabInactiveText;
|
||||
|
||||
Outline outline = btn.GetComponent<Outline>() ?? btn.gameObject.AddComponent<Outline>();
|
||||
outline.enabled = active;
|
||||
outline.effectColor = TabActiveOutline;
|
||||
outline.effectDistance = new Vector2(0.0f, -0.35f);
|
||||
}
|
||||
|
||||
private void FetchSongs()
|
||||
@@ -70,9 +95,10 @@ public class SongSelectManager : MonoBehaviour
|
||||
downloadManager.FetchSongsList(
|
||||
onSuccess: list =>
|
||||
{
|
||||
allSongs = list.songs;
|
||||
SaveCache(list);
|
||||
SongLibrary.Instance.ValidateWithFileSystem(downloadManager, list.songs);
|
||||
allSongs = list.songs ?? new List<SongInfo>();
|
||||
AddLocalForcedRankDummies(allSongs);
|
||||
SaveCache(new SongsList { version = list.version, songs = allSongs });
|
||||
SongLibrary.Instance.ValidateWithFileSystem(downloadManager, allSongs);
|
||||
loadingOverlay.SetActive(false);
|
||||
RefreshCards();
|
||||
},
|
||||
@@ -134,14 +160,16 @@ public class SongSelectManager : MonoBehaviour
|
||||
bc.fadeDuration = 0.1f;
|
||||
btn.colors = bc;
|
||||
|
||||
float textLeftInset = downloaded ? 12f : 5f;
|
||||
|
||||
// Title — RectMask2D 컨테이너 안에서 마퀴 스크롤
|
||||
var titleMask = new GameObject("TitleMask");
|
||||
titleMask.transform.SetParent(card.transform, false);
|
||||
var tmr = titleMask.AddComponent<RectTransform>();
|
||||
tmr.anchorMin = new Vector2(0f, 0.5f);
|
||||
tmr.anchorMax = new Vector2(1f, 1f);
|
||||
tmr.offsetMin = new Vector2(5f, 0f);
|
||||
tmr.offsetMax = new Vector2(downloaded ? -20f : -3f, 0f);
|
||||
tmr.offsetMin = new Vector2(textLeftInset, 0f);
|
||||
tmr.offsetMax = new Vector2(-3f, 0f);
|
||||
titleMask.AddComponent<RectMask2D>();
|
||||
|
||||
var titleGO = new GameObject("Title");
|
||||
@@ -166,41 +194,37 @@ public class SongSelectManager : MonoBehaviour
|
||||
var artistGO = new GameObject("Artist");
|
||||
artistGO.transform.SetParent(card.transform, false);
|
||||
var ar = artistGO.AddComponent<RectTransform>();
|
||||
ar.anchorMin = new Vector2(0f, 0f);
|
||||
ar.anchorMax = new Vector2(1f, 0.5f);
|
||||
ar.offsetMin = new Vector2(5f, 1f);
|
||||
ar.anchorMin = new Vector2(0f, 0.04f);
|
||||
ar.anchorMax = new Vector2(1f, 0.48f);
|
||||
ar.offsetMin = new Vector2(textLeftInset, 0f);
|
||||
ar.offsetMax = new Vector2(-3f, 0f);
|
||||
var aTmp = artistGO.AddComponent<TextMeshProUGUI>();
|
||||
if (_cardFont != null) aTmp.font = _cardFont;
|
||||
aTmp.text = song.artist;
|
||||
aTmp.fontSize = 4f;
|
||||
aTmp.color = new Color(1f, 1f, 1f, 0.6f);
|
||||
aTmp.alignment = TextAlignmentOptions.MidlineLeft;
|
||||
aTmp.text = song.artist;
|
||||
aTmp.fontSize = 4f;
|
||||
aTmp.enableAutoSizing = true;
|
||||
aTmp.fontSizeMin = 2.8f;
|
||||
aTmp.fontSizeMax = 4f;
|
||||
aTmp.color = new Color(1f, 1f, 1f, 0.6f);
|
||||
aTmp.alignment = TextAlignmentOptions.MidlineLeft;
|
||||
aTmp.overflowMode = TextOverflowModes.Ellipsis;
|
||||
aTmp.textWrappingMode = TextWrappingModes.NoWrap;
|
||||
|
||||
// Downloaded badge
|
||||
// Downloaded check mark
|
||||
if (downloaded)
|
||||
{
|
||||
var badge = new GameObject("Badge");
|
||||
badge.transform.SetParent(card.transform, false);
|
||||
var br = badge.AddComponent<RectTransform>();
|
||||
br.anchorMin = new Vector2(1f, 0.5f);
|
||||
br.anchorMax = new Vector2(1f, 0.5f);
|
||||
br.pivot = new Vector2(1f, 0.5f);
|
||||
br.anchoredPosition = new Vector2(-3f, 0f);
|
||||
br.sizeDelta = new Vector2(14f, 5.5f);
|
||||
badge.AddComponent<Image>().color = new Color(0.2f, 0.78f, 0.4f, 0.85f);
|
||||
var checkGO = new GameObject("OwnedCheck");
|
||||
checkGO.transform.SetParent(card.transform, false);
|
||||
var cr = checkGO.AddComponent<RectTransform>();
|
||||
cr.anchorMin = new Vector2(0f, 0f);
|
||||
cr.anchorMax = new Vector2(0f, 1f);
|
||||
cr.pivot = new Vector2(0f, 0.5f);
|
||||
cr.anchoredPosition = new Vector2(3.0f, 0f);
|
||||
cr.sizeDelta = new Vector2(6f, 0f);
|
||||
|
||||
var bl = new GameObject("Text");
|
||||
bl.transform.SetParent(badge.transform, false);
|
||||
var blr = bl.AddComponent<RectTransform>();
|
||||
blr.anchorMin = Vector2.zero;
|
||||
blr.anchorMax = Vector2.one;
|
||||
blr.offsetMin = blr.offsetMax = Vector2.zero;
|
||||
var blTmp = bl.AddComponent<TextMeshProUGUI>();
|
||||
blTmp.text = "OWNED";
|
||||
blTmp.fontSize = 3.5f;
|
||||
blTmp.color = Color.white;
|
||||
blTmp.alignment = TextAlignmentOptions.Center;
|
||||
Color checkColor = new Color(0.36f, 1.0f, 0.58f, 0.95f);
|
||||
CreateCheckStroke(checkGO.transform, "ShortStroke", new Vector2(1.8f, 7.1f), new Vector2(1.5f, 0.35f), 42.0f, checkColor);
|
||||
CreateCheckStroke(checkGO.transform, "LongStroke", new Vector2(3.25f, 7.85f), new Vector2(3.7f, 0.35f), -45.0f, checkColor);
|
||||
}
|
||||
|
||||
SongInfo captured = song;
|
||||
@@ -213,6 +237,25 @@ public class SongSelectManager : MonoBehaviour
|
||||
detailPanel.Show(song, downloadManager, this);
|
||||
}
|
||||
|
||||
private static void CreateCheckStroke(Transform parent, string name, Vector2 anchoredPosition,
|
||||
Vector2 size, float rotationZ, Color color)
|
||||
{
|
||||
var stroke = new GameObject(name);
|
||||
stroke.transform.SetParent(parent, false);
|
||||
|
||||
var rect = stroke.AddComponent<RectTransform>();
|
||||
rect.anchorMin = new Vector2(0f, 0f);
|
||||
rect.anchorMax = new Vector2(0f, 0f);
|
||||
rect.pivot = new Vector2(0.5f, 0.5f);
|
||||
rect.anchoredPosition = anchoredPosition;
|
||||
rect.sizeDelta = size;
|
||||
rect.localRotation = Quaternion.Euler(0f, 0f, rotationZ);
|
||||
|
||||
var img = stroke.AddComponent<Image>();
|
||||
img.color = color;
|
||||
img.raycastTarget = false;
|
||||
}
|
||||
|
||||
private static void SaveCache(SongsList list)
|
||||
{
|
||||
try { File.WriteAllText(CachePath, JsonUtility.ToJson(list, true)); }
|
||||
@@ -225,4 +268,61 @@ public class SongSelectManager : MonoBehaviour
|
||||
try { return JsonUtility.FromJson<SongsList>(File.ReadAllText(CachePath)); }
|
||||
catch { return null; }
|
||||
}
|
||||
|
||||
private static void AddLocalForcedRankDummies(List<SongInfo> songs)
|
||||
{
|
||||
string root = Path.Combine(Application.persistentDataPath, "beatsaber");
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_m", "M", 10);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_splus", "S+", 100);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_s", "S", 100);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_a", "A", 100);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_b", "B", 100);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_c", "C", 100);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_d", "D", 100);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_f", "F", 100);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_splus_border", "S+ 98%", 100);
|
||||
AddLocalForcedRankDummy(songs, root, "dummy_rank_f_zero", "F 0%", 20);
|
||||
}
|
||||
|
||||
private static void AddLocalForcedRankDummy(List<SongInfo> songs, string root, string id, string title, int noteCount)
|
||||
{
|
||||
if (songs.Exists(song => song.id == id))
|
||||
return;
|
||||
|
||||
string songDir = Path.Combine(root, id);
|
||||
string audioPath = Path.Combine(songDir, $"{id}.mp3");
|
||||
string mapFile = $"Map_{id}_forced.json";
|
||||
string mapPath = Path.Combine(songDir, mapFile);
|
||||
if (!File.Exists(audioPath) || !File.Exists(mapPath))
|
||||
return;
|
||||
|
||||
long audioSize = new FileInfo(audioPath).Length;
|
||||
long mapSize = new FileInfo(mapPath).Length;
|
||||
DifficultyInfo info = new DifficultyInfo
|
||||
{
|
||||
mapFile = mapFile,
|
||||
mapSize = mapSize,
|
||||
noteCount = noteCount
|
||||
};
|
||||
|
||||
songs.Insert(0, new SongInfo
|
||||
{
|
||||
id = id,
|
||||
title = title,
|
||||
artist = "Forced Rank Dummy",
|
||||
bpm = 120.0f,
|
||||
duration = 1,
|
||||
audioFile = $"dummy/{id}.mp3",
|
||||
audioSize = audioSize,
|
||||
coverImage = "",
|
||||
difficulties = new DifficultyMap
|
||||
{
|
||||
normal = info,
|
||||
hard = info,
|
||||
expert = info,
|
||||
expertplus = info
|
||||
},
|
||||
addedAt = "2026-05-29"
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,8 +156,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -18, y: 19.5}
|
||||
m_SizeDelta: {x: 30, y: 7}
|
||||
m_AnchoredPosition: {x: -19, y: 19.5}
|
||||
m_SizeDelta: {x: 34, y: 7}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &11933137
|
||||
MonoBehaviour:
|
||||
@@ -456,8 +456,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 4}
|
||||
m_SizeDelta: {x: 50, y: 0.4}
|
||||
m_AnchoredPosition: {x: 0, y: 4.2}
|
||||
m_SizeDelta: {x: 68, y: 0.4}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &97527770
|
||||
MonoBehaviour:
|
||||
@@ -652,7 +652,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -1267,8 +1267,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 12}
|
||||
m_SizeDelta: {x: 50, y: 6}
|
||||
m_AnchoredPosition: {x: -16.05, y: 10.8}
|
||||
m_SizeDelta: {x: 42, y: 4.8}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &285384529
|
||||
MonoBehaviour:
|
||||
@@ -1290,7 +1290,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text:
|
||||
m_text: Anesthesia
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
@@ -1299,7 +1299,7 @@ MonoBehaviour:
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
rgba: 3439329279
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 0.8}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
@@ -1312,7 +1312,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -1324,7 +1324,7 @@ MonoBehaviour:
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
@@ -1405,8 +1405,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -26.6, y: -9.4}
|
||||
m_SizeDelta: {x: 52.7, y: 49}
|
||||
m_AnchoredPosition: {x: -44, y: -9.4}
|
||||
m_SizeDelta: {x: 56, y: 49}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!1 &313102848
|
||||
GameObject:
|
||||
@@ -1682,7 +1682,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
m_IsActive: 0
|
||||
--- !u!224 &365318615
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -1830,16 +1830,16 @@ RectTransform:
|
||||
m_GameObject: {fileID: 365636951}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1536039027}
|
||||
m_Father: {fileID: 1223157292}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 12, y: -14}
|
||||
m_SizeDelta: {x: 22, y: 7}
|
||||
m_AnchoredPosition: {x: 17, y: -9.7}
|
||||
m_SizeDelta: {x: 27, y: 6}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &365636953
|
||||
MonoBehaviour:
|
||||
@@ -1957,7 +1957,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0.1, y: -9.4}
|
||||
m_AnchoredPosition: {x: -15, y: -9.4}
|
||||
m_SizeDelta: {x: 0.5, y: 49}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &393692317
|
||||
@@ -2300,16 +2300,16 @@ RectTransform:
|
||||
m_GameObject: {fileID: 549476134}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 138927897}
|
||||
m_Father: {fileID: 1223157292}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -12, y: -5}
|
||||
m_SizeDelta: {x: 22, y: 7}
|
||||
m_AnchoredPosition: {x: -17, y: -2}
|
||||
m_SizeDelta: {x: 27, y: 6}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &549476136
|
||||
MonoBehaviour:
|
||||
@@ -2428,7 +2428,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 15.5}
|
||||
m_SizeDelta: {x: 104, y: 0.5}
|
||||
m_SizeDelta: {x: 144, y: 0.5}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &584186484
|
||||
MonoBehaviour:
|
||||
@@ -2534,7 +2534,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0, y: 0}
|
||||
m_AnchorMax: {x: 1, y: 1}
|
||||
m_AnchoredPosition: {x: -0.54999924, y: 0.040000916}
|
||||
m_AnchoredPosition: {x: -0.55000305, y: 0.040000916}
|
||||
m_SizeDelta: {x: 1.1, y: 3.12}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &624828134
|
||||
@@ -2639,8 +2639,8 @@ RectTransform:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 661667650}
|
||||
m_LocalRotation: {x: 0, y: 0.38268343, z: 0, w: 0.92387956}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 20.29}
|
||||
m_LocalScale: {x: 0.25, y: 0.25, z: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 21.44}
|
||||
m_LocalScale: {x: 0.21, y: 0.21, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 140294464}
|
||||
@@ -2652,7 +2652,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 45, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 24.01, y: 4.71}
|
||||
m_AnchoredPosition: {x: 28.85, y: 4.71}
|
||||
m_SizeDelta: {x: 105.885, y: 71.226}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &661667652
|
||||
@@ -2786,8 +2786,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 14, y: 19.5}
|
||||
m_SizeDelta: {x: 30, y: 7}
|
||||
m_AnchoredPosition: {x: 17.5, y: 19.5}
|
||||
m_SizeDelta: {x: 34, y: 7}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &711973508
|
||||
MonoBehaviour:
|
||||
@@ -3087,7 +3087,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -3224,7 +3224,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -3310,16 +3310,16 @@ RectTransform:
|
||||
m_GameObject: {fileID: 848577108}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 2121890138}
|
||||
m_Father: {fileID: 1223157292}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 12, y: -5}
|
||||
m_SizeDelta: {x: 22, y: 7}
|
||||
m_AnchoredPosition: {x: 17, y: -2}
|
||||
m_SizeDelta: {x: 27, y: 6}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &848577110
|
||||
MonoBehaviour:
|
||||
@@ -3437,8 +3437,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 7}
|
||||
m_SizeDelta: {x: 50, y: 5}
|
||||
m_AnchoredPosition: {x: 20.5, y: 10.8}
|
||||
m_SizeDelta: {x: 28, y: 4.8}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &861505383
|
||||
MonoBehaviour:
|
||||
@@ -3460,7 +3460,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text:
|
||||
m_text: BPM 120
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
@@ -3469,7 +3469,7 @@ MonoBehaviour:
|
||||
m_fontMaterials: []
|
||||
m_fontColor32:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
rgba: 2583691263
|
||||
m_fontColor: {r: 1, g: 1, b: 1, a: 0.6}
|
||||
m_enableVertexGradient: 0
|
||||
m_colorMode: 3
|
||||
@@ -3482,7 +3482,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -3494,7 +3494,7 @@ MonoBehaviour:
|
||||
m_fontSizeMin: 18
|
||||
m_fontSizeMax: 72
|
||||
m_fontStyle: 0
|
||||
m_HorizontalAlignment: 2
|
||||
m_HorizontalAlignment: 1
|
||||
m_VerticalAlignment: 512
|
||||
m_textAlignment: 65535
|
||||
m_characterSpacing: 0
|
||||
@@ -3611,8 +3611,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -3, y: 18.5}
|
||||
m_SizeDelta: {x: 38, y: 8}
|
||||
m_AnchoredPosition: {x: -5.5, y: 17}
|
||||
m_SizeDelta: {x: 63, y: 7.4}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &921515098
|
||||
MonoBehaviour:
|
||||
@@ -3634,7 +3634,7 @@ MonoBehaviour:
|
||||
m_OnCullStateChanged:
|
||||
m_PersistentCalls:
|
||||
m_Calls: []
|
||||
m_text: ---
|
||||
m_text: Oxlo
|
||||
m_isRightToLeft: 0
|
||||
m_fontAsset: {fileID: 11400000, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
m_sharedMaterial: {fileID: 2180264, guid: 8f586378b4e144a9851e7b34d9b748ee, type: 2}
|
||||
@@ -3656,13 +3656,13 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
rgba: 4294967295
|
||||
m_fontSize: 6.5
|
||||
m_fontSizeBase: 6.5
|
||||
m_fontSize: 7.2
|
||||
m_fontSizeBase: 7.2
|
||||
m_fontWeight: 400
|
||||
m_enableAutoSizing: 0
|
||||
m_fontSizeMin: 18
|
||||
@@ -3817,16 +3817,16 @@ RectTransform:
|
||||
m_GameObject: {fileID: 967100893}
|
||||
m_LocalRotation: {x: -0, y: -0, z: -0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 829525444}
|
||||
m_Father: {fileID: 1223157292}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 16.400002, y: -22.900002}
|
||||
m_SizeDelta: {x: 16, y: 7}
|
||||
m_AnchoredPosition: {x: 22.5, y: -20.2}
|
||||
m_SizeDelta: {x: 18, y: 6.4}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &967100895
|
||||
MonoBehaviour:
|
||||
@@ -4019,8 +4019,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: -18.5}
|
||||
m_SizeDelta: {x: 50, y: 0.4}
|
||||
m_AnchoredPosition: {x: 0, y: -16}
|
||||
m_SizeDelta: {x: 68, y: 0.4}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1010856770
|
||||
MonoBehaviour:
|
||||
@@ -4095,7 +4095,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 23.5}
|
||||
m_SizeDelta: {x: 104, y: 0.5}
|
||||
m_SizeDelta: {x: 144, y: 0.5}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1014388332
|
||||
MonoBehaviour:
|
||||
@@ -4255,7 +4255,7 @@ GameObject:
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 0
|
||||
m_IsActive: 1
|
||||
--- !u!224 &1223157292
|
||||
RectTransform:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -4265,7 +4265,7 @@ RectTransform:
|
||||
m_GameObject: {fileID: 1223157291}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.89393, y: 0.89393, z: 0.89393}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1293606945}
|
||||
@@ -4287,8 +4287,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 26.6, y: -9.4}
|
||||
m_SizeDelta: {x: 52.7, y: 49}
|
||||
m_AnchoredPosition: {x: 29, y: -9.4}
|
||||
m_SizeDelta: {x: 86, y: 49}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1223157293
|
||||
MonoBehaviour:
|
||||
@@ -4486,7 +4486,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -4656,8 +4656,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 21, y: 20.5}
|
||||
m_SizeDelta: {x: 8, y: 7}
|
||||
m_AnchoredPosition: {x: 37, y: 20.5}
|
||||
m_SizeDelta: {x: 7, y: 6.5}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1293606946
|
||||
MonoBehaviour:
|
||||
@@ -4769,16 +4769,16 @@ RectTransform:
|
||||
m_GameObject: {fileID: 1388756479}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1245764537}
|
||||
m_Father: {fileID: 1223157292}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -9.5, y: -22.7}
|
||||
m_SizeDelta: {x: 34, y: 7}
|
||||
m_AnchoredPosition: {x: -12.5, y: -20.2}
|
||||
m_SizeDelta: {x: 40, y: 6.4}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1388756481
|
||||
MonoBehaviour:
|
||||
@@ -5026,16 +5026,16 @@ RectTransform:
|
||||
m_GameObject: {fileID: 1436526096}
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 0.9, y: 0.9, z: 0.9}
|
||||
m_ConstrainProportionsScale: 1
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 1786385005}
|
||||
m_Father: {fileID: 1223157292}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -12, y: -14}
|
||||
m_SizeDelta: {x: 22, y: 7}
|
||||
m_AnchoredPosition: {x: -17, y: -9.7}
|
||||
m_SizeDelta: {x: 27, y: 6}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1436526098
|
||||
MonoBehaviour:
|
||||
@@ -5241,8 +5241,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0.67, y: 4.46}
|
||||
m_SizeDelta: {x: 105.885, y: 68.223}
|
||||
m_AnchoredPosition: {x: 0.4, y: 4.5}
|
||||
m_SizeDelta: {x: 148, y: 68.2}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1445586371
|
||||
MonoBehaviour:
|
||||
@@ -5493,7 +5493,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -5933,7 +5933,7 @@ RectTransform:
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: 0, y: 28.5}
|
||||
m_SizeDelta: {x: 100, y: 9}
|
||||
m_SizeDelta: {x: 138, y: 9}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1754869934
|
||||
MonoBehaviour:
|
||||
@@ -6233,7 +6233,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -6626,7 +6626,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
@@ -6720,8 +6720,8 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -6, y: -21.5}
|
||||
m_SizeDelta: {x: 34, y: 7}
|
||||
m_AnchoredPosition: {x: -12.5, y: -20.2}
|
||||
m_SizeDelta: {x: 40, y: 6.4}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1888615411
|
||||
MonoBehaviour:
|
||||
@@ -7157,8 +7157,8 @@ RectTransform:
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 1946485404}
|
||||
m_LocalRotation: {x: 0, y: -0.38268343, z: 0, w: 0.92387956}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 18.33}
|
||||
m_LocalScale: {x: 0.25, y: 0.25, z: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 20.96}
|
||||
m_LocalScale: {x: 0.21, y: 0.21, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children:
|
||||
- {fileID: 2121492652}
|
||||
@@ -7167,7 +7167,7 @@ RectTransform:
|
||||
m_LocalEulerAnglesHint: {x: 0, y: -45, z: 0}
|
||||
m_AnchorMin: {x: 0.5, y: 0.5}
|
||||
m_AnchorMax: {x: 0.5, y: 0.5}
|
||||
m_AnchoredPosition: {x: -21.77, y: 4.39}
|
||||
m_AnchoredPosition: {x: -27.37, y: 4.39}
|
||||
m_SizeDelta: {x: 105.89, y: 66.53}
|
||||
m_Pivot: {x: 0.5, y: 0.5}
|
||||
--- !u!114 &1946485406
|
||||
@@ -7727,7 +7727,7 @@ MonoBehaviour:
|
||||
m_spriteAsset: {fileID: 0}
|
||||
m_tintAllSprites: 0
|
||||
m_StyleSheet: {fileID: 0}
|
||||
m_TextStyleHashCode: 0
|
||||
m_TextStyleHashCode: -1183493901
|
||||
m_overrideHtmlColors: 0
|
||||
m_faceColor:
|
||||
serializedVersion: 2
|
||||
|
||||
@@ -11,12 +11,16 @@ namespace VRBeats
|
||||
private string initialValue = "";
|
||||
private ScoreManager scoreManager = null;
|
||||
private GameObject resultRoot = null;
|
||||
private TextMeshProUGUI rankBackText = null;
|
||||
private TextMeshProUGUI rankShadowText = null;
|
||||
private TextMeshProUGUI rankDepthText = null;
|
||||
private TextMeshProUGUI rankRimText = null;
|
||||
private TextMeshProUGUI rankMainText = null;
|
||||
private TextMeshProUGUI rankHighlightText = null;
|
||||
private TextMeshProUGUI resultScoreText = null;
|
||||
private TextMeshProUGUI resultAccuracyText = null;
|
||||
private TextMeshProUGUI resultComboText = null;
|
||||
private CanvasGroup scoreHudCanvasGroup = null;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
@@ -24,6 +28,9 @@ namespace VRBeats
|
||||
initialValue += "0";
|
||||
|
||||
scoreManager = FindFirstObjectByType<ScoreManager>();
|
||||
if (scoreManager != null)
|
||||
scoreHudCanvasGroup = scoreManager.GetComponent<CanvasGroup>() ??
|
||||
scoreManager.gameObject.AddComponent<CanvasGroup>();
|
||||
ApplyPopupTextStyle();
|
||||
BuildResultLayout();
|
||||
}
|
||||
@@ -34,6 +41,7 @@ namespace VRBeats
|
||||
return;
|
||||
|
||||
SetTitleActive(false);
|
||||
SetScoreHudVisible(false);
|
||||
gameObject.CancelAllTweens();
|
||||
|
||||
if (resultRoot != null)
|
||||
@@ -58,6 +66,7 @@ namespace VRBeats
|
||||
scoreText.gameObject.SetActive(true);
|
||||
|
||||
SetTitleActive(true);
|
||||
SetScoreHudVisible(true);
|
||||
ApplyPopupTextStyle();
|
||||
|
||||
if (scoreText != null)
|
||||
@@ -67,9 +76,12 @@ namespace VRBeats
|
||||
private void PopulateResultLayout()
|
||||
{
|
||||
if (scoreManager == null ||
|
||||
rankBackText == null ||
|
||||
rankShadowText == null ||
|
||||
rankDepthText == null ||
|
||||
rankRimText == null ||
|
||||
rankMainText == null ||
|
||||
rankHighlightText == null ||
|
||||
resultScoreText == null ||
|
||||
resultAccuracyText == null ||
|
||||
resultComboText == null)
|
||||
@@ -78,16 +90,20 @@ namespace VRBeats
|
||||
string rank = scoreManager.Rank;
|
||||
Color mainColor = HexToColor(scoreManager.RankColorHex);
|
||||
Color depthColor = HexToColor(GetRankDepthColorHex(rank));
|
||||
Color rimColor = HexToColor(GetRankRimColorHex(rank));
|
||||
|
||||
rankBackText.text = rank;
|
||||
rankShadowText.text = rank;
|
||||
rankDepthText.text = rank;
|
||||
rankDepthText.color = depthColor;
|
||||
rankRimText.text = rank;
|
||||
rankMainText.text = rank;
|
||||
rankMainText.color = mainColor;
|
||||
rankHighlightText.text = rank;
|
||||
ApplyMetalRankColors(mainColor, depthColor, rimColor);
|
||||
resultScoreText.text =
|
||||
$"<size=48%><color=#A0C8FF>SCORE</color></size>\n{scoreManager.CurrentScore:N0}";
|
||||
$"<size=56%><color=#A0C8FF>SCORE</color></size>\n{scoreManager.CurrentScore:N0}";
|
||||
resultAccuracyText.text =
|
||||
$"<size=70%><color=#A0C8FF>ACCURACY</color></size> {scoreManager.AccuracyPercent:0.0}%";
|
||||
$"<color=#A0C8FF>ACCURACY</color> {scoreManager.AccuracyPercent:0.0}%";
|
||||
resultComboText.text = $"MAX COMBO {scoreManager.MaxCombo}";
|
||||
}
|
||||
|
||||
@@ -123,6 +139,16 @@ namespace VRBeats
|
||||
scoreText.richText = true;
|
||||
}
|
||||
|
||||
private void SetScoreHudVisible(bool visible)
|
||||
{
|
||||
if (scoreHudCanvasGroup == null)
|
||||
return;
|
||||
|
||||
scoreHudCanvasGroup.alpha = visible ? 1.0f : 0.0f;
|
||||
scoreHudCanvasGroup.interactable = false;
|
||||
scoreHudCanvasGroup.blocksRaycasts = false;
|
||||
}
|
||||
|
||||
private void BuildResultLayout()
|
||||
{
|
||||
if (scoreText == null)
|
||||
@@ -137,32 +163,47 @@ namespace VRBeats
|
||||
RectTransform rootRect = root.AddComponent<RectTransform>();
|
||||
rootRect.anchorMin = new Vector2(0.5f, 0.5f);
|
||||
rootRect.anchorMax = new Vector2(0.5f, 0.5f);
|
||||
rootRect.anchoredPosition = Vector2.zero;
|
||||
rootRect.sizeDelta = new Vector2(620.0f, 250.0f);
|
||||
rootRect.anchoredPosition = new Vector2(5.0f, 3.1f);
|
||||
rootRect.sizeDelta = new Vector2(82.0f, 34.0f);
|
||||
root.SetActive(false);
|
||||
resultRoot = root;
|
||||
|
||||
// Rank badge left side — hierarchy order = draw order (shadow first, main on top)
|
||||
// Panel-local coordinates are small world-canvas units, not screen pixels.
|
||||
rankBackText = MakeTmpLabel(root.transform, "RankBackText",
|
||||
new Vector2(-20.9f, -1.1f), new Vector2(37.0f, 27.0f), 16.0f,
|
||||
new Color(0.0f, 0.0f, 0.0f, 0.48f), TextAlignmentOptions.Midline);
|
||||
rankShadowText = MakeTmpLabel(root.transform, "RankShadowText",
|
||||
new Vector2(-166.0f, 6.0f), new Vector2(200.0f, 200.0f), 14.0f,
|
||||
new Color(0.0f, 0.0f, 0.0f, 0.55f), TextAlignmentOptions.Midline);
|
||||
new Vector2(-21.35f, -0.55f), new Vector2(37.0f, 27.0f), 16.0f,
|
||||
new Color(0.0f, 0.06f, 0.14f, 0.82f), TextAlignmentOptions.Midline);
|
||||
rankDepthText = MakeTmpLabel(root.transform, "RankDepthText",
|
||||
new Vector2(-168.0f, 8.0f), new Vector2(200.0f, 200.0f), 14.0f,
|
||||
new Vector2(-21.8f, -0.1f), new Vector2(37.0f, 27.0f), 16.0f,
|
||||
Color.white, TextAlignmentOptions.Midline);
|
||||
rankRimText = MakeTmpLabel(root.transform, "RankRimText",
|
||||
new Vector2(-22.15f, 0.22f), new Vector2(37.0f, 27.0f), 16.0f,
|
||||
Color.white, TextAlignmentOptions.Midline);
|
||||
rankMainText = MakeTmpLabel(root.transform, "RankMainText",
|
||||
new Vector2(-170.0f, 10.0f), new Vector2(200.0f, 200.0f), 14.0f,
|
||||
new Vector2(-22.45f, 0.5f), new Vector2(37.0f, 27.0f), 16.0f,
|
||||
Color.white, TextAlignmentOptions.Midline);
|
||||
rankHighlightText = MakeTmpLabel(root.transform, "RankHighlightText",
|
||||
new Vector2(-22.85f, 1.0f), new Vector2(37.0f, 27.0f), 16.0f,
|
||||
Color.white, TextAlignmentOptions.Midline);
|
||||
|
||||
// Score, accuracy, combo right side
|
||||
resultScoreText = MakeTmpLabel(root.transform, "ResultScoreText",
|
||||
new Vector2(70.0f, 58.0f), new Vector2(260.0f, 90.0f), 5.5f,
|
||||
new Vector2(16.8f, 7.4f), new Vector2(43.0f, 10.8f), 5.35f,
|
||||
Color.white, TextAlignmentOptions.MidlineLeft);
|
||||
resultAccuracyText = MakeTmpLabel(root.transform, "ResultAccuracyText",
|
||||
new Vector2(70.0f, 0.0f), new Vector2(260.0f, 46.0f), 3.4f,
|
||||
new Vector2(16.8f, -1.2f), new Vector2(43.0f, 5.4f), 3.05f,
|
||||
new Color(0.84f, 0.97f, 1.0f, 0.9f), TextAlignmentOptions.MidlineLeft);
|
||||
resultComboText = MakeTmpLabel(root.transform, "ResultComboText",
|
||||
new Vector2(70.0f, -52.0f), new Vector2(260.0f, 44.0f), 3.0f,
|
||||
new Vector2(16.8f, -6.8f), new Vector2(43.0f, 5.4f), 2.95f,
|
||||
new Color(0.84f, 0.97f, 1.0f, 1.0f), TextAlignmentOptions.MidlineLeft);
|
||||
|
||||
ConfigureRankLayer(rankBackText, new Color(0.0f, 0.0f, 0.0f, 0.72f), 0.34f);
|
||||
ConfigureRankLayer(rankShadowText, new Color(0.0f, 0.0f, 0.0f, 0.74f), 0.2f);
|
||||
ConfigureRankLayer(rankDepthText, new Color(0.0f, 0.0f, 0.0f, 0.55f), 0.13f);
|
||||
ConfigureRankLayer(rankRimText, new Color(1.0f, 1.0f, 1.0f, 0.82f), 0.08f);
|
||||
ConfigureRankLayer(rankMainText, new Color(0.0f, 0.16f, 0.28f, 0.7f), 0.06f);
|
||||
ConfigureRankLayer(rankHighlightText, new Color(1.0f, 1.0f, 1.0f, 0.35f), 0.02f);
|
||||
}
|
||||
|
||||
private TextMeshProUGUI MakeTmpLabel(Transform parent, string name,
|
||||
@@ -178,11 +219,14 @@ namespace VRBeats
|
||||
|
||||
TextMeshProUGUI tmp = go.AddComponent<TextMeshProUGUI>();
|
||||
tmp.fontSize = fontSize;
|
||||
tmp.enableAutoSizing = true;
|
||||
tmp.fontSizeMin = fontSize * 0.6f;
|
||||
tmp.fontSizeMax = fontSize;
|
||||
tmp.color = color;
|
||||
tmp.alignment = align;
|
||||
tmp.overflowMode = TextOverflowModes.Overflow;
|
||||
tmp.overflowMode = TextOverflowModes.Truncate;
|
||||
tmp.textWrappingMode = TextWrappingModes.NoWrap;
|
||||
tmp.lineSpacing = -8.0f;
|
||||
tmp.lineSpacing = -4.0f;
|
||||
tmp.raycastTarget = false;
|
||||
|
||||
if (scoreText != null && scoreText.font != null)
|
||||
@@ -194,6 +238,68 @@ namespace VRBeats
|
||||
return tmp;
|
||||
}
|
||||
|
||||
private static void ConfigureRankLayer(TextMeshProUGUI tmp, Color outlineColor, float outlineWidth)
|
||||
{
|
||||
if (tmp == null)
|
||||
return;
|
||||
|
||||
tmp.fontSizeMin = tmp.fontSize * 0.75f;
|
||||
tmp.outlineColor = outlineColor;
|
||||
tmp.outlineWidth = outlineWidth;
|
||||
tmp.characterSpacing = -1.0f;
|
||||
}
|
||||
|
||||
private void ApplyMetalRankColors(Color mainColor, Color depthColor, Color rimColor)
|
||||
{
|
||||
Color darkMetal = new Color(0.02f, 0.08f, 0.14f, 0.82f);
|
||||
Color steel = new Color(0.70f, 0.95f, 1.0f, 1.0f);
|
||||
Color whiteHot = new Color(1.0f, 1.0f, 1.0f, 1.0f);
|
||||
Color lowerMain = Color.Lerp(mainColor, depthColor, 0.55f);
|
||||
|
||||
SetSolidRankLayer(rankBackText, new Color(0.0f, 0.0f, 0.0f, 0.50f));
|
||||
SetSolidRankLayer(rankShadowText, darkMetal);
|
||||
SetRankGradient(rankDepthText,
|
||||
Color.Lerp(depthColor, steel, 0.22f),
|
||||
depthColor,
|
||||
new Color(0.0f, 0.12f, 0.22f, 0.95f),
|
||||
new Color(0.0f, 0.05f, 0.10f, 0.95f));
|
||||
SetRankGradient(rankRimText,
|
||||
whiteHot,
|
||||
rimColor,
|
||||
Color.Lerp(rimColor, mainColor, 0.35f),
|
||||
Color.Lerp(mainColor, depthColor, 0.45f));
|
||||
SetRankGradient(rankMainText,
|
||||
whiteHot,
|
||||
Color.Lerp(whiteHot, rimColor, 0.45f),
|
||||
Color.Lerp(mainColor, steel, 0.18f),
|
||||
lowerMain);
|
||||
SetRankGradient(rankHighlightText,
|
||||
new Color(1.0f, 1.0f, 1.0f, 0.42f),
|
||||
new Color(0.92f, 1.0f, 1.0f, 0.28f),
|
||||
new Color(1.0f, 1.0f, 1.0f, 0.08f),
|
||||
new Color(1.0f, 1.0f, 1.0f, 0.02f));
|
||||
}
|
||||
|
||||
private static void SetSolidRankLayer(TextMeshProUGUI tmp, Color color)
|
||||
{
|
||||
if (tmp == null)
|
||||
return;
|
||||
|
||||
tmp.enableVertexGradient = false;
|
||||
tmp.color = color;
|
||||
}
|
||||
|
||||
private static void SetRankGradient(TextMeshProUGUI tmp,
|
||||
Color topLeft, Color topRight, Color bottomLeft, Color bottomRight)
|
||||
{
|
||||
if (tmp == null)
|
||||
return;
|
||||
|
||||
tmp.enableVertexGradient = true;
|
||||
tmp.color = Color.white;
|
||||
tmp.colorGradient = new VertexGradient(topLeft, topRight, bottomLeft, bottomRight);
|
||||
}
|
||||
|
||||
private static string GetRankDepthColorHex(string rank)
|
||||
{
|
||||
switch (rank)
|
||||
@@ -209,6 +315,21 @@ namespace VRBeats
|
||||
}
|
||||
}
|
||||
|
||||
private static string GetRankRimColorHex(string rank)
|
||||
{
|
||||
switch (rank)
|
||||
{
|
||||
case "M": return "#FFFFFF";
|
||||
case "S+": return "#E8FFFF";
|
||||
case "S": return "#FFF4B8";
|
||||
case "A": return "#F1FFD8";
|
||||
case "B": return "#FFF5B8";
|
||||
case "C": return "#FFE0B8";
|
||||
case "D": return "#FFD5D5";
|
||||
default: return "#E8F0F8";
|
||||
}
|
||||
}
|
||||
|
||||
private static Color HexToColor(string hex)
|
||||
{
|
||||
if (ColorUtility.TryParseHtmlString(hex, out Color color))
|
||||
|
||||
@@ -142,6 +142,25 @@ namespace VRBeats
|
||||
UpdateScoreTween();
|
||||
}
|
||||
|
||||
public void ApplyForcedResult(int noteCount, int perfect, int great, int good, int miss, int forcedMaxCombo)
|
||||
{
|
||||
totalNoteCount = Mathf.Max(0, noteCount);
|
||||
perfectCount = Mathf.Max(0, perfect);
|
||||
greatCount = Mathf.Max(0, great);
|
||||
goodCount = Mathf.Max(0, good);
|
||||
missCount = Mathf.Max(0, miss);
|
||||
judgedNoteCount = perfectCount + greatCount + goodCount + missCount;
|
||||
earnedAccuracyPoints = perfectCount * 1000 + greatCount * 900 + goodCount * 700;
|
||||
maxCombo = Mathf.Clamp(forcedMaxCombo, 0, Mathf.Max(totalNoteCount, judgedNoteCount));
|
||||
currentCombo = maxCombo;
|
||||
currentMultiplier = missCount > 0 ? 1.0f : GetComboMultiplier(currentCombo);
|
||||
lastJudgement = missCount > 0 ? BeatJudgement.Miss : BeatJudgement.Perfect;
|
||||
judgementTimer = 0.45f;
|
||||
resultFinalized = false;
|
||||
UpdateScoreTween();
|
||||
UpdateMultiplierLoaderValue();
|
||||
}
|
||||
|
||||
public void CompleteSong()
|
||||
{
|
||||
if (resultFinalized)
|
||||
|
||||
Reference in New Issue
Block a user