514 lines
18 KiB
C#
514 lines
18 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Collections.Generic;
|
|
using System.Linq;
|
|
using System.Text;
|
|
using UnityEngine;
|
|
using UnityEngine.UI;
|
|
using TMPro;
|
|
|
|
namespace Superlazy.UI
|
|
{
|
|
public class SLUIValue : SLUIComponent
|
|
{
|
|
public string prefix;
|
|
public string postfix;
|
|
|
|
public bool useRaw;
|
|
|
|
public bool userInput;
|
|
|
|
public bool useUpdate;
|
|
|
|
private bool UseTag => tagID != string.Empty;
|
|
|
|
public string tagID;
|
|
|
|
public string bindingValue;
|
|
public string bindingMaxValue;
|
|
|
|
[NonSerialized]
|
|
public TextMeshProUGUI text;
|
|
|
|
[NonSerialized]
|
|
public Image image;
|
|
|
|
[NonSerialized]
|
|
public Slider slider;
|
|
|
|
private SLEntity oldValue = false;
|
|
private float oldMaxValue = -10000;
|
|
|
|
// text only
|
|
|
|
public bool useTypingEffect = false;
|
|
|
|
public float startDelay = 0.2f;
|
|
public float delay = 0.03f;
|
|
public string typingEndState = string.Empty;
|
|
public string typingEndBind = "Skipped";
|
|
public bool ignoreColorTag = false;
|
|
public string textSound = "SoundEffect/SE_Text";
|
|
|
|
// smoothing
|
|
|
|
public bool useSmoothing = false;
|
|
public float smoothingDelay = 1.0f;
|
|
private float smoothingValue = 0;
|
|
public string beforeSmoothingValue = string.Empty;
|
|
|
|
protected override void Validate()
|
|
{
|
|
text = GetComponent<TextMeshProUGUI>();
|
|
image = GetComponent<Image>();
|
|
slider = GetComponent<Slider>();
|
|
}
|
|
|
|
protected override void Init()
|
|
{
|
|
}
|
|
|
|
protected override void Enable()
|
|
{
|
|
if (text != null)
|
|
{
|
|
SLUIUtil.UpdateFont(text);
|
|
}
|
|
|
|
oldValue = false;
|
|
oldMaxValue = 0.0f;
|
|
|
|
if (useUpdate && useRaw && bindingValue.Contains("{"))
|
|
{
|
|
useTypingEffect = false;
|
|
useUpdate = true;
|
|
}
|
|
|
|
if (useUpdate)
|
|
{
|
|
SLGame.AddNotify("Time", OnChange);
|
|
}
|
|
|
|
if (useRaw)
|
|
{
|
|
OnChange();
|
|
return;
|
|
}
|
|
|
|
SLGame.AddNotify(bindParent.BindPath.CombinePath(bindingValue), OnChange);
|
|
|
|
if (bindingMaxValue != string.Empty)
|
|
{
|
|
SLGame.AddNotify(bindParent.BindPath.CombinePath(bindingMaxValue), OnChange);
|
|
}
|
|
|
|
if (text != null && useTypingEffect && typingEndBind != string.Empty)
|
|
{
|
|
SLGame.AddNotify(bindParent.BindPath.CombinePath(typingEndBind), OnSkipped);
|
|
}
|
|
}
|
|
|
|
protected override void Disable()
|
|
{
|
|
if (oldMaxValue <= -1000) return; // TEMP: SLUIValue Disabled가 최초 Enabled도 불리기 전에 불릴 가능성이 있음
|
|
|
|
if (text != null && useTypingEffect && typingEndBind != string.Empty)
|
|
{
|
|
SLGame.RemoveNotify(bindParent.BindPath.CombinePath(typingEndBind), OnSkipped);
|
|
}
|
|
|
|
if (useTypingEffect && string.IsNullOrEmpty(typingEndState) == false)
|
|
{
|
|
SLGame.Session["UIState"][typingEndState] = false;
|
|
}
|
|
|
|
if (useUpdate)
|
|
{
|
|
SLGame.RemoveNotify("Time", OnChange);
|
|
}
|
|
|
|
if (useRaw) return;
|
|
|
|
SLGame.RemoveNotify(bindParent.BindPath.CombinePath(bindingValue), OnChange);
|
|
|
|
if (bindingMaxValue != string.Empty)
|
|
{
|
|
SLGame.RemoveNotify(bindParent.BindPath.CombinePath(bindingMaxValue), OnChange);
|
|
}
|
|
}
|
|
|
|
private void OnChange()
|
|
{
|
|
if (bindParent.Active == false) return;
|
|
var sessionRoot = SLGame.SessionGet(bindParent.BindPath);
|
|
if (sessionRoot == false) return; // TEMP: 세션루트가 삭제되었지만, 삭제되되기전 코루틴 처리가 있을 수 있음
|
|
|
|
if (text != null)
|
|
{
|
|
OnChangeText();
|
|
}
|
|
else if (image != null)
|
|
{
|
|
OnChangeImage();
|
|
}
|
|
else if (slider != null)
|
|
{
|
|
OnChangeSlider();
|
|
}
|
|
}
|
|
|
|
private void OnChangeText()
|
|
{
|
|
if (useRaw)
|
|
{
|
|
text.text = SLString.GetString(bindingValue, SLGame.SessionGet(bindParent.BindPath));
|
|
}
|
|
else if (userInput)
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue).ToString())
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
else if (UseTag)
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(SLTag.Apply(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue), tagID), SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
else
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue), SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
|
|
if (ignoreColorTag)
|
|
{
|
|
text.text = RemoveColorTag(text.text);
|
|
}
|
|
|
|
if (useTypingEffect)
|
|
{
|
|
StopAllCoroutines();
|
|
StartCoroutine(ShowText());
|
|
}
|
|
|
|
if (useSmoothing)
|
|
{
|
|
StopAllCoroutines();
|
|
StartCoroutine(SmoothingText());
|
|
}
|
|
}
|
|
|
|
private void OnChangeImage()
|
|
{
|
|
var sessionRoot = SLGame.SessionGet(bindParent.BindPath);
|
|
var newValue = sessionRoot.Get(bindingValue);
|
|
|
|
if (UseTag)
|
|
{
|
|
newValue = SLTag.Apply(newValue, tagID);
|
|
}
|
|
|
|
if (oldValue == newValue)
|
|
{
|
|
return;
|
|
}
|
|
|
|
oldValue = newValue;
|
|
image.sprite = SLResources.GetSprite(newValue);
|
|
|
|
if (image.sprite == null)
|
|
{
|
|
SLLog.Error($"Can't Find Sprite. [{bindParent.BindPath}.{bindingValue}]: [{newValue}]");
|
|
}
|
|
}
|
|
|
|
private void OnChangeSlider()
|
|
{
|
|
var sessionRoot = SLGame.SessionGet(bindParent.BindPath);
|
|
|
|
float newValue = sessionRoot.Get(bindingValue);
|
|
float newMaxValue = SLGame.SessionGet(bindParent.BindPath).Get(bindingMaxValue);
|
|
|
|
if (oldValue == newValue && oldMaxValue == newMaxValue) return;
|
|
if (newValue < 0.0)
|
|
{
|
|
SLLog.Warn($"value can't negative. {bindParent.BindPath}.{bindingValue} : {newValue}", this);
|
|
return;
|
|
}
|
|
|
|
if (newMaxValue <= 0.0)
|
|
{
|
|
SLLog.Warn($"max value can't negative or zero. {bindParent.BindPath}.{bindingMaxValue} : {newMaxValue}", this);
|
|
return;
|
|
}
|
|
|
|
if (useSmoothing && smoothingValue < 0)
|
|
{
|
|
smoothingValue = oldValue;
|
|
}
|
|
|
|
oldValue = newValue;
|
|
oldMaxValue = newMaxValue;
|
|
if (useSmoothing)
|
|
{
|
|
StopAllCoroutines();
|
|
StartCoroutine(SmoothingSlider());
|
|
}
|
|
else
|
|
{
|
|
slider.value = oldValue / oldMaxValue;
|
|
slider.maxValue = 1;
|
|
}
|
|
}
|
|
|
|
// TypingEffect
|
|
|
|
private void OnSkipped()
|
|
{
|
|
var skipped = SLGame.SessionGet(bindParent.BindPath).Get(typingEndBind);
|
|
if (skipped)
|
|
{
|
|
StopAllCoroutines();
|
|
|
|
if (useRaw)
|
|
{
|
|
text.text = SLString.GetString(bindingValue, SLGame.SessionGet(bindParent.BindPath));
|
|
}
|
|
else if (userInput)
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue).ToString())
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
else if (UseTag)
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(SLTag.Apply(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue), tagID), SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
else
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue), SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(typingEndState) == false)
|
|
{
|
|
SLGame.Session["UIState"][typingEndState] = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
private IEnumerator ShowText()
|
|
{
|
|
var originalText = text.text;
|
|
|
|
var displayedText = new StringBuilder();
|
|
displayedText.Append("<color=#00000000>");
|
|
displayedText.Append(RemoveColorTag(originalText));
|
|
displayedText.Append("</color>");
|
|
text.text = displayedText.ToString();
|
|
|
|
yield return new WaitForSeconds(startDelay);
|
|
|
|
var currentIndex = -1;
|
|
var index = -1;
|
|
var openTags = new Stack<string>();
|
|
var startTime = Time.time;
|
|
|
|
while (true)
|
|
{
|
|
var elapsedTime = Time.time - startTime;
|
|
var newIndex = Mathf.FloorToInt(elapsedTime / delay);
|
|
if (currentIndex == -1) // 최초 0문자지만 여백을 다 채워두기 위한 트릭코드
|
|
{
|
|
newIndex = 0;
|
|
}
|
|
|
|
if (newIndex > currentIndex)
|
|
{
|
|
for (var i = 0; i < newIndex - currentIndex; i++)
|
|
{
|
|
if (index + 1 >= originalText.Length)
|
|
{
|
|
break;
|
|
}
|
|
|
|
index += 1;
|
|
while (index < originalText.Length && originalText[index] == '<')
|
|
{
|
|
var endIndex = originalText.IndexOf('>', index);
|
|
var tag = originalText.Substring(index + 1, endIndex - index - 1);
|
|
|
|
if (tag.StartsWith("/") == false)
|
|
{
|
|
openTags.Push(tag);
|
|
}
|
|
else
|
|
{
|
|
openTags.Pop();
|
|
}
|
|
|
|
index = endIndex + 1;
|
|
}
|
|
}
|
|
|
|
currentIndex = newIndex;
|
|
|
|
displayedText.Clear();
|
|
displayedText.Append(originalText.Substring(0, Math.Min(originalText.Length, index + 1)));
|
|
|
|
if (index < originalText.Length)
|
|
{
|
|
foreach (var tag in openTags)
|
|
{
|
|
var openTag = tag;
|
|
if (openTag.Contains("=")) openTag = openTag.Substring(0, openTag.IndexOf("="));
|
|
displayedText.Append($"</{openTag}>");
|
|
}
|
|
displayedText.Append("<color=#00000000>");
|
|
displayedText.Append(RemoveColorTag(originalText.Substring(index + 1, originalText.Length - index - 1)));
|
|
displayedText.Append("</color>");
|
|
}
|
|
text.text = displayedText.ToString();
|
|
SLSound.PlaySound(textSound, "TextSound", false, false, true, 0.5f);
|
|
}
|
|
|
|
if (index + 1 >= originalText.Length)
|
|
{
|
|
break;
|
|
}
|
|
|
|
yield return null;
|
|
}
|
|
|
|
if (bindParent.Active && string.IsNullOrEmpty(typingEndBind) == false)
|
|
{
|
|
SLGame.SessionGet(bindParent.BindPath).Set(typingEndBind, true);
|
|
}
|
|
|
|
if (string.IsNullOrEmpty(typingEndState) == false)
|
|
{
|
|
SLGame.Session["UIState"][typingEndState] = true;
|
|
}
|
|
}
|
|
|
|
private string RemoveColorTag(string text)
|
|
{
|
|
var result = new StringBuilder(text.Length);
|
|
var index = 0;
|
|
|
|
while (index < text.Length)
|
|
{
|
|
if (text[index] == '<' && text.Substring(index, 6).Equals("<color", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var endIndex = text.IndexOf('>', index) + 1;
|
|
index = endIndex;
|
|
}
|
|
else if (text[index] == '<' && text.Substring(index, 7).Equals("</color", StringComparison.OrdinalIgnoreCase))
|
|
{
|
|
var endIndex = text.IndexOf('>', index) + 1;
|
|
index = endIndex;
|
|
}
|
|
else
|
|
{
|
|
result.Append(text[index]);
|
|
index++;
|
|
}
|
|
}
|
|
return result.ToString();
|
|
}
|
|
|
|
private IEnumerator SmoothingSlider()
|
|
{
|
|
var startTime = Time.time;
|
|
|
|
while (true)
|
|
{
|
|
var time = Time.time - startTime;
|
|
smoothingValue = Mathf.Lerp(smoothingValue, oldValue, time / smoothingDelay);
|
|
|
|
if (time >= smoothingDelay)
|
|
{
|
|
break;
|
|
}
|
|
|
|
slider.value = smoothingValue / oldMaxValue;
|
|
slider.maxValue = 1;
|
|
yield return null;
|
|
}
|
|
|
|
slider.value = oldValue / oldMaxValue;
|
|
slider.maxValue = 1;
|
|
}
|
|
|
|
private IEnumerator SmoothingText()
|
|
{
|
|
var startTime = Time.time;
|
|
|
|
smoothingValue = SLGame.SessionGet(bindParent.BindPath).Get(beforeSmoothingValue);
|
|
float destValue = SLGame.SessionGet(bindParent.BindPath).Get(bindingValue);
|
|
|
|
while (true)
|
|
{
|
|
var time = Time.time - startTime;
|
|
smoothingValue = Mathf.Lerp(smoothingValue, destValue, time / smoothingDelay);
|
|
|
|
if (time >= smoothingDelay)
|
|
{
|
|
break;
|
|
}
|
|
|
|
if (useRaw)
|
|
{
|
|
text.text = smoothingValue.ToString();
|
|
}
|
|
else if (userInput)
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(smoothingValue.ToString())
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
else if (UseTag)
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(SLTag.Apply(smoothingValue, tagID), SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
else
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(smoothingValue.ToString(), SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
yield return null;
|
|
}
|
|
|
|
if (useRaw)
|
|
{
|
|
text.text = SLString.GetString(bindingValue, SLGame.SessionGet(bindParent.BindPath));
|
|
}
|
|
else if (userInput)
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue).ToString())
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
else if (UseTag)
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(SLTag.Apply(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue), tagID), SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
else
|
|
{
|
|
text.text = new StringBuilder(SLString.GetString(prefix, SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(SLGame.SessionGet(bindParent.BindPath).Get(bindingValue), SLGame.SessionGet(bindParent.BindPath)))
|
|
.Append(SLString.GetString(postfix, SLGame.SessionGet(bindParent.BindPath))).ToString();
|
|
}
|
|
}
|
|
}
|
|
} |