commit
b3e4b0fcd5
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 77a80d348c62e93459753f8e704f474d
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,152 @@
|
|||
/// Credit setchi (https://github.com/setchi)
|
||||
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||
|
||||
using UnityEditor;
|
||||
using UnityEditor.AnimatedValues;
|
||||
|
||||
// For manteinance, every new [SerializeField] variable in Scroller must be declared here
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
[CustomEditor(typeof(Scroller))]
|
||||
[CanEditMultipleObjects]
|
||||
public class ScrollerEditor : Editor
|
||||
{
|
||||
SerializedProperty viewport;
|
||||
SerializedProperty directionOfRecognize;
|
||||
SerializedProperty movementType;
|
||||
SerializedProperty elasticity;
|
||||
SerializedProperty scrollSensitivity;
|
||||
SerializedProperty inertia;
|
||||
SerializedProperty decelerationRate;
|
||||
SerializedProperty snap;
|
||||
SerializedProperty snapEnable;
|
||||
SerializedProperty snapVelocityThreshold;
|
||||
SerializedProperty snapDuration;
|
||||
SerializedProperty snapEasing;
|
||||
|
||||
AnimBool showElasticity;
|
||||
AnimBool showInertiaRelatedValues;
|
||||
AnimBool showSnapEnableRelatedValues;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
viewport = serializedObject.FindProperty("viewport");
|
||||
directionOfRecognize = serializedObject.FindProperty("directionOfRecognize");
|
||||
movementType = serializedObject.FindProperty("movementType");
|
||||
elasticity = serializedObject.FindProperty("elasticity");
|
||||
scrollSensitivity = serializedObject.FindProperty("scrollSensitivity");
|
||||
inertia = serializedObject.FindProperty("inertia");
|
||||
decelerationRate = serializedObject.FindProperty("decelerationRate");
|
||||
snap = serializedObject.FindProperty("snap");
|
||||
snapEnable = serializedObject.FindProperty("snap.Enable");
|
||||
snapVelocityThreshold = serializedObject.FindProperty("snap.VelocityThreshold");
|
||||
snapDuration = serializedObject.FindProperty("snap.Duration");
|
||||
snapEasing = serializedObject.FindProperty("snap.Easing");
|
||||
|
||||
showElasticity = new AnimBool(Repaint);
|
||||
showInertiaRelatedValues = new AnimBool(Repaint);
|
||||
showSnapEnableRelatedValues = new AnimBool(Repaint);
|
||||
SetAnimBools(true);
|
||||
}
|
||||
|
||||
void OnDisable()
|
||||
{
|
||||
showElasticity.valueChanged.RemoveListener(Repaint);
|
||||
showInertiaRelatedValues.valueChanged.RemoveListener(Repaint);
|
||||
showSnapEnableRelatedValues.valueChanged.RemoveListener(Repaint);
|
||||
}
|
||||
|
||||
void SetAnimBools(bool instant)
|
||||
{
|
||||
SetAnimBool(showElasticity, !movementType.hasMultipleDifferentValues && movementType.enumValueIndex == (int)Scroller.MovementType.Elastic, instant);
|
||||
SetAnimBool(showInertiaRelatedValues, !inertia.hasMultipleDifferentValues && inertia.boolValue, instant);
|
||||
SetAnimBool(showSnapEnableRelatedValues, !snapEnable.hasMultipleDifferentValues && snapEnable.boolValue, instant);
|
||||
}
|
||||
|
||||
void SetAnimBool(AnimBool a, bool value, bool instant)
|
||||
{
|
||||
if (instant)
|
||||
{
|
||||
a.value = value;
|
||||
}
|
||||
else
|
||||
{
|
||||
a.target = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
SetAnimBools(false);
|
||||
|
||||
serializedObject.Update();
|
||||
EditorGUILayout.PropertyField(viewport);
|
||||
EditorGUILayout.PropertyField(directionOfRecognize);
|
||||
EditorGUILayout.PropertyField(movementType);
|
||||
DrawMovementTypeRelatedValue();
|
||||
EditorGUILayout.PropertyField(scrollSensitivity);
|
||||
EditorGUILayout.PropertyField(inertia);
|
||||
DrawInertiaRelatedValues();
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
void DrawMovementTypeRelatedValue()
|
||||
{
|
||||
using (var group = new EditorGUILayout.FadeGroupScope(showElasticity.faded))
|
||||
{
|
||||
if (!group.visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.PropertyField(elasticity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawInertiaRelatedValues()
|
||||
{
|
||||
using (var group = new EditorGUILayout.FadeGroupScope(showInertiaRelatedValues.faded))
|
||||
{
|
||||
if (!group.visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
EditorGUILayout.PropertyField(decelerationRate);
|
||||
EditorGUILayout.PropertyField(snap);
|
||||
|
||||
using (new EditorGUI.IndentLevelScope())
|
||||
{
|
||||
DrawSnapRelatedValues();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSnapRelatedValues()
|
||||
{
|
||||
if (snap.isExpanded)
|
||||
{
|
||||
EditorGUILayout.PropertyField(snapEnable);
|
||||
|
||||
using (var group = new EditorGUILayout.FadeGroupScope(showSnapEnableRelatedValues.faded))
|
||||
{
|
||||
if (!group.visible)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
EditorGUILayout.PropertyField(snapVelocityThreshold);
|
||||
EditorGUILayout.PropertyField(snapDuration);
|
||||
EditorGUILayout.PropertyField(snapEasing);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: e82bfdd42ec254849830933cbaf350fa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,9 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 5a0b1710131366b4f82f636d29814556
|
||||
folderAsset: yes
|
||||
timeCreated: 1467468503
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -1,172 +0,0 @@
|
|||
/// Credit setchi (https://github.com/setchi)
|
||||
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
public abstract class FancyScrollView<TData, TContext> : MonoBehaviour where TContext : class
|
||||
{
|
||||
[SerializeField, Range(float.Epsilon, 1f)]
|
||||
float cellInterval = 0;
|
||||
[SerializeField, Range(0f, 1f)]
|
||||
float cellOffset = 0;
|
||||
[SerializeField]
|
||||
bool loop = false;
|
||||
[SerializeField]
|
||||
GameObject cellBase = null;
|
||||
[SerializeField]
|
||||
Transform cellContainer = null;
|
||||
|
||||
readonly List<FancyScrollViewCell<TData, TContext>> cells = new List<FancyScrollViewCell<TData, TContext>>();
|
||||
float currentPosition;
|
||||
|
||||
protected List<TData> cellData = new List<TData>();
|
||||
protected TContext Context { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the context.
|
||||
/// </summary>
|
||||
/// <param name="context">Context.</param>
|
||||
protected void SetContext(TContext context)
|
||||
{
|
||||
Context = context;
|
||||
|
||||
for (int i = 0; i < cells.Count; i++)
|
||||
{
|
||||
cells[i].SetContext(context);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the contents.
|
||||
/// </summary>
|
||||
protected void UpdateContents()
|
||||
{
|
||||
UpdatePosition(currentPosition, true);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the scroll position.
|
||||
/// </summary>
|
||||
/// <param name="position">Position.</param>
|
||||
/// <param name="forceUpdateContents">If set to <c>true</c> force update contents.</param>
|
||||
protected void UpdatePosition(float position, bool forceUpdateContents = false)
|
||||
{
|
||||
currentPosition = position;
|
||||
|
||||
var visibleMinPosition = position - (cellOffset / cellInterval);
|
||||
var firstCellPosition = (Mathf.Ceil(visibleMinPosition) - visibleMinPosition) * cellInterval;
|
||||
var dataStartIndex = Mathf.CeilToInt(visibleMinPosition);
|
||||
var count = 0;
|
||||
|
||||
for (float p = firstCellPosition; p <= 1f; p += cellInterval, count++)
|
||||
{
|
||||
if (count >= cells.Count)
|
||||
{
|
||||
cells.Add(CreateCell());
|
||||
}
|
||||
}
|
||||
|
||||
count = 0;
|
||||
|
||||
for (float p = firstCellPosition; p <= 1f; p += cellInterval, count++)
|
||||
{
|
||||
var dataIndex = dataStartIndex + count;
|
||||
var cell = cells[GetCircularIndex(dataIndex, cells.Count)];
|
||||
|
||||
UpdateCell(cell, dataIndex, forceUpdateContents);
|
||||
|
||||
if (cell.gameObject.activeSelf)
|
||||
{
|
||||
cell.UpdatePosition(p);
|
||||
}
|
||||
}
|
||||
|
||||
while (count < cells.Count)
|
||||
{
|
||||
cells[GetCircularIndex(dataStartIndex + count, cells.Count)].SetVisible(false);
|
||||
count++;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Updates the cell.
|
||||
/// </summary>
|
||||
/// <param name="cell">Cell.</param>
|
||||
/// <param name="dataIndex">Data index.</param>
|
||||
/// <param name="forceUpdateContents">If set to <c>true</c> force update contents.</param>
|
||||
void UpdateCell(FancyScrollViewCell<TData, TContext> cell, int dataIndex, bool forceUpdateContents = false)
|
||||
{
|
||||
if (loop)
|
||||
{
|
||||
dataIndex = GetCircularIndex(dataIndex, cellData.Count);
|
||||
}
|
||||
else if (dataIndex < 0 || dataIndex > cellData.Count - 1)
|
||||
{
|
||||
// セルに対応するデータが存在しなければセルを表示しない
|
||||
cell.SetVisible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (forceUpdateContents || cell.DataIndex != dataIndex || !cell.IsVisible)
|
||||
{
|
||||
cell.DataIndex = dataIndex;
|
||||
cell.SetVisible(true);
|
||||
cell.UpdateContent(cellData[dataIndex]);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates the cell.
|
||||
/// </summary>
|
||||
/// <returns>The cell.</returns>
|
||||
FancyScrollViewCell<TData, TContext> CreateCell()
|
||||
{
|
||||
var cellObject = Instantiate(cellBase, cellContainer);
|
||||
var cell = cellObject.GetComponent<FancyScrollViewCell<TData, TContext>>();
|
||||
|
||||
cell.SetContext(Context);
|
||||
cell.SetVisible(false);
|
||||
cell.DataIndex = -1;
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the circular index.
|
||||
/// </summary>
|
||||
/// <returns>The circular index.</returns>
|
||||
/// <param name="index">Index.</param>
|
||||
/// <param name="maxSize">Max size.</param>
|
||||
int GetCircularIndex(int index, int maxSize)
|
||||
{
|
||||
return index < 0 ? maxSize - 1 + (index + 1) % maxSize : index % maxSize;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
bool cachedLoop;
|
||||
float cachedCellInterval, cachedCellOffset;
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (cachedLoop != loop || cachedCellOffset != cellOffset || cachedCellInterval != cellInterval)
|
||||
{
|
||||
cachedLoop = loop;
|
||||
cachedCellOffset = cellOffset;
|
||||
cachedCellInterval = cellInterval;
|
||||
|
||||
UpdatePosition(currentPosition);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public sealed class FancyScrollViewNullContext
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class FancyScrollView<TData> : FancyScrollView<TData, FancyScrollViewNullContext>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
fileFormatVersion: 2
|
||||
guid: d1ddf7c4a2094c8429c834b8c71bb812
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,214 @@
|
|||
//
|
||||
// EasingCore - https://github.com/setchi/EasingCore
|
||||
//
|
||||
// The MIT License (MIT)
|
||||
//
|
||||
// Copyright (c) 2019 setchi
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in all
|
||||
// copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
// SOFTWARE.
|
||||
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEngine.UI.Extensions.EasingCore
|
||||
{
|
||||
public enum Ease
|
||||
{
|
||||
Linear,
|
||||
InBack,
|
||||
InBounce,
|
||||
InCirc,
|
||||
InCubic,
|
||||
InElastic,
|
||||
InExpo,
|
||||
InQuad,
|
||||
InQuart,
|
||||
InQuint,
|
||||
InSine,
|
||||
OutBack,
|
||||
OutBounce,
|
||||
OutCirc,
|
||||
OutCubic,
|
||||
OutElastic,
|
||||
OutExpo,
|
||||
OutQuad,
|
||||
OutQuart,
|
||||
OutQuint,
|
||||
OutSine,
|
||||
InOutBack,
|
||||
InOutBounce,
|
||||
InOutCirc,
|
||||
InOutCubic,
|
||||
InOutElastic,
|
||||
InOutExpo,
|
||||
InOutQuad,
|
||||
InOutQuart,
|
||||
InOutQuint,
|
||||
InOutSine,
|
||||
}
|
||||
|
||||
public static class EasingFunction
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the easing function
|
||||
/// </summary>
|
||||
/// <param name="type">ease type</param>
|
||||
/// <returns>easing function</returns>
|
||||
public static Func<float, float> Get(Ease type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case Ease.Linear: return Linear;
|
||||
case Ease.InBack: return InBack;
|
||||
case Ease.InBounce: return InBounce;
|
||||
case Ease.InCirc: return InCirc;
|
||||
case Ease.InCubic: return InCubic;
|
||||
case Ease.InElastic: return InElastic;
|
||||
case Ease.InExpo: return InExpo;
|
||||
case Ease.InQuad: return InQuad;
|
||||
case Ease.InQuart: return InQuart;
|
||||
case Ease.InQuint: return InQuint;
|
||||
case Ease.InSine: return InSine;
|
||||
case Ease.OutBack: return OutBack;
|
||||
case Ease.OutBounce: return OutBounce;
|
||||
case Ease.OutCirc: return OutCirc;
|
||||
case Ease.OutCubic: return OutCubic;
|
||||
case Ease.OutElastic: return OutElastic;
|
||||
case Ease.OutExpo: return OutExpo;
|
||||
case Ease.OutQuad: return OutQuad;
|
||||
case Ease.OutQuart: return OutQuart;
|
||||
case Ease.OutQuint: return OutQuint;
|
||||
case Ease.OutSine: return OutSine;
|
||||
case Ease.InOutBack: return InOutBack;
|
||||
case Ease.InOutBounce: return InOutBounce;
|
||||
case Ease.InOutCirc: return InOutCirc;
|
||||
case Ease.InOutCubic: return InOutCubic;
|
||||
case Ease.InOutElastic: return InOutElastic;
|
||||
case Ease.InOutExpo: return InOutExpo;
|
||||
case Ease.InOutQuad: return InOutQuad;
|
||||
case Ease.InOutQuart: return InOutQuart;
|
||||
case Ease.InOutQuint: return InOutQuint;
|
||||
case Ease.InOutSine: return InOutSine;
|
||||
default: return Linear;
|
||||
}
|
||||
}
|
||||
|
||||
static float Linear(float t) => t;
|
||||
|
||||
static float InBack(float t) => t * t * t - t * Mathf.Sin(t * Mathf.PI);
|
||||
|
||||
static float OutBack(float t) => 1f - InBack(1f - t);
|
||||
|
||||
static float InOutBack(float t) =>
|
||||
t < 0.5f
|
||||
? 0.5f * InBack(2f * t)
|
||||
: 0.5f * OutBack(2f * t - 1f) + 0.5f;
|
||||
|
||||
static float InBounce(float t) => 1f - OutBounce(1f - t);
|
||||
|
||||
static float OutBounce(float t) =>
|
||||
t < 4f / 11.0f ?
|
||||
(121f * t * t) / 16.0f :
|
||||
t < 8f / 11.0f ?
|
||||
(363f / 40.0f * t * t) - (99f / 10.0f * t) + 17f / 5.0f :
|
||||
t < 9f / 10.0f ?
|
||||
(4356f / 361.0f * t * t) - (35442f / 1805.0f * t) + 16061f / 1805.0f :
|
||||
(54f / 5.0f * t * t) - (513f / 25.0f * t) + 268f / 25.0f;
|
||||
|
||||
static float InOutBounce(float t) =>
|
||||
t < 0.5f
|
||||
? 0.5f * InBounce(2f * t)
|
||||
: 0.5f * OutBounce(2f * t - 1f) + 0.5f;
|
||||
|
||||
static float InCirc(float t) => 1f - Mathf.Sqrt(1f - (t * t));
|
||||
|
||||
static float OutCirc(float t) => Mathf.Sqrt((2f - t) * t);
|
||||
|
||||
static float InOutCirc(float t) =>
|
||||
t < 0.5f
|
||||
? 0.5f * (1 - Mathf.Sqrt(1f - 4f * (t * t)))
|
||||
: 0.5f * (Mathf.Sqrt(-((2f * t) - 3f) * ((2f * t) - 1f)) + 1f);
|
||||
|
||||
static float InCubic(float t) => t * t * t;
|
||||
|
||||
static float OutCubic(float t) => InCubic(t - 1f) + 1f;
|
||||
|
||||
static float InOutCubic(float t) =>
|
||||
t < 0.5f
|
||||
? 4f * t * t * t
|
||||
: 0.5f * InCubic(2f * t - 2f) + 1f;
|
||||
|
||||
static float InElastic(float t) => Mathf.Sin(13f * (Mathf.PI * 0.5f) * t) * Mathf.Pow(2f, 10f * (t - 1f));
|
||||
|
||||
static float OutElastic(float t) => Mathf.Sin(-13f * (Mathf.PI * 0.5f) * (t + 1)) * Mathf.Pow(2f, -10f * t) + 1f;
|
||||
|
||||
static float InOutElastic(float t) =>
|
||||
t < 0.5f
|
||||
? 0.5f * Mathf.Sin(13f * (Mathf.PI * 0.5f) * (2f * t)) * Mathf.Pow(2f, 10f * ((2f * t) - 1f))
|
||||
: 0.5f * (Mathf.Sin(-13f * (Mathf.PI * 0.5f) * ((2f * t - 1f) + 1f)) * Mathf.Pow(2f, -10f * (2f * t - 1f)) + 2f);
|
||||
|
||||
static float InExpo(float t) => Mathf.Approximately(0.0f, t) ? t : Mathf.Pow(2f, 10f * (t - 1f));
|
||||
|
||||
static float OutExpo(float t) => Mathf.Approximately(1.0f, t) ? t : 1f - Mathf.Pow(2f, -10f * t);
|
||||
|
||||
static float InOutExpo(float v) =>
|
||||
Mathf.Approximately(0.0f, v) || Mathf.Approximately(1.0f, v)
|
||||
? v
|
||||
: v < 0.5f
|
||||
? 0.5f * Mathf.Pow(2f, (20f * v) - 10f)
|
||||
: -0.5f * Mathf.Pow(2f, (-20f * v) + 10f) + 1f;
|
||||
|
||||
static float InQuad(float t) => t * t;
|
||||
|
||||
static float OutQuad(float t) => -t * (t - 2f);
|
||||
|
||||
static float InOutQuad(float t) =>
|
||||
t < 0.5f
|
||||
? 2f * t * t
|
||||
: -2f * t * t + 4f * t - 1f;
|
||||
|
||||
static float InQuart(float t) => t * t * t * t;
|
||||
|
||||
static float OutQuart(float t)
|
||||
{
|
||||
var u = t - 1f;
|
||||
return u * u * u * (1f - t) + 1f;
|
||||
}
|
||||
|
||||
static float InOutQuart(float t) =>
|
||||
t < 0.5f
|
||||
? 8f * InQuart(t)
|
||||
: -8f * InQuart(t - 1f) + 1f;
|
||||
|
||||
static float InQuint(float t) => t * t * t * t * t;
|
||||
|
||||
static float OutQuint(float t) => InQuint(t - 1f) + 1f;
|
||||
|
||||
static float InOutQuint(float t) =>
|
||||
t < 0.5f
|
||||
? 16f * InQuint(t)
|
||||
: 0.5f * InQuint(2f * t - 2f) + 1f;
|
||||
|
||||
static float InSine(float t) => Mathf.Sin((t - 1f) * (Mathf.PI * 0.5f)) + 1f;
|
||||
|
||||
static float OutSine(float t) => Mathf.Sin(t * (Mathf.PI * 0.5f));
|
||||
|
||||
static float InOutSine(float t) => 0.5f * (1f - Mathf.Cos(t * Mathf.PI));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b5e2a916ad19c74468262e656243bc6f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
|
@ -0,0 +1,149 @@
|
|||
/// Credit setchi (https://github.com/setchi)
|
||||
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
public abstract class FancyScrollView<TItemData, TContext> : MonoBehaviour where TContext : class, new()
|
||||
{
|
||||
[SerializeField, Range(float.Epsilon, 1f)] protected float cellInterval = 0.2f;
|
||||
[SerializeField, Range(0f, 1f)] protected float scrollOffset = 0.5f;
|
||||
[SerializeField] protected bool loop = false;
|
||||
[SerializeField] protected Transform cellContainer = default;
|
||||
|
||||
readonly IList<FancyScrollViewCell<TItemData, TContext>> pool =
|
||||
new List<FancyScrollViewCell<TItemData, TContext>>();
|
||||
|
||||
float currentPosition;
|
||||
|
||||
protected abstract GameObject CellPrefab { get; }
|
||||
protected IList<TItemData> ItemsSource { get; set; } = new List<TItemData>();
|
||||
protected TContext Context { get; } = new TContext();
|
||||
|
||||
/// <summary>
|
||||
/// Updates the contents.
|
||||
/// </summary>
|
||||
/// <param name="itemsSource">Items source.</param>
|
||||
protected void UpdateContents(IList<TItemData> itemsSource)
|
||||
{
|
||||
ItemsSource = itemsSource;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refreshes the cells.
|
||||
/// </summary>
|
||||
protected void Refresh() => UpdatePosition(currentPosition, true);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the scroll position.
|
||||
/// </summary>
|
||||
/// <param name="position">Position.</param>
|
||||
protected void UpdatePosition(float position) => UpdatePosition(position, false);
|
||||
|
||||
void UpdatePosition(float position, bool forceRefresh)
|
||||
{
|
||||
currentPosition = position;
|
||||
|
||||
var p = position - scrollOffset / cellInterval;
|
||||
var firstIndex = Mathf.CeilToInt(p);
|
||||
var firstPosition = (Mathf.Ceil(p) - p) * cellInterval;
|
||||
|
||||
if (firstPosition + pool.Count * cellInterval < 1f)
|
||||
{
|
||||
ResizePool(firstPosition);
|
||||
}
|
||||
|
||||
UpdateCells(firstPosition, firstIndex, forceRefresh);
|
||||
}
|
||||
|
||||
void ResizePool(float firstPosition)
|
||||
{
|
||||
if (CellPrefab == null)
|
||||
{
|
||||
throw new NullReferenceException(nameof(CellPrefab));
|
||||
}
|
||||
|
||||
if (cellContainer == null)
|
||||
{
|
||||
throw new MissingComponentException(nameof(cellContainer));
|
||||
}
|
||||
|
||||
var addCount = Mathf.CeilToInt((1f - firstPosition) / cellInterval) - pool.Count;
|
||||
for (var i = 0; i < addCount; i++)
|
||||
{
|
||||
var cell = Instantiate(CellPrefab, cellContainer).GetComponent<FancyScrollViewCell<TItemData, TContext>>();
|
||||
if (cell == null)
|
||||
{
|
||||
throw new MissingComponentException(
|
||||
$"FancyScrollViewCell<{typeof(TItemData).FullName}, {typeof(TContext).FullName}> " +
|
||||
$"component not found in {CellPrefab.name}.");
|
||||
}
|
||||
|
||||
cell.SetupContext(Context);
|
||||
cell.SetVisible(false);
|
||||
pool.Add(cell);
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateCells(float firstPosition, int firstIndex, bool forceRefresh)
|
||||
{
|
||||
for (var i = 0; i < pool.Count; i++)
|
||||
{
|
||||
var index = firstIndex + i;
|
||||
var position = firstPosition + i * cellInterval;
|
||||
var cell = pool[CircularIndex(index, pool.Count)];
|
||||
|
||||
if (loop)
|
||||
{
|
||||
index = CircularIndex(index, ItemsSource.Count);
|
||||
}
|
||||
|
||||
if (index < 0 || index >= ItemsSource.Count || position > 1f)
|
||||
{
|
||||
cell.SetVisible(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (forceRefresh || cell.Index != index || !cell.IsVisible)
|
||||
{
|
||||
cell.Index = index;
|
||||
cell.SetVisible(true);
|
||||
cell.UpdateContent(ItemsSource[index]);
|
||||
}
|
||||
|
||||
cell.UpdatePosition(position);
|
||||
}
|
||||
}
|
||||
|
||||
int CircularIndex(int i, int size) => size < 1 ? 0 : i < 0 ? size - 1 + (i + 1) % size : i % size;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
bool cachedLoop;
|
||||
float cachedCellInterval, cachedScrollOffset;
|
||||
|
||||
void LateUpdate()
|
||||
{
|
||||
if (cachedLoop != loop || cachedCellInterval != cellInterval || cachedScrollOffset != scrollOffset)
|
||||
{
|
||||
cachedLoop = loop;
|
||||
cachedCellInterval = cellInterval;
|
||||
cachedScrollOffset = scrollOffset;
|
||||
|
||||
UpdatePosition(currentPosition);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public sealed class FancyScrollViewNullContext
|
||||
{
|
||||
}
|
||||
|
||||
public abstract class FancyScrollView<TItemData> : FancyScrollView<TItemData, FancyScrollViewNullContext>
|
||||
{
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 51a6dd27af9048f45a7fc0019884d41e
|
||||
timeCreated: 1501610618
|
||||
licenseType: Free
|
||||
guid: 0e38f4de7b1b5a5429228884014d12ec
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
|
@ -1,21 +1,23 @@
|
|||
/// Credit setchi (https://github.com/setchi)
|
||||
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||
|
||||
using UnityEngine;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
public abstract class FancyScrollViewCell<TData, TContext> : MonoBehaviour where TContext : class
|
||||
public abstract class FancyScrollViewCell<TItemData, TContext> : MonoBehaviour where TContext : class, new()
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or sets the index of the data.
|
||||
/// </summary>
|
||||
/// <value>The index of the data.</value>
|
||||
public int DataIndex { get; set; }
|
||||
public int Index { get; set; } = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value indicating whether this <see cref="T:FancyScrollView.FancyScrollViewCell`2"/> is visible.
|
||||
/// </summary>
|
||||
/// <value><c>true</c> if is visible; otherwise, <c>false</c>.</value>
|
||||
public virtual bool IsVisible { get { return gameObject.activeSelf; } }
|
||||
public virtual bool IsVisible => gameObject.activeSelf;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the context.
|
||||
|
@ -24,41 +26,32 @@ namespace UnityEngine.UI.Extensions
|
|||
protected TContext Context { get; private set; }
|
||||
|
||||
/// <summary>
|
||||
/// Sets the context.
|
||||
/// Setup the context.
|
||||
/// </summary>
|
||||
/// <param name="context">Context.</param>
|
||||
public virtual void SetContext(TContext context)
|
||||
{
|
||||
Context = context;
|
||||
}
|
||||
public virtual void SetupContext(TContext context) => Context = context;
|
||||
|
||||
/// <summary>
|
||||
/// Sets the visible.
|
||||
/// </summary>
|
||||
/// <param name="visible">If set to <c>true</c> visible.</param>
|
||||
public virtual void SetVisible(bool visible)
|
||||
{
|
||||
gameObject.SetActive(visible);
|
||||
}
|
||||
public virtual void SetVisible(bool visible) => gameObject.SetActive(visible);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the content.
|
||||
/// </summary>
|
||||
/// <param name="itemData">Item data.</param>
|
||||
public virtual void UpdateContent(TData itemData)
|
||||
{
|
||||
}
|
||||
public abstract void UpdateContent(TItemData itemData);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the position.
|
||||
/// </summary>
|
||||
/// <param name="position">Position.</param>
|
||||
public virtual void UpdatePosition(float position)
|
||||
{
|
||||
}
|
||||
public abstract void UpdatePosition(float position);
|
||||
}
|
||||
|
||||
public abstract class FancyScrollViewCell<TData> : FancyScrollViewCell<TData, FancyScrollViewNullContext>
|
||||
public abstract class FancyScrollViewCell<TItemData> : FancyScrollViewCell<TItemData, FancyScrollViewNullContext>
|
||||
{
|
||||
public sealed override void SetupContext(FancyScrollViewNullContext context) => base.SetupContext(context);
|
||||
}
|
||||
}
|
|
@ -1,8 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 73c54b1a82a56fb4f906ab8c75f7a030
|
||||
timeCreated: 1501610618
|
||||
licenseType: Free
|
||||
guid: 6610dee308450ec40899aeedfd85e972
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
|
@ -0,0 +1,359 @@
|
|||
/// Credit setchi (https://github.com/setchi)
|
||||
/// Sourced from - https://github.com/setchi/FancyScrollView
|
||||
|
||||
using System;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI.Extensions.EasingCore;
|
||||
|
||||
namespace UnityEngine.UI.Extensions
|
||||
{
|
||||
public class Scroller : UIBehaviour, IBeginDragHandler, IEndDragHandler, IDragHandler
|
||||
{
|
||||
[SerializeField] RectTransform viewport = default;
|
||||
[SerializeField] ScrollDirection directionOfRecognize = ScrollDirection.Vertical;
|
||||
[SerializeField] MovementType movementType = MovementType.Elastic;
|
||||
[SerializeField] float elasticity = 0.1f;
|
||||
[SerializeField] float scrollSensitivity = 1f;
|
||||
[SerializeField] bool inertia = true;
|
||||
[SerializeField] float decelerationRate = 0.03f;
|
||||
[SerializeField] Snap snap = new Snap {
|
||||
Enable = true,
|
||||
VelocityThreshold = 0.5f,
|
||||
Duration = 0.3f,
|
||||
Easing = Ease.InOutCubic
|
||||
};
|
||||
|
||||
readonly AutoScrollState autoScrollState = new AutoScrollState();
|
||||
|
||||
Action<float> onValueChanged;
|
||||
Action<int> onSelectionChanged;
|
||||
|
||||
Vector2 pointerStartLocalPosition;
|
||||
float dragStartScrollPosition;
|
||||
float prevScrollPosition;
|
||||
float currentScrollPosition;
|
||||
|
||||
int totalCount;
|
||||
|
||||
bool dragging;
|
||||
float velocity;
|
||||
|
||||
enum ScrollDirection
|
||||
{
|
||||
Vertical,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
public enum MovementType
|
||||
{
|
||||
Unrestricted = ScrollRect.MovementType.Unrestricted,
|
||||
Elastic = ScrollRect.MovementType.Elastic,
|
||||
Clamped = ScrollRect.MovementType.Clamped
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
class Snap
|
||||
{
|
||||
public bool Enable;
|
||||
public float VelocityThreshold;
|
||||
public float Duration;
|
||||
public Ease Easing;
|
||||
}
|
||||
|
||||
static readonly Func<float, float> DefaultEasingFunction = EasingFunction.Get(Ease.OutCubic);
|
||||
|
||||
class AutoScrollState
|
||||
{
|
||||
public bool Enable;
|
||||
public bool Elastic;
|
||||
public float Duration;
|
||||
public Func<float, float> EasingFunction;
|
||||
public float StartTime;
|
||||
public float EndScrollPosition;
|
||||
|
||||
public Action OnComplete;
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
Enable = false;
|
||||
Elastic = false;
|
||||
Duration = 0f;
|
||||
StartTime = 0f;
|
||||
EasingFunction = DefaultEasingFunction;
|
||||
EndScrollPosition = 0f;
|
||||
OnComplete = null;
|
||||
}
|
||||
|
||||
public void Complete()
|
||||
{
|
||||
OnComplete?.Invoke();
|
||||
Reset();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnValueChanged(Action<float> callback) => onValueChanged = callback;
|
||||
|
||||
public void OnSelectionChanged(Action<int> callback) => onSelectionChanged = callback;
|
||||
|
||||
public void SetTotalCount(int totalCount) => this.totalCount = totalCount;
|
||||
|
||||
public void ScrollTo(int index, float duration, Action onComplete = null) => ScrollTo(index, duration, Ease.OutCubic, onComplete);
|
||||
|
||||
public void ScrollTo(int index, float duration, Ease easing, Action onComplete = null) => ScrollTo(index, duration, EasingFunction.Get(easing), onComplete);
|
||||
|
||||
public void ScrollTo(int index, float duration, Func<float, float> easingFunction, Action onComplete = null)
|
||||
{
|
||||
if (duration <= 0f)
|
||||
{
|
||||
JumpTo(index);
|
||||
return;
|
||||
}
|
||||
|
||||
autoScrollState.Reset();
|
||||
autoScrollState.Enable = true;
|
||||
autoScrollState.Duration = duration;
|
||||
autoScrollState.EasingFunction = easingFunction ?? DefaultEasingFunction;
|
||||
autoScrollState.StartTime = Time.unscaledTime;
|
||||
autoScrollState.EndScrollPosition = CalculateDestinationIndex(index);
|
||||
autoScrollState.OnComplete = onComplete;
|
||||
|
||||
velocity = 0f;
|
||||
dragStartScrollPosition = currentScrollPosition;
|
||||
|
||||
UpdateSelection(Mathf.RoundToInt(CircularPosition(autoScrollState.EndScrollPosition, totalCount)));
|
||||
}
|
||||
|
||||
public void JumpTo(int index)
|
||||
{
|
||||
autoScrollState.Reset();
|
||||
|
||||
velocity = 0f;
|
||||
dragging = false;
|
||||
|
||||
index = CalculateDestinationIndex(index);
|
||||
|
||||
UpdateSelection(index);
|
||||
UpdatePosition(index);
|
||||
}
|
||||
|
||||
void IBeginDragHandler.OnBeginDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
pointerStartLocalPosition = Vector2.zero;
|
||||
RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
viewport,
|
||||
eventData.position,
|
||||
eventData.pressEventCamera,
|
||||
out pointerStartLocalPosition);
|
||||
|
||||
dragStartScrollPosition = currentScrollPosition;
|
||||
dragging = true;
|
||||
autoScrollState.Reset();
|
||||
}
|
||||
|
||||
void IDragHandler.OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!dragging)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
|
||||
viewport,
|
||||
eventData.position,
|
||||
eventData.pressEventCamera,
|
||||
out var localCursor))
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var pointerDelta = localCursor - pointerStartLocalPosition;
|
||||
var position = (directionOfRecognize == ScrollDirection.Horizontal ? -pointerDelta.x : pointerDelta.y)
|
||||
/ ViewportSize
|
||||
* scrollSensitivity
|
||||
+ dragStartScrollPosition;
|
||||
|
||||
var offset = CalculateOffset(position);
|
||||
position += offset;
|
||||
|
||||
if (movementType == MovementType.Elastic)
|
||||
{
|
||||
if (offset != 0f)
|
||||
{
|
||||
position -= RubberDelta(offset, scrollSensitivity);
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePosition(position);
|
||||
}
|
||||
|
||||
void IEndDragHandler.OnEndDrag(PointerEventData eventData)
|
||||
{
|
||||
if (eventData.button != PointerEventData.InputButton.Left)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
dragging = false;
|
||||
}
|
||||
|
||||
float ViewportSize => directionOfRecognize == ScrollDirection.Horizontal
|
||||
? viewport.rect.size.x
|
||||
: viewport.rect.size.y;
|
||||
|
||||
float CalculateOffset(float position)
|
||||
{
|
||||
if (movementType == MovementType.Unrestricted)
|
||||
{
|
||||
return 0f;
|
||||
}
|
||||
|
||||
if (position < 0f)
|
||||
{
|
||||
return -position;
|
||||
}
|
||||
|
||||
if (position > totalCount - 1)
|
||||
{
|
||||
return totalCount - 1 - position;
|
||||
}
|
||||
|
||||
return 0f;
|
||||
}
|
||||
|
||||
void UpdatePosition(float position)
|
||||
{
|
||||
currentScrollPosition = position;
|
||||
onValueChanged?.Invoke(currentScrollPosition);
|
||||
}
|
||||
|
||||
void UpdateSelection(int index) => onSelectionChanged?.Invoke(index);
|
||||
|
||||
float RubberDelta(float overStretching, float viewSize) =>
|
||||
(1 - 1 / (Mathf.Abs(overStretching) * 0.55f / viewSize + 1)) * viewSize * Mathf.Sign(overStretching);
|
||||
|
||||
void Update()
|
||||
{
|
||||
var deltaTime = Time.unscaledDeltaTime;
|
||||
var offset = CalculateOffset(currentScrollPosition);
|
||||
|
||||
if (autoScrollState.Enable)
|
||||
{
|
||||
var position = 0f;
|
||||
|
||||
if (autoScrollState.Elastic)
|
||||
{
|
||||
position = Mathf.SmoothDamp(currentScrollPosition, currentScrollPosition + offset, ref velocity,
|
||||
elasticity, Mathf.Infinity, deltaTime);
|
||||
|
||||
if (Mathf.Abs(velocity) < 0.01f)
|
||||
{
|
||||
position = Mathf.Clamp(Mathf.RoundToInt(position), 0, totalCount - 1);
|
||||
velocity = 0f;
|
||||
autoScrollState.Complete();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
var alpha = Mathf.Clamp01((Time.unscaledTime - autoScrollState.StartTime) /
|
||||
Mathf.Max(autoScrollState.Duration, float.Epsilon));
|
||||
position = Mathf.LerpUnclamped(dragStartScrollPosition, autoScrollState.EndScrollPosition,
|
||||
autoScrollState.EasingFunction(alpha));
|
||||
|
||||
if (Mathf.Approximately(alpha, 1f))
|
||||
{
|
||||
autoScrollState.Complete();
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePosition(position);
|
||||
}
|
||||
else if (!dragging && (!Mathf.Approximately(offset, 0f) || !Mathf.Approximately(velocity, 0f)))
|
||||
{
|
||||
var position = currentScrollPosition;
|
||||
|
||||
if (movementType == MovementType.Elastic && !Mathf.Approximately(offset, 0f))
|
||||
{
|
||||
autoScrollState.Reset();
|
||||
autoScrollState.Enable = true;
|
||||
autoScrollState.Elastic = true;
|
||||
|
||||
UpdateSelection(Mathf.Clamp(Mathf.RoundToInt(position), 0, totalCount - 1));
|
||||
}
|
||||
else if (inertia)
|
||||
{
|
||||
velocity *= Mathf.Pow(decelerationRate, deltaTime);
|
||||
|
||||
if (Mathf.Abs(velocity) < 0.001f)
|
||||
{
|
||||
velocity = 0f;
|
||||
}
|
||||
|
||||
position += velocity * deltaTime;
|
||||
|
||||
if (snap.Enable && Mathf.Abs(velocity) < snap.VelocityThreshold)
|
||||
{
|
||||
ScrollTo(Mathf.RoundToInt(currentScrollPosition), snap.Duration, snap.Easing);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
velocity = 0f;
|
||||
}
|
||||
|
||||
if (!Mathf.Approximately(velocity, 0f))
|
||||
{
|
||||
if (movementType == MovementType.Clamped)
|
||||
{
|
||||
offset = CalculateOffset(position);
|
||||
position += offset;
|
||||
|
||||
if (Mathf.Approximately(position, 0f) || Mathf.Approximately(position, totalCount - 1f))
|
||||
{
|
||||
velocity = 0f;
|
||||
UpdateSelection(Mathf.RoundToInt(position));
|
||||
}
|
||||
}
|
||||
|
||||
UpdatePosition(position);
|
||||
}
|
||||
}
|
||||
|
||||
if (!autoScrollState.Enable && dragging && inertia)
|
||||
{
|
||||
var newVelocity = (currentScrollPosition - prevScrollPosition) / deltaTime;
|
||||
velocity = Mathf.Lerp(velocity, newVelocity, deltaTime * 10f);
|
||||
}
|
||||
|
||||
prevScrollPosition = currentScrollPosition;
|
||||
}
|
||||
|
||||
int CalculateDestinationIndex(int index) => movementType == MovementType.Unrestricted
|
||||
? CalculateClosestIndex(index)
|
||||
: Mathf.Clamp(index, 0, totalCount - 1);
|
||||
|
||||
int CalculateClosestIndex(int index)
|
||||
{
|
||||
var diff = CircularPosition(index, totalCount)
|
||||
- CircularPosition(currentScrollPosition, totalCount);
|
||||
|
||||
if (Mathf.Abs(diff) > totalCount * 0.5f)
|
||||
{
|
||||
diff = Mathf.Sign(-diff) * (totalCount - Mathf.Abs(diff));
|
||||
}
|
||||
|
||||
return Mathf.RoundToInt(diff + currentScrollPosition);
|
||||
}
|
||||
|
||||
float CircularPosition(float p, int size) => size < 1 ? 0 : p < 0 ? size - 1 + (p + 1) % size : p % size;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,11 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 006f67d6afad7c2479f7188b033aea31
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
Loading…
Reference in New Issue