验证码功能
This commit is contained in:
@@ -47,9 +47,6 @@ MonoBehaviour:
|
||||
- {fileID: 11400000, guid: ac71ee7888fd1754bb3280725ad0076b, type: 2}
|
||||
- {fileID: 11400000, guid: b9026802c7966cf4799a8df997d603e3, type: 2}
|
||||
- {fileID: 11400000, guid: d582f9080605ab34cbcde3249c980030, type: 2}
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
- {fileID: 0}
|
||||
- {fileID: 11400000, guid: 46e5fd2db66266e4698be9ad1b299913, type: 2}
|
||||
- {fileID: 11400000, guid: 6ea418572850f5a4496b8bf2ea95ea43, type: 2}
|
||||
- {fileID: 11400000, guid: 2bd43310d2c9f7147948458ae24b7969, type: 2}
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ MonoBehaviour:
|
||||
- Locale-zh-Hans
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: 72f4481345eb6c24594911deb872e0be
|
||||
m_Address: Fiction_Day1_night_zh-Hans
|
||||
m_Address: Fiction_Huoshan1_zh-Hans
|
||||
m_ReadOnly: 1
|
||||
m_SerializedLabels:
|
||||
- Locale-zh-Hans
|
||||
|
||||
+1
-1
@@ -114,7 +114,7 @@ MonoBehaviour:
|
||||
- Locale-en
|
||||
FlaggedDuringContentUpdateRestriction: 0
|
||||
- m_GUID: d9da3ee8cbe1f3f40a93ee2c3042330d
|
||||
m_Address: Fiction_Day1_night_en
|
||||
m_Address: Fiction_Huoshan1_en
|
||||
m_ReadOnly: 1
|
||||
m_SerializedLabels:
|
||||
- Locale-en
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -477,19 +477,15 @@ MonoBehaviour:
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
_filter:
|
||||
- 0.0048309183
|
||||
- 0.016401261
|
||||
- 0.04532712
|
||||
- 0.08293076
|
||||
- 0.12053438
|
||||
- 0.14946026
|
||||
- 0.1610306
|
||||
- 0.14946026
|
||||
- 0.12053438
|
||||
- 0.08293076
|
||||
- 0.04532712
|
||||
- 0.016401261
|
||||
- 0.0048309183
|
||||
- 0.007228916
|
||||
- 0.043749984
|
||||
- 0.12409639
|
||||
- 0.20444278
|
||||
- 0.24096388
|
||||
- 0.20444278
|
||||
- 0.12409639
|
||||
- 0.043749984
|
||||
- 0.007228916
|
||||
--- !u!114 &-6101378415725230565
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 3
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7943305f9752fa74eb451f477f323e21
|
||||
guid: 2fa76ffaa57f62244b77be9b25ca14c2
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c00f5e40d3b7f9a48a72591616c67de4
|
||||
folderAsset: yes
|
||||
guid: 2bf3639539862924083bdd785c5fa5e7
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,12 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
<<<<<<<< HEAD:Assets/Scenes/OPTest.unity.meta
|
||||
guid: 7cb899bcb936c224387f4de55defaac9
|
||||
DefaultImporter:
|
||||
========
|
||||
guid: 8215a14f930072e46bc8756e84ced2ca
|
||||
PrefabImporter:
|
||||
>>>>>>>> develop:Assets/Prefabs/Huoshan/PlugCableGroup.prefab.meta
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
+801
-2630
File diff suppressed because it is too large
Load Diff
@@ -10451,7 +10451,7 @@ MonoBehaviour:
|
||||
m_Script: {fileID: 11500000, guid: feee73ba51d6e1a4da81ed7f94ab4694, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
runMode: 1
|
||||
runMode: 0
|
||||
firstTalkSo: {fileID: 11400000, guid: 2f763a2c04ecafb4981379b7363f9791, type: 2}
|
||||
testTalkSo: {fileID: 11400000, guid: fe71f935f1f9a52458c994362567a211, type: 2}
|
||||
saveFileName:
|
||||
|
||||
+3102
-2556
File diff suppressed because it is too large
Load Diff
@@ -13,7 +13,7 @@ MonoBehaviour:
|
||||
m_Name: Prologue
|
||||
m_EditorClassIdentifier:
|
||||
nextScene: {fileID: 11400000, guid: ac5ca9a66ff22ab4b9cd5adbdade6b8c, type: 2}
|
||||
yarnProject: {fileID: 7545569452688597077, guid: 7943305f9752fa74eb451f477f323e21, type: 3}
|
||||
yarnProject: {fileID: 7545569452688597077, guid: 2fa76ffaa57f62244b77be9b25ca14c2, type: 3}
|
||||
firstSceneName: OpenFixScene
|
||||
isEndOfDay: 0
|
||||
nameToPlayer: "\u5E8F\u7AE0"
|
||||
|
||||
@@ -1,91 +0,0 @@
|
||||
using System;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Kit;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class DeepInClock : MonoBehaviour
|
||||
{
|
||||
#region 索引
|
||||
|
||||
private MinHand _minHand;
|
||||
private Transform _secondHand;
|
||||
private Transform _hourHand;
|
||||
|
||||
private SpriteLooper _cityLooper;
|
||||
|
||||
public event Action OnClockReached;
|
||||
public event Action OnClockEnd;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 参数
|
||||
|
||||
[Header("背景切换时长")] public int cityLoopDuration;
|
||||
[Header("开头全程所需时间")] public float rotateSpeed;
|
||||
|
||||
private bool _isReached;
|
||||
|
||||
#endregion
|
||||
|
||||
// 按分钟计算,全程1440分钟
|
||||
private BindProperty<float> _curTime;
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
|
||||
_minHand = transform.Find("fenzhen").GetComponent<MinHand>();
|
||||
_secondHand = transform.Find("miaozhen");
|
||||
_hourHand = transform.Find("shizhen");
|
||||
|
||||
_cityLooper = transform.Find("City").GetComponent<SpriteLooper>();
|
||||
|
||||
_curTime = new BindProperty<float>();
|
||||
_curTime.Register(UpdateCityLooper);
|
||||
|
||||
_minHand.OnMinHandReached += StartAutoRotate;
|
||||
_minHand.OnMinHandChanged += UpdateCurTime;
|
||||
|
||||
_minHand.IsActive = true;
|
||||
}
|
||||
|
||||
private void UpdateCityLooper(float curTime)
|
||||
{
|
||||
// 时间转为背景循环值
|
||||
var loopValue = curTime % cityLoopDuration / cityLoopDuration;
|
||||
_cityLooper.SetLoopProgress(loopValue);
|
||||
// 处理时针
|
||||
var hourNum = curTime / 1440;
|
||||
_hourHand.eulerAngles = new Vector3(0, 0, hourNum * 360);
|
||||
// 处理分针
|
||||
var minNum = curTime % 60 / 60;
|
||||
_minHand.transform.eulerAngles = new Vector3(0, 0, minNum * 360);
|
||||
|
||||
if (_curTime.Value > 1200 && !_isReached)
|
||||
{
|
||||
_isReached = true;
|
||||
OnClockReached?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
private void StartAutoRotate()
|
||||
{
|
||||
DOTween.To(() => _curTime.Value, value => _curTime.Value = value, 1440f, rotateSpeed)
|
||||
.SetEase(Ease.InQuad).OnComplete(OnRotateEnd);
|
||||
}
|
||||
|
||||
private void UpdateCurTime(float minHandAngle)
|
||||
{
|
||||
_curTime.Value = minHandAngle / 360 * 60;
|
||||
}
|
||||
|
||||
private void OnRotateEnd()
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
OnClockEnd?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 753608042500c23428ad33810592d3a0
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,40 +0,0 @@
|
||||
using AibisDream.Kit;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class LightRoom : MonoBehaviour
|
||||
{
|
||||
#region 索引
|
||||
|
||||
public SpriteRenderer room;
|
||||
public SpriteRenderer onA;
|
||||
|
||||
private bool _isClicked;
|
||||
|
||||
#endregion
|
||||
|
||||
public void OnBtnClick(BaseEventData eventData)
|
||||
{
|
||||
if (_isClicked)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
_isClicked = true;
|
||||
room.gameObject.SetActive(false);
|
||||
ActionKit.Sequence()
|
||||
.Delay(0.5f)
|
||||
.Callback(() => onA.DOFade(0, 1f))
|
||||
.Delay(1f, ZoomEnd)
|
||||
.Start(this);
|
||||
}
|
||||
|
||||
private void ZoomEnd()
|
||||
{
|
||||
DialogController.Instance.StartDialogNode("LightOn");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46dd8691ca2e18e46bfe764ce14ea847
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,89 +0,0 @@
|
||||
using System;
|
||||
using AibisDream.Framework;
|
||||
using AibisDream.Utility;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class MinHand : MonoBehaviour, IInteraction
|
||||
{
|
||||
#region 索引
|
||||
|
||||
private EventTriggerEx _trigger;
|
||||
|
||||
public event Action<float> OnMinHandChanged;
|
||||
public event Action OnMinHandReached;
|
||||
|
||||
#endregion
|
||||
|
||||
#region 参数
|
||||
|
||||
public float rotationSpeedLimit = 10f; // 旋转速度限制(度/秒)
|
||||
public float rotationThreshold = 30f; // 触发事件的角度阈值(度)
|
||||
|
||||
#endregion
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
_trigger = GetComponent<EventTriggerEx>();
|
||||
_trigger.Register(EventTriggerType.Drag, OnDrag);
|
||||
|
||||
EventSystemEx.Instance.isLocked = false;
|
||||
}
|
||||
|
||||
private void OnDrag(BaseEventData data)
|
||||
{
|
||||
// 这里是一些阻碍拖动的情况
|
||||
if (!IsActive) return;
|
||||
|
||||
if (data is not PointerEventData pointerData) return;
|
||||
|
||||
// 计算鼠标位置与分针中心点的向量
|
||||
Vector2 worldPoint = CameraKit.GetMouseWorldPos(pointerData.position);
|
||||
Vector2 direction = worldPoint - new Vector2(transform.position.x, transform.position.y);
|
||||
// 计算当前角度
|
||||
float mouseAngle = Mathf.Atan2(direction.y, direction.x) * Mathf.Rad2Deg;
|
||||
float currentAngle = CommonUtil.Angle360(mouseAngle - 90);
|
||||
|
||||
// 计算角度差
|
||||
float deltaAngle = Mathf.DeltaAngle(transform.eulerAngles.z, currentAngle);
|
||||
// 限制旋转方向(仅允许逆时针旋转)
|
||||
if (deltaAngle < 0)
|
||||
{
|
||||
deltaAngle = 0;
|
||||
}
|
||||
|
||||
// 限制旋转速度
|
||||
if (Mathf.Abs(deltaAngle) > rotationSpeedLimit * Time.deltaTime)
|
||||
{
|
||||
deltaAngle = rotationSpeedLimit * Time.deltaTime;
|
||||
}
|
||||
|
||||
// 更新分针的旋转
|
||||
transform.Rotate(0, 0, deltaAngle);
|
||||
|
||||
OnMinHandChanged?.Invoke(transform.eulerAngles.z);
|
||||
|
||||
// 触发事件
|
||||
if (transform.eulerAngles.z >= rotationThreshold)
|
||||
{
|
||||
// 触发事件逻辑
|
||||
Debug.Log("Rotation threshold reached!");
|
||||
IsActive = false;
|
||||
OnMinHandReached?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
#region 交互属性
|
||||
|
||||
public bool IsActive { get; set;}
|
||||
public bool IsAvailable => true;
|
||||
public GameObject GetGameObject()
|
||||
{
|
||||
return gameObject;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a04d4c06c6864b9cbaeb9d798ef6908d
|
||||
timeCreated: 1746508524
|
||||
@@ -5,22 +5,16 @@ using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using Yarn.Unity;
|
||||
using System.Collections;
|
||||
using UnityEngine.Timeline;
|
||||
using System.Collections.Generic;
|
||||
using DG.Tweening;
|
||||
using AibisDream.Utility;
|
||||
using System.Linq;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public class OpenSystem : MonoBehaviour
|
||||
{
|
||||
public DeepInClock deepInClock;
|
||||
public PlayableDirector openPlayable;
|
||||
public PlayableDirector breakPlayable;
|
||||
public PlayableDirector bubblePlayable;
|
||||
public LightRoom lightRoom;
|
||||
public GameObject screen;
|
||||
|
||||
public SpriteRenderer dreamSprite;
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace AibisDream.FixSystem
|
||||
{
|
||||
@@ -10,13 +11,66 @@ namespace AibisDream.FixSystem
|
||||
/// </summary>
|
||||
public class VerificationCodeSystem : MonoBehaviour
|
||||
{
|
||||
private Image _target;
|
||||
private Image _slot;
|
||||
private Slider _slider;
|
||||
|
||||
private void Awake()
|
||||
#region 必要组件
|
||||
|
||||
[SerializeField] private Image background;
|
||||
[SerializeField] private Image target;
|
||||
[SerializeField] private Image slot;
|
||||
[SerializeField] private SliderEx slider;
|
||||
|
||||
#endregion
|
||||
|
||||
private float _normalizePosX;
|
||||
public event Action<bool> OnVerificationEnd;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
StartVerification();
|
||||
}
|
||||
|
||||
public void StartVerification()
|
||||
{
|
||||
_normalizePosX = Random.Range(0.4f, 0.9f);
|
||||
// 随机生成数据,包括Slot位置,有资源之后增加背景图
|
||||
var slotWidth = target.rectTransform.rect.width;
|
||||
var backgroundWidth = background.rectTransform.rect.width - target.rectTransform.rect.width;
|
||||
|
||||
var slotPosX = _normalizePosX * backgroundWidth + slotWidth / 2;
|
||||
slot.rectTransform.anchoredPosition = new Vector2(slotPosX, slot.rectTransform.anchoredPosition.y);
|
||||
|
||||
// 初始化
|
||||
target.rectTransform.anchoredPosition = new Vector2(slotWidth / 2, target.rectTransform.anchoredPosition.y);
|
||||
slider.value = 0;
|
||||
|
||||
// 绑定事件
|
||||
slider.onEndDrag.AddListener(OnRelease);
|
||||
slider.onValueChanged.AddListener(OnValueChange);
|
||||
}
|
||||
|
||||
private void OnRelease(float value)
|
||||
{
|
||||
var isSuccess = Mathf.Abs(value - _normalizePosX) < 0.03f;
|
||||
OnVerificationEnd?.Invoke(isSuccess);
|
||||
slider.onValueChanged.RemoveAllListeners();
|
||||
slider.onEndDrag.RemoveAllListeners();
|
||||
// 如果失败就再来一次
|
||||
if (!isSuccess)
|
||||
{
|
||||
StartVerification();
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject.SetActive(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnValueChange(float value)
|
||||
{
|
||||
var slotWidth = target.rectTransform.rect.width;
|
||||
var backgroundWidth = background.rectTransform.rect.width - target.rectTransform.rect.width;
|
||||
|
||||
var targetPosX = value * backgroundWidth + slotWidth / 2;
|
||||
target.rectTransform.anchoredPosition = new Vector2(targetPosX, target.rectTransform.anchoredPosition.y);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.Kit
|
||||
{
|
||||
public class RepeatTrack : MonoBehaviour
|
||||
{
|
||||
public Sprite sprite;
|
||||
public float width;
|
||||
public float moveSpeed;
|
||||
|
||||
private SpriteRenderer _renderer1;
|
||||
private SpriteRenderer _renderer2;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
_renderer1 = GeneNewRenderer();
|
||||
_renderer1.transform.localPosition = Vector3.zero;
|
||||
}
|
||||
|
||||
private SpriteRenderer GeneNewRenderer()
|
||||
{
|
||||
var newRenderer = new GameObject().AddComponent<SpriteRenderer>();
|
||||
newRenderer.sprite = sprite;
|
||||
newRenderer.transform.SetParent(transform);
|
||||
newRenderer.sortingOrder = 5;
|
||||
newRenderer.sortingLayerName = "FixMiddle";
|
||||
newRenderer.maskInteraction = SpriteMaskInteraction.VisibleInsideMask;
|
||||
|
||||
return newRenderer;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
// Debug.Log("render" + _renderer1);
|
||||
// Debug.Log("bounds" + _renderer1.bounds);
|
||||
// Debug.Log("size" + _renderer1.bounds.size);
|
||||
var spriteWidth = _renderer1.bounds.size.x;
|
||||
if (-_renderer1.transform.localPosition.x + width > spriteWidth && !_renderer2)
|
||||
{
|
||||
// 可以新建下一个了
|
||||
_renderer2 = GeneNewRenderer();
|
||||
_renderer2.transform.localPosition = new Vector3(width, 0, 0);
|
||||
}
|
||||
|
||||
if (-_renderer1.transform.localPosition.x > spriteWidth)
|
||||
{
|
||||
Destroy(_renderer1.gameObject);
|
||||
_renderer1 = _renderer2;
|
||||
_renderer2 = null;
|
||||
}
|
||||
|
||||
_renderer1.transform.localPosition =
|
||||
new Vector3(_renderer1.transform.localPosition.x + moveSpeed * Time.deltaTime, 0, 0);
|
||||
if (_renderer2)
|
||||
{
|
||||
_renderer2.transform.localPosition =
|
||||
new Vector3(_renderer2.transform.localPosition.x + moveSpeed * Time.deltaTime, 0, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1f3b807c39d1418293491f15d9f6326b
|
||||
timeCreated: 1747141530
|
||||
@@ -1,88 +0,0 @@
|
||||
using System;
|
||||
using AibisDream.Kit;
|
||||
using AibisDream.Utility;
|
||||
using DG.Tweening;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.Kit
|
||||
{
|
||||
public class SpriteDeepIn : MonoBehaviour
|
||||
{
|
||||
private const int TopLayer = 20;
|
||||
private const int BottomLayer = 19;
|
||||
private const string LayerName = "FixMiddle";
|
||||
|
||||
public Sprite[] spriteArr;
|
||||
|
||||
public float duration;
|
||||
|
||||
public event Action OnFinished;
|
||||
|
||||
private SpriteRenderer _renderer1;
|
||||
private SpriteRenderer _renderer2;
|
||||
|
||||
private float _curProgress;
|
||||
private int _curIndex;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.K))
|
||||
{
|
||||
Play();
|
||||
}
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
_renderer2 = transform.Find("Renderer1").GetComponent<SpriteRenderer>();
|
||||
PlayNext();
|
||||
}
|
||||
|
||||
private void PlayNext()
|
||||
{
|
||||
_curIndex++;
|
||||
// 所有图片播放完毕则退出
|
||||
if (_curIndex >= spriteArr.Length)
|
||||
{
|
||||
OnFinished?.Invoke();
|
||||
return;
|
||||
}
|
||||
// 播放下一个图片
|
||||
InitNewSprite(_curIndex);
|
||||
// 缩放
|
||||
_curProgress = 0.01f;
|
||||
DOTween.To(() => _curProgress, value => _curProgress = value, 1, duration)
|
||||
.SetEase(Ease.InQuad)
|
||||
.OnUpdate(UpdateSprite)
|
||||
.OnComplete(PlayNext);
|
||||
}
|
||||
|
||||
private void InitNewSprite(int index)
|
||||
{
|
||||
if (_renderer1)
|
||||
{
|
||||
Destroy(_renderer1.gameObject);
|
||||
}
|
||||
|
||||
_renderer1 = _renderer2;
|
||||
_renderer2 = new GameObject().AddComponent<SpriteRenderer>();
|
||||
_renderer2.transform.SetParent(transform);
|
||||
// 处理层级
|
||||
_renderer1.sortingLayerName = LayerName;
|
||||
_renderer1.sortingOrder = BottomLayer;
|
||||
_renderer2.sortingLayerName = LayerName;
|
||||
_renderer2.sortingOrder = TopLayer;
|
||||
_renderer2.transform.localScale = Vector3.one * 0.01f;
|
||||
// 添加图片
|
||||
_renderer2.sprite = spriteArr[index];
|
||||
}
|
||||
|
||||
private void UpdateSprite()
|
||||
{
|
||||
// 大图片缩放
|
||||
_renderer1.transform.localScale = Vector3.one * (_curProgress * 100);
|
||||
// 小图片缩放
|
||||
_renderer2.transform.localScale = Vector3.one * _curProgress;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 885cefce8d27b9c44b433278584f254d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,74 +0,0 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace AibisDream.Kit
|
||||
{
|
||||
public class SpriteLooper : MonoBehaviour
|
||||
{
|
||||
private SpriteRenderer _fadeOutRenderer;
|
||||
private SpriteRenderer _fadeInRenderer;
|
||||
|
||||
public Sprite[] sprites;
|
||||
[Range(0, 1)]public float fadeRadio;
|
||||
|
||||
public float CurProgress { get; private set; }
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
InitRefs();
|
||||
}
|
||||
|
||||
private void InitRefs()
|
||||
{
|
||||
_fadeOutRenderer = transform.Find("Sprite1").GetComponent<SpriteRenderer>();
|
||||
_fadeInRenderer = transform.Find("Sprite2").GetComponent<SpriteRenderer>();
|
||||
}
|
||||
|
||||
public void Init()
|
||||
{
|
||||
CurProgress = 0;
|
||||
// 激活初始状态
|
||||
_fadeOutRenderer.sprite = sprites[0];
|
||||
_fadeOutRenderer.color = Color.white;
|
||||
_fadeInRenderer.sprite = sprites[1];
|
||||
_fadeInRenderer.color = Color.clear;
|
||||
}
|
||||
|
||||
public void SetLoopProgress(float progress)
|
||||
{
|
||||
CurProgress = progress;
|
||||
|
||||
// 将进度条转为图片序号和淡出进度
|
||||
var calculator = new LoopDataCalculator(progress, sprites.Length, fadeRadio);
|
||||
|
||||
_fadeOutRenderer.sprite = sprites[calculator.CurIdx];
|
||||
_fadeOutRenderer.color = calculator.FadeOutColor;
|
||||
_fadeInRenderer.sprite = sprites[calculator.NextIdx];
|
||||
_fadeInRenderer.color = calculator.FadeInColor;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly struct LoopDataCalculator
|
||||
{
|
||||
private readonly float _progress;
|
||||
private readonly float _localProgress;
|
||||
private readonly float _fadeRadio;
|
||||
public int CurIdx { get; }
|
||||
public int NextIdx { get; }
|
||||
|
||||
public LoopDataCalculator(float progress, int spriteCount, float fadeRadio)
|
||||
{
|
||||
_progress = progress;
|
||||
_localProgress = 1 / (float)spriteCount;
|
||||
_fadeRadio = fadeRadio;
|
||||
CurIdx = Mathf.FloorToInt(progress / _localProgress);
|
||||
NextIdx = CurIdx + 1 >= spriteCount ? 0 : CurIdx + 1;
|
||||
}
|
||||
|
||||
private float LeftProgress =>
|
||||
Mathf.Clamp01((_progress - (CurIdx + 1 - _fadeRadio) * _localProgress) / (_localProgress * _fadeRadio));
|
||||
|
||||
public Color FadeOutColor => new(1f, 1f, 1f, 1 - LeftProgress);
|
||||
|
||||
public Color FadeInColor => new(1f, 1f, 1f, LeftProgress);
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46b06a7e067e04142a7715ae3571abde
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,853 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
[ExecuteAlways]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
public class SliderEx : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
|
||||
{
|
||||
/// <summary>
|
||||
/// Setting that indicates one of four directions.
|
||||
/// </summary>
|
||||
public enum Direction
|
||||
{
|
||||
/// <summary>
|
||||
/// From the left to the right
|
||||
/// </summary>
|
||||
LeftToRight,
|
||||
|
||||
/// <summary>
|
||||
/// From the right to the left
|
||||
/// </summary>
|
||||
RightToLeft,
|
||||
|
||||
/// <summary>
|
||||
/// From the bottom to the top.
|
||||
/// </summary>
|
||||
BottomToTop,
|
||||
|
||||
/// <summary>
|
||||
/// From the top to the bottom.
|
||||
/// </summary>
|
||||
TopToBottom,
|
||||
}
|
||||
|
||||
private bool _isHolding;
|
||||
|
||||
[SerializeField] private RectTransform m_FillRect;
|
||||
|
||||
/// <summary>
|
||||
/// Optional RectTransform to use as fill for the slider.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
/// //Reference to new "RectTransform"(Child of FillArea).
|
||||
/// public RectTransform newFillRect;
|
||||
///
|
||||
/// //Deactivates the old FillRect and assigns a new one.
|
||||
/// void Start()
|
||||
/// {
|
||||
/// mainSlider.fillRect.gameObject.SetActive(false);
|
||||
/// mainSlider.fillRect = newFillRect;
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public RectTransform fillRect
|
||||
{
|
||||
get => m_FillRect;
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetClass(ref m_FillRect, value))
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private RectTransform m_HandleRect;
|
||||
|
||||
/// <summary>
|
||||
/// Optional RectTransform to use as a handle for the slider.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
/// //Reference to new "RectTransform" (Child of "Handle Slide Area").
|
||||
/// public RectTransform handleHighlighted;
|
||||
///
|
||||
/// //Deactivates the old Handle, then assigns and enables the new one.
|
||||
/// void Start()
|
||||
/// {
|
||||
/// mainSlider.handleRect.gameObject.SetActive(false);
|
||||
/// mainSlider.handleRect = handleHighlighted;
|
||||
/// mainSlider.handleRect.gameObject.SetActive(true);
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public RectTransform handleRect
|
||||
{
|
||||
get => m_HandleRect;
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetClass(ref m_HandleRect, value))
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Space] [SerializeField] private Direction m_Direction = Direction.LeftToRight;
|
||||
|
||||
/// <summary>
|
||||
/// The direction of the slider, from minimum to maximum value.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
///
|
||||
/// public void Start()
|
||||
/// {
|
||||
/// //Changes the direction of the slider.
|
||||
/// if (mainDirection == Direction.BottomToTop)
|
||||
/// {
|
||||
/// mainDirection = Direction.TopToBottom;
|
||||
/// }
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public Direction direction
|
||||
{
|
||||
get => m_Direction;
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_Direction, value)) UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_MinValue = 0;
|
||||
|
||||
/// <summary>
|
||||
/// The minimum allowed value of the slider.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// // Changes the minimum value of the slider to 10;
|
||||
/// mainSlider.minValue = 10;
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public float minValue
|
||||
{
|
||||
get => m_MinValue;
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_MinValue, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private float m_MaxValue = 1;
|
||||
|
||||
/// <summary>
|
||||
/// The maximum allowed value of the slider.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
///
|
||||
/// void Start()
|
||||
/// {
|
||||
/// // Changes the max value of the slider to 20;
|
||||
/// mainSlider.maxValue = 20;
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public float maxValue
|
||||
{
|
||||
get => m_MaxValue;
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_MaxValue, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] private bool m_WholeNumbers = false;
|
||||
|
||||
/// <summary>
|
||||
/// Should the value only be allowed to be whole numbers?
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
///
|
||||
/// public void Start()
|
||||
/// {
|
||||
/// //sets the slider's value to accept whole numbers only.
|
||||
/// mainSlider.wholeNumbers = true;
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public bool wholeNumbers
|
||||
{
|
||||
get => m_WholeNumbers;
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_WholeNumbers, value))
|
||||
{
|
||||
Set(m_Value);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField] protected float m_Value;
|
||||
|
||||
/// <summary>
|
||||
/// The current value of the slider.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
///
|
||||
/// //Invoked when a submit button is clicked.
|
||||
/// public void SubmitSliderSetting()
|
||||
/// {
|
||||
/// //Displays the value of the slider in the console.
|
||||
/// Debug.Log(mainSlider.value);
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public virtual float value
|
||||
{
|
||||
get => wholeNumbers ? Mathf.Round(m_Value) : m_Value;
|
||||
set => Set(value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the value of the slider without invoking onValueChanged callback.
|
||||
/// </summary>
|
||||
/// <param name="input">The new value for the slider.</param>
|
||||
public virtual void SetValueWithoutNotify(float input)
|
||||
{
|
||||
Set(input, false);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The current value of the slider normalized into a value between 0 and 1.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
///
|
||||
/// //Set to invoke when "OnValueChanged" method is called.
|
||||
/// void CheckNormalisedValue()
|
||||
/// {
|
||||
/// //Displays the normalised value of the slider everytime the value changes.
|
||||
/// Debug.Log(mainSlider.normalizedValue);
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public float NormalizedValue
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Mathf.Approximately(minValue, maxValue))
|
||||
return 0;
|
||||
return Mathf.InverseLerp(minValue, maxValue, value);
|
||||
}
|
||||
set => this.value = Mathf.Lerp(minValue, maxValue, value);
|
||||
}
|
||||
|
||||
[Space] [SerializeField] private UnityEvent<float> m_OnValueChanged = new();
|
||||
|
||||
/// <summary>
|
||||
/// Callback executed when the value of the slider is changed.
|
||||
/// </summary>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
///
|
||||
/// public void Start()
|
||||
/// {
|
||||
/// //Adds a listener to the main slider and invokes a method when the value changes.
|
||||
/// mainSlider.onValueChanged.AddListener(delegate {ValueChangeCheck(); });
|
||||
/// }
|
||||
///
|
||||
/// // Invoked when the value of the slider changes.
|
||||
/// public void ValueChangeCheck()
|
||||
/// {
|
||||
/// Debug.Log(mainSlider.value);
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
///</code>
|
||||
/// </example>
|
||||
public UnityEvent<float> onValueChanged
|
||||
{
|
||||
get => m_OnValueChanged;
|
||||
set => m_OnValueChanged = value;
|
||||
}
|
||||
|
||||
[SerializeField] private UnityEvent m_OnStartDrag = new();
|
||||
public UnityEvent onStartDrag
|
||||
{
|
||||
get => m_OnStartDrag;
|
||||
set => m_OnStartDrag = value;
|
||||
}
|
||||
|
||||
[SerializeField] private UnityEvent<float> m_OnEndDrag = new();
|
||||
public UnityEvent<float> onEndDrag
|
||||
{
|
||||
get => m_OnEndDrag;
|
||||
set => m_OnEndDrag = value;
|
||||
}
|
||||
|
||||
// Private fields
|
||||
|
||||
private Image m_FillImage;
|
||||
private Transform m_FillTransform;
|
||||
private RectTransform m_FillContainerRect;
|
||||
private Transform m_HandleTransform;
|
||||
private RectTransform m_HandleContainerRect;
|
||||
|
||||
// The offset from handle position to mouse down position
|
||||
private Vector2 m_Offset = Vector2.zero;
|
||||
|
||||
// field is never assigned warning
|
||||
#pragma warning disable 649
|
||||
private DrivenRectTransformTracker m_Tracker;
|
||||
#pragma warning restore 649
|
||||
|
||||
// This "delayed" mechanism is required for case 1037681.
|
||||
private bool m_DelayedUpdateVisuals = false;
|
||||
|
||||
// Size of each step.
|
||||
float stepSize => wholeNumbers ? 1 : (maxValue - minValue) * 0.1f;
|
||||
|
||||
protected SliderEx()
|
||||
{
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
|
||||
if (wholeNumbers)
|
||||
{
|
||||
m_MinValue = Mathf.Round(m_MinValue);
|
||||
m_MaxValue = Mathf.Round(m_MaxValue);
|
||||
}
|
||||
|
||||
//Onvalidate is called before OnEnabled. We need to make sure not to touch any other objects before OnEnable is run.
|
||||
if (IsActive())
|
||||
{
|
||||
UpdateCachedReferences();
|
||||
// Update rects in next update since other things might affect them even if value didn't change.
|
||||
m_DelayedUpdateVisuals = true;
|
||||
}
|
||||
|
||||
if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) && !Application.isPlaying)
|
||||
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
|
||||
}
|
||||
|
||||
#endif // if UNITY_EDITOR
|
||||
|
||||
public virtual void Rebuild(CanvasUpdate executing)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (executing == CanvasUpdate.Prelayout)
|
||||
onValueChanged.Invoke(value);
|
||||
#endif
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See ICanvasElement.LayoutComplete
|
||||
/// </summary>
|
||||
public virtual void LayoutComplete()
|
||||
{
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See ICanvasElement.GraphicUpdateComplete
|
||||
/// </summary>
|
||||
public virtual void GraphicUpdateComplete()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
UpdateCachedReferences();
|
||||
Set(m_Value, false);
|
||||
// Update rects since they need to be initialized correctly.
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
m_Tracker.Clear();
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the rect based on the delayed update visuals.
|
||||
/// Got around issue of calling sendMessage from onValidate.
|
||||
/// </summary>
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (m_DelayedUpdateVisuals)
|
||||
{
|
||||
m_DelayedUpdateVisuals = false;
|
||||
Set(m_Value, false);
|
||||
UpdateVisuals();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnDidApplyAnimationProperties()
|
||||
{
|
||||
// Has value changed? Various elements of the slider have the old normalisedValue assigned, we can use this to perform a comparison.
|
||||
// We also need to ensure the value stays within min/max.
|
||||
m_Value = ClampValue(m_Value);
|
||||
float oldNormalizedValue = NormalizedValue;
|
||||
if (m_FillContainerRect != null)
|
||||
{
|
||||
if (m_FillImage != null && m_FillImage.type == Image.Type.Filled)
|
||||
oldNormalizedValue = m_FillImage.fillAmount;
|
||||
else
|
||||
oldNormalizedValue =
|
||||
(ReverseValue ? 1 - m_FillRect.anchorMin[(int)axis] : m_FillRect.anchorMax[(int)axis]);
|
||||
}
|
||||
else if (m_HandleContainerRect != null)
|
||||
oldNormalizedValue =
|
||||
(ReverseValue ? 1 - m_HandleRect.anchorMin[(int)axis] : m_HandleRect.anchorMin[(int)axis]);
|
||||
|
||||
UpdateVisuals();
|
||||
|
||||
if (!Mathf.Approximately(oldNormalizedValue, NormalizedValue))
|
||||
{
|
||||
UISystemProfilerApi.AddMarker("Slider.value", this);
|
||||
onValueChanged.Invoke(m_Value);
|
||||
}
|
||||
|
||||
// UUM-34170 Apparently, some properties on slider such as IsInteractable and Normalcolor Animation is broken.
|
||||
// We need to call base here to render the animation on Scene
|
||||
base.OnDidApplyAnimationProperties();
|
||||
}
|
||||
|
||||
void UpdateCachedReferences()
|
||||
{
|
||||
if (m_FillRect && m_FillRect != (RectTransform)transform)
|
||||
{
|
||||
m_FillTransform = m_FillRect.transform;
|
||||
m_FillImage = m_FillRect.GetComponent<Image>();
|
||||
if (m_FillTransform.parent != null)
|
||||
m_FillContainerRect = m_FillTransform.parent.GetComponent<RectTransform>();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_FillRect = null;
|
||||
m_FillContainerRect = null;
|
||||
m_FillImage = null;
|
||||
}
|
||||
|
||||
if (m_HandleRect && m_HandleRect != (RectTransform)transform)
|
||||
{
|
||||
m_HandleTransform = m_HandleRect.transform;
|
||||
if (m_HandleTransform.parent != null)
|
||||
m_HandleContainerRect = m_HandleTransform.parent.GetComponent<RectTransform>();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HandleRect = null;
|
||||
m_HandleContainerRect = null;
|
||||
}
|
||||
}
|
||||
|
||||
float ClampValue(float input)
|
||||
{
|
||||
float newValue = Mathf.Clamp(input, minValue, maxValue);
|
||||
if (wholeNumbers)
|
||||
newValue = Mathf.Round(newValue);
|
||||
return newValue;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the value of the slider.
|
||||
/// </summary>
|
||||
/// <param name="input">The new value for the slider.</param>
|
||||
/// <param name="sendCallback">If the OnValueChanged callback should be invoked.</param>
|
||||
/// <remarks>
|
||||
/// Process the input to ensure the value is between min and max value. If the input is different set the value and send the callback is required.
|
||||
/// </remarks>
|
||||
protected virtual void Set(float input, bool sendCallback = true)
|
||||
{
|
||||
// Clamp the input
|
||||
float newValue = ClampValue(input);
|
||||
|
||||
// If the stepped value doesn't match the last one, it's time to update
|
||||
if (Mathf.Approximately(m_Value, newValue))
|
||||
return;
|
||||
|
||||
m_Value = newValue;
|
||||
UpdateVisuals();
|
||||
if (sendCallback)
|
||||
{
|
||||
UISystemProfilerApi.AddMarker("Slider.value", this);
|
||||
m_OnValueChanged.Invoke(newValue);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRectTransformDimensionsChange()
|
||||
{
|
||||
base.OnRectTransformDimensionsChange();
|
||||
|
||||
//This can be invoked before OnEnabled is called. So we shouldn't be accessing other objects, before OnEnable is called.
|
||||
if (!IsActive())
|
||||
return;
|
||||
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
enum Axis
|
||||
{
|
||||
Horizontal = 0,
|
||||
Vertical = 1
|
||||
}
|
||||
|
||||
Axis axis =>
|
||||
m_Direction is Direction.LeftToRight or Direction.RightToLeft
|
||||
? Axis.Horizontal
|
||||
: Axis.Vertical;
|
||||
|
||||
private bool ReverseValue => m_Direction is Direction.RightToLeft or Direction.TopToBottom;
|
||||
|
||||
// Force-update the slider. Useful if you've changed the properties and want it to update visually.
|
||||
private void UpdateVisuals()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (!Application.isPlaying)
|
||||
UpdateCachedReferences();
|
||||
#endif
|
||||
|
||||
m_Tracker.Clear();
|
||||
|
||||
if (m_FillContainerRect != null)
|
||||
{
|
||||
m_Tracker.Add(this, m_FillRect, DrivenTransformProperties.Anchors);
|
||||
Vector2 anchorMin = Vector2.zero;
|
||||
Vector2 anchorMax = Vector2.one;
|
||||
|
||||
if (m_FillImage != null && m_FillImage.type == Image.Type.Filled)
|
||||
{
|
||||
m_FillImage.fillAmount = NormalizedValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ReverseValue)
|
||||
anchorMin[(int)axis] = 1 - NormalizedValue;
|
||||
else
|
||||
anchorMax[(int)axis] = NormalizedValue;
|
||||
}
|
||||
|
||||
m_FillRect.anchorMin = anchorMin;
|
||||
m_FillRect.anchorMax = anchorMax;
|
||||
}
|
||||
|
||||
if (m_HandleContainerRect != null)
|
||||
{
|
||||
m_Tracker.Add(this, m_HandleRect, DrivenTransformProperties.Anchors);
|
||||
Vector2 anchorMin = Vector2.zero;
|
||||
Vector2 anchorMax = Vector2.one;
|
||||
anchorMin[(int)axis] = anchorMax[(int)axis] = (ReverseValue ? (1 - NormalizedValue) : NormalizedValue);
|
||||
m_HandleRect.anchorMin = anchorMin;
|
||||
m_HandleRect.anchorMax = anchorMax;
|
||||
}
|
||||
}
|
||||
|
||||
// Update the slider's position based on the mouse.
|
||||
void UpdateDrag(PointerEventData eventData, Camera cam)
|
||||
{
|
||||
RectTransform clickRect = m_HandleContainerRect ?? m_FillContainerRect;
|
||||
if (clickRect != null && clickRect.rect.size[(int)axis] > 0)
|
||||
{
|
||||
Vector2 position = Vector2.zero;
|
||||
if (!MultipleDisplayUtilities.GetRelativeMousePositionForDrag(eventData, ref position))
|
||||
return;
|
||||
|
||||
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, position, cam,
|
||||
out var localCursor))
|
||||
return;
|
||||
localCursor -= clickRect.rect.position;
|
||||
|
||||
float val = Mathf.Clamp01((localCursor - m_Offset)[(int)axis] / clickRect.rect.size[(int)axis]);
|
||||
NormalizedValue = ReverseValue ? 1f - val : val;
|
||||
}
|
||||
}
|
||||
|
||||
private bool MayDrag(PointerEventData eventData)
|
||||
{
|
||||
return IsActive() && IsInteractable() && eventData.button == PointerEventData.InputButton.Left;
|
||||
}
|
||||
|
||||
public override void OnPointerDown(PointerEventData eventData)
|
||||
{
|
||||
if (!MayDrag(eventData))
|
||||
return;
|
||||
|
||||
base.OnPointerDown(eventData);
|
||||
|
||||
m_Offset = Vector2.zero;
|
||||
if (m_HandleContainerRect != null && RectTransformUtility.RectangleContainsScreenPoint(m_HandleRect,
|
||||
eventData.pointerPressRaycast.screenPosition, eventData.enterEventCamera))
|
||||
{
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect,
|
||||
eventData.pointerPressRaycast.screenPosition, eventData.pressEventCamera,
|
||||
out var localMousePos))
|
||||
m_Offset = localMousePos;
|
||||
_isHolding = true;
|
||||
|
||||
m_OnStartDrag?.Invoke();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnPointerUp(PointerEventData eventData)
|
||||
{
|
||||
if (_isHolding)
|
||||
{
|
||||
_isHolding = false;
|
||||
m_OnEndDrag?.Invoke(value);
|
||||
}
|
||||
|
||||
if (!MayDrag(eventData)) return;
|
||||
|
||||
base.OnPointerUp(eventData);
|
||||
}
|
||||
|
||||
public virtual void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!_isHolding || !MayDrag(eventData))
|
||||
return;
|
||||
|
||||
UpdateDrag(eventData, eventData.pressEventCamera);
|
||||
}
|
||||
|
||||
public override void OnMove(AxisEventData eventData)
|
||||
{
|
||||
if (!IsActive() || !IsInteractable())
|
||||
{
|
||||
base.OnMove(eventData);
|
||||
return;
|
||||
}
|
||||
|
||||
switch (eventData.moveDir)
|
||||
{
|
||||
case MoveDirection.Left:
|
||||
if (axis == Axis.Horizontal && FindSelectableOnLeft() == null)
|
||||
Set(ReverseValue ? value + stepSize : value - stepSize);
|
||||
else
|
||||
base.OnMove(eventData);
|
||||
break;
|
||||
case MoveDirection.Right:
|
||||
if (axis == Axis.Horizontal && FindSelectableOnRight() == null)
|
||||
Set(ReverseValue ? value - stepSize : value + stepSize);
|
||||
else
|
||||
base.OnMove(eventData);
|
||||
break;
|
||||
case MoveDirection.Up:
|
||||
if (axis == Axis.Vertical && FindSelectableOnUp() == null)
|
||||
Set(ReverseValue ? value - stepSize : value + stepSize);
|
||||
else
|
||||
base.OnMove(eventData);
|
||||
break;
|
||||
case MoveDirection.Down:
|
||||
if (axis == Axis.Vertical && FindSelectableOnDown() == null)
|
||||
Set(ReverseValue ? value + stepSize : value - stepSize);
|
||||
else
|
||||
base.OnMove(eventData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See Selectable.FindSelectableOnLeft
|
||||
/// </summary>
|
||||
public override Selectable FindSelectableOnLeft()
|
||||
{
|
||||
if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
|
||||
return null;
|
||||
return base.FindSelectableOnLeft();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See Selectable.FindSelectableOnRight
|
||||
/// </summary>
|
||||
public override Selectable FindSelectableOnRight()
|
||||
{
|
||||
if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
|
||||
return null;
|
||||
return base.FindSelectableOnRight();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See Selectable.FindSelectableOnUp
|
||||
/// </summary>
|
||||
public override Selectable FindSelectableOnUp()
|
||||
{
|
||||
if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
|
||||
return null;
|
||||
return base.FindSelectableOnUp();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// See Selectable.FindSelectableOnDown
|
||||
/// </summary>
|
||||
public override Selectable FindSelectableOnDown()
|
||||
{
|
||||
if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
|
||||
return null;
|
||||
return base.FindSelectableOnDown();
|
||||
}
|
||||
|
||||
public virtual void OnInitializePotentialDrag(PointerEventData eventData)
|
||||
{
|
||||
eventData.useDragThreshold = false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the direction of this slider, optionally changing the layout as well.
|
||||
/// </summary>
|
||||
/// <param name="vDirection">The direction of the slider</param>
|
||||
/// <param name="includeRectLayouts">Should the layout be flipped together with the slider direction</param>
|
||||
/// <example>
|
||||
/// <code>
|
||||
/// <![CDATA[
|
||||
/// using UnityEngine;
|
||||
/// using System.Collections;
|
||||
/// using UnityEngine.UI; // Required when Using UI elements.
|
||||
///
|
||||
/// public class Example : MonoBehaviour
|
||||
/// {
|
||||
/// public Slider mainSlider;
|
||||
///
|
||||
/// public void Start()
|
||||
/// {
|
||||
/// mainSlider.SetDirection(Direction.LeftToRight, false);
|
||||
/// }
|
||||
/// }
|
||||
/// ]]>
|
||||
/// </code>
|
||||
/// </example>
|
||||
public void SetDirection(Direction vDirection, bool includeRectLayouts)
|
||||
{
|
||||
Axis oldAxis = axis;
|
||||
bool oldReverse = ReverseValue;
|
||||
this.direction = vDirection;
|
||||
|
||||
if (!includeRectLayouts)
|
||||
return;
|
||||
|
||||
if (axis != oldAxis)
|
||||
RectTransformUtility.FlipLayoutAxes(transform as RectTransform, true, true);
|
||||
|
||||
if (ReverseValue != oldReverse)
|
||||
RectTransformUtility.FlipLayoutOnAxis(transform as RectTransform, (int)axis, true, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cb0e4398af6e4967956eef0e64893e87
|
||||
timeCreated: 1754543039
|
||||
@@ -0,0 +1,138 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
|
||||
namespace AibisDream
|
||||
{
|
||||
public static class SetPropertyUtility
|
||||
{
|
||||
public static bool SetColor(ref Color currentValue, Color newValue)
|
||||
{
|
||||
if (Mathf.Approximately(currentValue.r, newValue.r) && Mathf.Approximately(currentValue.g, newValue.g) &&
|
||||
Mathf.Approximately(currentValue.b, newValue.b) && Mathf.Approximately(currentValue.a, newValue.a))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(currentValue, newValue))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
|
||||
{
|
||||
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static class MultipleDisplayUtilities
|
||||
{
|
||||
/// <summary>
|
||||
/// Converts the current drag position into a relative position for the display.
|
||||
/// </summary>
|
||||
/// <param name="eventData"></param>
|
||||
/// <param name="position"></param>
|
||||
/// <returns>Returns true except when the drag operation is not on the same display as it originated</returns>
|
||||
public static bool GetRelativeMousePositionForDrag(PointerEventData eventData, ref Vector2 position)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
position = eventData.position;
|
||||
#else
|
||||
int pressDisplayIndex = eventData.pointerPressRaycast.displayIndex;
|
||||
var relativePosition = RelativeMouseAtScaled(eventData.position);
|
||||
int currentDisplayIndex = (int)relativePosition.z;
|
||||
|
||||
// Discard events on a different display.
|
||||
if (currentDisplayIndex != pressDisplayIndex)
|
||||
return false;
|
||||
|
||||
// If we are not on the main display then we must use the relative position.
|
||||
position = pressDisplayIndex != 0 ? (Vector2)relativePosition : eventData.position;
|
||||
#endif
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// A version of Display.RelativeMouseAt that scales the position when the main display has a different rendering resolution to the system resolution.
|
||||
/// By default, the mouse position is relative to the main render area, we need to adjust this so it is relative to the system resolution
|
||||
/// in order to correctly determine the position on other displays.
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public static Vector3 RelativeMouseAtScaled(Vector2 position)
|
||||
{
|
||||
#if !UNITY_EDITOR && !UNITY_WSA
|
||||
// If the main display is now the same resolution as the system then we need to scale the mouse position. (case 1141732)
|
||||
if (Display.main.renderingWidth != Display.main.systemWidth || Display.main.renderingHeight != Display.main.systemHeight)
|
||||
{
|
||||
// The system will add padding when in full-screen and using a non-native aspect ratio. (case UUM-7893)
|
||||
// For example Rendering 1920x1080 with a systeem resolution of 3440x1440 would create black bars on each side that are 330 pixels wide.
|
||||
// we need to account for this or it will offset our coordinates when we are not on the main display.
|
||||
var systemAspectRatio = Display.main.systemWidth / (float)Display.main.systemHeight;
|
||||
|
||||
var sizePlusPadding = new Vector2(Display.main.renderingWidth, Display.main.renderingHeight);
|
||||
var padding = Vector2.zero;
|
||||
if (Screen.fullScreen)
|
||||
{
|
||||
var aspectRatio = Screen.width / (float)Screen.height;
|
||||
if (Display.main.systemHeight * aspectRatio < Display.main.systemWidth)
|
||||
{
|
||||
// Horizontal padding
|
||||
sizePlusPadding.x = Display.main.renderingHeight * systemAspectRatio;
|
||||
padding.x = (sizePlusPadding.x - Display.main.renderingWidth) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Vertical padding
|
||||
sizePlusPadding.y = Display.main.renderingWidth / systemAspectRatio;
|
||||
padding.y = (sizePlusPadding.y - Display.main.renderingHeight) * 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
var sizePlusPositivePadding = sizePlusPadding - padding;
|
||||
|
||||
// If we are not inside of the main display then we must adjust the mouse position so it is scaled by
|
||||
// the main display and adjusted for any padding that may have been added due to different aspect ratios.
|
||||
if (position.y < -padding.y || position.y > sizePlusPositivePadding.y ||
|
||||
position.x < -padding.x || position.x > sizePlusPositivePadding.x)
|
||||
{
|
||||
var adjustedPosition = position;
|
||||
|
||||
if (!Screen.fullScreen)
|
||||
{
|
||||
// When in windowed mode, the window will be centered with the 0,0 coordinate at the top left, we need to adjust so it is relative to the screen instead.
|
||||
adjustedPosition.x -= (Display.main.renderingWidth - Display.main.systemWidth) * 0.5f;
|
||||
adjustedPosition.y -= (Display.main.renderingHeight - Display.main.systemHeight) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Scale the mouse position to account for the black bars when in a non-native aspect ratio.
|
||||
adjustedPosition += padding;
|
||||
adjustedPosition.x *= Display.main.systemWidth / sizePlusPadding.x;
|
||||
adjustedPosition.y *= Display.main.systemHeight / sizePlusPadding.y;
|
||||
}
|
||||
|
||||
var relativePos = Display.RelativeMouseAt(adjustedPosition);
|
||||
|
||||
// If we are not on the main display then return the adjusted position.
|
||||
if (relativePos.z != 0)
|
||||
return relativePos;
|
||||
}
|
||||
|
||||
// We are using the main display.
|
||||
return new Vector3(position.x, position.y, 0);
|
||||
}
|
||||
#endif
|
||||
return Display.RelativeMouseAt(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 152c2cb0ff764bf995fc346ff3a490f8
|
||||
timeCreated: 1754552564
|
||||
Reference in New Issue
Block a user