You've already forked FateViewer
Add project files.
This commit is contained in:
8
Assets/Scripts/Apng.meta
Normal file
8
Assets/Scripts/Apng.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 055f725890d872b4bb22fa493ed06356
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
281
Assets/Scripts/Apng/SharpApng.cs
Normal file
281
Assets/Scripts/Apng/SharpApng.cs
Normal file
@@ -0,0 +1,281 @@
|
||||
/* HaRepacker - WZ extractor and repacker
|
||||
* Copyright (C) 2009, 2010 haha01haha01
|
||||
|
||||
* This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
* You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.*/
|
||||
|
||||
namespace SharpApng
|
||||
{
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using uGIF;
|
||||
using UnityEngine;
|
||||
|
||||
public class Frame : IDisposable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private Image m_bmp;
|
||||
private int m_den;
|
||||
private int m_num;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Frame(Image bmp, int num, int den)
|
||||
{
|
||||
this.m_num = num;
|
||||
this.m_den = den;
|
||||
this.m_bmp = bmp;
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region Properties
|
||||
|
||||
public Image Bitmap
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_bmp;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_bmp = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int DelayDen
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_den;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_den = value;
|
||||
}
|
||||
}
|
||||
|
||||
public int DelayNum
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_num;
|
||||
}
|
||||
set
|
||||
{
|
||||
m_num = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Properties
|
||||
|
||||
#region Methods
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal class Apng : IDisposable
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private List<Frame> m_frames = new List<Frame>();
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Constructors
|
||||
|
||||
public Apng()
|
||||
{
|
||||
}
|
||||
|
||||
#endregion Constructors
|
||||
|
||||
#region Indexers
|
||||
|
||||
public Frame this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
if (index < m_frames.Count) return m_frames[index];
|
||||
else return null;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (index < m_frames.Count) m_frames[index] = value;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion Indexers
|
||||
|
||||
#region Methods
|
||||
|
||||
public void AddFrame(Frame frame)
|
||||
{
|
||||
m_frames.Add(frame);
|
||||
}
|
||||
|
||||
public void AddFrame(Image bmp, int num, int den)
|
||||
{
|
||||
m_frames.Add(new Frame(bmp, num, den));
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
foreach (Frame frame in m_frames)
|
||||
frame.Dispose();
|
||||
m_frames.Clear();
|
||||
}
|
||||
|
||||
public void WriteApng(string path, bool firstFrameHidden, bool disposeAfter)
|
||||
{
|
||||
Size maxSize = new Size(m_frames.Max(f => f.Bitmap.width), m_frames.Max(f => f.Bitmap.height));
|
||||
for (int i = 0; i < m_frames.Count; i++)
|
||||
{
|
||||
Frame frame = m_frames[i];
|
||||
//if (frame.Bitmap.Width != maxSize.Width || frame.Bitmap.Height != maxSize.Height)
|
||||
//frame.Bitmap = ExtendImage(frame.Bitmap, maxSize);
|
||||
ApngBasicWrapper.CreateFrameManaged(frame.Bitmap, frame.DelayNum, frame.DelayDen, i);
|
||||
}
|
||||
ApngBasicWrapper.SaveApngManaged(path, m_frames.Count, maxSize.Width, maxSize.Height, firstFrameHidden);
|
||||
if (disposeAfter) Dispose();
|
||||
}
|
||||
|
||||
private static Image ExtendImage(Image source, Size newSize)
|
||||
{
|
||||
Image result = new Image(newSize.Width, newSize.Height);
|
||||
//using (Graphics g = Graphics.FromImage(result))
|
||||
//{
|
||||
// g.DrawImageUnscaled(source, 0, 0);
|
||||
//}
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
|
||||
internal static class ApngBasicWrapper
|
||||
{
|
||||
#region Fields
|
||||
|
||||
private const string apngdll = "apng64.dll";
|
||||
private const int PIXEL_DEPTH = 4;
|
||||
|
||||
#endregion Fields
|
||||
|
||||
#region Methods
|
||||
|
||||
internal static void CreateFrameManaged(Image source, int num, int den, int i)
|
||||
{
|
||||
IntPtr ptr = MarshalByteArray(TranslateImage(source));
|
||||
CreateFrame(ptr, num, den, i, source.width * source.height * PIXEL_DEPTH);
|
||||
ReleaseData(ptr);
|
||||
}
|
||||
|
||||
internal static void SaveApngManaged(string path, int frameCount, int width, int height, bool firstFrameHidden)
|
||||
{
|
||||
IntPtr pathPtr = MarshalString(path);
|
||||
byte firstFrame = firstFrameHidden ? (byte)1 : (byte)0;
|
||||
SaveAPNG(pathPtr, frameCount, width, height, PIXEL_DEPTH, firstFrame);
|
||||
|
||||
var bufferSize = GetBufferSize();
|
||||
//Call and return the pointer
|
||||
IntPtr returnedPtr = GetBufferContent();
|
||||
|
||||
//Create new Variable to Store the result
|
||||
byte[] returnedResult = new byte[bufferSize];
|
||||
|
||||
//Copy from result pointer to the C# variable
|
||||
Marshal.Copy(returnedPtr, returnedResult, 0, bufferSize);
|
||||
File.WriteAllBytes(path, returnedResult);
|
||||
|
||||
Debug.Log("saved");
|
||||
ReleaseData(pathPtr);
|
||||
}
|
||||
|
||||
[DllImport(apngdll, CallingConvention = CallingConvention.StdCall)]
|
||||
private static extern void CreateFrame(IntPtr pdata, int num, int den, int i, int len);
|
||||
|
||||
[DllImport(apngdll)]
|
||||
private static extern void SaveAPNG(IntPtr path, int frameCount, int width, int height, int bytesPerPixel, byte firstFrameHidden);
|
||||
|
||||
[DllImport(apngdll)]
|
||||
private static extern int GetBufferSize();
|
||||
|
||||
[DllImport(apngdll)]
|
||||
private static extern IntPtr GetBufferContent();
|
||||
|
||||
private static IntPtr MarshalByteArray(byte[] source)
|
||||
{
|
||||
int size = Marshal.SizeOf(source[0]) * source.Length;
|
||||
IntPtr pnt = Marshal.AllocHGlobal(size);
|
||||
Marshal.Copy(source, 0, pnt, source.Length);
|
||||
return pnt;
|
||||
}
|
||||
|
||||
private static IntPtr MarshalString(string source)
|
||||
{
|
||||
byte[] toMarshal = Encoding.ASCII.GetBytes(source);
|
||||
int size = Marshal.SizeOf(source[0]) * source.Length;
|
||||
IntPtr pnt = Marshal.AllocHGlobal(size + Marshal.SizeOf(source[0]));
|
||||
Marshal.Copy(toMarshal, 0, pnt, source.Length);
|
||||
//Marshal.Copy(new byte[] { 0 }, 0, new IntPtr(pnt.ToInt32() + size), 1);
|
||||
return pnt;
|
||||
}
|
||||
|
||||
private static void ReleaseData(IntPtr ptr)
|
||||
{
|
||||
Marshal.FreeHGlobal(ptr);
|
||||
}
|
||||
|
||||
static byte[] TranslateImage(Image texture)
|
||||
{
|
||||
int width = texture.width, height = texture.height;
|
||||
Color32[] original = new Color32[texture.pixels.Length];
|
||||
texture.pixels.CopyTo(original, 0);
|
||||
byte[] result = new byte[texture.width * texture.height * PIXEL_DEPTH];
|
||||
|
||||
int p = 0;
|
||||
Debug.Log("1");
|
||||
for (int y = 0; y < height; y++)
|
||||
{
|
||||
for (int x = 0; x < width; x++)
|
||||
{
|
||||
int index = (y * width + x);
|
||||
int index2 = ((height-y-1) * width + x);
|
||||
result[index * PIXEL_DEPTH] = original[index2].b;
|
||||
result[index * PIXEL_DEPTH + 1] = original[index2].g;
|
||||
result[index * PIXEL_DEPTH + 2] = original[index2].r;
|
||||
result[index * PIXEL_DEPTH + 3] = original[index2].a;
|
||||
}
|
||||
p += 1;
|
||||
}
|
||||
Debug.Log("2");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
#endregion Methods
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Apng/SharpApng.cs.meta
Normal file
11
Assets/Scripts/Apng/SharpApng.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de9592c4ae9713d41ae7a9ae40d1b549
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
125
Assets/Scripts/CameraOrbit.cs
Normal file
125
Assets/Scripts/CameraOrbit.cs
Normal file
@@ -0,0 +1,125 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class CameraOrbit : MonoBehaviour
|
||||
{
|
||||
public static CameraOrbit Instance;
|
||||
bool controlOn;
|
||||
|
||||
[Header("Light")]
|
||||
public Vector3 TargetCenter;
|
||||
|
||||
EventSystem eventSystem;
|
||||
|
||||
[Header("Orbit Camera")]
|
||||
public float camZoomMin = 1, camZoomMax = 15;
|
||||
|
||||
public float camZoom = 2.4f;
|
||||
public float moveSpeed = 1;
|
||||
public float zoomSpeed = 1f;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
eventSystem = EventSystem.current;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
OrbitAround(false);
|
||||
}
|
||||
|
||||
float baseZoom;
|
||||
float baseDist;
|
||||
Vector2 lastMouse;
|
||||
Vector2 lastTouch;
|
||||
int lastTouchCount;
|
||||
|
||||
void OrbitAround(bool aroundCharacter = false)
|
||||
{
|
||||
Vector2 mouse = Input.mousePosition;
|
||||
Vector2 mouseDelta = (mouse - lastMouse) * Time.deltaTime;
|
||||
Vector2 touchDelta = Vector2.zero;
|
||||
lastMouse = mouse;
|
||||
|
||||
TargetCenter = Vector3.zero;
|
||||
|
||||
Vector3 position = transform.position;
|
||||
|
||||
if (Input.GetMouseButtonDown(0) && Input.touchCount == 0 && !eventSystem.IsPointerOverGameObject())
|
||||
{
|
||||
controlOn = true;
|
||||
}
|
||||
if (Input.GetMouseButton(0) && controlOn)
|
||||
{
|
||||
position -= mouseDelta.x * moveSpeed * transform.right;
|
||||
position -= mouseDelta.y * moveSpeed * transform.up;
|
||||
}
|
||||
else
|
||||
{
|
||||
controlOn = false;
|
||||
}
|
||||
|
||||
Vector2 touch0 = Vector2.zero, touch1;
|
||||
if (Input.touchCount > 0 && !eventSystem.IsPointerOverGameObject(0))
|
||||
{
|
||||
touch0 = Input.GetTouch(0).position;
|
||||
if (lastTouchCount > Input.touchCount || lastTouch == -Vector2.one)
|
||||
{
|
||||
touchDelta = Vector2.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
touchDelta = (touch0 - lastTouch) * Time.deltaTime;
|
||||
}
|
||||
lastTouch = touch0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastTouch = -Vector2.one;
|
||||
baseDist = 0;
|
||||
lastTouchCount = 0;
|
||||
}
|
||||
if (Input.touchCount == 1 && !eventSystem.IsPointerOverGameObject(0))
|
||||
{
|
||||
position -= touchDelta.x * moveSpeed * transform.right;
|
||||
position -= touchDelta.y * moveSpeed * transform.up;
|
||||
lastTouchCount = 1;
|
||||
}
|
||||
else if (Input.touchCount >= 2 && !eventSystem.IsPointerOverGameObject(0))
|
||||
{
|
||||
touch1 = Input.GetTouch(1).position;
|
||||
if (baseDist == 0)
|
||||
{
|
||||
baseDist = Vector2.Distance(touch0, touch1);
|
||||
baseZoom = camZoom;
|
||||
}
|
||||
camZoom = baseZoom - (Vector2.Distance(touch0, touch1) - baseDist) * 0.01f;
|
||||
lastTouchCount = 2;
|
||||
}
|
||||
|
||||
if (!eventSystem.IsPointerOverGameObject())
|
||||
{
|
||||
camZoom -= Input.mouseScrollDelta.y * zoomSpeed;
|
||||
}
|
||||
|
||||
camZoom = Mathf.Clamp(camZoom, camZoomMin, camZoomMax);
|
||||
float camDist = camZoom;
|
||||
Camera.main.orthographicSize = camDist;
|
||||
transform.position = position;
|
||||
}
|
||||
|
||||
public void SetZoomSpeed(float value)
|
||||
{
|
||||
zoomSpeed = value;
|
||||
}
|
||||
|
||||
public void SetMoveSpeed(float value)
|
||||
{
|
||||
moveSpeed = value;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/CameraOrbit.cs.meta
Normal file
11
Assets/Scripts/CameraOrbit.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 278fb6ec5b3d906479f56f047f620777
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
154
Assets/Scripts/CameraOrbit3D.cs
Normal file
154
Assets/Scripts/CameraOrbit3D.cs
Normal file
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class CameraOrbit3D : MonoBehaviour
|
||||
{
|
||||
public static bool CameraLock = true;
|
||||
public static int CameraMode = 0;
|
||||
private Camera cam;
|
||||
bool controlOn, heightOn;
|
||||
|
||||
public GameObject CameraTargetHelper;
|
||||
public Vector3 TargetCenter;
|
||||
|
||||
EventSystem eventSystem;
|
||||
|
||||
[Header("Orbit Camera")]
|
||||
float camHeightMin = 2, camHeightMax = 2;
|
||||
float targetHeightMin = -100, targetHeightMax = 100f;
|
||||
|
||||
public float camZoom = 2.4f;
|
||||
public float camHeight = 0.87f;
|
||||
public float targetHeight = 0.87f;
|
||||
public float fov = 45;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
cam = GetComponentInChildren<Camera>();
|
||||
eventSystem = EventSystem.current;
|
||||
CameraLock = false;
|
||||
}
|
||||
|
||||
void Update()
|
||||
{
|
||||
OrbitAround(false);
|
||||
}
|
||||
|
||||
float baseZoom;
|
||||
float baseDist;
|
||||
Vector2 lastMouse;
|
||||
Vector2 lastTouch;
|
||||
int lastTouchCount;
|
||||
|
||||
#region Camera
|
||||
/// <summary>
|
||||
/// Orbit camera around world center
|
||||
/// </summary>
|
||||
void OrbitAround(bool aroundCharacter = false)
|
||||
{
|
||||
CameraOrbit original = GetComponent<CameraOrbit>();
|
||||
Vector2 mouse = Input.mousePosition;
|
||||
Vector2 mouseDelta = (mouse - lastMouse) * Time.deltaTime;
|
||||
Vector2 touchDelta = Vector2.zero;
|
||||
lastMouse = mouse;
|
||||
|
||||
TargetCenter = Vector3.zero;
|
||||
|
||||
cam.fieldOfView = fov;
|
||||
Vector3 position = transform.position;
|
||||
Vector3 rotation = cam.transform.localEulerAngles;
|
||||
|
||||
if (Input.GetMouseButtonDown(0) && Input.touchCount == 0 && !eventSystem.IsPointerOverGameObject())
|
||||
{
|
||||
controlOn = true;
|
||||
}
|
||||
if (Input.GetMouseButton(0) && controlOn)
|
||||
{
|
||||
position -= mouseDelta.x * original.moveSpeed * transform.right;
|
||||
camHeight -= mouseDelta.y * original.moveSpeed;
|
||||
}
|
||||
else
|
||||
{
|
||||
controlOn = false;
|
||||
}
|
||||
|
||||
if (Input.GetMouseButtonDown(1) && Input.touchCount == 0 && !eventSystem.IsPointerOverGameObject())
|
||||
{
|
||||
heightOn = true;
|
||||
}
|
||||
if (Input.GetMouseButton(1) && heightOn)
|
||||
{
|
||||
targetHeight -= mouseDelta.y * 0.5f;
|
||||
targetHeight = Mathf.Clamp(targetHeight, targetHeightMin, targetHeightMax);
|
||||
}
|
||||
else
|
||||
{
|
||||
heightOn = false;
|
||||
}
|
||||
|
||||
|
||||
Vector2 touch0 = Vector2.zero, touch1;
|
||||
if (Input.touchCount > 0 && !eventSystem.IsPointerOverGameObject(0))
|
||||
{
|
||||
touch0 = Input.GetTouch(0).position;
|
||||
if (lastTouchCount > Input.touchCount || lastTouch == -Vector2.one)
|
||||
{
|
||||
touchDelta = Vector2.zero;
|
||||
}
|
||||
else
|
||||
{
|
||||
touchDelta = (touch0 - lastTouch) * Time.deltaTime;
|
||||
}
|
||||
lastTouch = touch0;
|
||||
}
|
||||
else
|
||||
{
|
||||
lastTouch = -Vector2.one;
|
||||
baseDist = 0;
|
||||
lastTouchCount = 0;
|
||||
}
|
||||
if (Input.touchCount == 1 && !eventSystem.IsPointerOverGameObject(0))
|
||||
{
|
||||
position -= touchDelta.x * original.moveSpeed * transform.right;
|
||||
camHeight -= touchDelta.y * original.moveSpeed;
|
||||
lastTouchCount = 1;
|
||||
}
|
||||
else if(Input.touchCount >= 2 && !eventSystem.IsPointerOverGameObject(0))
|
||||
{
|
||||
touch1 = Input.GetTouch(1).position;
|
||||
if (baseDist == 0)
|
||||
{
|
||||
baseDist = Vector2.Distance(touch0, touch1);
|
||||
baseZoom = camZoom;
|
||||
}
|
||||
camZoom = baseZoom - (Vector2.Distance(touch0, touch1) - baseDist) * 0.01f;
|
||||
targetHeight -= touchDelta.y * 0.5f;
|
||||
targetHeight = Mathf.Clamp(targetHeight, targetHeightMin, targetHeightMax);
|
||||
lastTouchCount = 2;
|
||||
}
|
||||
|
||||
if (!eventSystem.IsPointerOverGameObject())
|
||||
{
|
||||
camZoom -= Input.mouseScrollDelta.y * original.zoomSpeed;
|
||||
}
|
||||
camZoom = Mathf.Clamp(camZoom, original.camZoomMin, original.camZoomMax);
|
||||
float camDist = camZoom;
|
||||
camHeightMax = targetHeight + camDist;
|
||||
camHeightMin = targetHeight - camDist;
|
||||
camHeight = Mathf.Clamp(camHeight, camHeightMin, camHeightMax);
|
||||
|
||||
Vector3 target = TargetCenter + targetHeight * Vector3.up; //set target offsets
|
||||
|
||||
position.y = TargetCenter.y + camHeight; //set camera height
|
||||
transform.position = position; //set final position of camera at target
|
||||
|
||||
//Debug.Log(rotation);
|
||||
transform.LookAt(target); //look at target position
|
||||
transform.position = target - transform.forward * camDist; //move away from target
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
11
Assets/Scripts/CameraOrbit3D.cs.meta
Normal file
11
Assets/Scripts/CameraOrbit3D.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: df0c736ae643c464986a460f3f8686f1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
30
Assets/Scripts/Error.cs
Normal file
30
Assets/Scripts/Error.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class Error : MonoBehaviour
|
||||
{
|
||||
public static GameObject ErrorText;
|
||||
public static GameObject CanvasContent;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
ErrorText = Resources.Load("ErrorText") as GameObject;
|
||||
CanvasContent = GameObject.Find("Canvas/ErrorScrollView/Viewport/Content");
|
||||
}
|
||||
|
||||
public static void Log(Color color, string message, float time = 5)
|
||||
{
|
||||
Log(message, color, time);
|
||||
}
|
||||
|
||||
public static void Log(string message, Color color, float time = 5)
|
||||
{
|
||||
Debug.Log(message);
|
||||
Text text = Instantiate(ErrorText, CanvasContent.transform).GetComponent<Text>();
|
||||
text.text = message;
|
||||
text.color = color;
|
||||
Destroy(text.gameObject, CanvasContent.transform.childCount + 1 * time);
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Error.cs.meta
Normal file
11
Assets/Scripts/Error.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 07843c4377dd7cb4495bedfa1057ddc7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
69
Assets/Scripts/FateAssetManager.cs
Normal file
69
Assets/Scripts/FateAssetManager.cs
Normal file
@@ -0,0 +1,69 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
public class FateAssetManager : MonoBehaviour
|
||||
{
|
||||
public static FateAssetManager Instance;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public static IEnumerator DownloadTexture(string url, System.Action<Texture2D> callback)
|
||||
{
|
||||
Texture2D outTex = null;
|
||||
Debug.Log("Downloading Texture " + url);
|
||||
UnityWebRequest www = UnityWebRequestTexture.GetTexture(url);
|
||||
yield return www.SendWebRequest();
|
||||
|
||||
if (www.result != UnityWebRequest.Result.Success)
|
||||
{
|
||||
Debug.Log(www.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
outTex = ((DownloadHandlerTexture)www.downloadHandler).texture;
|
||||
outTex.wrapMode = TextureWrapMode.Clamp;
|
||||
}
|
||||
callback(outTex);
|
||||
}
|
||||
|
||||
public static IEnumerator DownloadText(string url, System.Action<string> callback)
|
||||
{
|
||||
UnityWebRequest www = UnityWebRequest.Get(url);
|
||||
yield return www.SendWebRequest();
|
||||
if (www.result != UnityWebRequest.Result.Success)
|
||||
{
|
||||
Debug.Log(url);
|
||||
Debug.Log(www.error);
|
||||
callback(null);
|
||||
}
|
||||
else
|
||||
{
|
||||
var str = www.downloadHandler.text;
|
||||
callback(str);
|
||||
}
|
||||
}
|
||||
|
||||
public static IEnumerator DownloadBundle(string url, System.Action<AssetBundle> callback)
|
||||
{
|
||||
Error.Log(Color.green, $"Downloading bundle from {url}");
|
||||
UnityWebRequest www = UnityWebRequestAssetBundle.GetAssetBundle(url);
|
||||
yield return www.SendWebRequest();
|
||||
AssetBundle bundlea = null;
|
||||
if (www.result != UnityWebRequest.Result.Success)
|
||||
{
|
||||
Error.Log(Color.red, www.error);
|
||||
}
|
||||
else
|
||||
{
|
||||
bundlea = DownloadHandlerAssetBundle.GetContent(www);
|
||||
}
|
||||
|
||||
callback(bundlea);
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/FateAssetManager.cs.meta
Normal file
11
Assets/Scripts/FateAssetManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a27da48354afb9a4faf06ab69ecb72df
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
487
Assets/Scripts/FateModelBuilder.cs
Normal file
487
Assets/Scripts/FateModelBuilder.cs
Normal file
@@ -0,0 +1,487 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class FateModelBuilder : MonoBehaviour
|
||||
{
|
||||
public Material ParticleMaterial;
|
||||
public static FateModelBuilder Instance;
|
||||
public bool LoadingInProgress = false;
|
||||
|
||||
public AnimatorOverrideController AnimatorController;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public IEnumerator ReplaceServant(string id)
|
||||
{
|
||||
if (LoadingInProgress)
|
||||
{
|
||||
Error.Log(Color.red, "Loading already in progress!");
|
||||
yield break;
|
||||
}
|
||||
if (FateViewerMain.SelectedServant != null)
|
||||
{
|
||||
FateViewerMain.SelectedServant.DeleteModel();
|
||||
}
|
||||
yield return LoadServant(id);
|
||||
}
|
||||
|
||||
public IEnumerator LoadServant(string id)
|
||||
{
|
||||
if (LoadingInProgress) yield break;
|
||||
LoadingInProgress = true;
|
||||
|
||||
var Servants = FateViewerMain.Instance.Servants;
|
||||
int idNum = int.Parse(id);
|
||||
var urlBase = $"{FateViewerMain.AAContent}Servants/{idNum}";
|
||||
|
||||
var costume = Servants.GetAllCostumes().FirstOrDefault(s => s.battleCharaId == idNum);
|
||||
if (costume != null)
|
||||
{
|
||||
var servant = Servants.Entries.First(s => s.costumes.Contains(costume));
|
||||
|
||||
var lcButt = UIController.Instance.LoadedCharaButton;
|
||||
lcButt.GetComponentInChildren<TMPro.TextMeshProUGUI>().text = servant.name + " - AA database";
|
||||
lcButt.GetComponentInChildren<Button>().onClick.RemoveAllListeners();
|
||||
lcButt.GetComponentInChildren<Button>().onClick.AddListener(() => Application.OpenURL("https://apps.atlasacademy.io/db/JP/servant/" + servant.collectionNo));
|
||||
}
|
||||
|
||||
AssetBundle assetBundle = null;
|
||||
string url = $"{urlBase}/manifest.json";
|
||||
Manifest manifest = null;
|
||||
yield return FateAssetManager.DownloadText(url, (txt) =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(txt)) return;
|
||||
txt = $"{{\"Entries\": {txt} }}";
|
||||
manifest = (Manifest)JsonUtility.FromJson(txt, typeof(Manifest));
|
||||
});
|
||||
|
||||
if (manifest == null)
|
||||
{
|
||||
Error.Log(Color.red, "Failed to download manifest from " + url);
|
||||
LoadingInProgress = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
Error.Log(Color.green, "Loading character id " + id);
|
||||
|
||||
url = $"{urlBase}/{manifest.GetFilePath(idNum.ToString())}";
|
||||
yield return FateAssetManager.DownloadBundle(url, (cb) =>
|
||||
{
|
||||
assetBundle = cb;
|
||||
});
|
||||
if (assetBundle == null)
|
||||
{
|
||||
Error.Log(Color.red, "Loading assetbundle failed!");
|
||||
LoadingInProgress = false;
|
||||
yield break;
|
||||
}
|
||||
StartCoroutine(BuildModel(assetBundle, manifest, urlBase));
|
||||
}
|
||||
|
||||
public void ReplaceTexture()
|
||||
{
|
||||
StartCoroutine(ReplaceTexture1());
|
||||
}
|
||||
|
||||
private IEnumerator ReplaceTexture1()
|
||||
{
|
||||
if (!FateViewerMain.SelectedServant)
|
||||
{
|
||||
Error.Log(Color.red, "No servant loaded!");
|
||||
UIController.Instance.ReactivateTextureLoad();
|
||||
yield break;
|
||||
}
|
||||
var uploader = WebGLUpDownExamples._webGLUpload;
|
||||
var newMat = new Material(Shader.Find("Legacy Shaders/Diffuse"));
|
||||
//var targetMaterial = Materials.FirstOrDefault(m=>m.mainTexture.name )
|
||||
uploader.UploadTexture(WebGLUpload.ImageFormat.png, 0, true, newMat);
|
||||
do
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
}
|
||||
while (!uploader.TextureReady);
|
||||
uploader.TextureReady = false;
|
||||
|
||||
Debug.Log($"file {newMat.mainTexture.name} loaded");
|
||||
foreach (var mat in FateViewerMain.SelectedServant.Materials)
|
||||
{
|
||||
if (mat.mainTexture.name == newMat.mainTexture.name)
|
||||
{
|
||||
mat.mainTexture = newMat.mainTexture;
|
||||
}
|
||||
}
|
||||
Destroy(newMat);
|
||||
UIController.Instance.ReactivateTextureLoad();
|
||||
}
|
||||
|
||||
public IEnumerator BuildModel(AssetBundle assetBundle, Manifest manifest, string modelUrl)
|
||||
{
|
||||
if (assetBundle == null)
|
||||
{
|
||||
Error.Log(Color.red, "Asset load fail");
|
||||
Debug.LogError("Asset load fail");
|
||||
LoadingInProgress = false;
|
||||
assetBundle.Unload(true);
|
||||
yield break;
|
||||
}
|
||||
|
||||
FateServantContainer servant = new GameObject().AddComponent<FateServantContainer>();
|
||||
servant.name = assetBundle.name;
|
||||
|
||||
foreach (var asset in assetBundle.LoadAllAssets())
|
||||
{
|
||||
if (asset == null) { continue; }
|
||||
else if (asset.GetType() == typeof(GameObject))
|
||||
{
|
||||
if((asset as GameObject).name == "chr")
|
||||
{
|
||||
servant.BodyMain = asset as GameObject;
|
||||
}
|
||||
}
|
||||
else if (asset.GetType() == typeof(Texture2D))
|
||||
{
|
||||
Texture2D tex = asset as Texture2D;
|
||||
yield return FateAssetManager.DownloadTexture(modelUrl + "/" + manifest.GetFilePath(tex.name + ".png"), (tex2) =>
|
||||
{
|
||||
if(tex2 == null)
|
||||
{
|
||||
Error.Log(Color.red, "Downloading " + tex.name + " failed");
|
||||
return;
|
||||
}
|
||||
tex2.name = tex.name;
|
||||
servant.Textures.Add(tex2);
|
||||
});
|
||||
}
|
||||
else if (asset.GetType() == typeof(Material))
|
||||
{
|
||||
servant.Materials.Add(asset as Material);
|
||||
}
|
||||
else if (asset.GetType() == typeof(TextAsset))
|
||||
{
|
||||
}
|
||||
else if (asset.GetType() == typeof(AnimationClip))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
//Error.Log(Color.yellow, asset.GetType().ToString());
|
||||
//Debug.LogWarning(asset.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
UIController.Instance.CutoffSlider?.onValueChanged.RemoveAllListeners();
|
||||
foreach (Material mat in servant.Materials)
|
||||
{
|
||||
if (mat.shader.name.Contains("Particle"))
|
||||
{
|
||||
mat.shader = Shader.Find("Particles/Standard Unlit");
|
||||
var tex = mat.mainTexture;
|
||||
var color = mat.color;
|
||||
mat.CopyPropertiesFromMaterial(ParticleMaterial);
|
||||
mat.mainTexture = tex;
|
||||
mat.color = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.shader = Shader.Find("FateShader3Compatible");
|
||||
if (mat.mainTexture != null)
|
||||
{
|
||||
var texture = servant.Textures.FirstOrDefault(t => t.name == mat.mainTexture.name);
|
||||
if (texture != null)
|
||||
{
|
||||
mat.SetTexture("_MainTex", texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error.Log(Color.red, $"Texture {mat.mainTexture.name} not found");
|
||||
}
|
||||
var alpha = servant.Textures.FirstOrDefault(t => t.name == mat.mainTexture.name + "a" || t.name == mat.mainTexture.name + "_alpha");
|
||||
if (alpha)
|
||||
{
|
||||
mat.SetTexture("_Alpha", alpha);
|
||||
}
|
||||
}
|
||||
Material temp = mat;
|
||||
mat.SetFloat("_Cutoff", 0.91f);
|
||||
UIController.Instance.CutoffSlider?.onValueChanged.AddListener((value) => { temp.SetFloat("_Cutoff", value / 100);});
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(servant.BodyMain == null)
|
||||
{
|
||||
Error.Log(Color.red, "Servant body was not loaded");
|
||||
assetBundle.Unload(true);
|
||||
LoadingInProgress = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
servant.BodyMain = Instantiate(servant.BodyMain, servant.transform);
|
||||
servant.InstantiatedObjects.Add(servant.BodyMain);
|
||||
var simpleAnimation = servant.GetComponentInChildren<SimpleAnimation>();
|
||||
simpleAnimation.enabled = false;
|
||||
servant.AnimationClips.AddRange(simpleAnimation.GetStates());
|
||||
|
||||
servant.Animator = servant.BodyMain.GetComponentInChildren<Animator>();
|
||||
if (servant.Animator)
|
||||
{
|
||||
servant.OverrideController = new AnimatorOverrideController(AnimatorController);
|
||||
servant.OverrideController["clip"] = null;
|
||||
servant.Animator.speed = 0;
|
||||
servant.Animator.runtimeAnimatorController = servant.OverrideController;
|
||||
servant.Animator.Play(null);
|
||||
}
|
||||
|
||||
GameObject MeshToggle = Resources.Load("MeshToggle") as GameObject;
|
||||
var meshes = servant.Meshes = servant.BodyMain.GetComponentsInChildren<Renderer>().ToList();
|
||||
for (int i = 0; i < meshes.Count; i++)
|
||||
{
|
||||
int meshId = i;
|
||||
GameObject go = Instantiate(MeshToggle, UIController.Instance.MeshesListContent);
|
||||
servant.InstantiatedObjects.Add(go);
|
||||
go.GetComponentInChildren<TMPro.TextMeshProUGUI>().text = meshes[i].name;
|
||||
if (meshes[i].enabled)
|
||||
{
|
||||
string[] splitName = meshes[i].name.Split('_');
|
||||
if (splitName.Length >= 3)
|
||||
{
|
||||
//Debug.LogWarning(meshes[i].name);
|
||||
string partName = splitName[0];
|
||||
var sameParts = meshes.Where(r => r.name.Split('_').Length >= 3).Where(r => r.name.Split('_')[0] == partName);
|
||||
var bestPart = sameParts.OrderBy(r => r.name.Split('_')[2]).Reverse().Take(1);
|
||||
//Debug.LogWarning(sameParts.Count());
|
||||
foreach (var part in sameParts.Except(bestPart))
|
||||
{
|
||||
part.enabled = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
go.GetComponentInChildren<Toggle>().isOn = meshes[i].enabled;
|
||||
go.GetComponentInChildren<Toggle>().onValueChanged.AddListener((value) => meshes[meshId].enabled = value);
|
||||
}
|
||||
FateViewerMain.Instance.SpawnedServants.Add(servant);
|
||||
FateViewerMain.SelectedServant = servant;
|
||||
UIController.Instance.SetBodyAnimationDropdownData(servant.AnimationClips.Select(a => a.name).ToList());
|
||||
var animId = UIController.Instance.BodyAnimationDropdown.options.IndexOf(UIController.Instance.BodyAnimationDropdown.options.FirstOrDefault(a => a.text == "Default"));
|
||||
UIController.Instance.BodyAnimationDropdown.SetValueWithoutNotify(animId);
|
||||
servant.PlayAnimation("Default");
|
||||
assetBundle.Unload(false);
|
||||
CenterCamera();
|
||||
LoadingInProgress = false;
|
||||
}
|
||||
|
||||
|
||||
public IEnumerator BuildNP(AssetBundle assetBundle)
|
||||
{
|
||||
if (assetBundle == null)
|
||||
{
|
||||
Error.Log(Color.red, "Asset load fail");
|
||||
Debug.LogError("Asset load fail");
|
||||
LoadingInProgress = false;
|
||||
assetBundle.Unload(true);
|
||||
yield break;
|
||||
}
|
||||
|
||||
FateServantContainer servant = new GameObject().AddComponent<FateServantContainer>();
|
||||
servant.name = assetBundle.name;
|
||||
|
||||
foreach (var asset in assetBundle.LoadAllAssets())
|
||||
{
|
||||
if (asset == null) { continue; }
|
||||
else if (asset.GetType() == typeof(GameObject))
|
||||
{
|
||||
if (asset.name.StartsWith("chr_"))
|
||||
{
|
||||
servant.BodyMain = asset as GameObject;
|
||||
}
|
||||
else if (asset.name.StartsWith("model_"))
|
||||
{
|
||||
Instantiate(asset, servant.transform);
|
||||
}
|
||||
}
|
||||
else if (asset.GetType() == typeof(Texture2D))
|
||||
{
|
||||
Texture2D tex = asset as Texture2D;
|
||||
servant.Textures.Add(tex);
|
||||
}
|
||||
else if (asset.GetType() == typeof(Material))
|
||||
{
|
||||
servant.Materials.Add(asset as Material);
|
||||
}
|
||||
else if (asset.GetType() == typeof(TextAsset))
|
||||
{
|
||||
}
|
||||
else if (asset.GetType() == typeof(AnimationClip))
|
||||
{
|
||||
}
|
||||
else
|
||||
{
|
||||
Error.Log(Color.yellow, asset.GetType().ToString());
|
||||
Debug.LogWarning(asset.GetType());
|
||||
}
|
||||
}
|
||||
|
||||
UIController.Instance.CutoffSlider?.onValueChanged.RemoveAllListeners();
|
||||
foreach (Material mat in servant.Materials)
|
||||
{
|
||||
if (mat.shader.name.Contains("Particle"))
|
||||
{
|
||||
mat.shader = Shader.Find("Particles/Standard Unlit");
|
||||
var tex = mat.mainTexture;
|
||||
var color = mat.color;
|
||||
mat.CopyPropertiesFromMaterial(ParticleMaterial);
|
||||
mat.mainTexture = tex;
|
||||
mat.color = color;
|
||||
}
|
||||
else
|
||||
{
|
||||
mat.shader = Shader.Find("FateShader3Compatible");
|
||||
if (mat.mainTexture != null)
|
||||
{
|
||||
var texture = servant.Textures.FirstOrDefault(t => t.name == mat.mainTexture.name);
|
||||
if (texture != null)
|
||||
{
|
||||
mat.SetTexture("_MainTex", texture);
|
||||
}
|
||||
else
|
||||
{
|
||||
Error.Log(Color.red, $"Texture {mat.mainTexture.name} not found");
|
||||
}
|
||||
var alpha = servant.Textures.FirstOrDefault(t => t.name == mat.mainTexture.name + "a" || t.name == mat.mainTexture.name + "_alpha");
|
||||
if (alpha)
|
||||
{
|
||||
mat.SetTexture("_Alpha", alpha);
|
||||
}
|
||||
}
|
||||
Material temp = mat;
|
||||
mat.SetFloat("_Cutoff", 0.91f);
|
||||
UIController.Instance.CutoffSlider?.onValueChanged.AddListener((value) => { temp.SetFloat("_Cutoff", value / 100); });
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (servant.BodyMain == null)
|
||||
{
|
||||
Error.Log(Color.red, "Servant body was not loaded");
|
||||
assetBundle.Unload(true);
|
||||
LoadingInProgress = false;
|
||||
yield break;
|
||||
}
|
||||
|
||||
servant.BodyMain = Instantiate(servant.BodyMain, servant.transform);
|
||||
servant.InstantiatedObjects.Add(servant.BodyMain);
|
||||
servant.BodyMain.SetActive(true);
|
||||
var simpleAnimation = servant.GetComponentInChildren<SimpleAnimation>();
|
||||
simpleAnimation.enabled = false;
|
||||
servant.AnimationClips.AddRange(simpleAnimation.GetStates());
|
||||
|
||||
servant.Animator = servant.BodyMain.GetComponentInChildren<Animator>();
|
||||
if (servant.Animator)
|
||||
{
|
||||
servant.OverrideController = new AnimatorOverrideController(AnimatorController);
|
||||
servant.OverrideController["clip"] = null;
|
||||
servant.Animator.speed = 0;
|
||||
servant.Animator.runtimeAnimatorController = servant.OverrideController;
|
||||
servant.Animator.Play(null);
|
||||
}
|
||||
|
||||
//GameObject MeshToggle = Resources.Load("MeshToggle") as GameObject;
|
||||
//var meshes = servant.Meshes = servant.BodyMain.GetComponentsInChildren<Renderer>().ToList();
|
||||
//for (int i = 0; i < meshes.Count; i++)
|
||||
//{
|
||||
// int meshId = i;
|
||||
// GameObject go = Instantiate(MeshToggle, UIController.Instance.MeshesListContent);
|
||||
// servant.InstantiatedObjects.Add(go);
|
||||
// go.GetComponentInChildren<TMPro.TextMeshProUGUI>().text = meshes[i].name;
|
||||
// if (meshes[i].enabled)
|
||||
// {
|
||||
// string[] splitName = meshes[i].name.Split('_');
|
||||
// if (splitName.Length >= 3)
|
||||
// {
|
||||
// string partName = splitName[0];
|
||||
// var sameParts = meshes.Where(r => r.name.Split('_').Length >= 3).Where(r => r.name.Split('_')[0] == partName);
|
||||
// var bestPart = sameParts.OrderBy(r => r.name.Split('_')[2]).Reverse().Take(1);
|
||||
// foreach (var part in sameParts.Except(bestPart))
|
||||
// {
|
||||
// part.enabled = false;
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// go.GetComponentInChildren<Toggle>().isOn = meshes[i].enabled;
|
||||
// go.GetComponentInChildren<Toggle>().onValueChanged.AddListener((value) => meshes[meshId].enabled = value);
|
||||
//}
|
||||
|
||||
FateViewerMain.Instance.SpawnedServants.Add(servant);
|
||||
FateViewerMain.SelectedServant = servant;
|
||||
UIController.Instance.SetBodyAnimationDropdownData(servant.AnimationClips.Select(a => a.name).ToList());
|
||||
var animId = 0;
|
||||
UIController.Instance.BodyAnimationDropdown.SetValueWithoutNotify(animId);
|
||||
servant.PlayAnimation("Default");
|
||||
assetBundle.Unload(false);
|
||||
CenterCamera();
|
||||
LoadingInProgress = false;
|
||||
}
|
||||
|
||||
public void CenterCamera()
|
||||
{
|
||||
/*
|
||||
foreach (Transform t in MainBone)
|
||||
{
|
||||
AnimBounds.Encapsulate(new Bounds(t.transform.position, Vector3.one * 1.5f));
|
||||
}
|
||||
Bounds AnimBounds = CharaModel.GetComponentInChildren<SkinnedMeshRenderer>().bounds; //CharaModel.GetComponentInChildren<SkinnedMeshRenderer>().localBounds;
|
||||
foreach (var renderer in CharaModel.GetComponentsInChildren<SkinnedMeshRenderer>())
|
||||
{
|
||||
AnimBounds.Encapsulate(renderer.bounds);
|
||||
}
|
||||
Camera.main.transform.position = new Vector3(-5, AnimBounds.center.y, 0);
|
||||
Camera.main.transform.eulerAngles = new Vector3(0, 90, 0);
|
||||
var orbit = GameObject.FindObjectOfType<CameraOrbit>();
|
||||
var max = Mathf.Max(AnimBounds.size.x, AnimBounds.size.y, AnimBounds.size.z);
|
||||
orbit.camZoom = max / 2;
|
||||
orbit.camZoomMax = max > 15 ? max : 15;
|
||||
orbit.camZoomMin = 0.2f;
|
||||
*/
|
||||
|
||||
var orbit = GameObject.FindObjectOfType<CameraOrbit>();
|
||||
orbit.camZoom = 1.5f;
|
||||
orbit.camZoomMax = 500;
|
||||
orbit.camZoomMin = 0.2f;
|
||||
Camera.main.transform.eulerAngles = new Vector3(0, 90, 0);
|
||||
Camera.main.transform.position = new Vector3(-5, 1, 0);
|
||||
}
|
||||
|
||||
//public IEnumerator CreateRuntimeMask()
|
||||
//{
|
||||
// //GameObject activeGameObject = CharaModel;
|
||||
// //AvatarMask avatarMask = new AvatarMask();
|
||||
// //avatarMask.AddTransformPath(activeGameObject.transform);
|
||||
|
||||
// //var layers = OriginalController.layers;
|
||||
// //layers[1].avatarMask = avatarMask;
|
||||
// //OriginalController.layers = layers;
|
||||
// //Animator.runtimeAnimatorController = OriginalController;
|
||||
|
||||
// //for (int i = 0; i < avatarMask.transformCount; i++)
|
||||
// //{
|
||||
// // bool value = avatarMask.GetTransformPath(i).Contains("joint_eye") || avatarMask.GetTransformPath(i).Contains("joint_mouth");
|
||||
// // avatarMask.SetTransformActive(i, value);
|
||||
// //}
|
||||
|
||||
// //OverrideController = new AnimatorOverrideController(Animator.runtimeAnimatorController);
|
||||
// //Animator.runtimeAnimatorController = OverrideController;
|
||||
|
||||
// yield return PlayAnimation("Default");
|
||||
// yield return PlayAnimationLayer2("Default");
|
||||
//}
|
||||
}
|
||||
11
Assets/Scripts/FateModelBuilder.cs.meta
Normal file
11
Assets/Scripts/FateModelBuilder.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2635ae45de879d24f8ef8ed4092a90b7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
138
Assets/Scripts/FateNPContainer.cs
Normal file
138
Assets/Scripts/FateNPContainer.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class FateNPContainer : MonoBehaviour
|
||||
{
|
||||
public GameObject BodyMain;
|
||||
public List<SimpleAnimation.State> AnimationClips = new List<SimpleAnimation.State>();
|
||||
public List<Texture2D> Textures = new List<Texture2D>();
|
||||
public List<Material> Materials = new List<Material>();
|
||||
public List<Renderer> Meshes = new List<Renderer>();
|
||||
public Animator Animator;
|
||||
public AnimatorOverrideController OverrideController;
|
||||
|
||||
public float CurrentFrame = 0;
|
||||
public float CurrentFrame2 = 0;
|
||||
private AnimationClip _currentClip;
|
||||
public int ClipFrameCount = 0;
|
||||
public int ClipFrameCount2 = 0;
|
||||
private bool _animationReady;
|
||||
private bool _animationReady2;
|
||||
|
||||
[Header("Garbage")]
|
||||
public List<GameObject> InstantiatedObjects = new List<GameObject>();
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (_animationReady)
|
||||
{
|
||||
Animate();
|
||||
}
|
||||
}
|
||||
|
||||
private void Animate()
|
||||
{
|
||||
Animator.Play("clip", 0, Mathf.Round(CurrentFrame) / ClipFrameCount);
|
||||
CurrentFrame += FateViewerMain.Instance.TimeScale;
|
||||
CurrentFrame = (CurrentFrame) % (ClipFrameCount + 1);
|
||||
}
|
||||
|
||||
public void PlayAnimation(string animationName)
|
||||
{
|
||||
_animationReady = false;
|
||||
AnimationClip bbb = AnimationClips.FirstOrDefault(c => c.name == animationName).clip;
|
||||
OverrideController["clip"] = bbb;
|
||||
_currentClip = OverrideController["clip"];
|
||||
CurrentFrame = 0;
|
||||
ClipFrameCount = Mathf.RoundToInt(_currentClip.length * _currentClip.frameRate);
|
||||
Debug.Log("----now playing----");
|
||||
Debug.Log(_currentClip.name);
|
||||
Debug.Log($"Framerate: {_currentClip.frameRate}");
|
||||
Debug.Log($"Length: {_currentClip.length}");
|
||||
Debug.Log($"Frame Count: {_currentClip.frameRate * _currentClip.length}({ClipFrameCount})");
|
||||
Animator?.Play("clip", 0, 0);
|
||||
_animationReady = true;
|
||||
}
|
||||
|
||||
public void PlayAnimationLayer2(string animationName)
|
||||
{
|
||||
_animationReady2 = false;
|
||||
AnimationClip bbb = AnimationClips.FirstOrDefault(c => c.name == animationName).clip;
|
||||
OverrideController["clip2"] = bbb;
|
||||
_currentClip = OverrideController["clip2"];
|
||||
CurrentFrame2 = 0;
|
||||
ClipFrameCount2 = Mathf.RoundToInt(_currentClip.length * _currentClip.frameRate);
|
||||
Debug.Log("----now playing----");
|
||||
Debug.Log(_currentClip.name);
|
||||
Debug.Log($"Framerate: {_currentClip.frameRate}");
|
||||
Debug.Log($"Length: {_currentClip.length}");
|
||||
Debug.Log($"Frame Count: {_currentClip.frameRate * _currentClip.length}({ClipFrameCount2})");
|
||||
Animator?.Play("clip2", 1, 0);
|
||||
_animationReady2 = true;
|
||||
}
|
||||
|
||||
#region affect things
|
||||
|
||||
public void ToggleTextureFiltering()
|
||||
{
|
||||
if (Textures.Count <= 0) return;
|
||||
FilterMode filter = Textures[0].filterMode;
|
||||
foreach (var tex in Textures)
|
||||
{
|
||||
tex.filterMode = filter == FilterMode.Point ? FilterMode.Bilinear : FilterMode.Point;
|
||||
}
|
||||
}
|
||||
|
||||
public void SwitchShaderToScreenshot(bool value)
|
||||
{
|
||||
foreach (var mat in Materials)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
if (mat.shader.name == "FateShader3Compatible")
|
||||
{
|
||||
mat.shader = Shader.Find("FateScreenshotShaderCompatible");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mat.shader.name == "FateScreenshotShaderCompatible")
|
||||
{
|
||||
mat.shader = Shader.Find("FateShader3Compatible");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void DeleteModel()
|
||||
{
|
||||
_animationReady = false;
|
||||
|
||||
foreach (var rend in BodyMain.GetComponentsInChildren<Renderer>())
|
||||
{
|
||||
for (int i = rend.materials.Length - 1; i >= 0; i--)
|
||||
{
|
||||
Destroy(rend.materials[i]);
|
||||
}
|
||||
}
|
||||
for (int i = Textures.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Destroy(Textures[i]);
|
||||
}
|
||||
for (int i = InstantiatedObjects.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (InstantiatedObjects[i] != null)
|
||||
{
|
||||
Destroy(InstantiatedObjects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Destroy(this.gameObject, 0.5f);
|
||||
|
||||
Resources.UnloadUnusedAssets();
|
||||
System.GC.Collect();
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/FateNPContainer.cs.meta
Normal file
11
Assets/Scripts/FateNPContainer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e4a606390c64e1b42b06632b11729acc
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
148
Assets/Scripts/FateServantContainer.cs
Normal file
148
Assets/Scripts/FateServantContainer.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class FateServantContainer : MonoBehaviour
|
||||
{
|
||||
public GameObject BodyMain;
|
||||
public List<SimpleAnimation.State> AnimationClips = new List<SimpleAnimation.State>();
|
||||
public List<Texture2D> Textures = new List<Texture2D>();
|
||||
public List<Material> Materials = new List<Material>();
|
||||
public List<Renderer> Meshes = new List<Renderer>();
|
||||
public Animator Animator;
|
||||
public AnimatorOverrideController OverrideController;
|
||||
|
||||
public float CurrentFrame = 0;
|
||||
public float CurrentFrame2 = 0;
|
||||
private AnimationClip _currentClip;
|
||||
public int ClipFrameCount = 0;
|
||||
public int ClipFrameCount2 = 0;
|
||||
private bool _animationReady;
|
||||
private bool _animationReady2;
|
||||
|
||||
[Header("Garbage")]
|
||||
public List<GameObject> InstantiatedObjects = new List<GameObject>();
|
||||
|
||||
private void Update()
|
||||
{
|
||||
//if (Input.GetKeyDown(KeyCode.F))
|
||||
//{
|
||||
// StartCoroutine(CreateRuntimeMask());
|
||||
//}
|
||||
if (_animationReady)// && _animationReady2)
|
||||
{
|
||||
Animate();
|
||||
}
|
||||
}
|
||||
|
||||
private void Animate()
|
||||
{
|
||||
//Debug.Log($"Frame: {CurrentFrame}/{ClipFrameCount}");
|
||||
//Debug.Log($"Frame: {CurrentFrame2}/{ClipFrameCount2}");
|
||||
Animator.Play("clip", 0, Mathf.Round(CurrentFrame) / ClipFrameCount);
|
||||
CurrentFrame += FateViewerMain.Instance.TimeScale;
|
||||
CurrentFrame = (CurrentFrame) % (ClipFrameCount + 1);
|
||||
|
||||
//Animator.Play("clip2", 1, Mathf.Round(CurrentFrame2) / ClipFrameCount2);
|
||||
//CurrentFrame2 += FateViewerMain.Instance.TimeScale;
|
||||
//CurrentFrame2 = Mathf.Clamp(CurrentFrame2, 0, ClipFrameCount2);
|
||||
}
|
||||
|
||||
public void PlayAnimation(string animationName)
|
||||
{
|
||||
_animationReady = false;
|
||||
AnimationClip bbb = AnimationClips.FirstOrDefault(c => c.name == animationName).clip;
|
||||
OverrideController["clip"] = bbb;
|
||||
_currentClip = OverrideController["clip"];
|
||||
CurrentFrame = 0;
|
||||
ClipFrameCount = Mathf.RoundToInt(_currentClip.length * _currentClip.frameRate);
|
||||
Debug.Log("----now playing----");
|
||||
Debug.Log(_currentClip.name);
|
||||
Debug.Log($"Framerate: {_currentClip.frameRate}");
|
||||
Debug.Log($"Length: {_currentClip.length}");
|
||||
Debug.Log($"Frame Count: {_currentClip.frameRate * _currentClip.length}({ClipFrameCount})");
|
||||
Animator?.Play("clip", 0, 0);
|
||||
_animationReady = true;
|
||||
}
|
||||
|
||||
public void PlayAnimationLayer2(string animationName)
|
||||
{
|
||||
_animationReady2 = false;
|
||||
AnimationClip bbb = AnimationClips.FirstOrDefault(c => c.name == animationName).clip;
|
||||
OverrideController["clip2"] = bbb;
|
||||
_currentClip = OverrideController["clip2"];
|
||||
CurrentFrame2 = 0;
|
||||
ClipFrameCount2 = Mathf.RoundToInt(_currentClip.length * _currentClip.frameRate);
|
||||
Debug.Log("----now playing----");
|
||||
Debug.Log(_currentClip.name);
|
||||
Debug.Log($"Framerate: {_currentClip.frameRate}");
|
||||
Debug.Log($"Length: {_currentClip.length}");
|
||||
Debug.Log($"Frame Count: {_currentClip.frameRate * _currentClip.length}({ClipFrameCount2})");
|
||||
Animator?.Play("clip2", 1, 0);
|
||||
_animationReady2 = true;
|
||||
}
|
||||
|
||||
#region affect things
|
||||
|
||||
public void ToggleTextureFiltering()
|
||||
{
|
||||
if (Textures.Count <= 0) return;
|
||||
FilterMode filter = Textures[0].filterMode;
|
||||
foreach (var tex in Textures)
|
||||
{
|
||||
tex.filterMode = filter == FilterMode.Point ? FilterMode.Bilinear : FilterMode.Point;
|
||||
}
|
||||
}
|
||||
|
||||
public void SwitchShaderToScreenshot(bool value)
|
||||
{
|
||||
foreach (var mat in Materials)
|
||||
{
|
||||
if (value)
|
||||
{
|
||||
if (mat.shader.name == "FateShader3Compatible")
|
||||
{
|
||||
mat.shader = Shader.Find("FateScreenshotShaderCompatible");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (mat.shader.name == "FateScreenshotShaderCompatible")
|
||||
{
|
||||
mat.shader = Shader.Find("FateShader3Compatible");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void DeleteModel()
|
||||
{
|
||||
_animationReady = false;
|
||||
|
||||
foreach (var rend in BodyMain.GetComponentsInChildren<Renderer>())
|
||||
{
|
||||
for (int i = rend.materials.Length - 1; i >= 0; i--)
|
||||
{
|
||||
Destroy(rend.materials[i]);
|
||||
}
|
||||
}
|
||||
for (int i = Textures.Count - 1; i >= 0; i--)
|
||||
{
|
||||
Destroy(Textures[i]);
|
||||
}
|
||||
for (int i = InstantiatedObjects.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if(InstantiatedObjects[i] != null)
|
||||
{
|
||||
Destroy(InstantiatedObjects[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Destroy(this.gameObject, 0.5f);
|
||||
|
||||
Resources.UnloadUnusedAssets();
|
||||
System.GC.Collect();
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/FateServantContainer.cs.meta
Normal file
11
Assets/Scripts/FateServantContainer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2acb976eaa1073f40a3075dbbda868ed
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
343
Assets/Scripts/FateViewerMain.cs
Normal file
343
Assets/Scripts/FateViewerMain.cs
Normal file
@@ -0,0 +1,343 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using System;
|
||||
using UnityEngine.UI;
|
||||
using System.Linq;
|
||||
#if PLATFORM_ANDROID
|
||||
using UnityEngine.Android;
|
||||
#endif
|
||||
|
||||
public class FateViewerMain : MonoBehaviour
|
||||
{
|
||||
public static FateViewerMain Instance;
|
||||
|
||||
[Header("Online Data")]
|
||||
public string AAAPI = "https://api.atlasacademy.io/export/";
|
||||
public static string AAContent { get; set; } = "https://static.atlasacademy.io/JP/";
|
||||
public string Region = "JP";
|
||||
public string debugUrl = "this.is.a.test/website/modelViewer.html?id=303800";
|
||||
|
||||
[Header("Selected Servant")]
|
||||
public List<FateServantContainer> SpawnedServants = new List<FateServantContainer>();
|
||||
public static FateServantContainer SelectedServant;
|
||||
|
||||
[Header("General")]
|
||||
public string AnimationName;
|
||||
public BasicServant Servants;
|
||||
public BasicServant Enemies;
|
||||
|
||||
[Header("Global")]
|
||||
public GameObject Cam;
|
||||
public float TimeScale = 1;
|
||||
public Slider TimeScaleSlider;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null)
|
||||
{
|
||||
Destroy(Instance);
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Application.targetFrameRate = 30;
|
||||
Cam = Camera.main.gameObject;
|
||||
|
||||
StartCoroutine(AtlasStart());
|
||||
}
|
||||
|
||||
private IEnumerator AtlasStart()
|
||||
{
|
||||
Error.Log(Color.green, "Version: " + Application.version);
|
||||
string url = Application.absoluteURL;
|
||||
string fullId = "";
|
||||
string ascension = "1";
|
||||
|
||||
#if UNITY_EDITOR || PLATFORM_STANDALONE
|
||||
url = debugUrl;
|
||||
#endif
|
||||
//Error.Log(Color.green, url);
|
||||
string[] parts = url.Split('?');
|
||||
foreach (var part in parts)
|
||||
{
|
||||
string partL = part.ToLower();
|
||||
if (partL.StartsWith("id="))
|
||||
{
|
||||
if (int.TryParse(partL.Split('=')[1], out int result))
|
||||
{
|
||||
fullId = result.ToString();
|
||||
}
|
||||
}
|
||||
else if (partL.StartsWith("ascension="))
|
||||
{
|
||||
ascension = partL.Split('=')[1];
|
||||
}
|
||||
else if (partL.StartsWith("customurl="))
|
||||
{
|
||||
AAContent = part.Split('=')[1];
|
||||
}
|
||||
else if (partL.StartsWith("region="))
|
||||
{
|
||||
switch (partL.Split('=')[1])
|
||||
{
|
||||
case "na":
|
||||
Region = "NA"; break;
|
||||
case "jp":
|
||||
Region = "JP"; break;
|
||||
default:
|
||||
Error.Log(Color.yellow, $"Region {partL.Split('=')[1]} not available. Defaulting to JP");
|
||||
Region = "JP";
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if (partL.StartsWith("animation="))
|
||||
{
|
||||
AnimationName = partL.Split('=')[1];
|
||||
}
|
||||
else if (partL.StartsWith("debug"))
|
||||
{
|
||||
Error.CanvasContent.SetActive(true);
|
||||
foreach (var parameter in url.Split('?'))
|
||||
{
|
||||
if (parameter.StartsWith("http"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
else if (parameter.Split('=').Length <= 1)
|
||||
{
|
||||
Error.Log(Color.green, $"{parameter} is ON");
|
||||
}
|
||||
else
|
||||
{
|
||||
Error.Log(Color.green, $"{parameter.Split('=')[0]} is {parameter.Split('=')[1]}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
yield return LoadCharaList();
|
||||
yield return LoadEnemyList();
|
||||
//StartCoroutine(LoadStage("39510"));
|
||||
//yield break;
|
||||
if (string.IsNullOrEmpty(fullId) || fullId == "-1")
|
||||
{
|
||||
Error.Log(Color.yellow, "Loading random");
|
||||
int result = Servants.GetAllCostumes()[UnityEngine.Random.Range(0, Servants.GetAllCostumes().Count)].battleCharaId;
|
||||
StartCoroutine(FateModelBuilder.Instance.LoadServant(result.ToString()));
|
||||
}
|
||||
else
|
||||
{
|
||||
StartCoroutine(FateModelBuilder.Instance.LoadServant(fullId));
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeAnimationTimeScale(float time)
|
||||
{
|
||||
TimeScale = time / 100;
|
||||
}
|
||||
|
||||
public void ChangeAnimationFrame(int value)
|
||||
{
|
||||
TimeScaleSlider.value = 0;
|
||||
foreach(var servant in GameObject.FindObjectsOfType<FateServantContainer>())
|
||||
{
|
||||
servant.CurrentFrame = mod(Mathf.RoundToInt(servant.CurrentFrame + value), servant.ClipFrameCount + 1);
|
||||
}
|
||||
}
|
||||
|
||||
int mod(int x, int m)
|
||||
{
|
||||
return (x % m + m) % m;
|
||||
}
|
||||
|
||||
public IEnumerator LoadCharaList()
|
||||
{
|
||||
string url = $"{AAAPI}JP/basic_servant_lang_en.json";
|
||||
if (Region == "NA")
|
||||
{
|
||||
url = $"{AAAPI}NA/basic_servant.json";
|
||||
}
|
||||
yield return FateAssetManager.DownloadText(url, (txt) =>
|
||||
{
|
||||
txt = $"{{\"Entries\": {txt} }}";
|
||||
Servants = Newtonsoft.Json.JsonConvert.DeserializeObject<BasicServant>(txt);
|
||||
foreach (var servant in Servants.Entries)
|
||||
{
|
||||
servant.costumes = servant.costume.Select(c => c.Value).ToList();
|
||||
if (servant.costumes.FirstOrDefault(c => c.battleCharaId == servant.id) == null)
|
||||
servant.costumes.Insert(0, new BasicServant.Costume()
|
||||
{
|
||||
battleCharaId = servant.id,
|
||||
id = 0,
|
||||
shortName = servant.name,
|
||||
});
|
||||
}
|
||||
Servants.Entries = Servants.Entries.OrderBy(e => e.collectionNo).ToList();
|
||||
});
|
||||
|
||||
if (Servants.Entries.Count > 0)
|
||||
{
|
||||
GameObject servantContainer = Resources.Load("ServantContainer") as GameObject;
|
||||
foreach (var servant in Servants.Entries)
|
||||
{
|
||||
var servant1 = servant;
|
||||
ServantUIContainer go = Instantiate(servantContainer, UIController.Instance.ServantList.content).GetComponent<ServantUIContainer>();
|
||||
go.Servant = servant1;
|
||||
go.FaceUrl = servant1.face;
|
||||
go.ID.text = servant1.id.ToString();
|
||||
go.Name.text = servant1.name.ToString();
|
||||
go.Button.onClick.AddListener(() => {
|
||||
UIController.Instance.OpenServantCostumePanel(servant1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerator LoadEnemyList()
|
||||
{
|
||||
string url = $"{AAAPI}JP/basic_svt_lang_en.json";
|
||||
Dictionary<string, List<BasicServant.Costume>> entries = new Dictionary<string, List<BasicServant.Costume>>();
|
||||
yield return FateAssetManager.DownloadText(url, (txt) =>
|
||||
{
|
||||
txt = $"{{\"Entries\": {txt} }}";
|
||||
Enemies = Newtonsoft.Json.JsonConvert.DeserializeObject<BasicServant>(txt);
|
||||
Enemies.Entries = Enemies.Entries.Where(e => e.type == "enemy").ToList();
|
||||
Enemies.Entries = Enemies.Entries.OrderBy(e => e.name).ToList();
|
||||
foreach (var enemy in Enemies.Entries)
|
||||
{
|
||||
enemy.costumes = enemy.costume.Select(c => c.Value).ToList();
|
||||
foreach (var costume in enemy.costumes)
|
||||
{
|
||||
var cos = new BasicServant.Costume()
|
||||
{
|
||||
name = costume.name,
|
||||
shortName = costume.shortName,
|
||||
id = costume.id,
|
||||
battleCharaId = costume.battleCharaId
|
||||
};
|
||||
if (entries.ContainsKey(enemy.name))
|
||||
{
|
||||
if (!entries[enemy.name].Any(c => c.battleCharaId == costume.battleCharaId))
|
||||
entries[enemy.name].Add(cos);
|
||||
}
|
||||
else
|
||||
{
|
||||
entries[enemy.name] = new List<BasicServant.Costume>() { cos };
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (entries.Count() > 0)
|
||||
{
|
||||
GameObject servantContainer = Resources.Load("ServantContainer") as GameObject;
|
||||
foreach (var enemy in entries)
|
||||
{
|
||||
var servant1 = enemy.Value;
|
||||
ServantUIContainer go = Instantiate(servantContainer, UIController.Instance.EnemiesList.content).GetComponent<ServantUIContainer>();
|
||||
//go.Servant = servant1[0];
|
||||
go.FaceUrl = $"https://static.atlasacademy.io/JP/Enemys/{servant1[0].battleCharaId}1.png";
|
||||
go.ID.text = servant1[0].battleCharaId.ToString();
|
||||
go.Name.text = enemy.Key;
|
||||
go.Button.onClick.AddListener(() => {
|
||||
UIController.Instance.OpenEnemyCostumePanel(servant1);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleCameraMode()
|
||||
{
|
||||
if(Cam.GetComponent<CameraOrbit>().enabled == false)
|
||||
{
|
||||
Cam.GetComponent<CameraOrbit3D>().enabled = false;
|
||||
Cam.GetComponent<Camera>().orthographic = true;
|
||||
Cam.GetComponent<CameraOrbit>().enabled = true;
|
||||
FateModelBuilder.Instance.CenterCamera();
|
||||
}
|
||||
else
|
||||
{
|
||||
Cam.GetComponent<CameraOrbit>().enabled = false;
|
||||
Cam.GetComponent<Camera>().orthographic = false;
|
||||
Cam.GetComponent<CameraOrbit3D>().enabled = true;
|
||||
}
|
||||
}
|
||||
|
||||
#region Unused/WIP
|
||||
//IEnumerator GalleryMode()
|
||||
//{
|
||||
// foreach (var servant in Servants.Entries)
|
||||
// {
|
||||
// yield return FateModelBuilder.Instance.ReplaceServant(servant.id.ToString());
|
||||
// do
|
||||
// {
|
||||
// yield return new WaitForEndOfFrame();
|
||||
// }
|
||||
// while (FateModelBuilder.Instance.LoadingInProgress);
|
||||
// yield return new WaitForEndOfFrame();
|
||||
// Screenshot.GrabFrame(2000, 2000);
|
||||
// yield return new WaitForEndOfFrame();
|
||||
// }
|
||||
//}
|
||||
|
||||
//IEnumerator LoadStage(string id)
|
||||
//{
|
||||
// AssetBundle assetBundle = AssetBundle.LoadFromMemory((Resources.Load(id) as TextAsset).bytes);
|
||||
// List<GameObject> SpawnedGos = new List<GameObject>();
|
||||
// foreach (string name in assetBundle.GetAllAssetNames())
|
||||
// {
|
||||
// //Error.Log(Color.green, name);
|
||||
// object asset = assetBundle.LoadAsset(name);
|
||||
// if (asset == null) { continue; }
|
||||
// else if (asset.GetType() == typeof(GameObject))
|
||||
// {
|
||||
// if (name.EndsWith(".prefab"))
|
||||
// SpawnedGos.Add(Instantiate(asset as GameObject));
|
||||
// }
|
||||
// }
|
||||
// foreach (var go in SpawnedGos)
|
||||
// {
|
||||
// foreach (var rend in go.GetComponentsInChildren<Renderer>())
|
||||
// {
|
||||
// foreach (Material mat in rend.materials)
|
||||
// {
|
||||
// if (mat.name.ToLower().Contains("particle"))
|
||||
// {
|
||||
// mat.shader = Shader.Find("Particles/Standard Unlit");
|
||||
// var tex = mat.mainTexture;
|
||||
// var color = mat.color;
|
||||
// mat.CopyPropertiesFromMaterial(FateModelBuilder.Instance.ParticleMaterial);
|
||||
// mat.mainTexture = tex;
|
||||
// mat.color = color;
|
||||
// }
|
||||
// else
|
||||
// mat.shader = Shader.Find("FateStgShader");
|
||||
// }
|
||||
// }
|
||||
// foreach (var particles in go.GetComponentsInChildren<ParticleSystemRenderer>())
|
||||
// {
|
||||
// particles.sortingOrder = 1000;
|
||||
// }
|
||||
// }
|
||||
// assetBundle.Unload(false);
|
||||
// yield break;
|
||||
//}
|
||||
|
||||
//public void LoadNP()
|
||||
//{
|
||||
// var NP1 = AssetBundle.LoadFromMemory(((TextAsset)Resources.Load("NoblePhantasm/403800")).bytes);
|
||||
// StartCoroutine(FateModelBuilder.Instance.BuildNP(NP1));
|
||||
//}
|
||||
|
||||
//public static string GetDownloadFolder()
|
||||
//{
|
||||
// string[] temp = (Application.persistentDataPath.Replace("Android", "")).Split(new string[] { "//" }, System.StringSplitOptions.None);
|
||||
|
||||
// return (temp[0] + "/Download");
|
||||
//}
|
||||
#endregion
|
||||
}
|
||||
11
Assets/Scripts/FateViewerMain.cs.meta
Normal file
11
Assets/Scripts/FateViewerMain.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: dec20ea0ce00a8e42973c5a4f74e55e2
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
8
Assets/Scripts/HSVPicker.meta
Normal file
8
Assets/Scripts/HSVPicker.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e705b8da674681d43a72563db32ed69c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
5
Assets/Scripts/HSVPicker/Editor.meta
Normal file
5
Assets/Scripts/HSVPicker/Editor.meta
Normal file
@@ -0,0 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2a9e9df3c14e9034eb587348635c8f09
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
userData:
|
||||
65
Assets/Scripts/HSVPicker/Editor/BoxSliderEditor.cs
Normal file
65
Assets/Scripts/HSVPicker/Editor/BoxSliderEditor.cs
Normal file
@@ -0,0 +1,65 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UI;
|
||||
|
||||
namespace HSVPicker.Editors
|
||||
{
|
||||
[CustomEditor(typeof(BoxSlider), true)]
|
||||
[CanEditMultipleObjects]
|
||||
public class BoxSliderEditor : SelectableEditor
|
||||
{
|
||||
|
||||
SerializedProperty m_HandleRect;
|
||||
SerializedProperty m_MinValue;
|
||||
SerializedProperty m_MaxValue;
|
||||
SerializedProperty m_WholeNumbers;
|
||||
SerializedProperty m_Value;
|
||||
SerializedProperty m_ValueY;
|
||||
SerializedProperty m_OnValueChanged;
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
m_HandleRect = serializedObject.FindProperty("m_HandleRect");
|
||||
|
||||
m_MinValue = serializedObject.FindProperty("m_MinValue");
|
||||
m_MaxValue = serializedObject.FindProperty("m_MaxValue");
|
||||
m_WholeNumbers = serializedObject.FindProperty("m_WholeNumbers");
|
||||
m_Value = serializedObject.FindProperty("m_Value");
|
||||
m_ValueY = serializedObject.FindProperty("m_ValueY");
|
||||
m_OnValueChanged = serializedObject.FindProperty("m_OnValueChanged");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
base.OnInspectorGUI();
|
||||
EditorGUILayout.Space();
|
||||
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(m_HandleRect);
|
||||
|
||||
if (m_HandleRect.objectReferenceValue != null)
|
||||
{
|
||||
EditorGUI.BeginChangeCheck();
|
||||
|
||||
|
||||
EditorGUILayout.PropertyField(m_MinValue);
|
||||
EditorGUILayout.PropertyField(m_MaxValue);
|
||||
EditorGUILayout.PropertyField(m_WholeNumbers);
|
||||
EditorGUILayout.Slider(m_Value, m_MinValue.floatValue, m_MaxValue.floatValue);
|
||||
EditorGUILayout.Slider(m_ValueY, m_MinValue.floatValue, m_MaxValue.floatValue);
|
||||
|
||||
// Draw the event notification options
|
||||
EditorGUILayout.Space();
|
||||
EditorGUILayout.PropertyField(m_OnValueChanged);
|
||||
}
|
||||
else
|
||||
{
|
||||
EditorGUILayout.HelpBox("Specify a RectTransform for the slider fill or the slider handle or both. Each must have a parent RectTransform that it can slide within.", MessageType.Info);
|
||||
}
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/Editor/BoxSliderEditor.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/Editor/BoxSliderEditor.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8701e045b26e51f4eb345f2ccb3c13f5
|
||||
timeCreated: 1426804458
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
17
Assets/Scripts/HSVPicker/Editor/HSVPicker.Editors.asmdef
Normal file
17
Assets/Scripts/HSVPicker/Editor/HSVPicker.Editors.asmdef
Normal file
@@ -0,0 +1,17 @@
|
||||
{
|
||||
"name": "HSVPicker.Editors",
|
||||
"references": [
|
||||
"HSVPicker"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 485edc8694d264a8fb6d3a830531425d
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Scripts/HSVPicker/Enums.meta
Normal file
9
Assets/Scripts/HSVPicker/Enums.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5d3904d3d18ddd544820bd8518990fee
|
||||
folderAsset: yes
|
||||
timeCreated: 1442586617
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
13
Assets/Scripts/HSVPicker/Enums/ColorValues.cs
Normal file
13
Assets/Scripts/HSVPicker/Enums/ColorValues.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
|
||||
public enum ColorValues
|
||||
{
|
||||
R,
|
||||
G,
|
||||
B,
|
||||
A,
|
||||
|
||||
Hue,
|
||||
Saturation,
|
||||
Value
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/Enums/ColorValues.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/Enums/ColorValues.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 859a1720e083e504cb68917f781e87c7
|
||||
timeCreated: 1442586608
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Scripts/HSVPicker/Events.meta
Normal file
9
Assets/Scripts/HSVPicker/Events.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bb0d49c64210014e9a24ed9345928c2
|
||||
folderAsset: yes
|
||||
timeCreated: 1442747310
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Scripts/HSVPicker/Events/ColorChangedEvent.cs
Normal file
9
Assets/Scripts/HSVPicker/Events/ColorChangedEvent.cs
Normal file
@@ -0,0 +1,9 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using UnityEngine.Events;
|
||||
|
||||
[Serializable]
|
||||
public class ColorChangedEvent : UnityEvent<Color>
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff46fbecea7739f4690e4285c88f53c5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
6
Assets/Scripts/HSVPicker/Events/HSVChangedEvent.cs
Normal file
6
Assets/Scripts/HSVPicker/Events/HSVChangedEvent.cs
Normal file
@@ -0,0 +1,6 @@
|
||||
using UnityEngine.Events;
|
||||
|
||||
public class HSVChangedEvent : UnityEvent<float, float, float>
|
||||
{
|
||||
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/Events/HSVChangedEvent.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/Events/HSVChangedEvent.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d95ce8fba3dbbf4eb14411412169b88
|
||||
timeCreated: 1442747317
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/Scripts/HSVPicker/HSVPicker.asmdef
Normal file
15
Assets/Scripts/HSVPicker/HSVPicker.asmdef
Normal file
@@ -0,0 +1,15 @@
|
||||
{
|
||||
"name": "HSVPicker",
|
||||
"references": [
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
7
Assets/Scripts/HSVPicker/HSVPicker.asmdef.meta
Normal file
7
Assets/Scripts/HSVPicker/HSVPicker.asmdef.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 413a95a52ca644b7dac76988ad8915af
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9189
Assets/Scripts/HSVPicker/Picker 2.0.prefab
Normal file
9189
Assets/Scripts/HSVPicker/Picker 2.0.prefab
Normal file
File diff suppressed because it is too large
Load Diff
8
Assets/Scripts/HSVPicker/Picker 2.0.prefab.meta
Normal file
8
Assets/Scripts/HSVPicker/Picker 2.0.prefab.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 916ee089a0d7b63419075f91e1c657ec
|
||||
timeCreated: 1442747914
|
||||
licenseType: Free
|
||||
NativeFormatImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/Scripts/HSVPicker/README.txt
Normal file
28
Assets/Scripts/HSVPicker/README.txt
Normal file
@@ -0,0 +1,28 @@
|
||||
HSV color picker using Unity UI.
|
||||
Github https://github.com/judah4/HSV-Color-Picker-Unity
|
||||
|
||||
Usage:
|
||||
Drag picker prefab onto a UI canvas.
|
||||
|
||||
Setup:
|
||||
On the color picker setup section.
|
||||
|
||||
Show Rgb: Show RGB sliders.
|
||||
|
||||
Show Hsv: Show HSV sliders.
|
||||
|
||||
Show Alpha: Show the alpha slider.
|
||||
|
||||
Show Color Box: Show the larger color selection box and color column.
|
||||
|
||||
Show Color Slider Toggle: Show the button to toggle the HSV and RGB sliders.
|
||||
|
||||
Show Header: Options to show the top header with color preview and hex code.
|
||||
* Hide: Hide the top header.
|
||||
* Show Color: Show only the color preview in the header.
|
||||
* Show Color Code: Show only the color code in the header.
|
||||
* Show All: Show the entire top header.
|
||||
|
||||
Color Presets:
|
||||
The prefabs starts with 4 colors in the color presets. This can be updated in the Setup section of the picker prefab.
|
||||
Set the Preset Colors Id for different shared list between color pickers.
|
||||
7
Assets/Scripts/HSVPicker/README.txt.meta
Normal file
7
Assets/Scripts/HSVPicker/README.txt.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 78aa9aa1471451045b0f2f552ad0c361
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Scripts/HSVPicker/UI.meta
Normal file
9
Assets/Scripts/HSVPicker/UI.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b5fe4e314cbd9944bcaa93e814e9bd5
|
||||
folderAsset: yes
|
||||
timeCreated: 1442586536
|
||||
licenseType: Free
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
30
Assets/Scripts/HSVPicker/UI/ColorImage.cs
Normal file
30
Assets/Scripts/HSVPicker/UI/ColorImage.cs
Normal file
@@ -0,0 +1,30 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace HSVPicker
|
||||
{
|
||||
[RequireComponent(typeof(Image))]
|
||||
public class ColorImage : MonoBehaviour
|
||||
{
|
||||
public ColorPicker picker;
|
||||
|
||||
private Image image;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
image = GetComponent<Image>();
|
||||
picker.onValueChanged.AddListener(ColorChanged);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
picker.onValueChanged.RemoveListener(ColorChanged);
|
||||
}
|
||||
|
||||
private void ColorChanged(Color newColor)
|
||||
{
|
||||
image.color = newColor;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/UI/ColorImage.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/UI/ColorImage.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6bca58eb07ad66b498a2f158bcb13225
|
||||
timeCreated: 1442675622
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
92
Assets/Scripts/HSVPicker/UI/ColorLabel.cs
Normal file
92
Assets/Scripts/HSVPicker/UI/ColorLabel.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
|
||||
namespace HSVPicker
|
||||
{
|
||||
|
||||
[RequireComponent(typeof(TMP_Text))]
|
||||
public class ColorLabel : MonoBehaviour
|
||||
{
|
||||
public ColorPicker picker;
|
||||
|
||||
public ColorValues type;
|
||||
|
||||
public string prefix = "R: ";
|
||||
public float minValue = 0;
|
||||
public float maxValue = 255;
|
||||
|
||||
public int precision = 0;
|
||||
|
||||
[SerializeField, HideInInspector]
|
||||
private TMP_Text label;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
label = GetComponent<TMP_Text>();
|
||||
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (Application.isPlaying && picker != null)
|
||||
{
|
||||
picker.onValueChanged.AddListener(ColorChanged);
|
||||
picker.onHSVChanged.AddListener(HSVChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (picker != null)
|
||||
{
|
||||
picker.onValueChanged.RemoveListener(ColorChanged);
|
||||
picker.onHSVChanged.RemoveListener(HSVChanged);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
private void OnValidate()
|
||||
{
|
||||
label = GetComponent<TMP_Text>();
|
||||
UpdateValue();
|
||||
}
|
||||
#endif
|
||||
|
||||
private void ColorChanged(Color color)
|
||||
{
|
||||
UpdateValue();
|
||||
}
|
||||
|
||||
private void HSVChanged(float hue, float sateration, float value)
|
||||
{
|
||||
UpdateValue();
|
||||
}
|
||||
|
||||
private void UpdateValue()
|
||||
{
|
||||
if(label == null)
|
||||
return;
|
||||
|
||||
if (picker == null)
|
||||
{
|
||||
label.text = prefix + "-";
|
||||
}
|
||||
else
|
||||
{
|
||||
float value = minValue + (picker.GetValue(type) * (maxValue - minValue));
|
||||
|
||||
label.text = prefix + ConvertToDisplayString(value);
|
||||
}
|
||||
}
|
||||
|
||||
private string ConvertToDisplayString(float value)
|
||||
{
|
||||
if (precision > 0)
|
||||
return value.ToString("f " + precision);
|
||||
else
|
||||
return Mathf.FloorToInt(value).ToString();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/UI/ColorLabel.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/UI/ColorLabel.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6b10e832a32d2d14facd8a3f489ee8d6
|
||||
timeCreated: 1442587803
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
306
Assets/Scripts/HSVPicker/UI/ColorPicker.cs
Normal file
306
Assets/Scripts/HSVPicker/UI/ColorPicker.cs
Normal file
@@ -0,0 +1,306 @@
|
||||
using UnityEngine;
|
||||
namespace HSVPicker
|
||||
{
|
||||
public class ColorPicker : MonoBehaviour
|
||||
{
|
||||
|
||||
private float _hue = 0;
|
||||
private float _saturation = 0;
|
||||
private float _brightness = 0;
|
||||
|
||||
[SerializeField]
|
||||
private Color _color = Color.red;
|
||||
|
||||
[Header("Setup")]
|
||||
public ColorPickerSetup Setup;
|
||||
|
||||
[Header("Event")]
|
||||
public ColorChangedEvent onValueChanged = new ColorChangedEvent();
|
||||
public HSVChangedEvent onHSVChanged = new HSVChangedEvent();
|
||||
|
||||
public Color CurrentColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return _color;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (CurrentColor == value)
|
||||
return;
|
||||
|
||||
_color = value;
|
||||
|
||||
RGBChanged();
|
||||
|
||||
SendChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
private void Start()
|
||||
{
|
||||
Setup.AlphaSlidiers.Toggle(Setup.ShowAlpha);
|
||||
Setup.ColorToggleElement.Toggle(Setup.ShowColorSliderToggle);
|
||||
Setup.RgbSliders.Toggle(Setup.ShowRgb);
|
||||
Setup.HsvSliders.Toggle(Setup.ShowHsv);
|
||||
Setup.ColorBox.Toggle(Setup.ShowColorBox);
|
||||
|
||||
HandleHeaderSetting(Setup.ShowHeader);
|
||||
UpdateColorToggleText();
|
||||
|
||||
RGBChanged();
|
||||
SendChangedEvent();
|
||||
}
|
||||
|
||||
public float H
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hue;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_hue == value)
|
||||
return;
|
||||
|
||||
_hue = value;
|
||||
|
||||
HSVChanged();
|
||||
|
||||
SendChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
public float S
|
||||
{
|
||||
get
|
||||
{
|
||||
return _saturation;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_saturation == value)
|
||||
return;
|
||||
|
||||
_saturation = value;
|
||||
|
||||
HSVChanged();
|
||||
|
||||
SendChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
public float V
|
||||
{
|
||||
get
|
||||
{
|
||||
return _brightness;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_brightness == value)
|
||||
return;
|
||||
|
||||
_brightness = value;
|
||||
|
||||
HSVChanged();
|
||||
|
||||
SendChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
public float R
|
||||
{
|
||||
get
|
||||
{
|
||||
return _color.r;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_color.r == value)
|
||||
return;
|
||||
|
||||
_color.r = value;
|
||||
|
||||
RGBChanged();
|
||||
|
||||
SendChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
public float G
|
||||
{
|
||||
get
|
||||
{
|
||||
return _color.g;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_color.g == value)
|
||||
return;
|
||||
|
||||
_color.g = value;
|
||||
|
||||
RGBChanged();
|
||||
|
||||
SendChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
public float B
|
||||
{
|
||||
get
|
||||
{
|
||||
return _color.b;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_color.b == value)
|
||||
return;
|
||||
|
||||
_color.b = value;
|
||||
|
||||
RGBChanged();
|
||||
|
||||
SendChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
private float A
|
||||
{
|
||||
get
|
||||
{
|
||||
return _color.a;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (_color.a == value)
|
||||
return;
|
||||
|
||||
_color.a = value;
|
||||
|
||||
SendChangedEvent();
|
||||
}
|
||||
}
|
||||
|
||||
private void RGBChanged()
|
||||
{
|
||||
HsvColor color = HSVUtil.ConvertRgbToHsv(CurrentColor);
|
||||
|
||||
_hue = color.normalizedH;
|
||||
_saturation = color.normalizedS;
|
||||
_brightness = color.normalizedV;
|
||||
}
|
||||
|
||||
private void HSVChanged()
|
||||
{
|
||||
Color color = HSVUtil.ConvertHsvToRgb(_hue * 360, _saturation, _brightness, _color.a);
|
||||
|
||||
_color = color;
|
||||
}
|
||||
|
||||
private void SendChangedEvent()
|
||||
{
|
||||
onValueChanged.Invoke(CurrentColor);
|
||||
onHSVChanged.Invoke(_hue, _saturation, _brightness);
|
||||
}
|
||||
|
||||
public void AssignColor(ColorValues type, float value)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ColorValues.R:
|
||||
R = value;
|
||||
break;
|
||||
case ColorValues.G:
|
||||
G = value;
|
||||
break;
|
||||
case ColorValues.B:
|
||||
B = value;
|
||||
break;
|
||||
case ColorValues.A:
|
||||
A = value;
|
||||
break;
|
||||
case ColorValues.Hue:
|
||||
H = value;
|
||||
break;
|
||||
case ColorValues.Saturation:
|
||||
S = value;
|
||||
break;
|
||||
case ColorValues.Value:
|
||||
V = value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public void AssignColor(Color color)
|
||||
{
|
||||
CurrentColor = color;
|
||||
}
|
||||
|
||||
public float GetValue(ColorValues type)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ColorValues.R:
|
||||
return R;
|
||||
case ColorValues.G:
|
||||
return G;
|
||||
case ColorValues.B:
|
||||
return B;
|
||||
case ColorValues.A:
|
||||
return A;
|
||||
case ColorValues.Hue:
|
||||
return H;
|
||||
case ColorValues.Saturation:
|
||||
return S;
|
||||
case ColorValues.Value:
|
||||
return V;
|
||||
default:
|
||||
throw new System.NotImplementedException("");
|
||||
}
|
||||
}
|
||||
|
||||
public void ToggleColorSliders()
|
||||
{
|
||||
Setup.ShowHsv = !Setup.ShowHsv;
|
||||
Setup.ShowRgb = !Setup.ShowRgb;
|
||||
Setup.HsvSliders.Toggle(Setup.ShowHsv);
|
||||
Setup.RgbSliders.Toggle(Setup.ShowRgb);
|
||||
|
||||
|
||||
UpdateColorToggleText();
|
||||
}
|
||||
|
||||
void UpdateColorToggleText()
|
||||
{
|
||||
if (Setup.ShowRgb)
|
||||
{
|
||||
Setup.SliderToggleButtonText.text = "RGB";
|
||||
}
|
||||
|
||||
if (Setup.ShowHsv)
|
||||
{
|
||||
Setup.SliderToggleButtonText.text = "HSV";
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleHeaderSetting(ColorPickerSetup.ColorHeaderShowing setupShowHeader)
|
||||
{
|
||||
if (setupShowHeader == ColorPickerSetup.ColorHeaderShowing.Hide)
|
||||
{
|
||||
Setup.ColorHeader.Toggle(false);
|
||||
return;
|
||||
}
|
||||
|
||||
Setup.ColorHeader.Toggle(true);
|
||||
|
||||
Setup.ColorPreview.Toggle(setupShowHeader != ColorPickerSetup.ColorHeaderShowing.ShowColorCode);
|
||||
Setup.ColorCode.Toggle(setupShowHeader != ColorPickerSetup.ColorHeaderShowing.ShowColor);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
8
Assets/Scripts/HSVPicker/UI/ColorPicker.cs.meta
Normal file
8
Assets/Scripts/HSVPicker/UI/ColorPicker.cs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8262e4a8322117f4da079921eaa72834
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
58
Assets/Scripts/HSVPicker/UI/ColorPickerSetup.cs
Normal file
58
Assets/Scripts/HSVPicker/UI/ColorPickerSetup.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
|
||||
using UnityEngine;
|
||||
using TMPro;
|
||||
|
||||
namespace HSVPicker
|
||||
{
|
||||
[System.Serializable]
|
||||
public class ColorPickerSetup
|
||||
{
|
||||
public enum ColorHeaderShowing
|
||||
{
|
||||
Hide,
|
||||
ShowColor,
|
||||
ShowColorCode,
|
||||
ShowAll,
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class UiElements
|
||||
{
|
||||
public RectTransform[] Elements;
|
||||
|
||||
|
||||
public void Toggle(bool active)
|
||||
{
|
||||
for (int cnt = 0; cnt < Elements.Length; cnt++)
|
||||
{
|
||||
Elements[cnt].gameObject.SetActive(active);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public bool ShowRgb = true;
|
||||
public bool ShowHsv;
|
||||
public bool ShowAlpha = true;
|
||||
public bool ShowColorBox = true;
|
||||
public bool ShowColorSliderToggle = true;
|
||||
|
||||
public ColorHeaderShowing ShowHeader = ColorHeaderShowing.ShowAll;
|
||||
|
||||
public UiElements RgbSliders;
|
||||
public UiElements HsvSliders;
|
||||
public UiElements ColorToggleElement;
|
||||
public UiElements AlphaSlidiers;
|
||||
|
||||
|
||||
public UiElements ColorHeader;
|
||||
public UiElements ColorCode;
|
||||
public UiElements ColorPreview;
|
||||
|
||||
public UiElements ColorBox;
|
||||
public TMP_Text SliderToggleButtonText;
|
||||
|
||||
public string PresetColorsId = "default";
|
||||
public Color[] DefaultPresetColors;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/HSVPicker/UI/ColorPickerSetup.cs.meta
Normal file
11
Assets/Scripts/HSVPicker/UI/ColorPickerSetup.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f1e0a31fe4cdb5458d5a88aa1268434
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
67
Assets/Scripts/HSVPicker/UI/ColorPresetManager.cs
Normal file
67
Assets/Scripts/HSVPicker/UI/ColorPresetManager.cs
Normal file
@@ -0,0 +1,67 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
|
||||
namespace HSVPicker
|
||||
{
|
||||
public static class ColorPresetManager
|
||||
{
|
||||
private static Dictionary<string, ColorPresetList> _presets = new Dictionary<string, ColorPresetList>();
|
||||
|
||||
public static ColorPresetList Get(string listId = "default")
|
||||
{
|
||||
ColorPresetList preset;
|
||||
if (!_presets.TryGetValue(listId, out preset))
|
||||
{
|
||||
preset = new ColorPresetList(listId);
|
||||
_presets.Add(listId, preset);
|
||||
}
|
||||
|
||||
return preset;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
public class ColorPresetList
|
||||
{
|
||||
public string ListId { get; private set; }
|
||||
public List<Color> Colors { get; private set; }
|
||||
|
||||
public event UnityAction<List<Color>> OnColorsUpdated;
|
||||
|
||||
public ColorPresetList(string listId, List<Color> colors = null)
|
||||
{
|
||||
if (colors == null)
|
||||
{
|
||||
colors = new List<Color>();
|
||||
}
|
||||
|
||||
Colors = colors;
|
||||
ListId = listId;
|
||||
}
|
||||
|
||||
public void AddColor(Color color)
|
||||
{
|
||||
Colors.Add(color);
|
||||
if (OnColorsUpdated != null)
|
||||
{
|
||||
OnColorsUpdated.Invoke(Colors);
|
||||
}
|
||||
}
|
||||
|
||||
public void UpdateList(IEnumerable<Color> colors)
|
||||
{
|
||||
Colors.Clear();
|
||||
Colors.AddRange(colors);
|
||||
|
||||
if (OnColorsUpdated != null)
|
||||
{
|
||||
OnColorsUpdated.Invoke(Colors);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/HSVPicker/UI/ColorPresetManager.cs.meta
Normal file
11
Assets/Scripts/HSVPicker/UI/ColorPresetManager.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 55b59bed8e892614e9397d8a20e36e0c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
86
Assets/Scripts/HSVPicker/UI/ColorPresets.cs
Normal file
86
Assets/Scripts/HSVPicker/UI/ColorPresets.cs
Normal file
@@ -0,0 +1,86 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace HSVPicker
|
||||
{
|
||||
public class ColorPresets : MonoBehaviour
|
||||
{
|
||||
public ColorPicker picker;
|
||||
public GameObject[] presets;
|
||||
public Image createPresetImage;
|
||||
|
||||
private ColorPresetList _colors;
|
||||
|
||||
void Awake()
|
||||
{
|
||||
// picker.onHSVChanged.AddListener(HSVChanged);
|
||||
picker.onValueChanged.AddListener(ColorChanged);
|
||||
}
|
||||
|
||||
void Start()
|
||||
{
|
||||
_colors = ColorPresetManager.Get(picker.Setup.PresetColorsId);
|
||||
|
||||
if (_colors.Colors.Count < picker.Setup.DefaultPresetColors.Length)
|
||||
{
|
||||
_colors.UpdateList(picker.Setup.DefaultPresetColors);
|
||||
}
|
||||
|
||||
_colors.OnColorsUpdated += OnColorsUpdate;
|
||||
OnColorsUpdate(_colors.Colors);
|
||||
}
|
||||
|
||||
private void OnColorsUpdate(List<Color> colors)
|
||||
{
|
||||
for (int cnt = 0; cnt < presets.Length; cnt++)
|
||||
{
|
||||
if (colors.Count <= cnt)
|
||||
{
|
||||
presets[cnt].SetActive(false);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
presets[cnt].SetActive(true);
|
||||
presets[cnt].GetComponent<Image>().color = colors[cnt];
|
||||
|
||||
}
|
||||
|
||||
createPresetImage.gameObject.SetActive(colors.Count < presets.Length);
|
||||
|
||||
}
|
||||
|
||||
public void CreatePresetButton()
|
||||
{
|
||||
_colors.AddColor(picker.CurrentColor);
|
||||
|
||||
// for (var i = 0; i < presets.Length; i++)
|
||||
//{
|
||||
// if (!presets[i].activeSelf)
|
||||
// {
|
||||
// presets[i].SetActive(true);
|
||||
// presets[i].GetComponent<Image>().color = picker.CurrentColor;
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
}
|
||||
|
||||
public void PresetSelect(Image sender)
|
||||
{
|
||||
picker.CurrentColor = sender.color;
|
||||
}
|
||||
|
||||
// Not working, it seems ConvertHsvToRgb() is broken. It doesn't work when fed
|
||||
// input h, s, v as shown below.
|
||||
// private void HSVChanged(float h, float s, float v)
|
||||
// {
|
||||
// createPresetImage.color = HSVUtil.ConvertHsvToRgb(h, s, v, 1);
|
||||
// }
|
||||
private void ColorChanged(Color color)
|
||||
{
|
||||
createPresetImage.color = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/UI/ColorPresets.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/UI/ColorPresets.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0923373e76e77402c9c53a2f1250ad3e
|
||||
timeCreated: 1456875791
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
92
Assets/Scripts/HSVPicker/UI/ColorSlider.cs
Normal file
92
Assets/Scripts/HSVPicker/UI/ColorSlider.cs
Normal file
@@ -0,0 +1,92 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
namespace HSVPicker
|
||||
{
|
||||
/// <summary>
|
||||
/// Displays one of the color values of aColorPicker
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(Slider))]
|
||||
public class ColorSlider : MonoBehaviour
|
||||
{
|
||||
public ColorPicker hsvpicker;
|
||||
|
||||
/// <summary>
|
||||
/// Which value this slider can edit.
|
||||
/// </summary>
|
||||
public ColorValues type;
|
||||
|
||||
private Slider slider;
|
||||
|
||||
private bool listen = true;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
slider = GetComponent<Slider>();
|
||||
|
||||
hsvpicker.onValueChanged.AddListener(ColorChanged);
|
||||
hsvpicker.onHSVChanged.AddListener(HSVChanged);
|
||||
slider.onValueChanged.AddListener(SliderChanged);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
hsvpicker.onValueChanged.RemoveListener(ColorChanged);
|
||||
hsvpicker.onHSVChanged.RemoveListener(HSVChanged);
|
||||
slider.onValueChanged.RemoveListener(SliderChanged);
|
||||
}
|
||||
|
||||
private void ColorChanged(Color newColor)
|
||||
{
|
||||
listen = false;
|
||||
switch (type)
|
||||
{
|
||||
case ColorValues.R:
|
||||
slider.normalizedValue = newColor.r;
|
||||
break;
|
||||
case ColorValues.G:
|
||||
slider.normalizedValue = newColor.g;
|
||||
break;
|
||||
case ColorValues.B:
|
||||
slider.normalizedValue = newColor.b;
|
||||
break;
|
||||
case ColorValues.A:
|
||||
slider.normalizedValue = newColor.a;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HSVChanged(float hue, float saturation, float value)
|
||||
{
|
||||
listen = false;
|
||||
switch (type)
|
||||
{
|
||||
case ColorValues.Hue:
|
||||
slider.normalizedValue = hue; //1 - hue;
|
||||
break;
|
||||
case ColorValues.Saturation:
|
||||
slider.normalizedValue = saturation;
|
||||
break;
|
||||
case ColorValues.Value:
|
||||
slider.normalizedValue = value;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void SliderChanged(float newValue)
|
||||
{
|
||||
if (listen)
|
||||
{
|
||||
newValue = slider.normalizedValue;
|
||||
//if (type == ColorValues.Hue)
|
||||
// newValue = 1 - newValue;
|
||||
|
||||
hsvpicker.AssignColor(type, newValue);
|
||||
}
|
||||
listen = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/UI/ColorSlider.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/UI/ColorSlider.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c600592efa0cf25479655321bf4fb08a
|
||||
timeCreated: 1442586558
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
206
Assets/Scripts/HSVPicker/UI/ColorSliderImage.cs
Normal file
206
Assets/Scripts/HSVPicker/UI/ColorSliderImage.cs
Normal file
@@ -0,0 +1,206 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
namespace HSVPicker
|
||||
{
|
||||
[RequireComponent(typeof(RawImage)), ExecuteInEditMode()]
|
||||
public class ColorSliderImage : MonoBehaviour
|
||||
{
|
||||
public ColorPicker picker;
|
||||
|
||||
/// <summary>
|
||||
/// Which value this slider can edit.
|
||||
/// </summary>
|
||||
public ColorValues type;
|
||||
|
||||
public Slider.Direction direction;
|
||||
|
||||
private RawImage image;
|
||||
|
||||
private RectTransform rectTransform
|
||||
{
|
||||
get
|
||||
{
|
||||
return transform as RectTransform;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
image = GetComponent<RawImage>();
|
||||
|
||||
if(Application.isPlaying)
|
||||
RegenerateTexture();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (picker != null && Application.isPlaying)
|
||||
{
|
||||
picker.onValueChanged.AddListener(ColorChanged);
|
||||
picker.onHSVChanged.AddListener(HSVChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (picker != null)
|
||||
{
|
||||
picker.onValueChanged.RemoveListener(ColorChanged);
|
||||
picker.onHSVChanged.RemoveListener(HSVChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (image.texture != null)
|
||||
DestroyImmediate(image.texture);
|
||||
}
|
||||
|
||||
private void ColorChanged(Color newColor)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ColorValues.R:
|
||||
case ColorValues.G:
|
||||
case ColorValues.B:
|
||||
case ColorValues.Saturation:
|
||||
case ColorValues.Value:
|
||||
RegenerateTexture();
|
||||
break;
|
||||
case ColorValues.A:
|
||||
case ColorValues.Hue:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HSVChanged(float hue, float saturation, float value)
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case ColorValues.R:
|
||||
case ColorValues.G:
|
||||
case ColorValues.B:
|
||||
case ColorValues.Saturation:
|
||||
case ColorValues.Value:
|
||||
RegenerateTexture();
|
||||
break;
|
||||
case ColorValues.A:
|
||||
case ColorValues.Hue:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegenerateTexture()
|
||||
{
|
||||
Color32 baseColor = picker != null ? picker.CurrentColor : Color.black;
|
||||
|
||||
float h = picker != null ? picker.H : 0;
|
||||
float s = picker != null ? picker.S : 0;
|
||||
float v = picker != null ? picker.V : 0;
|
||||
|
||||
Texture2D texture;
|
||||
Color32[] colors;
|
||||
|
||||
bool vertical = direction == Slider.Direction.BottomToTop || direction == Slider.Direction.TopToBottom;
|
||||
bool inverted = direction == Slider.Direction.TopToBottom || direction == Slider.Direction.RightToLeft;
|
||||
|
||||
int size;
|
||||
switch (type)
|
||||
{
|
||||
case ColorValues.R:
|
||||
case ColorValues.G:
|
||||
case ColorValues.B:
|
||||
case ColorValues.A:
|
||||
size = 255;
|
||||
break;
|
||||
case ColorValues.Hue:
|
||||
size = 360;
|
||||
break;
|
||||
case ColorValues.Saturation:
|
||||
case ColorValues.Value:
|
||||
size = 100;
|
||||
break;
|
||||
default:
|
||||
throw new System.NotImplementedException("");
|
||||
}
|
||||
if (vertical)
|
||||
texture = new Texture2D(1, size);
|
||||
else
|
||||
texture = new Texture2D(size, 1);
|
||||
|
||||
texture.hideFlags = HideFlags.DontSave;
|
||||
colors = new Color32[size];
|
||||
|
||||
switch (type)
|
||||
{
|
||||
case ColorValues.R:
|
||||
for (byte i = 0; i < size; i++)
|
||||
{
|
||||
colors[inverted ? size - 1 - i : i] = new Color32(i, baseColor.g, baseColor.b, 255);
|
||||
}
|
||||
break;
|
||||
case ColorValues.G:
|
||||
for (byte i = 0; i < size; i++)
|
||||
{
|
||||
colors[inverted ? size - 1 - i : i] = new Color32(baseColor.r, i, baseColor.b, 255);
|
||||
}
|
||||
break;
|
||||
case ColorValues.B:
|
||||
for (byte i = 0; i < size; i++)
|
||||
{
|
||||
colors[inverted ? size - 1 - i : i] = new Color32(baseColor.r, baseColor.g, i, 255);
|
||||
}
|
||||
break;
|
||||
case ColorValues.A:
|
||||
for (byte i = 0; i < size; i++)
|
||||
{
|
||||
colors[inverted ? size - 1 - i : i] = new Color32(i, i, i, 255);
|
||||
}
|
||||
break;
|
||||
case ColorValues.Hue:
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(i, 1, 1, 1);
|
||||
}
|
||||
break;
|
||||
case ColorValues.Saturation:
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(h * 360, (float)i / size, v, 1);
|
||||
}
|
||||
break;
|
||||
case ColorValues.Value:
|
||||
for (int i = 0; i < size; i++)
|
||||
{
|
||||
colors[inverted ? size - 1 - i : i] = HSVUtil.ConvertHsvToRgb(h * 360, s, (float)i / size, 1);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new System.NotImplementedException("");
|
||||
}
|
||||
texture.SetPixels32(colors);
|
||||
texture.Apply();
|
||||
|
||||
if (image.texture != null)
|
||||
DestroyImmediate(image.texture);
|
||||
image.texture = texture;
|
||||
|
||||
switch (direction)
|
||||
{
|
||||
case Slider.Direction.BottomToTop:
|
||||
case Slider.Direction.TopToBottom:
|
||||
image.uvRect = new Rect(0, 0, 2, 1);
|
||||
break;
|
||||
case Slider.Direction.LeftToRight:
|
||||
case Slider.Direction.RightToLeft:
|
||||
image.uvRect = new Rect(0, 0, 1, 2);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/UI/ColorSliderImage.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/UI/ColorSliderImage.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7ca76dd9ad6eb204c9b0481aece34497
|
||||
timeCreated: 1442682013
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
53
Assets/Scripts/HSVPicker/UI/HexColorField.cs
Normal file
53
Assets/Scripts/HSVPicker/UI/HexColorField.cs
Normal file
@@ -0,0 +1,53 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using TMPro;
|
||||
namespace HSVPicker
|
||||
{
|
||||
[RequireComponent(typeof(TMP_InputField))]
|
||||
public class HexColorField : MonoBehaviour
|
||||
{
|
||||
public ColorPicker hsvpicker;
|
||||
|
||||
public bool displayAlpha;
|
||||
|
||||
private TMP_InputField hexInputField;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
hexInputField = GetComponent<TMP_InputField>();
|
||||
|
||||
// Add listeners to keep text (and color) up to date
|
||||
hexInputField.onEndEdit.AddListener(UpdateColor);
|
||||
hsvpicker.onValueChanged.AddListener(UpdateHex);
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
hexInputField.onValueChanged.RemoveListener(UpdateColor);
|
||||
hsvpicker.onValueChanged.RemoveListener(UpdateHex);
|
||||
}
|
||||
|
||||
private void UpdateHex(Color newColor)
|
||||
{
|
||||
hexInputField.text = ColorToHex(newColor);
|
||||
}
|
||||
|
||||
private void UpdateColor(string newHex)
|
||||
{
|
||||
Color color;
|
||||
if (!newHex.StartsWith("#"))
|
||||
newHex = "#"+newHex;
|
||||
if (ColorUtility.TryParseHtmlString(newHex, out color))
|
||||
hsvpicker.CurrentColor = color;
|
||||
else
|
||||
Debug.Log("hex value is in the wrong format, valid formats are: #RGB, #RGBA, #RRGGBB and #RRGGBBAA (# is optional)");
|
||||
}
|
||||
|
||||
private string ColorToHex(Color32 color)
|
||||
{
|
||||
return displayAlpha
|
||||
? string.Format("#{0:X2}{1:X2}{2:X2}{3:X2}", color.r, color.g, color.b, color.a)
|
||||
: string.Format("#{0:X2}{1:X2}{2:X2}", color.r, color.g, color.b);
|
||||
}
|
||||
}
|
||||
}
|
||||
8
Assets/Scripts/HSVPicker/UI/HexColorField.cs.meta
Normal file
8
Assets/Scripts/HSVPicker/UI/HexColorField.cs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d85c534b3c1560544b09d0996dfeba84
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
121
Assets/Scripts/HSVPicker/UI/SVBoxSlider.cs
Normal file
121
Assets/Scripts/HSVPicker/UI/SVBoxSlider.cs
Normal file
@@ -0,0 +1,121 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace HSVPicker
|
||||
{
|
||||
[RequireComponent(typeof(BoxSlider), typeof(RawImage)), ExecuteInEditMode()]
|
||||
public class SVBoxSlider : MonoBehaviour
|
||||
{
|
||||
public ColorPicker picker;
|
||||
|
||||
private BoxSlider slider;
|
||||
private RawImage image;
|
||||
|
||||
private int textureWidth = 128;
|
||||
private int textureHeight = 128;
|
||||
|
||||
private float lastH = -1;
|
||||
private bool listen = true;
|
||||
|
||||
public RectTransform rectTransform
|
||||
{
|
||||
get
|
||||
{
|
||||
return transform as RectTransform;
|
||||
}
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
slider = GetComponent<BoxSlider>();
|
||||
image = GetComponent<RawImage>();
|
||||
if(Application.isPlaying)
|
||||
{
|
||||
RegenerateSVTexture ();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (Application.isPlaying && picker != null)
|
||||
{
|
||||
slider.onValueChanged.AddListener(SliderChanged);
|
||||
picker.onHSVChanged.AddListener(HSVChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
if (picker != null)
|
||||
{
|
||||
slider.onValueChanged.RemoveListener(SliderChanged);
|
||||
picker.onHSVChanged.RemoveListener(HSVChanged);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if ( image.texture != null )
|
||||
{
|
||||
DestroyImmediate (image.texture);
|
||||
}
|
||||
}
|
||||
|
||||
private void SliderChanged(float saturation, float value)
|
||||
{
|
||||
if (listen)
|
||||
{
|
||||
picker.AssignColor(ColorValues.Saturation, saturation);
|
||||
picker.AssignColor(ColorValues.Value, value);
|
||||
}
|
||||
listen = true;
|
||||
}
|
||||
|
||||
private void HSVChanged(float h, float s, float v)
|
||||
{
|
||||
if (!lastH.Equals(h))
|
||||
{
|
||||
lastH = h;
|
||||
RegenerateSVTexture();
|
||||
}
|
||||
|
||||
if (!s.Equals(slider.normalizedValue))
|
||||
{
|
||||
listen = false;
|
||||
slider.normalizedValue = s;
|
||||
}
|
||||
|
||||
if (!v.Equals(slider.normalizedValueY))
|
||||
{
|
||||
listen = false;
|
||||
slider.normalizedValueY = v;
|
||||
}
|
||||
}
|
||||
|
||||
private void RegenerateSVTexture()
|
||||
{
|
||||
double h = picker != null ? picker.H * 360 : 0;
|
||||
|
||||
if ( image.texture != null )
|
||||
DestroyImmediate (image.texture);
|
||||
|
||||
var texture = new Texture2D (textureWidth, textureHeight);
|
||||
texture.wrapMode = TextureWrapMode.Clamp;
|
||||
texture.hideFlags = HideFlags.DontSave;
|
||||
|
||||
for ( int s = 0; s < textureWidth; s++ )
|
||||
{
|
||||
Color[] colors = new Color[textureHeight];
|
||||
for ( int v = 0; v < textureHeight; v++ )
|
||||
{
|
||||
colors[v] = HSVUtil.ConvertHsvToRgb (h, (float)s / textureWidth, (float)v / textureHeight, 1);
|
||||
}
|
||||
texture.SetPixels (s, 0, 1, textureHeight, colors);
|
||||
}
|
||||
texture.Apply();
|
||||
|
||||
image.texture = texture;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Assets/Scripts/HSVPicker/UI/SVBoxSlider.cs.meta
Normal file
12
Assets/Scripts/HSVPicker/UI/SVBoxSlider.cs.meta
Normal file
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1e4240873631f724496efec97d7151b3
|
||||
timeCreated: 1442650713
|
||||
licenseType: Free
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Scripts/HSVPicker/UtilityScripts.meta
Normal file
9
Assets/Scripts/HSVPicker/UtilityScripts.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2b33138f525222146865861432dbe845
|
||||
folderAsset: yes
|
||||
timeCreated: 1426051345
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
448
Assets/Scripts/HSVPicker/UtilityScripts/BoxSlider.cs
Normal file
448
Assets/Scripts/HSVPicker/UtilityScripts/BoxSlider.cs
Normal file
@@ -0,0 +1,448 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Events;
|
||||
using UnityEngine.EventSystems;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace HSVPicker
|
||||
{
|
||||
[AddComponentMenu("UI/BoxSlider", 35)]
|
||||
[RequireComponent(typeof(RectTransform))]
|
||||
public class BoxSlider : Selectable, IDragHandler, IInitializePotentialDragHandler, ICanvasElement
|
||||
{
|
||||
public enum Direction
|
||||
{
|
||||
LeftToRight,
|
||||
RightToLeft,
|
||||
BottomToTop,
|
||||
TopToBottom,
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class BoxSliderEvent : UnityEvent<float, float> { }
|
||||
|
||||
[SerializeField]
|
||||
private RectTransform m_HandleRect;
|
||||
public RectTransform handleRect { get { return m_HandleRect; } set { if (SetClass(ref m_HandleRect, value)) { UpdateCachedReferences(); UpdateVisuals(); } } }
|
||||
|
||||
[Space(6)]
|
||||
|
||||
[SerializeField]
|
||||
private float m_MinValue = 0;
|
||||
public float minValue { get { return m_MinValue; } set { if (SetStruct(ref m_MinValue, value)) { Set(m_Value); SetY (m_ValueY); UpdateVisuals(); } } }
|
||||
|
||||
[SerializeField]
|
||||
private float m_MaxValue = 1;
|
||||
public float maxValue { get { return m_MaxValue; } set { if (SetStruct(ref m_MaxValue, value)) { Set(m_Value); SetY (m_ValueY); UpdateVisuals(); } } }
|
||||
|
||||
[SerializeField]
|
||||
private bool m_WholeNumbers = false;
|
||||
public bool wholeNumbers { get { return m_WholeNumbers; } set { if (SetStruct(ref m_WholeNumbers, value)) { Set(m_Value); SetY (m_ValueY); UpdateVisuals(); } } }
|
||||
|
||||
[SerializeField]
|
||||
private float m_Value = 1f;
|
||||
public float value
|
||||
{
|
||||
get
|
||||
{
|
||||
if (wholeNumbers)
|
||||
return Mathf.Round(m_Value);
|
||||
return m_Value;
|
||||
}
|
||||
set
|
||||
{
|
||||
Set(value);
|
||||
}
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float m_ValueY = 1f;
|
||||
public float valueY
|
||||
{
|
||||
get
|
||||
{
|
||||
if (wholeNumbers)
|
||||
return Mathf.Round(m_ValueY);
|
||||
return m_ValueY;
|
||||
}
|
||||
set
|
||||
{
|
||||
SetY(value);
|
||||
}
|
||||
}
|
||||
|
||||
public float normalizedValueY
|
||||
{
|
||||
get
|
||||
{
|
||||
if (Mathf.Approximately(minValue, maxValue))
|
||||
return 0;
|
||||
return Mathf.InverseLerp(minValue, maxValue, valueY);
|
||||
}
|
||||
set
|
||||
{
|
||||
this.valueY = Mathf.Lerp(minValue, maxValue, value);
|
||||
}
|
||||
}
|
||||
|
||||
[Space(6)]
|
||||
|
||||
// Allow for delegate-based subscriptions for faster events than 'eventReceiver', and allowing for multiple receivers.
|
||||
[SerializeField]
|
||||
private BoxSliderEvent m_OnValueChanged = new BoxSliderEvent();
|
||||
public BoxSliderEvent onValueChanged { get { return m_OnValueChanged; } set { m_OnValueChanged = 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;
|
||||
|
||||
private DrivenRectTransformTracker m_Tracker;
|
||||
|
||||
// Size of each step.
|
||||
float stepSize { get { return wholeNumbers ? 1 : (maxValue - minValue) * 0.1f; } }
|
||||
|
||||
protected BoxSlider()
|
||||
{ }
|
||||
|
||||
#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();
|
||||
Set(m_Value, false);
|
||||
SetY(m_ValueY, false);
|
||||
// Update rects since other things might affect them even if value didn't change.
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
#if UNITY_2018_3_OR_NEWER
|
||||
|
||||
if (!UnityEditor.PrefabUtility.IsPartOfPrefabAsset(this) && !Application.isPlaying)
|
||||
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
|
||||
|
||||
#else
|
||||
|
||||
var prefabType = UnityEditor.PrefabUtility.GetPrefabType(this);
|
||||
if (prefabType != UnityEditor.PrefabType.Prefab && !Application.isPlaying)
|
||||
CanvasUpdateRegistry.RegisterCanvasElementForLayoutRebuild(this);
|
||||
#endif
|
||||
}
|
||||
#endif // if UNITY_EDITOR
|
||||
|
||||
public virtual void Rebuild(CanvasUpdate executing)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (executing == CanvasUpdate.Prelayout)
|
||||
onValueChanged.Invoke(value, valueY);
|
||||
#endif
|
||||
}
|
||||
|
||||
public void LayoutComplete()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void GraphicUpdateComplete()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
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 bool SetStruct<T>(ref T currentValue, T newValue) where T: struct
|
||||
{
|
||||
if (currentValue.Equals(newValue))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
UpdateCachedReferences();
|
||||
Set(m_Value, false);
|
||||
SetY(m_ValueY, false);
|
||||
// Update rects since they need to be initialized correctly.
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
m_Tracker.Clear();
|
||||
base.OnDisable();
|
||||
}
|
||||
|
||||
void UpdateCachedReferences()
|
||||
{
|
||||
|
||||
if (m_HandleRect)
|
||||
{
|
||||
m_HandleTransform = m_HandleRect.transform;
|
||||
if (m_HandleTransform.parent != null)
|
||||
m_HandleContainerRect = m_HandleTransform.parent.GetComponent<RectTransform>();
|
||||
}
|
||||
else
|
||||
{
|
||||
m_HandleContainerRect = null;
|
||||
}
|
||||
}
|
||||
|
||||
// Set the valueUpdate the visible Image.
|
||||
void Set(float input)
|
||||
{
|
||||
Set(input, true);
|
||||
}
|
||||
|
||||
void Set(float input, bool sendCallback)
|
||||
{
|
||||
// Clamp the input
|
||||
float newValue = Mathf.Clamp(input, minValue, maxValue);
|
||||
if (wholeNumbers)
|
||||
newValue = Mathf.Round(newValue);
|
||||
|
||||
// If the stepped value doesn't match the last one, it's time to update
|
||||
if (m_Value.Equals(newValue))
|
||||
return;
|
||||
|
||||
m_Value = newValue;
|
||||
UpdateVisuals();
|
||||
if (sendCallback)
|
||||
m_OnValueChanged.Invoke(newValue, valueY);
|
||||
}
|
||||
|
||||
void SetY(float input)
|
||||
{
|
||||
SetY(input, true);
|
||||
}
|
||||
|
||||
void SetY(float input, bool sendCallback)
|
||||
{
|
||||
// Clamp the input
|
||||
float newValue = Mathf.Clamp(input, minValue, maxValue);
|
||||
if (wholeNumbers)
|
||||
newValue = Mathf.Round(newValue);
|
||||
|
||||
// If the stepped value doesn't match the last one, it's time to update
|
||||
if (m_ValueY.Equals(newValue))
|
||||
return;
|
||||
|
||||
m_ValueY = newValue;
|
||||
UpdateVisuals();
|
||||
if (sendCallback)
|
||||
m_OnValueChanged.Invoke(value, newValue);
|
||||
}
|
||||
|
||||
|
||||
protected override void OnRectTransformDimensionsChange()
|
||||
{
|
||||
base.OnRectTransformDimensionsChange();
|
||||
UpdateVisuals();
|
||||
}
|
||||
|
||||
enum Axis
|
||||
{
|
||||
Horizontal = 0,
|
||||
Vertical = 1
|
||||
}
|
||||
|
||||
|
||||
// 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();
|
||||
|
||||
|
||||
//to business!
|
||||
if (m_HandleContainerRect != null)
|
||||
{
|
||||
m_Tracker.Add(this, m_HandleRect, DrivenTransformProperties.Anchors);
|
||||
Vector2 anchorMin = Vector2.zero;
|
||||
Vector2 anchorMax = Vector2.one;
|
||||
anchorMin[0] = anchorMax[0] = (normalizedValue);
|
||||
anchorMin[1] = anchorMax[1] = ( normalizedValueY);
|
||||
|
||||
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;
|
||||
if (clickRect != null && clickRect.rect.size[0] > 0)
|
||||
{
|
||||
Vector2 localCursor;
|
||||
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(clickRect, eventData.position, cam, out localCursor))
|
||||
return;
|
||||
localCursor -= clickRect.rect.position;
|
||||
|
||||
float val = Mathf.Clamp01((localCursor - m_Offset)[0] / clickRect.rect.size[0]);
|
||||
normalizedValue = (val);
|
||||
|
||||
float valY = Mathf.Clamp01((localCursor - m_Offset)[1] / clickRect.rect.size[1]);
|
||||
normalizedValueY = ( valY);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
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.position, eventData.enterEventCamera))
|
||||
{
|
||||
Vector2 localMousePos;
|
||||
if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_HandleRect, eventData.position, eventData.pressEventCamera, out localMousePos))
|
||||
m_Offset = localMousePos;
|
||||
m_Offset.y = -m_Offset.y;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Outside the slider handle - jump to this point instead
|
||||
UpdateDrag(eventData, eventData.pressEventCamera);
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void OnDrag(PointerEventData eventData)
|
||||
{
|
||||
if (!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);
|
||||
// SetY (reverseValue ? valueY + stepSize : valueY - stepSize);
|
||||
// }
|
||||
// else
|
||||
// base.OnMove(eventData);
|
||||
// break;
|
||||
// case MoveDirection.Right:
|
||||
// if (axis == Axis.Horizontal && FindSelectableOnRight() == null) {
|
||||
// Set(reverseValue ? value - stepSize : value + stepSize);
|
||||
// SetY(reverseValue ? valueY - stepSize : valueY + stepSize);
|
||||
// }
|
||||
// else
|
||||
// base.OnMove(eventData);
|
||||
// break;
|
||||
// case MoveDirection.Up:
|
||||
// if (axis == Axis.Vertical && FindSelectableOnUp() == null) {
|
||||
// Set(reverseValue ? value - stepSize : value + stepSize);
|
||||
// SetY(reverseValue ? valueY - stepSize : valueY + stepSize);
|
||||
// }
|
||||
// else
|
||||
// base.OnMove(eventData);
|
||||
// break;
|
||||
// case MoveDirection.Down:
|
||||
// if (axis == Axis.Vertical && FindSelectableOnDown() == null) {
|
||||
// Set(reverseValue ? value + stepSize : value - stepSize);
|
||||
// SetY(reverseValue ? valueY + stepSize : valueY - stepSize);
|
||||
// }
|
||||
// else
|
||||
// base.OnMove(eventData);
|
||||
// break;
|
||||
// }
|
||||
//}
|
||||
|
||||
//public override Selectable FindSelectableOnLeft()
|
||||
//{
|
||||
// if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
|
||||
// return null;
|
||||
// return base.FindSelectableOnLeft();
|
||||
//}
|
||||
|
||||
//public override Selectable FindSelectableOnRight()
|
||||
//{
|
||||
// if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Horizontal)
|
||||
// return null;
|
||||
// return base.FindSelectableOnRight();
|
||||
//}
|
||||
|
||||
//public override Selectable FindSelectableOnUp()
|
||||
//{
|
||||
// if (navigation.mode == Navigation.Mode.Automatic && axis == Axis.Vertical)
|
||||
// return null;
|
||||
// return base.FindSelectableOnUp();
|
||||
//}
|
||||
|
||||
//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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 37c44bc94a9a7f241b5b552f3ff89458
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
210
Assets/Scripts/HSVPicker/UtilityScripts/HSVUtil.cs
Normal file
210
Assets/Scripts/HSVPicker/UtilityScripts/HSVUtil.cs
Normal file
@@ -0,0 +1,210 @@
|
||||
using UnityEngine;
|
||||
using System;
|
||||
|
||||
namespace HSVPicker
|
||||
{
|
||||
|
||||
#region ColorUtilities
|
||||
|
||||
public static class HSVUtil
|
||||
{
|
||||
|
||||
public static HsvColor ConvertRgbToHsv(Color color)
|
||||
{
|
||||
return ConvertRgbToHsv((int)(color.r * 255), (int)(color.g * 255), (int)(color.b * 255));
|
||||
}
|
||||
|
||||
//Converts an RGB color to an HSV color.
|
||||
public static HsvColor ConvertRgbToHsv(double r, double b, double g)
|
||||
{
|
||||
double delta, min;
|
||||
double h = 0, s, v;
|
||||
|
||||
min = Math.Min(Math.Min(r, g), b);
|
||||
v = Math.Max(Math.Max(r, g), b);
|
||||
delta = v - min;
|
||||
|
||||
if (v.Equals(0))
|
||||
s = 0;
|
||||
else
|
||||
s = delta / v;
|
||||
|
||||
if (s.Equals(0))
|
||||
h = 360;
|
||||
else
|
||||
{
|
||||
if (r.Equals(v))
|
||||
h = (g - b) / delta;
|
||||
else if (g.Equals(v))
|
||||
h = 2 + (b - r) / delta;
|
||||
else if (b.Equals(v))
|
||||
h = 4 + (r - g) / delta;
|
||||
|
||||
h *= 60;
|
||||
if (h <= 0.0)
|
||||
h += 360;
|
||||
}
|
||||
|
||||
HsvColor hsvColor = new HsvColor();
|
||||
hsvColor.H = 360 - h;
|
||||
hsvColor.S = s;
|
||||
hsvColor.V = v / 255;
|
||||
|
||||
return hsvColor;
|
||||
|
||||
}
|
||||
|
||||
// Converts an HSV color to an RGB color.
|
||||
public static Color ConvertHsvToRgb(double h, double s, double v, float alpha)
|
||||
{
|
||||
|
||||
double r = 0, g = 0, b = 0;
|
||||
|
||||
if (s.Equals(0))
|
||||
{
|
||||
r = v;
|
||||
g = v;
|
||||
b = v;
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
int i;
|
||||
double f, p, q, t;
|
||||
|
||||
|
||||
if (h.Equals(360))
|
||||
h = 0;
|
||||
else
|
||||
h = h / 60;
|
||||
|
||||
i = (int)(h);
|
||||
f = h - i;
|
||||
|
||||
p = v * (1.0 - s);
|
||||
q = v * (1.0 - (s * f));
|
||||
t = v * (1.0 - (s * (1.0f - f)));
|
||||
|
||||
|
||||
switch (i)
|
||||
{
|
||||
case 0:
|
||||
r = v;
|
||||
g = t;
|
||||
b = p;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
r = q;
|
||||
g = v;
|
||||
b = p;
|
||||
break;
|
||||
|
||||
case 2:
|
||||
r = p;
|
||||
g = v;
|
||||
b = t;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
r = p;
|
||||
g = q;
|
||||
b = v;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
r = t;
|
||||
g = p;
|
||||
b = v;
|
||||
break;
|
||||
|
||||
default:
|
||||
r = v;
|
||||
g = p;
|
||||
b = q;
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return new Color((float)r, (float)g, (float)b, alpha);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
#endregion ColorUtilities
|
||||
|
||||
|
||||
// Describes a color in terms of
|
||||
// Hue, Saturation, and Value (brightness)
|
||||
#region HsvColor
|
||||
public struct HsvColor
|
||||
{
|
||||
/// <summary>
|
||||
/// The Hue, ranges between 0 and 360
|
||||
/// </summary>
|
||||
public double H;
|
||||
|
||||
/// <summary>
|
||||
/// The saturation, ranges between 0 and 1
|
||||
/// </summary>
|
||||
public double S;
|
||||
|
||||
// The value (brightness), ranges between 0 and 1
|
||||
public double V;
|
||||
|
||||
public float normalizedH
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)H / 360f;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
H = (double)value * 360;
|
||||
}
|
||||
}
|
||||
|
||||
public float normalizedS
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)S;
|
||||
}
|
||||
set
|
||||
{
|
||||
S = (double)value;
|
||||
}
|
||||
}
|
||||
|
||||
public float normalizedV
|
||||
{
|
||||
get
|
||||
{
|
||||
return (float)V;
|
||||
}
|
||||
set
|
||||
{
|
||||
V = (double)value;
|
||||
}
|
||||
}
|
||||
|
||||
public HsvColor(double h, double s, double v)
|
||||
{
|
||||
this.H = h;
|
||||
this.S = s;
|
||||
this.V = v;
|
||||
}
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return "{" + H.ToString("f2") + "," + S.ToString("f2") + "," + V.ToString("f2") + "}";
|
||||
}
|
||||
}
|
||||
#endregion HsvColor
|
||||
|
||||
|
||||
}
|
||||
|
||||
8
Assets/Scripts/HSVPicker/UtilityScripts/HSVUtil.cs.meta
Normal file
8
Assets/Scripts/HSVPicker/UtilityScripts/HSVUtil.cs.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f3189246d7fc204faba7a1e9c08e0af
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
11
Assets/Scripts/HSVPicker/package.json
Normal file
11
Assets/Scripts/HSVPicker/package.json
Normal file
@@ -0,0 +1,11 @@
|
||||
{
|
||||
"name": "judah4.hsvcolorpickerunity",
|
||||
"displayName": "HSVPicker",
|
||||
"version": "3.0.1",
|
||||
"unity": "2019.4",
|
||||
"description": "HSV color picker for Unity UI",
|
||||
"keywords": [
|
||||
],
|
||||
"dependencies": {
|
||||
}
|
||||
}
|
||||
7
Assets/Scripts/HSVPicker/package.json.meta
Normal file
7
Assets/Scripts/HSVPicker/package.json.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d46aec3749789425caab28d9edf026cf
|
||||
TextScriptImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
70
Assets/Scripts/JsonClasses.cs
Normal file
70
Assets/Scripts/JsonClasses.cs
Normal file
@@ -0,0 +1,70 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
|
||||
[Serializable]
|
||||
public class Manifest
|
||||
{
|
||||
public List<ManifestEntry> Entries = new List<ManifestEntry>();
|
||||
|
||||
public string GetFilePath(string input)
|
||||
{
|
||||
try { return Entries.FirstOrDefault(e => Path.GetFileName(e.path).ToLower() == input.ToLower()).path; }
|
||||
catch { Error.Log(UnityEngine.Color.red, input + " not found in Manifest"); return null; }
|
||||
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ManifestEntry
|
||||
{
|
||||
public string path;
|
||||
public string type;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class BasicServant
|
||||
{
|
||||
public List<BasicServantEntry> Entries = new List<BasicServantEntry>();
|
||||
|
||||
public List<Costume> GetAllCostumes()
|
||||
{
|
||||
return Entries.SelectMany(e => e.costumes).ToList();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class BasicServantEntry
|
||||
{
|
||||
public string name;
|
||||
public int id;
|
||||
public int collectionNo;
|
||||
public string type;
|
||||
public string flag;
|
||||
public string className;
|
||||
public string attribute;
|
||||
public int rarity;
|
||||
public int atkMax;
|
||||
public int hpMax;
|
||||
public string face;
|
||||
public Dictionary<string, Costume> costume;
|
||||
public List<Costume> costumes;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class Costume
|
||||
{
|
||||
public int id;
|
||||
public int costumeCollectionNo;
|
||||
public int battleCharaId;
|
||||
public string name;
|
||||
public string shortName;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class FileInput
|
||||
{
|
||||
public string blob;
|
||||
public string name;
|
||||
}
|
||||
11
Assets/Scripts/JsonClasses.cs.meta
Normal file
11
Assets/Scripts/JsonClasses.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cf9c6b22e49e5f84cb5eea6843a0714f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
87
Assets/Scripts/KeyboardShortcuts.cs
Normal file
87
Assets/Scripts/KeyboardShortcuts.cs
Normal file
@@ -0,0 +1,87 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class KeyboardShortcuts : MonoBehaviour
|
||||
{
|
||||
public static KeyboardShortcuts Instance;
|
||||
public List<char> KeyStrokes = new List<char>();
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (Instance != null)
|
||||
{
|
||||
Destroy(Instance);
|
||||
}
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void DropdownPrevious(Dropdown dropdown)
|
||||
{
|
||||
dropdown.value = dropdown.value - 1 < 0 ? dropdown.options.Count - 1 : dropdown.value - 1;
|
||||
}
|
||||
|
||||
public void DropdownNext(Dropdown dropdown)
|
||||
{
|
||||
dropdown.value = dropdown.value + 1 >= dropdown.options.Count ? 0 : dropdown.value + 1;
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
KatboiSequence();
|
||||
|
||||
if (Input.anyKeyDown && !string.IsNullOrEmpty(Input.inputString))
|
||||
{
|
||||
try
|
||||
{
|
||||
}
|
||||
catch(System.Exception e)
|
||||
{
|
||||
Debug.LogWarning("caught " + e);
|
||||
}
|
||||
}
|
||||
|
||||
//Time
|
||||
if (Input.GetKeyDown(KeyCode.LeftArrow))
|
||||
{
|
||||
FateViewerMain.Instance.ChangeAnimationFrame(-1);
|
||||
}
|
||||
|
||||
if (Input.GetKeyDown(KeyCode.RightArrow))
|
||||
{
|
||||
FateViewerMain.Instance.ChangeAnimationFrame(1);
|
||||
}
|
||||
}
|
||||
|
||||
private void KatboiSequence()
|
||||
{
|
||||
List<string> sequences = new List<string>()
|
||||
{
|
||||
"KATBOI01"
|
||||
};
|
||||
|
||||
if (Input.anyKeyDown && !string.IsNullOrEmpty(Input.inputString))
|
||||
{
|
||||
if (KeyStrokes.Count >= 10)
|
||||
{
|
||||
KeyStrokes = ((IEnumerable<char>)KeyStrokes).Reverse().Take(10).Reverse().ToList();
|
||||
}
|
||||
KeyStrokes.Add(Input.inputString.ToUpper()[0]);
|
||||
}
|
||||
|
||||
string passcode = sequences.FirstOrDefault(s => new string(KeyStrokes.ToArray()).Contains(s));
|
||||
|
||||
if (!string.IsNullOrEmpty(passcode))
|
||||
{
|
||||
switch (passcode)
|
||||
{
|
||||
case "KATBOI01":
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
KeyStrokes.Clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/KeyboardShortcuts.cs.meta
Normal file
11
Assets/Scripts/KeyboardShortcuts.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9299d9abed8fe544d9243415030b02fb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
29
Assets/Scripts/MatchWidth.cs
Normal file
29
Assets/Scripts/MatchWidth.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using UnityEngine;
|
||||
|
||||
public class MatchWidth : MonoBehaviour
|
||||
{
|
||||
public float sceneWidth = 1;
|
||||
public float sceneHeight = 1;
|
||||
|
||||
UnityEngine.UI.CanvasScaler _canvas;
|
||||
|
||||
void Start()
|
||||
{
|
||||
_canvas = GameObject.FindObjectOfType<UnityEngine.UI.CanvasScaler>();
|
||||
}
|
||||
|
||||
// Adjust the camera's height so the desired scene width fits in view
|
||||
// even if the screen/window size changes dynamically.
|
||||
void Update()
|
||||
{
|
||||
if ((float)Screen.width / Screen.height > (float)sceneWidth / sceneHeight)
|
||||
{
|
||||
_canvas.matchWidthOrHeight = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_canvas.matchWidthOrHeight = 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
11
Assets/Scripts/MatchWidth.cs.meta
Normal file
11
Assets/Scripts/MatchWidth.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 04b7f5d5c02504e4bb1b88be0835b9e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
33
Assets/Scripts/PermissionRationaleDialog.cs
Normal file
33
Assets/Scripts/PermissionRationaleDialog.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using UnityEngine;
|
||||
#if PLATFORM_ANDROID
|
||||
using UnityEngine.Android;
|
||||
#endif
|
||||
|
||||
public class PermissionsRationaleDialog : MonoBehaviour
|
||||
{
|
||||
// const int kDialogWidth = 300;
|
||||
// const int kDialogHeight = 100;
|
||||
// private bool windowOpen = true;
|
||||
|
||||
// void DoMyWindow(int windowID)
|
||||
// {
|
||||
// GUI.Label(new Rect(10, 20, kDialogWidth - 20, kDialogHeight - 50), "Enable access to files.");
|
||||
// GUI.Button(new Rect(10, kDialogHeight - 30, 100, 20), "No");
|
||||
// if (GUI.Button(new Rect(kDialogWidth - 110, kDialogHeight - 30, 100, 20), "Yes"))
|
||||
// {
|
||||
//#if PLATFORM_ANDROID
|
||||
// Permission.RequestUserPermission(Permission.ExternalStorageRead);
|
||||
//#endif
|
||||
// windowOpen = false;
|
||||
// }
|
||||
// }
|
||||
|
||||
// void OnGUI()
|
||||
// {
|
||||
// if (windowOpen)
|
||||
// {
|
||||
// Rect rect = new Rect((Screen.width / 2) - (kDialogWidth / 2), (Screen.height / 2) - (kDialogHeight / 2), kDialogWidth, kDialogHeight);
|
||||
// GUI.ModalWindow(0, rect, DoMyWindow, "Permissions Request Dialog");
|
||||
// }
|
||||
// }
|
||||
}
|
||||
11
Assets/Scripts/PermissionRationaleDialog.cs.meta
Normal file
11
Assets/Scripts/PermissionRationaleDialog.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 560a5b4714b2e394c8d51e04d0770f59
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
52
Assets/Scripts/RendererExtensions.cs
Normal file
52
Assets/Scripts/RendererExtensions.cs
Normal file
@@ -0,0 +1,52 @@
|
||||
using UnityEngine;
|
||||
|
||||
//https://gist.github.com/AkhmadMax, modified
|
||||
public static class RendererExtensions
|
||||
{
|
||||
/// <summary>
|
||||
/// Counts the bounding box corners of the given RectTransform that are visible from the given Camera in screen space.
|
||||
/// </summary>
|
||||
/// <returns>The amount of bounding box corners that are visible from the Camera.</returns>
|
||||
/// <param name="rectTransform">Rect transform.</param>
|
||||
/// <param name="camera">Camera.</param>
|
||||
private static int CountCornersVisibleFrom(this RectTransform rectTransform)
|
||||
{
|
||||
Rect screenBounds = new Rect(0f, 0f, Screen.width, Screen.height); // Screen space bounds (assumes camera renders across the entire screen)
|
||||
Vector3[] objectCorners = new Vector3[4];
|
||||
rectTransform.GetWorldCorners(objectCorners);
|
||||
|
||||
int visibleCorners = 0;
|
||||
for (var i = 0; i < objectCorners.Length; i++) // For each corner in rectTransform
|
||||
{
|
||||
if (screenBounds.Contains(objectCorners[i])) // If the corner is inside the screen
|
||||
{
|
||||
visibleCorners++;
|
||||
}
|
||||
}
|
||||
return visibleCorners;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this RectTransform is fully visible from the specified camera.
|
||||
/// Works by checking if each bounding box corner of this RectTransform is inside the cameras screen space view frustrum.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if is fully visible from the specified camera; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="rectTransform">Rect transform.</param>
|
||||
/// <param name="camera">Camera.</param>
|
||||
public static bool IsFullyVisibleFrom(this RectTransform rectTransform)
|
||||
{
|
||||
return CountCornersVisibleFrom(rectTransform) == 4; // True if all 4 corners are visible
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines if this RectTransform is at least partially visible from the specified camera.
|
||||
/// Works by checking if any bounding box corner of this RectTransform is inside the cameras screen space view frustrum.
|
||||
/// </summary>
|
||||
/// <returns><c>true</c> if is at least partially visible from the specified camera; otherwise, <c>false</c>.</returns>
|
||||
/// <param name="rectTransform">Rect transform.</param>
|
||||
/// <param name="camera">Camera.</param>
|
||||
public static bool IsVisible(this RectTransform rectTransform)
|
||||
{
|
||||
return CountCornersVisibleFrom(rectTransform) > 0; // True if any corners are visible
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/RendererExtensions.cs.meta
Normal file
11
Assets/Scripts/RendererExtensions.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 53a97b6d15f6176478ede149c0c52a9d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
142
Assets/Scripts/Screenshot.cs
Normal file
142
Assets/Scripts/Screenshot.cs
Normal file
@@ -0,0 +1,142 @@
|
||||
using SharpApng;
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using uGIF;
|
||||
using UnityEngine;
|
||||
|
||||
public class Screenshot : MonoBehaviour
|
||||
{
|
||||
public static Screenshot Instance;
|
||||
bool recording = false;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public static void ScreenshotDefault()
|
||||
{
|
||||
var image = GrabFrame(int.Parse(UIController.Instance.SSWidth.text), int.Parse(UIController.Instance.SSHeight.text));
|
||||
|
||||
string fileName = string.Format("FateViewer_{0}", DateTime.Now.ToString("yyyy-MM-dd_HH-mm-ss-fff"));
|
||||
byte[] pngShot = ImageConversion.EncodeToPNG(image);
|
||||
WebGLDownload.DownloadFile(pngShot, fileName, "png");
|
||||
|
||||
Destroy(image);
|
||||
}
|
||||
|
||||
public static Texture2D GrabFrame(int width, int height, bool gifBackground = false)
|
||||
{
|
||||
var dimensions = GetResolution(width, height);
|
||||
width = dimensions.x;
|
||||
height = dimensions.y;
|
||||
|
||||
Camera cam = Camera.main;
|
||||
int oldMask = cam.cullingMask;
|
||||
var bak_cam_clearFlags = cam.clearFlags;
|
||||
cam.cullingMask = ~LayerMask.GetMask("UI");
|
||||
|
||||
if (gifBackground)
|
||||
{
|
||||
cam.clearFlags = CameraClearFlags.SolidColor;
|
||||
cam.backgroundColor = new Color32(0, 0, 0, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
cam.clearFlags = CameraClearFlags.Depth;
|
||||
}
|
||||
|
||||
var tex_color = new Texture2D(width, height, TextureFormat.ARGB32, false);
|
||||
var tex_alpha = new Texture2D(width, height, TextureFormat.ARGB32, false);
|
||||
var render_texture = RenderTexture.GetTemporary(width, height, 24, RenderTextureFormat.ARGB32);
|
||||
var grab_area = new Rect(0, 0, width, height);
|
||||
|
||||
RenderTexture.active = render_texture;
|
||||
cam.targetTexture = render_texture;
|
||||
|
||||
cam.Render();
|
||||
tex_color.ReadPixels(grab_area, 0, 0);
|
||||
tex_color.Apply();
|
||||
|
||||
foreach(var servant in GameObject.FindObjectsOfType<FateServantContainer>())
|
||||
{
|
||||
servant.SwitchShaderToScreenshot(true);
|
||||
}
|
||||
|
||||
cam.Render();
|
||||
tex_alpha.ReadPixels(grab_area, 0, 0);
|
||||
tex_alpha.Apply();
|
||||
|
||||
var alpha = tex_alpha.GetPixels();
|
||||
var color = tex_color.GetPixels();
|
||||
for (int i = 0; i < color.Length; i++)
|
||||
{
|
||||
color[i].a = alpha[i].a;
|
||||
}
|
||||
|
||||
tex_color.SetPixels(color);
|
||||
Destroy(tex_alpha);
|
||||
|
||||
foreach (var servant in GameObject.FindObjectsOfType<FateServantContainer>())
|
||||
{
|
||||
servant.SwitchShaderToScreenshot(false);
|
||||
}
|
||||
|
||||
cam.clearFlags = bak_cam_clearFlags;
|
||||
cam.cullingMask = oldMask;
|
||||
cam.targetTexture = null;
|
||||
RenderTexture.active = null;
|
||||
RenderTexture.ReleaseTemporary(render_texture);
|
||||
|
||||
return tex_color;
|
||||
}
|
||||
|
||||
public static Vector2Int GetResolution(int width, int height)
|
||||
{
|
||||
if (width == 0 && height == 0)
|
||||
{
|
||||
width = Screen.width;
|
||||
height = Screen.height;
|
||||
}
|
||||
else if (width == 0)
|
||||
{
|
||||
float ratio = (float)Screen.width / (float)Screen.height;
|
||||
width = Mathf.RoundToInt((float)height * ratio);
|
||||
}
|
||||
else if (height == 0)
|
||||
{
|
||||
float ratio = (float)Screen.height / (float)Screen.width;
|
||||
height = Mathf.RoundToInt((float)width * ratio);
|
||||
}
|
||||
return new Vector2Int(width, height);
|
||||
}
|
||||
|
||||
public void StartAnimRecord()
|
||||
{
|
||||
if (recording) return;
|
||||
recording = true;
|
||||
StartCoroutine(RecordAnim());
|
||||
}
|
||||
|
||||
public IEnumerator RecordAnim()
|
||||
{
|
||||
Error.Log(Color.yellow, "Recording! Don't touch anything!");
|
||||
FateViewerMain.SelectedServant.CurrentFrame = 0;
|
||||
|
||||
StartCoroutine(CaptureToGIFCustom.Instance.Encode());
|
||||
while (FateViewerMain.SelectedServant.CurrentFrame <= FateViewerMain.SelectedServant.ClipFrameCount)
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
var tex = GrabFrame(int.Parse(UIController.Instance.GifWidth.text), int.Parse(UIController.Instance.GifHeight.text), true);
|
||||
CaptureToGIFCustom.Instance.Frames.Add(new Image(tex));
|
||||
Destroy(tex);
|
||||
//Debug.Log(FateViewerMain.SelectedServant.CurrentFrame);
|
||||
if (FateViewerMain.SelectedServant.CurrentFrame == FateViewerMain.SelectedServant.ClipFrameCount) break;
|
||||
}
|
||||
CaptureToGIFCustom.Instance.stop = true;
|
||||
recording = false;
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/Screenshot.cs.meta
Normal file
11
Assets/Scripts/Screenshot.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16e36c739b6e83d43b3787f158318a87
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
35
Assets/Scripts/ServantUIContainer.cs
Normal file
35
Assets/Scripts/ServantUIContainer.cs
Normal file
@@ -0,0 +1,35 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public class ServantUIContainer : MonoBehaviour
|
||||
{
|
||||
public BasicServant.BasicServantEntry Servant;
|
||||
public string FaceUrl;
|
||||
public Image Face;
|
||||
public TMPro.TextMeshProUGUI Name;
|
||||
public TMPro.TextMeshProUGUI ID;
|
||||
public Button Button;
|
||||
bool _done;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
if (_done) return;
|
||||
StartCoroutine(LoadIcon());
|
||||
}
|
||||
|
||||
private IEnumerator LoadIcon()
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
while (!GetComponent<RectTransform>().IsVisible())
|
||||
{
|
||||
yield return new WaitForEndOfFrame();
|
||||
}
|
||||
_done = true;
|
||||
if (!string.IsNullOrEmpty(FaceUrl))
|
||||
{
|
||||
Davinci.get().load(FaceUrl).into(Face).start();
|
||||
}
|
||||
}
|
||||
}
|
||||
11
Assets/Scripts/ServantUIContainer.cs.meta
Normal file
11
Assets/Scripts/ServantUIContainer.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8f4f0afd5a5cafa4c9b498907eb2f207
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
9
Assets/Scripts/SimpleAnimationComponent.meta
Normal file
9
Assets/Scripts/SimpleAnimationComponent.meta
Normal file
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8fc03674866ae9a4f9fdacc1444511bf
|
||||
folderAsset: yes
|
||||
timeCreated: 1493740709
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
public static class CustomPlayableExtensions
|
||||
{
|
||||
public static void ResetTime(this Playable playable, float time)
|
||||
{
|
||||
playable.SetTime(time);
|
||||
playable.SetTime(time);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d6aadfd4af940c47a915f6e609245bd
|
||||
timeCreated: 1519667576
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/SimpleAnimationComponent/Editor.meta
Normal file
10
Assets/Scripts/SimpleAnimationComponent/Editor.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 13eb8d583b55e3f4998b9c8d1fc4f631
|
||||
folderAsset: yes
|
||||
timeCreated: 1502472444
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,12 @@
|
||||
{
|
||||
"name": "SimpleAnimationComponent-Editor",
|
||||
"references": [
|
||||
"SimpleAnimationComponent"
|
||||
],
|
||||
"optionalUnityReferences": [],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4073e604354115342b874ea3137b12f7
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,92 @@
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
[CustomEditor(typeof(SimpleAnimation))]
|
||||
public class SimpleAnimationEditor : Editor
|
||||
{
|
||||
static class Styles
|
||||
{
|
||||
public static GUIContent animation = new GUIContent("Animation", "The clip that will be played if Play() is called, or if \"Play Automatically\" is enabled");
|
||||
public static GUIContent animations = new GUIContent("Animations", "These clips will define the States the component will start with");
|
||||
public static GUIContent playAutomatically = new GUIContent("Play Automatically", "If checked, the default clip will automatically be played");
|
||||
public static GUIContent animatePhysics = new GUIContent("Animate Physics", "If checked, animations will be updated at the same frequency as Fixed Update");
|
||||
|
||||
public static GUIContent cullingMode = new GUIContent("Culling Mode", "Controls what is updated when the object has been culled");
|
||||
}
|
||||
|
||||
SerializedProperty clip;
|
||||
SerializedProperty states;
|
||||
SerializedProperty playAutomatically;
|
||||
SerializedProperty animatePhysics;
|
||||
SerializedProperty cullingMode;
|
||||
|
||||
void OnEnable()
|
||||
{
|
||||
clip = serializedObject.FindProperty("m_Clip");
|
||||
states = serializedObject.FindProperty("m_States");
|
||||
playAutomatically = serializedObject.FindProperty("m_PlayAutomatically");
|
||||
animatePhysics = serializedObject.FindProperty("m_AnimatePhysics");
|
||||
cullingMode = serializedObject.FindProperty("m_CullingMode");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
EditorGUILayout.PropertyField(clip, Styles.animation);
|
||||
EditorGUILayout.PropertyField(states, Styles.animations, true);
|
||||
EditorGUILayout.PropertyField(playAutomatically, Styles.playAutomatically);
|
||||
EditorGUILayout.PropertyField(animatePhysics, Styles.animatePhysics);
|
||||
EditorGUILayout.PropertyField(cullingMode, Styles.cullingMode);
|
||||
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
[CustomPropertyDrawer(typeof(SimpleAnimation.EditorState))]
|
||||
class StateDrawer : PropertyDrawer
|
||||
{
|
||||
class Styles
|
||||
{
|
||||
public static readonly GUIContent disabledTooltip = new GUIContent("", "The Default state cannot be edited, change the Animation clip to change the Default State");
|
||||
}
|
||||
|
||||
// Draw the property inside the given rect
|
||||
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
|
||||
{
|
||||
// Using BeginProperty / EndProperty on the parent property means that
|
||||
// prefab override logic works on the entire property.
|
||||
EditorGUI.BeginProperty(position, label, property);
|
||||
|
||||
// Draw label
|
||||
position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
|
||||
|
||||
// Don't make child fields be indented
|
||||
var indent = EditorGUI.indentLevel;
|
||||
EditorGUI.indentLevel = 0;
|
||||
|
||||
EditorGUILayout.BeginHorizontal();
|
||||
// Calculate rects
|
||||
Rect clipRect = new Rect(position.x, position.y, position.width/2 - 5, position.height);
|
||||
Rect nameRect = new Rect(position.x + position.width/2 + 5, position.y, position.width/2 - 5, position.height);
|
||||
|
||||
|
||||
EditorGUI.BeginDisabledGroup(property.FindPropertyRelative("defaultState").boolValue);
|
||||
EditorGUI.PropertyField(nameRect, property.FindPropertyRelative("clip"), GUIContent.none);
|
||||
EditorGUI.PropertyField(clipRect, property.FindPropertyRelative("name"), GUIContent.none);
|
||||
if (property.FindPropertyRelative("defaultState").boolValue)
|
||||
{
|
||||
EditorGUI.LabelField(position, Styles.disabledTooltip);
|
||||
}
|
||||
|
||||
EditorGUI.EndDisabledGroup();
|
||||
|
||||
EditorGUILayout.EndHorizontal();
|
||||
// Set indent back to what it was
|
||||
EditorGUI.indentLevel = indent;
|
||||
|
||||
EditorGUI.EndProperty();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b42bbe25e28af494dadccf960ecfc32e
|
||||
timeCreated: 1502472599
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
211
Assets/Scripts/SimpleAnimationComponent/SimpleAnimation.cs
Normal file
211
Assets/Scripts/SimpleAnimationComponent/SimpleAnimation.cs
Normal file
@@ -0,0 +1,211 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public partial class SimpleAnimation: MonoBehaviour
|
||||
{
|
||||
public interface State
|
||||
{
|
||||
bool enabled { get; set; }
|
||||
bool isValid { get; }
|
||||
float time { get; set; }
|
||||
float normalizedTime { get; set; }
|
||||
float speed { get; set; }
|
||||
string name { get; set; }
|
||||
float weight { get; set; }
|
||||
float length { get; }
|
||||
AnimationClip clip { get; }
|
||||
WrapMode wrapMode { get; set; }
|
||||
|
||||
}
|
||||
public Animator animator
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Animator == null)
|
||||
{
|
||||
m_Animator = GetComponent<Animator>();
|
||||
}
|
||||
return m_Animator;
|
||||
}
|
||||
}
|
||||
|
||||
public bool animatePhysics
|
||||
{
|
||||
get { return m_AnimatePhysics; }
|
||||
set { m_AnimatePhysics = value; animator.updateMode = m_AnimatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal; }
|
||||
}
|
||||
|
||||
public AnimatorCullingMode cullingMode
|
||||
{
|
||||
get { return animator.cullingMode; }
|
||||
set { m_CullingMode = value; animator.cullingMode = m_CullingMode; }
|
||||
}
|
||||
|
||||
public bool isPlaying { get { return m_Playable.IsPlaying(); } }
|
||||
|
||||
public bool playAutomatically
|
||||
{
|
||||
get { return m_PlayAutomatically; }
|
||||
set { m_PlayAutomatically = value; }
|
||||
}
|
||||
|
||||
public AnimationClip clip
|
||||
{
|
||||
get { return m_Clip; }
|
||||
set
|
||||
{
|
||||
LegacyClipCheck(value);
|
||||
m_Clip = value;
|
||||
}
|
||||
}
|
||||
|
||||
public WrapMode wrapMode
|
||||
{
|
||||
get { return m_WrapMode; }
|
||||
set { m_WrapMode = value; }
|
||||
}
|
||||
|
||||
public void AddClip(AnimationClip clip, string newName)
|
||||
{
|
||||
LegacyClipCheck(clip);
|
||||
AddState(clip, newName);
|
||||
}
|
||||
|
||||
public void Blend(string stateName, float targetWeight, float fadeLength)
|
||||
{
|
||||
m_Animator.enabled = true;
|
||||
Kick();
|
||||
m_Playable.Blend(stateName, targetWeight, fadeLength);
|
||||
}
|
||||
|
||||
public void CrossFade(string stateName, float fadeLength)
|
||||
{
|
||||
m_Animator.enabled = true;
|
||||
Kick();
|
||||
m_Playable.Crossfade(stateName, fadeLength);
|
||||
}
|
||||
|
||||
public void CrossFadeQueued(string stateName, float fadeLength, QueueMode queueMode)
|
||||
{
|
||||
m_Animator.enabled = true;
|
||||
Kick();
|
||||
m_Playable.CrossfadeQueued(stateName, fadeLength, queueMode);
|
||||
}
|
||||
|
||||
public int GetClipCount()
|
||||
{
|
||||
return m_Playable.GetClipCount();
|
||||
}
|
||||
|
||||
public bool IsPlaying(string stateName)
|
||||
{
|
||||
return m_Playable.IsPlaying(stateName);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
m_Playable.StopAll();
|
||||
}
|
||||
|
||||
public void Stop(string stateName)
|
||||
{
|
||||
m_Playable.Stop(stateName);
|
||||
}
|
||||
|
||||
public void Sample()
|
||||
{
|
||||
m_Graph.Evaluate();
|
||||
}
|
||||
|
||||
public bool Play()
|
||||
{
|
||||
m_Animator.enabled = true;
|
||||
Kick();
|
||||
if (m_Clip != null && m_PlayAutomatically)
|
||||
{
|
||||
m_Playable.Play(kDefaultStateName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void AddState(AnimationClip clip, string name)
|
||||
{
|
||||
LegacyClipCheck(clip);
|
||||
Kick();
|
||||
if (m_Playable.AddClip(clip, name))
|
||||
{
|
||||
RebuildStates();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void RemoveState(string name)
|
||||
{
|
||||
if (m_Playable.RemoveClip(name))
|
||||
{
|
||||
RebuildStates();
|
||||
}
|
||||
}
|
||||
|
||||
public bool Play(string stateName)
|
||||
{
|
||||
m_Animator.enabled = true;
|
||||
Kick();
|
||||
return m_Playable.Play(stateName);
|
||||
}
|
||||
|
||||
public void PlayQueued(string stateName, QueueMode queueMode)
|
||||
{
|
||||
m_Animator.enabled = true;
|
||||
Kick();
|
||||
m_Playable.PlayQueued(stateName, queueMode);
|
||||
}
|
||||
|
||||
public void RemoveClip(AnimationClip clip)
|
||||
{
|
||||
if (clip == null)
|
||||
throw new System.NullReferenceException("clip");
|
||||
|
||||
if ( m_Playable.RemoveClip(clip) )
|
||||
{
|
||||
RebuildStates();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Rewind()
|
||||
{
|
||||
Kick();
|
||||
m_Playable.Rewind();
|
||||
}
|
||||
|
||||
public void Rewind(string stateName)
|
||||
{
|
||||
Kick();
|
||||
m_Playable.Rewind(stateName);
|
||||
}
|
||||
|
||||
public State GetState(string stateName)
|
||||
{
|
||||
SimpleAnimationPlayable.IState state = m_Playable.GetState(stateName);
|
||||
if (state == null)
|
||||
return null;
|
||||
|
||||
return new StateImpl(state, this);
|
||||
}
|
||||
|
||||
public IEnumerable<State> GetStates()
|
||||
{
|
||||
return new StateEnumerable(this);
|
||||
}
|
||||
|
||||
public State this[string name]
|
||||
{
|
||||
get { return GetState(name); }
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3759e2aae0f7b9a47bb98fc64bf3c543
|
||||
timeCreated: 1493315774
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,3 @@
|
||||
{
|
||||
"name": "SimpleAnimationComponent"
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: aff632302a0b84b498c3f33f7639b4d3
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,754 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Animations;
|
||||
using System;
|
||||
|
||||
public partial class SimpleAnimationPlayable : PlayableBehaviour
|
||||
{
|
||||
LinkedList<QueuedState> m_StateQueue;
|
||||
StateManagement m_States;
|
||||
bool m_Initialized;
|
||||
|
||||
bool m_KeepStoppedPlayablesConnected = true;
|
||||
public bool keepStoppedPlayablesConnected
|
||||
{
|
||||
get { return m_KeepStoppedPlayablesConnected; }
|
||||
set
|
||||
{
|
||||
if (value != m_KeepStoppedPlayablesConnected)
|
||||
{
|
||||
m_KeepStoppedPlayablesConnected = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void UpdateStoppedPlayablesConnections()
|
||||
{
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
if (state == null)
|
||||
continue;
|
||||
if (state.enabled)
|
||||
continue;
|
||||
if (keepStoppedPlayablesConnected)
|
||||
{
|
||||
ConnectInput(state.index);
|
||||
}
|
||||
else
|
||||
{
|
||||
DisconnectInput(state.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected Playable m_ActualPlayable;
|
||||
protected Playable self { get { return m_ActualPlayable; } }
|
||||
public Playable playable { get { return self; } }
|
||||
protected PlayableGraph graph { get { return self.GetGraph(); } }
|
||||
|
||||
AnimationMixerPlayable m_Mixer;
|
||||
|
||||
public System.Action onDone = null;
|
||||
public SimpleAnimationPlayable()
|
||||
{
|
||||
m_States = new StateManagement();
|
||||
this.m_StateQueue = new LinkedList<QueuedState>();
|
||||
}
|
||||
|
||||
public Playable GetInput(int index)
|
||||
{
|
||||
if (index >= m_Mixer.GetInputCount())
|
||||
return Playable.Null;
|
||||
|
||||
return m_Mixer.GetInput(index);
|
||||
}
|
||||
|
||||
public override void OnPlayableCreate(Playable playable)
|
||||
{
|
||||
m_ActualPlayable = playable;
|
||||
|
||||
var mixer = AnimationMixerPlayable.Create(graph, 1, true);
|
||||
m_Mixer = mixer;
|
||||
|
||||
self.SetInputCount(1);
|
||||
self.SetInputWeight(0, 1);
|
||||
graph.Connect(m_Mixer, 0, self, 0);
|
||||
}
|
||||
|
||||
public IEnumerable<IState> GetStates()
|
||||
{
|
||||
return new StateEnumerable(this);
|
||||
}
|
||||
|
||||
public IState GetState(string name)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
return new StateHandle(this, state.index, state.playable);
|
||||
}
|
||||
|
||||
private StateInfo DoAddClip(string name, AnimationClip clip)
|
||||
{
|
||||
//Start new State
|
||||
StateInfo newState = m_States.InsertState();
|
||||
newState.Initialize(name, clip, clip.wrapMode);
|
||||
//Find at which input the state will be connected
|
||||
int index = newState.index;
|
||||
|
||||
//Increase input count if needed
|
||||
if (index == m_Mixer.GetInputCount())
|
||||
{
|
||||
m_Mixer.SetInputCount(index + 1);
|
||||
}
|
||||
|
||||
var clipPlayable = AnimationClipPlayable.Create(graph, clip);
|
||||
clipPlayable.SetApplyFootIK(false);
|
||||
clipPlayable.SetApplyPlayableIK(false);
|
||||
if (!clip.isLooping || newState.wrapMode == WrapMode.Once)
|
||||
{
|
||||
clipPlayable.SetDuration(clip.length);
|
||||
}
|
||||
newState.SetPlayable(clipPlayable);
|
||||
newState.Pause();
|
||||
|
||||
if (keepStoppedPlayablesConnected)
|
||||
ConnectInput(newState.index);
|
||||
|
||||
return newState;
|
||||
}
|
||||
|
||||
public bool AddClip(AnimationClip clip, string name)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state != null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot add state with name {0}, because a state with that name already exists", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
DoAddClip(name, clip);
|
||||
UpdateDoneStatus();
|
||||
InvalidateStates();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveClip(string name)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot remove state with name {0}, because a state with that name doesn't exist", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
RemoveClones(state);
|
||||
InvalidateStates();
|
||||
m_States.RemoveState(state.index);
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RemoveClip(AnimationClip clip)
|
||||
{
|
||||
InvalidateStates();
|
||||
return m_States.RemoveClip(clip);
|
||||
}
|
||||
|
||||
public bool Play(string name)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot play state with name {0} because there is no state with that name", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
return Play(state.index);
|
||||
}
|
||||
|
||||
private bool Play(int index)
|
||||
{
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
if (state.index == index)
|
||||
{
|
||||
state.Enable();
|
||||
state.ForceWeight(1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
DoStop(i);
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool PlayQueued(string name, QueueMode queueMode)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot queue Play to state with name {0} because there is no state with that name", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
return PlayQueued(state.index, queueMode);
|
||||
}
|
||||
|
||||
bool PlayQueued(int index, QueueMode queueMode)
|
||||
{
|
||||
StateInfo newState = CloneState(index);
|
||||
|
||||
if (queueMode == QueueMode.PlayNow)
|
||||
{
|
||||
Play(newState.index);
|
||||
return true;
|
||||
}
|
||||
|
||||
m_StateQueue.AddLast(new QueuedState(StateInfoToHandle(newState), 0f));
|
||||
return true;
|
||||
}
|
||||
|
||||
public void Rewind(string name)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot Rewind state with name {0} because there is no state with that name", name));
|
||||
return;
|
||||
}
|
||||
|
||||
Rewind(state.index);
|
||||
}
|
||||
|
||||
private void Rewind(int index)
|
||||
{
|
||||
m_States.SetStateTime(index, 0f);
|
||||
}
|
||||
|
||||
public void Rewind()
|
||||
{
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
if (m_States[i] != null)
|
||||
m_States.SetStateTime(i, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
private void RemoveClones(StateInfo state)
|
||||
{
|
||||
var it = m_StateQueue.First;
|
||||
while (it != null)
|
||||
{
|
||||
var next = it.Next;
|
||||
|
||||
StateInfo queuedState = m_States[it.Value.state.index];
|
||||
if (queuedState.parentState.index == state.index)
|
||||
{
|
||||
m_StateQueue.Remove(it);
|
||||
DoStop(queuedState.index);
|
||||
}
|
||||
|
||||
it = next;
|
||||
}
|
||||
}
|
||||
|
||||
public bool Stop(string name)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot stop state with name {0} because there is no state with that name", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
DoStop(state.index);
|
||||
|
||||
UpdateDoneStatus();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private void DoStop(int index)
|
||||
{
|
||||
StateInfo state = m_States[index];
|
||||
if (state == null)
|
||||
return;
|
||||
m_States.StopState(index, state.isClone);
|
||||
if (!state.isClone)
|
||||
{
|
||||
RemoveClones(state);
|
||||
}
|
||||
}
|
||||
|
||||
public bool StopAll()
|
||||
{
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
DoStop(i);
|
||||
}
|
||||
|
||||
playable.SetDone(true);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool IsPlaying()
|
||||
{
|
||||
return m_States.AnyStatePlaying();
|
||||
}
|
||||
|
||||
public bool IsPlaying(string stateName)
|
||||
{
|
||||
StateInfo state = m_States.FindState(stateName);
|
||||
if (state == null)
|
||||
return false;
|
||||
|
||||
return state.enabled || IsClonePlaying(state);
|
||||
}
|
||||
|
||||
private bool IsClonePlaying(StateInfo state)
|
||||
{
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo otherState = m_States[i];
|
||||
if (otherState == null)
|
||||
continue;
|
||||
|
||||
if (otherState.isClone && otherState.enabled && otherState.parentState.index == state.index)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public int GetClipCount()
|
||||
{
|
||||
int count=0;
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
if (m_States[i] != null)
|
||||
{
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
private void SetupLerp(StateInfo state, float targetWeight, float time)
|
||||
{
|
||||
float travel = Mathf.Abs(state.weight - targetWeight);
|
||||
float newSpeed = time != 0f ? travel / time : Mathf.Infinity;
|
||||
|
||||
// If we're fading to the same target as before but slower, assume CrossFade was called multiple times and ignore new speed
|
||||
if (state.fading && Mathf.Approximately(state.targetWeight, targetWeight) && newSpeed < state.fadeSpeed)
|
||||
return;
|
||||
|
||||
state.FadeTo(targetWeight, newSpeed);
|
||||
}
|
||||
|
||||
private bool Crossfade(int index, float time)
|
||||
{
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
if (state == null)
|
||||
continue;
|
||||
|
||||
if (state.index == index)
|
||||
{
|
||||
m_States.EnableState(index);
|
||||
}
|
||||
|
||||
if (state.enabled == false)
|
||||
continue;
|
||||
|
||||
float targetWeight = state.index == index ? 1.0f : 0.0f;
|
||||
SetupLerp(state, targetWeight, time);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private StateInfo CloneState(int index)
|
||||
{
|
||||
StateInfo original = m_States[index];
|
||||
string newName = original.stateName + "Queued Clone";
|
||||
StateInfo clone = DoAddClip(newName, original.clip);
|
||||
clone.SetAsCloneOf(new StateHandle(this, original.index, original.playable));
|
||||
return clone;
|
||||
}
|
||||
|
||||
public bool Crossfade(string name, float time)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot crossfade to state with name {0} because there is no state with that name", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (time == 0f)
|
||||
return Play(state.index);
|
||||
|
||||
return Crossfade(state.index, time);
|
||||
}
|
||||
|
||||
public bool CrossfadeQueued(string name, float time, QueueMode queueMode)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot queue crossfade to state with name {0} because there is no state with that name", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
return CrossfadeQueued(state.index, time, queueMode);
|
||||
}
|
||||
|
||||
private bool CrossfadeQueued(int index, float time, QueueMode queueMode)
|
||||
{
|
||||
StateInfo newState = CloneState(index);
|
||||
|
||||
if (queueMode == QueueMode.PlayNow)
|
||||
{
|
||||
Crossfade(newState.index, time);
|
||||
return true;
|
||||
}
|
||||
|
||||
m_StateQueue.AddLast(new QueuedState(StateInfoToHandle(newState), time));
|
||||
return true;
|
||||
}
|
||||
|
||||
private bool Blend(int index, float targetWeight, float time)
|
||||
{
|
||||
StateInfo state = m_States[index];
|
||||
if (state.enabled == false)
|
||||
m_States.EnableState(index);
|
||||
|
||||
if (time == 0f)
|
||||
{
|
||||
state.ForceWeight(targetWeight);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetupLerp(state, targetWeight, time);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Blend(string name, float targetWeight, float time)
|
||||
{
|
||||
StateInfo state = m_States.FindState(name);
|
||||
if (state == null)
|
||||
{
|
||||
Debug.LogError(string.Format("Cannot blend state with name {0} because there is no state with that name", name));
|
||||
return false;
|
||||
}
|
||||
|
||||
return Blend(state.index, targetWeight, time);
|
||||
}
|
||||
|
||||
public override void OnGraphStop(Playable playable)
|
||||
{
|
||||
//if the playable is not valid, then we are destroying, and our children won't be valid either
|
||||
if (!self.IsValid())
|
||||
return;
|
||||
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
if (state == null)
|
||||
continue;
|
||||
|
||||
if (state.fadeSpeed == 0f && state.targetWeight == 0f)
|
||||
{
|
||||
Playable input = m_Mixer.GetInput(state.index);
|
||||
if (!input.Equals(Playable.Null))
|
||||
{
|
||||
input.ResetTime(0f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void UpdateDoneStatus()
|
||||
{
|
||||
if (!m_States.AnyStatePlaying())
|
||||
{
|
||||
bool wasDone = playable.IsDone();
|
||||
playable.SetDone(true);
|
||||
if (!wasDone && onDone != null)
|
||||
{
|
||||
onDone();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void CleanClonedStates()
|
||||
{
|
||||
for (int i = m_States.Count-1; i >= 0; i--)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
if (state == null)
|
||||
continue;
|
||||
|
||||
if (state.isReadyForCleanup)
|
||||
{
|
||||
Playable toDestroy = m_Mixer.GetInput(state.index);
|
||||
graph.Disconnect(m_Mixer, state.index);
|
||||
graph.DestroyPlayable(toDestroy);
|
||||
m_States.RemoveState(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DisconnectInput(int index)
|
||||
{
|
||||
if (keepStoppedPlayablesConnected)
|
||||
{
|
||||
m_States[index].Pause();
|
||||
}
|
||||
graph.Disconnect(m_Mixer, index);
|
||||
}
|
||||
|
||||
private void ConnectInput(int index)
|
||||
{
|
||||
StateInfo state = m_States[index];
|
||||
graph.Connect(state.playable, 0, m_Mixer, state.index);
|
||||
}
|
||||
|
||||
private void UpdateStates(float deltaTime)
|
||||
{
|
||||
bool mustUpdateWeights = false;
|
||||
float totalWeight = 0f;
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
|
||||
//Skip deleted states
|
||||
if (state == null)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
//Update crossfade weight
|
||||
if (state.fading)
|
||||
{
|
||||
state.SetWeight(Mathf.MoveTowards(state.weight, state.targetWeight, state.fadeSpeed *deltaTime));
|
||||
if (Mathf.Approximately(state.weight, state.targetWeight))
|
||||
{
|
||||
state.ForceWeight(state.targetWeight);
|
||||
if (state.weight == 0f)
|
||||
{
|
||||
state.Stop();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.enabledDirty)
|
||||
{
|
||||
if (state.enabled)
|
||||
state.Play();
|
||||
else
|
||||
state.Pause();
|
||||
|
||||
if (!keepStoppedPlayablesConnected)
|
||||
{
|
||||
Playable input = m_Mixer.GetInput(i);
|
||||
//if state is disabled but the corresponding input is connected, disconnect it
|
||||
if (input.IsValid() && !state.enabled)
|
||||
{
|
||||
DisconnectInput(i);
|
||||
}
|
||||
else if (state.enabled && !input.IsValid())
|
||||
{
|
||||
ConnectInput(state.index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (state.enabled && state.wrapMode == WrapMode.Once)
|
||||
{
|
||||
bool stateIsDone = state.isDone;
|
||||
float speed = state.speed;
|
||||
float time = state.GetTime();
|
||||
float duration = state.playableDuration;
|
||||
|
||||
stateIsDone |= speed < 0f && time < 0f;
|
||||
stateIsDone |= speed >= 0f && time >= duration;
|
||||
if (stateIsDone)
|
||||
{
|
||||
state.Stop();
|
||||
state.Disable();
|
||||
if (!keepStoppedPlayablesConnected)
|
||||
DisconnectInput(state.index);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
totalWeight += state.weight;
|
||||
if (state.weightDirty)
|
||||
{
|
||||
mustUpdateWeights = true;
|
||||
}
|
||||
state.ResetDirtyFlags();
|
||||
}
|
||||
|
||||
if (mustUpdateWeights)
|
||||
{
|
||||
bool hasAnyWeight = totalWeight > 0.0f;
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
if (state == null)
|
||||
continue;
|
||||
|
||||
float weight = hasAnyWeight ? state.weight / totalWeight : 0.0f;
|
||||
m_Mixer.SetInputWeight(state.index, weight);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private float CalculateQueueTimes()
|
||||
{
|
||||
float longestTime = -1f;
|
||||
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
//Skip deleted states
|
||||
if (state == null || !state.enabled || !state.playable.IsValid())
|
||||
continue;
|
||||
|
||||
if (state.wrapMode == WrapMode.Loop)
|
||||
{
|
||||
return Mathf.Infinity;
|
||||
}
|
||||
|
||||
float speed = state.speed;
|
||||
float stateTime = m_States.GetStateTime(state.index);
|
||||
float remainingTime;
|
||||
if (speed > 0 )
|
||||
{
|
||||
remainingTime = (state.clip.length - stateTime) / speed;
|
||||
}
|
||||
else if(speed < 0 )
|
||||
{
|
||||
remainingTime = (stateTime) / speed;
|
||||
}
|
||||
else
|
||||
{
|
||||
remainingTime = Mathf.Infinity;
|
||||
}
|
||||
|
||||
if (remainingTime > longestTime)
|
||||
{
|
||||
longestTime = remainingTime;
|
||||
}
|
||||
}
|
||||
|
||||
return longestTime;
|
||||
}
|
||||
|
||||
private void ClearQueuedStates()
|
||||
{
|
||||
using (var it = m_StateQueue.GetEnumerator())
|
||||
{
|
||||
while (it.MoveNext())
|
||||
{
|
||||
QueuedState queuedState = it.Current;
|
||||
m_States.StopState(queuedState.state.index, true);
|
||||
}
|
||||
}
|
||||
m_StateQueue.Clear();
|
||||
}
|
||||
|
||||
private void UpdateQueuedStates()
|
||||
{
|
||||
bool mustCalculateQueueTimes = true;
|
||||
float remainingTime = -1f;
|
||||
|
||||
var it = m_StateQueue.First;
|
||||
while(it != null)
|
||||
{
|
||||
if (mustCalculateQueueTimes)
|
||||
{
|
||||
remainingTime = CalculateQueueTimes();
|
||||
mustCalculateQueueTimes = false;
|
||||
}
|
||||
|
||||
QueuedState queuedState = it.Value;
|
||||
|
||||
if (queuedState.fadeTime >= remainingTime)
|
||||
{
|
||||
Crossfade(queuedState.state.index, queuedState.fadeTime);
|
||||
mustCalculateQueueTimes = true;
|
||||
m_StateQueue.RemoveFirst();
|
||||
it = m_StateQueue.First;
|
||||
}
|
||||
else
|
||||
{
|
||||
it = it.Next;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
void InvalidateStateTimes()
|
||||
{
|
||||
int count = m_States.Count;
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
if (state == null)
|
||||
continue;
|
||||
|
||||
state.InvalidateTime();
|
||||
}
|
||||
}
|
||||
|
||||
public override void PrepareFrame(Playable owner, FrameData data)
|
||||
{
|
||||
InvalidateStateTimes();
|
||||
|
||||
UpdateQueuedStates();
|
||||
|
||||
UpdateStates(data.deltaTime);
|
||||
|
||||
//Once everything is calculated, update done status
|
||||
UpdateDoneStatus();
|
||||
|
||||
CleanClonedStates();
|
||||
}
|
||||
|
||||
public bool ValidateInput(int index, Playable input)
|
||||
{
|
||||
if (!ValidateIndex(index))
|
||||
return false;
|
||||
|
||||
StateInfo state = m_States[index];
|
||||
if (state == null || !state.playable.IsValid() || state.playable.GetHandle() != input.GetHandle())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool ValidateIndex(int index)
|
||||
{
|
||||
return index >= 0 && index < m_States.Count;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e979d7febf8bb72429b0869d1791a78a
|
||||
timeCreated: 1493310304
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,718 @@
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
using UnityEngine.Animations;
|
||||
using System;
|
||||
|
||||
public partial class SimpleAnimationPlayable : PlayableBehaviour
|
||||
{
|
||||
private int m_StatesVersion = 0;
|
||||
|
||||
private void InvalidateStates() { m_StatesVersion++; }
|
||||
private class StateEnumerable: IEnumerable<IState>
|
||||
{
|
||||
private SimpleAnimationPlayable m_Owner;
|
||||
public StateEnumerable(SimpleAnimationPlayable owner)
|
||||
{
|
||||
m_Owner = owner;
|
||||
}
|
||||
|
||||
public IEnumerator<IState> GetEnumerator()
|
||||
{
|
||||
return new StateEnumerator(m_Owner);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return new StateEnumerator(m_Owner);
|
||||
}
|
||||
|
||||
class StateEnumerator : IEnumerator<IState>
|
||||
{
|
||||
private int m_Index = -1;
|
||||
private int m_Version;
|
||||
private SimpleAnimationPlayable m_Owner;
|
||||
public StateEnumerator(SimpleAnimationPlayable owner)
|
||||
{
|
||||
m_Owner = owner;
|
||||
m_Version = m_Owner.m_StatesVersion;
|
||||
Reset();
|
||||
}
|
||||
|
||||
private bool IsValid() { return m_Owner != null && m_Version == m_Owner.m_StatesVersion; }
|
||||
|
||||
IState GetCurrentHandle(int index)
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new InvalidOperationException("The collection has been modified, this Enumerator is invalid");
|
||||
|
||||
if (index < 0 || index >= m_Owner.m_States.Count)
|
||||
throw new InvalidOperationException("Enumerator is invalid");
|
||||
|
||||
StateInfo state = m_Owner.m_States[index];
|
||||
if (state == null)
|
||||
throw new InvalidOperationException("Enumerator is invalid");
|
||||
|
||||
return new StateHandle(m_Owner, state.index, state.playable);
|
||||
}
|
||||
|
||||
object IEnumerator.Current { get { return GetCurrentHandle(m_Index); } }
|
||||
|
||||
IState IEnumerator<IState>.Current { get { return GetCurrentHandle(m_Index); } }
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new InvalidOperationException("The collection has been modified, this Enumerator is invalid");
|
||||
|
||||
do
|
||||
{ m_Index++; } while (m_Index < m_Owner.m_States.Count && m_Owner.m_States[m_Index] == null);
|
||||
|
||||
return m_Index < m_Owner.m_States.Count;
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new InvalidOperationException("The collection has been modified, this Enumerator is invalid");
|
||||
m_Index = -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IState
|
||||
{
|
||||
bool IsValid();
|
||||
|
||||
bool enabled { get; set; }
|
||||
|
||||
float time { get; set; }
|
||||
|
||||
float normalizedTime { get; set; }
|
||||
|
||||
float speed { get; set; }
|
||||
|
||||
string name { get; set; }
|
||||
|
||||
float weight { get; set; }
|
||||
|
||||
float length { get; }
|
||||
|
||||
AnimationClip clip { get; }
|
||||
|
||||
WrapMode wrapMode { get; }
|
||||
}
|
||||
|
||||
public class StateHandle : IState
|
||||
{
|
||||
public StateHandle(SimpleAnimationPlayable s, int index, Playable target)
|
||||
{
|
||||
m_Parent = s;
|
||||
m_Index = index;
|
||||
m_Target = target;
|
||||
}
|
||||
|
||||
public bool IsValid()
|
||||
{
|
||||
return m_Parent.ValidateInput(m_Index, m_Target);
|
||||
}
|
||||
|
||||
public bool enabled
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
return m_Parent.m_States[m_Index].enabled;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
if (value)
|
||||
m_Parent.m_States.EnableState(m_Index);
|
||||
else
|
||||
m_Parent.m_States.DisableState(m_Index);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public float time
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
return m_Parent.m_States.GetStateTime(m_Index);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
m_Parent.m_States.SetStateTime(m_Index, value);
|
||||
}
|
||||
}
|
||||
|
||||
public float normalizedTime
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
|
||||
float length = m_Parent.m_States.GetClipLength(m_Index);
|
||||
if (length == 0f)
|
||||
length = 1f;
|
||||
|
||||
return m_Parent.m_States.GetStateTime(m_Index) / length;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
|
||||
float length = m_Parent.m_States.GetClipLength(m_Index);
|
||||
if (length == 0f)
|
||||
length = 1f;
|
||||
|
||||
m_Parent.m_States.SetStateTime(m_Index, value *= length);
|
||||
}
|
||||
}
|
||||
|
||||
public float speed
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
return m_Parent.m_States.GetStateSpeed(m_Index);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
m_Parent.m_States.SetStateSpeed(m_Index, value);
|
||||
}
|
||||
}
|
||||
|
||||
public string name
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
return m_Parent.m_States.GetStateName(m_Index);
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
if (value == null)
|
||||
throw new System.ArgumentNullException("A null string is not a valid name");
|
||||
m_Parent.m_States.SetStateName(m_Index, value);
|
||||
}
|
||||
}
|
||||
|
||||
public float weight
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
return m_Parent.m_States[m_Index].weight;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
if (value < 0)
|
||||
throw new System.ArgumentException("Weights cannot be negative");
|
||||
|
||||
m_Parent.m_States.SetInputWeight(m_Index, value);
|
||||
}
|
||||
}
|
||||
|
||||
public float length
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
return m_Parent.m_States.GetStateLength(m_Index);
|
||||
}
|
||||
}
|
||||
|
||||
public AnimationClip clip
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
return m_Parent.m_States.GetStateClip(m_Index);
|
||||
}
|
||||
}
|
||||
|
||||
public WrapMode wrapMode
|
||||
{
|
||||
get
|
||||
{
|
||||
if (!IsValid())
|
||||
throw new System.InvalidOperationException("This StateHandle is not valid");
|
||||
return m_Parent.m_States.GetStateWrapMode(m_Index);
|
||||
}
|
||||
}
|
||||
|
||||
public int index { get { return m_Index; } }
|
||||
|
||||
private SimpleAnimationPlayable m_Parent;
|
||||
private int m_Index;
|
||||
private Playable m_Target;
|
||||
}
|
||||
|
||||
private class StateInfo
|
||||
{
|
||||
public void Initialize(string name, AnimationClip clip, WrapMode wrapMode)
|
||||
{
|
||||
m_StateName = name;
|
||||
m_Clip = clip;
|
||||
m_WrapMode = wrapMode;
|
||||
}
|
||||
|
||||
public float GetTime()
|
||||
{
|
||||
if (m_TimeIsUpToDate)
|
||||
return m_Time;
|
||||
|
||||
m_Time = (float)m_Playable.GetTime();
|
||||
m_TimeIsUpToDate = true;
|
||||
return m_Time;
|
||||
}
|
||||
|
||||
public void SetTime(float newTime)
|
||||
{
|
||||
m_Time = newTime;
|
||||
m_Playable.ResetTime(m_Time);
|
||||
m_Playable.SetDone(m_Time >= m_Playable.GetDuration());
|
||||
}
|
||||
|
||||
public void Enable()
|
||||
{
|
||||
if (m_Enabled)
|
||||
return;
|
||||
|
||||
m_EnabledDirty = true;
|
||||
m_Enabled = true;
|
||||
}
|
||||
|
||||
public void Disable()
|
||||
{
|
||||
if (m_Enabled == false)
|
||||
return;
|
||||
|
||||
m_EnabledDirty = true;
|
||||
m_Enabled = false;
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
m_Playable.SetPlayState(PlayState.Paused);
|
||||
}
|
||||
|
||||
public void Play()
|
||||
{
|
||||
m_Playable.SetPlayState(PlayState.Playing);
|
||||
}
|
||||
|
||||
public void Stop()
|
||||
{
|
||||
m_FadeSpeed = 0f;
|
||||
ForceWeight(0.0f);
|
||||
Disable();
|
||||
SetTime(0.0f);
|
||||
m_Playable.SetDone(false);
|
||||
if (isClone)
|
||||
{
|
||||
m_ReadyForCleanup = true;
|
||||
}
|
||||
}
|
||||
|
||||
public void ForceWeight(float weight)
|
||||
{
|
||||
m_TargetWeight = weight;
|
||||
m_Fading = false;
|
||||
m_FadeSpeed = 0f;
|
||||
SetWeight(weight);
|
||||
}
|
||||
|
||||
public void SetWeight(float weight)
|
||||
{
|
||||
m_Weight = weight;
|
||||
m_WeightDirty = true;
|
||||
}
|
||||
|
||||
public void FadeTo(float weight, float speed)
|
||||
{
|
||||
m_Fading = Mathf.Abs(speed) > 0f;
|
||||
m_FadeSpeed = speed;
|
||||
m_TargetWeight = weight;
|
||||
}
|
||||
|
||||
public void DestroyPlayable()
|
||||
{
|
||||
if (m_Playable.IsValid())
|
||||
{
|
||||
m_Playable.GetGraph().DestroySubgraph(m_Playable);
|
||||
}
|
||||
}
|
||||
|
||||
public void SetAsCloneOf(StateHandle handle)
|
||||
{
|
||||
m_ParentState = handle;
|
||||
m_IsClone = true;
|
||||
}
|
||||
|
||||
public bool enabled
|
||||
{
|
||||
get { return m_Enabled; }
|
||||
}
|
||||
|
||||
private bool m_Enabled;
|
||||
|
||||
public int index
|
||||
{
|
||||
get { return m_Index; }
|
||||
set
|
||||
{
|
||||
Debug.Assert(m_Index == 0, "Should never reassign Index");
|
||||
m_Index = value;
|
||||
}
|
||||
}
|
||||
|
||||
private int m_Index;
|
||||
|
||||
public string stateName
|
||||
{
|
||||
get { return m_StateName; }
|
||||
set { m_StateName = value; }
|
||||
}
|
||||
|
||||
private string m_StateName;
|
||||
|
||||
public bool fading
|
||||
{
|
||||
get { return m_Fading; }
|
||||
}
|
||||
|
||||
private bool m_Fading;
|
||||
|
||||
|
||||
private float m_Time;
|
||||
|
||||
public float targetWeight
|
||||
{
|
||||
get { return m_TargetWeight; }
|
||||
}
|
||||
|
||||
private float m_TargetWeight;
|
||||
|
||||
public float weight
|
||||
{
|
||||
get { return m_Weight; }
|
||||
}
|
||||
|
||||
float m_Weight;
|
||||
|
||||
public float fadeSpeed
|
||||
{
|
||||
get { return m_FadeSpeed; }
|
||||
}
|
||||
|
||||
float m_FadeSpeed;
|
||||
|
||||
public float speed
|
||||
{
|
||||
get { return (float)m_Playable.GetSpeed(); }
|
||||
set { m_Playable.SetSpeed(value); }
|
||||
}
|
||||
|
||||
public float playableDuration
|
||||
{
|
||||
get { return (float)m_Playable.GetDuration(); }
|
||||
}
|
||||
|
||||
public AnimationClip clip
|
||||
{
|
||||
get { return m_Clip; }
|
||||
}
|
||||
|
||||
private AnimationClip m_Clip;
|
||||
|
||||
public void SetPlayable(Playable playable)
|
||||
{
|
||||
m_Playable = playable;
|
||||
}
|
||||
|
||||
public bool isDone { get { return m_Playable.IsDone(); } }
|
||||
|
||||
public Playable playable
|
||||
{
|
||||
get { return m_Playable; }
|
||||
}
|
||||
|
||||
private Playable m_Playable;
|
||||
|
||||
public WrapMode wrapMode
|
||||
{
|
||||
get { return m_WrapMode; }
|
||||
}
|
||||
|
||||
private WrapMode m_WrapMode;
|
||||
|
||||
//Clone information
|
||||
public bool isClone
|
||||
{
|
||||
get { return m_IsClone; }
|
||||
}
|
||||
|
||||
private bool m_IsClone;
|
||||
|
||||
public bool isReadyForCleanup
|
||||
{
|
||||
get { return m_ReadyForCleanup; }
|
||||
}
|
||||
|
||||
private bool m_ReadyForCleanup;
|
||||
|
||||
public StateHandle parentState
|
||||
{
|
||||
get { return m_ParentState; }
|
||||
}
|
||||
|
||||
public StateHandle m_ParentState;
|
||||
|
||||
public bool enabledDirty { get { return m_EnabledDirty; } }
|
||||
public bool weightDirty { get { return m_WeightDirty; } }
|
||||
|
||||
public void ResetDirtyFlags()
|
||||
{
|
||||
m_EnabledDirty = false;
|
||||
m_WeightDirty = false;
|
||||
}
|
||||
|
||||
private bool m_WeightDirty;
|
||||
private bool m_EnabledDirty;
|
||||
|
||||
public void InvalidateTime() { m_TimeIsUpToDate = false; }
|
||||
private bool m_TimeIsUpToDate;
|
||||
}
|
||||
|
||||
private StateHandle StateInfoToHandle(StateInfo info)
|
||||
{
|
||||
return new StateHandle(this, info.index, info.playable);
|
||||
}
|
||||
|
||||
private class StateManagement
|
||||
{
|
||||
private List<StateInfo> m_States;
|
||||
|
||||
public int Count { get { return m_Count; } }
|
||||
|
||||
private int m_Count;
|
||||
|
||||
public StateInfo this[int i]
|
||||
{
|
||||
get
|
||||
{
|
||||
return m_States[i];
|
||||
}
|
||||
}
|
||||
|
||||
public StateManagement()
|
||||
{
|
||||
m_States = new List<StateInfo>();
|
||||
}
|
||||
|
||||
public StateInfo InsertState()
|
||||
{
|
||||
StateInfo state = new StateInfo();
|
||||
|
||||
int firstAvailable = m_States.FindIndex(s => s == null);
|
||||
if (firstAvailable == -1)
|
||||
{
|
||||
firstAvailable = m_States.Count;
|
||||
m_States.Add(state);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_States.Insert(firstAvailable, state);
|
||||
}
|
||||
|
||||
state.index = firstAvailable;
|
||||
m_Count++;
|
||||
return state;
|
||||
}
|
||||
public bool AnyStatePlaying()
|
||||
{
|
||||
return m_States.FindIndex(s => s != null && s.enabled) != -1;
|
||||
}
|
||||
|
||||
public void RemoveState(int index)
|
||||
{
|
||||
StateInfo removed = m_States[index];
|
||||
m_States[index] = null;
|
||||
removed.DestroyPlayable();
|
||||
m_Count = m_States.Count;
|
||||
}
|
||||
|
||||
public bool RemoveClip(AnimationClip clip)
|
||||
{
|
||||
bool removed = false;
|
||||
for (int i = 0; i < m_States.Count; i++)
|
||||
{
|
||||
StateInfo state = m_States[i];
|
||||
if (state != null &&state.clip == clip)
|
||||
{
|
||||
RemoveState(i);
|
||||
removed = true;
|
||||
}
|
||||
}
|
||||
return removed;
|
||||
}
|
||||
|
||||
public StateInfo FindState(string name)
|
||||
{
|
||||
int index = m_States.FindIndex(s => s != null && s.stateName == name);
|
||||
if (index == -1)
|
||||
return null;
|
||||
|
||||
return m_States[index];
|
||||
}
|
||||
|
||||
public void EnableState(int index)
|
||||
{
|
||||
StateInfo state = m_States[index];
|
||||
state.Enable();
|
||||
}
|
||||
|
||||
public void DisableState(int index)
|
||||
{
|
||||
StateInfo state = m_States[index];
|
||||
state.Disable();
|
||||
}
|
||||
|
||||
public void SetInputWeight(int index, float weight)
|
||||
{
|
||||
StateInfo state = m_States[index];
|
||||
state.SetWeight(weight);
|
||||
|
||||
}
|
||||
|
||||
public void SetStateTime(int index, float time)
|
||||
{
|
||||
StateInfo state = m_States[index];
|
||||
state.SetTime(time);
|
||||
}
|
||||
|
||||
public float GetStateTime(int index)
|
||||
{
|
||||
StateInfo state = m_States[index];
|
||||
return state.GetTime();
|
||||
}
|
||||
|
||||
public bool IsCloneOf(int potentialCloneIndex, int originalIndex)
|
||||
{
|
||||
StateInfo potentialClone = m_States[potentialCloneIndex];
|
||||
return potentialClone.isClone && potentialClone.parentState.index == originalIndex;
|
||||
}
|
||||
|
||||
public float GetStateSpeed(int index)
|
||||
{
|
||||
return m_States[index].speed;
|
||||
}
|
||||
public void SetStateSpeed(int index, float value)
|
||||
{
|
||||
m_States[index].speed = value;
|
||||
}
|
||||
|
||||
public float GetInputWeight(int index)
|
||||
{
|
||||
return m_States[index].weight;
|
||||
}
|
||||
|
||||
public float GetStateLength(int index)
|
||||
{
|
||||
AnimationClip clip = m_States[index].clip;
|
||||
if (clip == null)
|
||||
return 0f;
|
||||
float speed = m_States[index].speed;
|
||||
if (speed == 0f)
|
||||
return Mathf.Infinity;
|
||||
|
||||
return clip.length / speed;
|
||||
}
|
||||
|
||||
public float GetClipLength(int index)
|
||||
{
|
||||
AnimationClip clip = m_States[index].clip;
|
||||
if (clip == null)
|
||||
return 0f;
|
||||
|
||||
return clip.length;
|
||||
}
|
||||
|
||||
public float GetStatePlayableDuration(int index)
|
||||
{
|
||||
return m_States[index].playableDuration;
|
||||
}
|
||||
|
||||
public AnimationClip GetStateClip(int index)
|
||||
{
|
||||
return m_States[index].clip;
|
||||
}
|
||||
|
||||
public WrapMode GetStateWrapMode(int index)
|
||||
{
|
||||
return m_States[index].wrapMode;
|
||||
}
|
||||
|
||||
public string GetStateName(int index)
|
||||
{
|
||||
return m_States[index].stateName;
|
||||
}
|
||||
|
||||
public void SetStateName(int index, string name)
|
||||
{
|
||||
m_States[index].stateName = name;
|
||||
}
|
||||
|
||||
public void StopState(int index, bool cleanup)
|
||||
{
|
||||
if (cleanup)
|
||||
{
|
||||
RemoveState(index);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_States[index].Stop();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private struct QueuedState
|
||||
{
|
||||
public QueuedState(StateHandle s, float t)
|
||||
{
|
||||
state = s;
|
||||
fadeTime = t;
|
||||
}
|
||||
|
||||
public StateHandle state;
|
||||
public float fadeTime;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ce4f5507fa3bef446a3981a7e6d2475e
|
||||
timeCreated: 1502387922
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
405
Assets/Scripts/SimpleAnimationComponent/SimpleAnimation_impl.cs
Normal file
405
Assets/Scripts/SimpleAnimationComponent/SimpleAnimation_impl.cs
Normal file
@@ -0,0 +1,405 @@
|
||||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
using UnityEngine.Playables;
|
||||
|
||||
[RequireComponent(typeof(Animator))]
|
||||
public partial class SimpleAnimation: MonoBehaviour, IAnimationClipSource
|
||||
{
|
||||
const string kDefaultStateName = "Default";
|
||||
private class StateEnumerable : IEnumerable<State>
|
||||
{
|
||||
private SimpleAnimation m_Owner;
|
||||
public StateEnumerable(SimpleAnimation owner)
|
||||
{
|
||||
m_Owner = owner;
|
||||
}
|
||||
|
||||
public IEnumerator<State> GetEnumerator()
|
||||
{
|
||||
return new StateEnumerator(m_Owner);
|
||||
}
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
{
|
||||
return new StateEnumerator(m_Owner);
|
||||
}
|
||||
|
||||
class StateEnumerator : IEnumerator<State>
|
||||
{
|
||||
private SimpleAnimation m_Owner;
|
||||
private IEnumerator<SimpleAnimationPlayable.IState> m_Impl;
|
||||
public StateEnumerator(SimpleAnimation owner)
|
||||
{
|
||||
m_Owner = owner;
|
||||
m_Impl = m_Owner.m_Playable.GetStates().GetEnumerator();
|
||||
Reset();
|
||||
}
|
||||
|
||||
State GetCurrent()
|
||||
{
|
||||
return new StateImpl(m_Impl.Current, m_Owner);
|
||||
}
|
||||
|
||||
object IEnumerator.Current { get { return GetCurrent(); } }
|
||||
|
||||
State IEnumerator<State>.Current { get { return GetCurrent(); } }
|
||||
|
||||
public void Dispose() { }
|
||||
|
||||
public bool MoveNext()
|
||||
{
|
||||
return m_Impl.MoveNext();
|
||||
}
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
m_Impl.Reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
private class StateImpl : State
|
||||
{
|
||||
public StateImpl(SimpleAnimationPlayable.IState handle, SimpleAnimation component)
|
||||
{
|
||||
m_StateHandle = handle;
|
||||
m_Component = component;
|
||||
}
|
||||
|
||||
private SimpleAnimationPlayable.IState m_StateHandle;
|
||||
private SimpleAnimation m_Component;
|
||||
|
||||
bool State.enabled
|
||||
{
|
||||
get { return m_StateHandle.enabled; }
|
||||
set
|
||||
{
|
||||
m_StateHandle.enabled = value;
|
||||
if (value)
|
||||
{
|
||||
m_Component.Kick();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool State.isValid
|
||||
{
|
||||
get { return m_StateHandle.IsValid(); }
|
||||
}
|
||||
float State.time
|
||||
{
|
||||
get { return m_StateHandle.time; }
|
||||
set { m_StateHandle.time = value;
|
||||
m_Component.Kick(); }
|
||||
}
|
||||
float State.normalizedTime
|
||||
{
|
||||
get { return m_StateHandle.normalizedTime; }
|
||||
set { m_StateHandle.normalizedTime = value;
|
||||
m_Component.Kick();}
|
||||
}
|
||||
float State.speed
|
||||
{
|
||||
get { return m_StateHandle.speed; }
|
||||
set { m_StateHandle.speed = value;
|
||||
m_Component.Kick();}
|
||||
}
|
||||
|
||||
string State.name
|
||||
{
|
||||
get { return m_StateHandle.name; }
|
||||
set { m_StateHandle.name = value; }
|
||||
}
|
||||
float State.weight
|
||||
{
|
||||
get { return m_StateHandle.weight; }
|
||||
set { m_StateHandle.weight = value;
|
||||
m_Component.Kick();}
|
||||
}
|
||||
float State.length
|
||||
{
|
||||
get { return m_StateHandle.length; }
|
||||
}
|
||||
|
||||
AnimationClip State.clip
|
||||
{
|
||||
get { return m_StateHandle.clip; }
|
||||
}
|
||||
|
||||
WrapMode State.wrapMode
|
||||
{
|
||||
get { return m_StateHandle.wrapMode; }
|
||||
set { Debug.LogError("Not Implemented"); }
|
||||
}
|
||||
}
|
||||
|
||||
[System.Serializable]
|
||||
public class EditorState
|
||||
{
|
||||
public AnimationClip clip;
|
||||
public string name;
|
||||
public bool defaultState;
|
||||
}
|
||||
|
||||
protected void Kick()
|
||||
{
|
||||
if (!m_IsPlaying)
|
||||
{
|
||||
m_Graph.Play();
|
||||
m_IsPlaying = true;
|
||||
}
|
||||
}
|
||||
|
||||
protected PlayableGraph m_Graph;
|
||||
protected PlayableHandle m_LayerMixer;
|
||||
protected PlayableHandle m_TransitionMixer;
|
||||
protected Animator m_Animator;
|
||||
protected bool m_Initialized;
|
||||
protected bool m_IsPlaying;
|
||||
|
||||
protected SimpleAnimationPlayable m_Playable;
|
||||
|
||||
[SerializeField]
|
||||
protected bool m_PlayAutomatically = true;
|
||||
|
||||
[SerializeField]
|
||||
protected bool m_AnimatePhysics = false;
|
||||
|
||||
[SerializeField]
|
||||
protected AnimatorCullingMode m_CullingMode = AnimatorCullingMode.CullUpdateTransforms;
|
||||
|
||||
[SerializeField]
|
||||
protected WrapMode m_WrapMode;
|
||||
|
||||
[SerializeField]
|
||||
protected AnimationClip m_Clip;
|
||||
|
||||
[SerializeField]
|
||||
private EditorState[] m_States;
|
||||
|
||||
protected virtual void OnEnable()
|
||||
{
|
||||
Initialize();
|
||||
m_Graph.Play();
|
||||
if (m_PlayAutomatically)
|
||||
{
|
||||
Stop();
|
||||
Play();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void OnDisable()
|
||||
{
|
||||
if (m_Initialized)
|
||||
{
|
||||
Stop();
|
||||
m_Graph.Stop();
|
||||
}
|
||||
}
|
||||
|
||||
private void Reset()
|
||||
{
|
||||
if (m_Graph.IsValid())
|
||||
m_Graph.Destroy();
|
||||
|
||||
m_Initialized = false;
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
if (m_Initialized)
|
||||
return;
|
||||
|
||||
m_Animator = GetComponent<Animator>();
|
||||
m_Animator.updateMode = m_AnimatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
|
||||
m_Animator.cullingMode = m_CullingMode;
|
||||
m_Graph = PlayableGraph.Create();
|
||||
m_Graph.SetTimeUpdateMode(DirectorUpdateMode.GameTime);
|
||||
SimpleAnimationPlayable template = new SimpleAnimationPlayable();
|
||||
|
||||
var playable = ScriptPlayable<SimpleAnimationPlayable>.Create(m_Graph, template, 1);
|
||||
m_Playable = playable.GetBehaviour();
|
||||
m_Playable.onDone += OnPlayableDone;
|
||||
if (m_States == null)
|
||||
{
|
||||
m_States = new EditorState[1];
|
||||
m_States[0] = new EditorState();
|
||||
m_States[0].defaultState = true;
|
||||
m_States[0].name = "Default";
|
||||
}
|
||||
|
||||
|
||||
if (m_States != null)
|
||||
{
|
||||
foreach (var state in m_States)
|
||||
{
|
||||
if (state.clip)
|
||||
{
|
||||
m_Playable.AddClip(state.clip, state.name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EnsureDefaultStateExists();
|
||||
|
||||
AnimationPlayableUtilities.Play(m_Animator, m_Playable.playable, m_Graph);
|
||||
Play();
|
||||
Kick();
|
||||
m_Initialized = true;
|
||||
}
|
||||
|
||||
private void EnsureDefaultStateExists()
|
||||
{
|
||||
if ( m_Playable != null && m_Clip != null && m_Playable.GetState(kDefaultStateName) == null )
|
||||
{
|
||||
m_Playable.AddClip(m_Clip, kDefaultStateName);
|
||||
Kick();
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
Initialize();
|
||||
}
|
||||
|
||||
protected void OnDestroy()
|
||||
{
|
||||
if (m_Graph.IsValid())
|
||||
{
|
||||
m_Graph.Destroy();
|
||||
}
|
||||
}
|
||||
|
||||
private void OnPlayableDone()
|
||||
{
|
||||
m_Graph.Stop();
|
||||
m_IsPlaying = false;
|
||||
}
|
||||
|
||||
private void RebuildStates()
|
||||
{
|
||||
var playableStates = GetStates();
|
||||
var list = new List<EditorState>();
|
||||
foreach (var state in playableStates)
|
||||
{
|
||||
var newState = new EditorState();
|
||||
newState.clip = state.clip;
|
||||
newState.name = state.name;
|
||||
list.Add(newState);
|
||||
}
|
||||
m_States = list.ToArray();
|
||||
}
|
||||
|
||||
EditorState CreateDefaultEditorState()
|
||||
{
|
||||
var defaultState = new EditorState();
|
||||
defaultState.name = "Default";
|
||||
defaultState.clip = m_Clip;
|
||||
defaultState.defaultState = true;
|
||||
|
||||
return defaultState;
|
||||
}
|
||||
|
||||
static void LegacyClipCheck(AnimationClip clip)
|
||||
{
|
||||
if (clip && clip.legacy)
|
||||
{
|
||||
throw new ArgumentException(string.Format("Legacy clip {0} cannot be used in this component. Set .legacy property to false before using this clip", clip));
|
||||
}
|
||||
}
|
||||
|
||||
void InvalidLegacyClipError(string clipName, string stateName)
|
||||
{
|
||||
Debug.LogErrorFormat(this.gameObject,"Animation clip {0} in state {1} is Legacy. Set clip.legacy to false, or reimport as Generic to use it with SimpleAnimationComponent", clipName, stateName);
|
||||
}
|
||||
|
||||
private void OnValidate()
|
||||
{
|
||||
//Don't mess with runtime data
|
||||
if (Application.isPlaying)
|
||||
return;
|
||||
|
||||
if (m_Clip && m_Clip.legacy)
|
||||
{
|
||||
Debug.LogErrorFormat(this.gameObject,"Animation clip {0} is Legacy. Set clip.legacy to false, or reimport as Generic to use it with SimpleAnimationComponent", m_Clip.name);
|
||||
m_Clip = null;
|
||||
}
|
||||
|
||||
//Ensure at least one state exists
|
||||
if (m_States == null || m_States.Length == 0)
|
||||
{
|
||||
m_States = new EditorState[1];
|
||||
}
|
||||
|
||||
//Create default state if it's null
|
||||
if (m_States[0] == null)
|
||||
{
|
||||
m_States[0] = CreateDefaultEditorState();
|
||||
}
|
||||
|
||||
//If first state is not the default state, create a new default state at index 0 and push back the rest
|
||||
if (m_States[0].defaultState == false || m_States[0].name != "Default")
|
||||
{
|
||||
var oldArray = m_States;
|
||||
m_States = new EditorState[oldArray.Length + 1];
|
||||
m_States[0] = CreateDefaultEditorState();
|
||||
oldArray.CopyTo(m_States, 1);
|
||||
}
|
||||
|
||||
//If default clip changed, update the default state
|
||||
if (m_States[0].clip != m_Clip)
|
||||
m_States[0].clip = m_Clip;
|
||||
|
||||
|
||||
//Make sure only one state is default
|
||||
for (int i = 1; i < m_States.Length; i++)
|
||||
{
|
||||
if (m_States[i] == null)
|
||||
{
|
||||
m_States[i] = new EditorState();
|
||||
}
|
||||
m_States[i].defaultState = false;
|
||||
}
|
||||
|
||||
//Ensure state names are unique
|
||||
int stateCount = m_States.Length;
|
||||
string[] names = new string[stateCount];
|
||||
|
||||
for (int i = 0; i < stateCount; i++)
|
||||
{
|
||||
EditorState state = m_States[i];
|
||||
if (state.name == "" && state.clip)
|
||||
{
|
||||
state.name = state.clip.name;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
state.name = ObjectNames.GetUniqueName(names, state.name);
|
||||
#endif
|
||||
names[i] = state.name;
|
||||
|
||||
if (state.clip && state.clip.legacy)
|
||||
{
|
||||
InvalidLegacyClipError(state.clip.name, state.name);
|
||||
state.clip = null;
|
||||
}
|
||||
}
|
||||
|
||||
m_Animator = GetComponent<Animator>();
|
||||
m_Animator.updateMode = m_AnimatePhysics ? AnimatorUpdateMode.AnimatePhysics : AnimatorUpdateMode.Normal;
|
||||
m_Animator.cullingMode = m_CullingMode;
|
||||
}
|
||||
|
||||
public void GetAnimationClips(List<AnimationClip> results)
|
||||
{
|
||||
foreach (var state in m_States)
|
||||
{
|
||||
if (state.clip != null)
|
||||
results.Add(state.clip);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 11c2ad7a923243841ab35b83723a6473
|
||||
timeCreated: 1502394771
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Scripts/SimpleAnimationComponent/Tests.meta
Normal file
10
Assets/Scripts/SimpleAnimationComponent/Tests.meta
Normal file
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 52d9c3bfd6589ad4fad615672d33562b
|
||||
folderAsset: yes
|
||||
timeCreated: 1502464957
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user