Resolve WES-187 "Unit tests account and system"
This commit is contained in:
committed by
Jerome Coudron
parent
c4b6c60288
commit
b9bbef8dcf
14
Assets/Architecture/Scripts/ArchitectureScripts.asmdef
Normal file
14
Assets/Architecture/Scripts/ArchitectureScripts.asmdef
Normal file
@@ -0,0 +1,14 @@
|
||||
{
|
||||
"name": "ArchitectureScripts",
|
||||
"rootNamespace": "",
|
||||
"references": [],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e83ddf9a537a96b4a804a16bb7872ec1
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
15
Assets/Architecture/Scripts/CourseIndex.cs
Normal file
15
Assets/Architecture/Scripts/CourseIndex.cs
Normal file
@@ -0,0 +1,15 @@
|
||||
|
||||
/// <summary>
|
||||
/// Enum for easy indexing and checking if a course is of a certain kind
|
||||
/// </summary>
|
||||
public enum CourseIndex
|
||||
{
|
||||
FINGERSPELLING,
|
||||
BASIC_SIGNS,
|
||||
CLOTHING,
|
||||
ANIMALS,
|
||||
FOOD,
|
||||
HOBBIES,
|
||||
HOUSE,
|
||||
FAMILY
|
||||
}
|
||||
11
Assets/Architecture/Scripts/CourseIndex.cs.meta
Normal file
11
Assets/Architecture/Scripts/CourseIndex.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a5bf21dee022ed0489face1c734359de
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
10
Assets/Architecture/Scripts/MinigameIndex.cs
Normal file
10
Assets/Architecture/Scripts/MinigameIndex.cs
Normal file
@@ -0,0 +1,10 @@
|
||||
|
||||
/// <summary>
|
||||
/// Enum for easy indexing and checking if a minigame is of a certain kind
|
||||
/// </summary>
|
||||
public enum MinigameIndex
|
||||
{
|
||||
SPELLING_BEE,
|
||||
HANGMAN,
|
||||
JUST_SIGN
|
||||
}
|
||||
11
Assets/Architecture/Scripts/MinigameIndex.cs.meta
Normal file
11
Assets/Architecture/Scripts/MinigameIndex.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 97282ff3b465e3c4682d218b3819b2e8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
542
Assets/Architecture/Scripts/PersistentDataController.cs
Normal file
542
Assets/Architecture/Scripts/PersistentDataController.cs
Normal file
@@ -0,0 +1,542 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.Serialization.Formatters.Binary;
|
||||
using UnityEngine;
|
||||
|
||||
/// <summary>
|
||||
/// PersistentDataController singleton
|
||||
/// </summary>
|
||||
public class PersistentDataController
|
||||
{
|
||||
/// <summary>
|
||||
/// The instance controlling the singleton
|
||||
/// </summary>
|
||||
private static PersistentDataController instance = null;
|
||||
|
||||
/// <summary>
|
||||
/// Current implementation version of the PersistentDataController
|
||||
/// </summary>
|
||||
/// <remarks>MSB represent sprint version, LSB represent subversion</remarks>
|
||||
public const int VERSION = 0x04_03;
|
||||
|
||||
/// <summary>
|
||||
/// Path of the <c>.json</c>-file to store all serialized data
|
||||
/// </summary>
|
||||
public static string PATH = null;
|
||||
|
||||
/// <summary>
|
||||
/// Class to hold a list of data records
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PersistentDataContainer
|
||||
{
|
||||
/// <summary>
|
||||
/// A helper class for handling the stored progress
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class PersistentDataEntry
|
||||
{
|
||||
/// <summary>
|
||||
/// The key, used to reference the data object
|
||||
/// </summary>
|
||||
public string key;
|
||||
|
||||
/// <summary>
|
||||
/// The object, representated as a list of byte (which can be serialized)
|
||||
/// </summary>
|
||||
public List<byte> data = new List<byte>();
|
||||
|
||||
public PersistentDataEntry(string key, byte[] data) : this(key, data.ToList())
|
||||
{ }
|
||||
|
||||
public PersistentDataEntry(string key, List<byte> data)
|
||||
{
|
||||
this.key = key;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// List of data records
|
||||
/// </summary>
|
||||
public List<PersistentDataEntry> entries = new List<PersistentDataEntry>();
|
||||
|
||||
/// <summary>
|
||||
/// Update the value of a certain key,
|
||||
/// or add a new value if the key was not present.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the data to be added/updated</typeparam>
|
||||
/// <param name="key">The key, used for referencing the data</param>
|
||||
/// <param name="data">The object of type <typeparamref name="T"/></param>
|
||||
/// <returns><c>true</c> if successful, <c>false</c> otherwise</returns>
|
||||
public bool Set<T>(string key, T data)
|
||||
{
|
||||
if (data == null)
|
||||
return false;
|
||||
|
||||
PersistentDataEntry entry = entries.Find(x => x.key == key);
|
||||
|
||||
// Hacky serialization stuff
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
bf.Serialize(ms, data);
|
||||
if (entry != null)
|
||||
{
|
||||
entry.data.Clear();
|
||||
entry.data.AddRange(ms.ToArray());
|
||||
}
|
||||
else
|
||||
{
|
||||
entries.Add(new PersistentDataEntry(key, ms.ToArray()));
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the data object of a certain key
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the data object</typeparam>
|
||||
/// <param name="key">The key referencing the data object</param>
|
||||
/// <returns>The data, cast to a type <typeparamref name="T"/></returns>
|
||||
/// <exception cref="KeyNotFoundException"></exception>
|
||||
/// <exception cref="InvalidCastException"></exception>
|
||||
public T Get<T>(string key)
|
||||
{
|
||||
BinaryFormatter bf = new BinaryFormatter();
|
||||
using (MemoryStream ms = new MemoryStream())
|
||||
{
|
||||
// Find the correct key
|
||||
foreach (PersistentDataEntry entry in entries)
|
||||
{
|
||||
if (entry.key == key)
|
||||
{
|
||||
// Hacky serialization stuff
|
||||
byte[] data = entry.data.ToArray();
|
||||
ms.Write(data, 0, data.Length);
|
||||
ms.Seek(0, SeekOrigin.Begin);
|
||||
return (T)bf.Deserialize(ms);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Raise an exception when key is not found
|
||||
throw new KeyNotFoundException();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a key-value from the data.
|
||||
/// </summary>
|
||||
/// <param name="key">The key referencing the data object</param>
|
||||
/// <exception cref="KeyNotFoundException"></exception>
|
||||
public void Remove(string key)
|
||||
{
|
||||
if (!Has(key))
|
||||
throw new KeyNotFoundException();
|
||||
|
||||
entries.Remove(entries.Find(x => x.key == key));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove and return value from the data.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the data object</typeparam>
|
||||
/// <param name="key">The key referencing the data object</param>
|
||||
/// <param name="save">Whether the removal of the data should also be saved to disk</param>
|
||||
/// <returns></returns>
|
||||
public T Pop<T>(string key)
|
||||
{
|
||||
T data = Get<T>(key);
|
||||
Remove(key);
|
||||
return data;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Check whether a key is present
|
||||
/// </summary>
|
||||
/// <param name="key">The key to check</param>
|
||||
/// <returns>true if a item can be found with the specified key</returns>
|
||||
public bool Has(string key)
|
||||
{
|
||||
return entries.Find(x => x.key == key) != null;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stored user data record
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SavedUserData : PersistentDataContainer
|
||||
{
|
||||
public string username = null;
|
||||
public int avatarIndex = -1;
|
||||
public double playtime = 0.0;
|
||||
public List<SavedMinigameProgress> minigames = new List<SavedMinigameProgress>();
|
||||
public List<SavedCourseProgress> courses = new List<SavedCourseProgress>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stored course progress data record
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SavedCourseProgress : PersistentDataContainer
|
||||
{
|
||||
|
||||
/// <summary>
|
||||
/// Update the progress value of the SavedLearnableProgress with the given learnableName.
|
||||
/// </summary>
|
||||
/// <param name="learnableName"></param>
|
||||
/// <param name="addValue"></param>
|
||||
public void UpdateLearnable(string learnableName, float addValue)
|
||||
{
|
||||
SavedLearnableProgress learnable = learnables.Find(l => l.name == learnableName);
|
||||
if (learnable == null)
|
||||
throw new KeyNotFoundException();
|
||||
|
||||
// Update the progress value of the SavedLearnableProgress
|
||||
learnable.progress += addValue;
|
||||
// crop the learnable progress around -5 and 5
|
||||
if (learnable.progress > 5.0f)
|
||||
learnable.progress = 5.0f;
|
||||
else if (learnable.progress < -5.0f)
|
||||
learnable.progress = -5.0f;
|
||||
|
||||
// if learnable progress is big enough it is "completed"
|
||||
if (learnable.progress > 3)
|
||||
completedLearnables++;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
///
|
||||
/// </summary>
|
||||
/// <returns> bool which indicates if there are enough inUseLearnables </returns>
|
||||
private bool EnoughLearnables()
|
||||
{
|
||||
// There need to be more then 5 non completed learnables
|
||||
return inUseLearnables - completedLearnables > 5 || totalLearnables == inUseLearnables;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find a SavedLearnableProgress with the given name
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <returns> SavedLearnableProgress with the given name </returns>
|
||||
public SavedLearnableProgress FindLearnable(string name)
|
||||
{
|
||||
return learnables.Find(l => l.name == name);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Find learnable in learnables which is not yet in use, and set it active
|
||||
/// </summary>
|
||||
/// <returns> SavedLearnableProgress learnable </returns>
|
||||
private SavedLearnableProgress UseUnusedLearnable()
|
||||
{
|
||||
SavedLearnableProgress learnable = learnables.Find(l => !l.inUse);
|
||||
if (learnable == null)
|
||||
return null;
|
||||
|
||||
learnable.inUse = true;
|
||||
inUseLearnables++;
|
||||
return learnable;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a random inUse learnable
|
||||
/// </summary>
|
||||
/// <returns> a randomly selected inUse SavedLearnable which is not yet completed</returns>
|
||||
public SavedLearnableProgress GetRandomLearnable()
|
||||
{
|
||||
if (!EnoughLearnables())
|
||||
return UseUnusedLearnable();
|
||||
|
||||
// only select inUse learnables which are not yet completed (progress < 3.5f)
|
||||
List<SavedLearnableProgress> inUseLearnables = learnables.FindAll(l => l.inUse && l.progress <= 3.5f);
|
||||
|
||||
if (inUseLearnables.Count == 0)
|
||||
return null;
|
||||
|
||||
// Select a random index from the in-use learnables list
|
||||
int randomIndex = UnityEngine.Random.Range(0, inUseLearnables.Count);
|
||||
return inUseLearnables[randomIndex];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Create new SavedLearnableProgress object and assigns the index and name values
|
||||
/// </summary>
|
||||
/// <param name="name"></param>
|
||||
/// <param name="index"></param>
|
||||
/// <returns> bool which indicates the success of the function</returns>
|
||||
public bool AddLearnable(string name, int index)
|
||||
{
|
||||
if (learnables.Any(learnable => learnable.name == name || learnable.index == index))
|
||||
return false;
|
||||
|
||||
SavedLearnableProgress savedLearnableProgress = new SavedLearnableProgress();
|
||||
savedLearnableProgress.index = index;
|
||||
savedLearnableProgress.name = name;
|
||||
learnables.Add(savedLearnableProgress);
|
||||
totalLearnables++;
|
||||
return true;
|
||||
}
|
||||
|
||||
public CourseIndex courseIndex;
|
||||
public float progress = -1.0f;
|
||||
public int completedLearnables = 0;
|
||||
public int inUseLearnables = 0;
|
||||
public int totalLearnables = 0;
|
||||
public List<SavedLearnableProgress> learnables = new List<SavedLearnableProgress>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stored individual learnable progress
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SavedLearnableProgress : PersistentDataContainer
|
||||
{
|
||||
public int index;
|
||||
public bool inUse = false;
|
||||
public string name;
|
||||
public float progress = 0.0f;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stored minigame progress data record
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class SavedMinigameProgress : PersistentDataContainer
|
||||
{
|
||||
public MinigameIndex minigameIndex;
|
||||
public List<Score> latestScores = new List<Score>();
|
||||
public List<Score> highestScores = new List<Score>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Stored WeSign data record
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
private class SavedDataStructure
|
||||
{
|
||||
public int version = VERSION;
|
||||
public List<SavedUserData> users = new List<SavedUserData>();
|
||||
public int currentUser = -1;
|
||||
public MinigameIndex currentMinigame;
|
||||
public CourseIndex currentCourse;
|
||||
public ThemeIndex currentTheme;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// The object holding the data references
|
||||
/// </summary>
|
||||
private SavedDataStructure json = new SavedDataStructure();
|
||||
|
||||
/// <summary>
|
||||
/// Get the instance loaded by the singleton
|
||||
/// </summary>
|
||||
/// <returns><c>PersistentDataController</c> instance</returns>
|
||||
public static PersistentDataController GetInstance()
|
||||
{
|
||||
// Create a new instance if non exists
|
||||
if (instance == null || PATH == null)
|
||||
{
|
||||
if (PATH == null)
|
||||
PersistentDataController.PATH = $"{Application.persistentDataPath}/wesign_saved_data.json";
|
||||
instance = new PersistentDataController();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// PersistentDataController contructor
|
||||
/// </summary>
|
||||
private PersistentDataController()
|
||||
{
|
||||
Load();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Clear everything stored in the PersistentDataController, won't save to disk
|
||||
/// </summary>
|
||||
public void Clear()
|
||||
{
|
||||
json.users.Clear();
|
||||
json.currentUser = -1;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Save all data to disk
|
||||
/// </summary>
|
||||
public void Save()
|
||||
{
|
||||
string text = JsonUtility.ToJson(json);
|
||||
File.CreateText(PATH).Close();
|
||||
File.WriteAllText(PATH, text);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Override current data with the data from disk, will just clear if no data was found.
|
||||
/// </summary>
|
||||
/// <param name="overrideOnFail"><c>true</c> if you want to override the existing file if it exists and the loading failed.</param>
|
||||
/// <remarks>If the data on disk is outdated (version number is lower than the current version), the loading will also fail</remarks>
|
||||
/// <returns><c>true</c> if successful, <c>false</c> otherwise</returns>
|
||||
public bool Load(bool overrideOnFail = true)
|
||||
{
|
||||
Clear();
|
||||
if (!File.Exists(PATH))
|
||||
goto failed;
|
||||
|
||||
try
|
||||
{
|
||||
string text = File.ReadAllText(PATH);
|
||||
SavedDataStructure newJson = JsonUtility.FromJson<SavedDataStructure>(text);
|
||||
if (newJson == null || newJson.version != VERSION)
|
||||
goto failed;
|
||||
|
||||
json = newJson;
|
||||
return true;
|
||||
}
|
||||
catch (Exception) { goto failed; }
|
||||
|
||||
failed:
|
||||
if (overrideOnFail)
|
||||
Save();
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Add a user to the WeSign data record
|
||||
/// </summary>
|
||||
/// <param name="user">User data record</param>
|
||||
/// <param name="save">Whether to save the addition immediately to disk</param>
|
||||
public void AddUser(SavedUserData user, bool save = true)
|
||||
{
|
||||
if (json.users.Count == 0)
|
||||
json.currentUser = 0;
|
||||
json.users.Add(user);
|
||||
|
||||
if (save)
|
||||
Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get a list of all user data records
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public List<SavedUserData> GetUsers()
|
||||
{
|
||||
return json.users;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of the current user
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public int GetCurrentUser()
|
||||
{
|
||||
return json.currentUser;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the index of the current record
|
||||
/// </summary>
|
||||
/// <param name="index">New index</param>
|
||||
/// <param name="save">Whether to save the change immediately to disk</param>
|
||||
/// <exception cref="IndexOutOfRangeException"></exception>
|
||||
public void SetCurrentUser(int index, bool save = true)
|
||||
{
|
||||
if (index < 0 || json.users.Count <= index)
|
||||
throw new IndexOutOfRangeException();
|
||||
json.currentUser = index;
|
||||
|
||||
if (save)
|
||||
Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Remove a user data record
|
||||
/// </summary>
|
||||
/// <param name="index">Index of the user</param>
|
||||
/// <param name="save">Whether to save the deletion immediately to disk</param>
|
||||
/// <exception cref="IndexOutOfRangeException"></exception>
|
||||
public void DeleteUser(int index, bool save = true)
|
||||
{
|
||||
if (index < 0 || json.users.Count <= index)
|
||||
throw new IndexOutOfRangeException();
|
||||
|
||||
if (0 < json.currentUser && index <= json.currentUser)
|
||||
json.currentUser--;
|
||||
json.users.RemoveAt(index);
|
||||
|
||||
if (save)
|
||||
Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current course
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public CourseIndex GetCurrentCourse()
|
||||
{
|
||||
return json.currentCourse;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the current course
|
||||
/// </summary>
|
||||
/// <param name="course">New course index</param>
|
||||
/// <param name="save">Whether to save the change immediately to disk</param>
|
||||
public void SetCurrentCourse(CourseIndex course, bool save = true)
|
||||
{
|
||||
json.currentCourse = course;
|
||||
|
||||
if (save)
|
||||
Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current minigame
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public MinigameIndex GetCurrentMinigame()
|
||||
{
|
||||
return json.currentMinigame;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the current minigame
|
||||
/// </summary>
|
||||
/// <param name="minigame">New minigame index</param>
|
||||
/// <param name="save">Whether to save the change immediately to disk</param>
|
||||
public void SetCurrentMinigame(MinigameIndex minigame, bool save = true)
|
||||
{
|
||||
json.currentMinigame = minigame;
|
||||
|
||||
if (save)
|
||||
Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current theme
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
public ThemeIndex GetCurrentTheme()
|
||||
{
|
||||
return json.currentTheme;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Set the current theme
|
||||
/// </summary>
|
||||
/// <param name="theme">New theme index</param>
|
||||
/// <param name="save">Whether to save the change immediately to disk</param>
|
||||
public void SetCurrentTheme(ThemeIndex theme, bool save = true)
|
||||
{
|
||||
json.currentTheme = theme;
|
||||
|
||||
if (save)
|
||||
Save();
|
||||
}
|
||||
}
|
||||
11
Assets/Architecture/Scripts/PersistentDataController.cs.meta
Normal file
11
Assets/Architecture/Scripts/PersistentDataController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 164b1accbeff688429a4311f1e40bd59
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
12
Assets/Architecture/Scripts/Score.cs
Normal file
12
Assets/Architecture/Scripts/Score.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
/// <summary>
|
||||
/// Score class
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public class Score
|
||||
{
|
||||
public int scoreValue;
|
||||
public string time;
|
||||
}
|
||||
|
||||
11
Assets/Architecture/Scripts/Score.cs.meta
Normal file
11
Assets/Architecture/Scripts/Score.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 16056ca3e1523f78cbd727cea2bfe047
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
647
Assets/Architecture/Scripts/SlicedSlider.cs
Normal file
647
Assets/Architecture/Scripts/SlicedSlider.cs
Normal file
@@ -0,0 +1,647 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
||||
using UnityEngine.U2D;
|
||||
#endif
|
||||
using Sprites = UnityEngine.Sprites;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
|
||||
// Custom Editor to order the variables in the Inspector similar to Image component
|
||||
[CustomEditor(typeof(SlicedSlider)), CanEditMultipleObjects]
|
||||
public class SlicedSliderEditor : Editor
|
||||
{
|
||||
private SerializedProperty spriteProp, colorProp;
|
||||
private GUIContent spriteLabel;
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
spriteProp = serializedObject.FindProperty("m_Sprite");
|
||||
colorProp = serializedObject.FindProperty("m_Color");
|
||||
spriteLabel = new GUIContent("Source Image");
|
||||
}
|
||||
|
||||
public override void OnInspectorGUI()
|
||||
{
|
||||
serializedObject.Update();
|
||||
|
||||
EditorGUILayout.PropertyField(spriteProp, spriteLabel);
|
||||
EditorGUILayout.PropertyField(colorProp);
|
||||
DrawPropertiesExcluding(serializedObject, "m_Script", "m_Sprite", "m_Color", "m_OnCullStateChanged");
|
||||
|
||||
serializedObject.ApplyModifiedProperties();
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// Credit: https://bitbucket.org/Unity-Technologies/ui/src/2018.4/UnityEngine.UI/UI/Core/Image.cs
|
||||
[RequireComponent(typeof(CanvasRenderer))]
|
||||
[AddComponentMenu("UI/Sliced Slider", 11)]
|
||||
public class SlicedSlider : MaskableGraphic, ISerializationCallbackReceiver, ILayoutElement, ICanvasRaycastFilter
|
||||
{
|
||||
private static class SetPropertyUtility
|
||||
{
|
||||
public static bool SetStruct<T>(ref T currentValue, T newValue) where T : struct
|
||||
{
|
||||
if (EqualityComparer<T>.Default.Equals(currentValue, newValue))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool SetClass<T>(ref T currentValue, T newValue) where T : class
|
||||
{
|
||||
if ((currentValue == null && newValue == null) || (currentValue != null && currentValue.Equals(newValue)))
|
||||
return false;
|
||||
|
||||
currentValue = newValue;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public enum FillDirection { Right = 0, Left = 1, Up = 2, Down = 3 }
|
||||
|
||||
private static readonly Vector3[] s_Vertices = new Vector3[4];
|
||||
private static readonly Vector2[] s_UVs = new Vector2[4];
|
||||
private static readonly Vector2[] s_SlicedVertices = new Vector2[4];
|
||||
private static readonly Vector2[] s_SlicedUVs = new Vector2[4];
|
||||
|
||||
#pragma warning disable 1692
|
||||
#pragma warning disable IDE1006 // Suppress 'Naming rule violation' warnings
|
||||
#pragma warning disable 0649
|
||||
[SerializeField]
|
||||
private Sprite m_Sprite;
|
||||
public Sprite sprite
|
||||
{
|
||||
get { return m_Sprite; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetClass(ref m_Sprite, value))
|
||||
{
|
||||
SetAllDirty();
|
||||
TrackImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private FillDirection m_FillDirection;
|
||||
public FillDirection fillDirection
|
||||
{
|
||||
get { return m_FillDirection; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_FillDirection, value))
|
||||
SetVerticesDirty();
|
||||
}
|
||||
}
|
||||
|
||||
[Range(0, 1)]
|
||||
[SerializeField]
|
||||
private float m_FillAmount = 1f;
|
||||
public float fillAmount
|
||||
{
|
||||
get { return m_FillAmount; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_FillAmount, Mathf.Clamp01(value)))
|
||||
SetVerticesDirty();
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private bool m_FillCenter = true;
|
||||
public bool fillCenter
|
||||
{
|
||||
get { return m_FillCenter; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetStruct(ref m_FillCenter, value))
|
||||
SetVerticesDirty();
|
||||
}
|
||||
}
|
||||
|
||||
[SerializeField]
|
||||
private float m_PixelsPerUnitMultiplier = 1f;
|
||||
public float pixelsPerUnitMultiplier
|
||||
{
|
||||
get { return m_PixelsPerUnitMultiplier; }
|
||||
set { m_PixelsPerUnitMultiplier = Mathf.Max(0.01f, value); }
|
||||
}
|
||||
|
||||
public float pixelsPerUnit
|
||||
{
|
||||
get
|
||||
{
|
||||
float spritePixelsPerUnit = 100;
|
||||
if (activeSprite)
|
||||
spritePixelsPerUnit = activeSprite.pixelsPerUnit;
|
||||
|
||||
float referencePixelsPerUnit = 100;
|
||||
if (canvas)
|
||||
referencePixelsPerUnit = canvas.referencePixelsPerUnit;
|
||||
|
||||
return m_PixelsPerUnitMultiplier * spritePixelsPerUnit / referencePixelsPerUnit;
|
||||
}
|
||||
}
|
||||
#pragma warning restore 0649
|
||||
|
||||
[NonSerialized]
|
||||
private Sprite m_OverrideSprite;
|
||||
public Sprite overrideSprite
|
||||
{
|
||||
get { return activeSprite; }
|
||||
set
|
||||
{
|
||||
if (SetPropertyUtility.SetClass(ref m_OverrideSprite, value))
|
||||
{
|
||||
SetAllDirty();
|
||||
TrackImage();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Sprite activeSprite { get { return m_OverrideSprite != null ? m_OverrideSprite : m_Sprite; } }
|
||||
|
||||
public override Texture mainTexture
|
||||
{
|
||||
get
|
||||
{
|
||||
if (activeSprite != null)
|
||||
return activeSprite.texture;
|
||||
|
||||
return material != null && material.mainTexture != null ? material.mainTexture : s_WhiteTexture;
|
||||
}
|
||||
}
|
||||
|
||||
public bool hasBorder
|
||||
{
|
||||
get
|
||||
{
|
||||
if (activeSprite != null)
|
||||
{
|
||||
Vector4 v = activeSprite.border;
|
||||
return v.sqrMagnitude > 0f;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public override Material material
|
||||
{
|
||||
get
|
||||
{
|
||||
if (m_Material != null)
|
||||
return m_Material;
|
||||
|
||||
if (activeSprite && activeSprite.associatedAlphaSplitTexture != null)
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
if (Application.isPlaying)
|
||||
#endif
|
||||
return Image.defaultETC1GraphicMaterial;
|
||||
}
|
||||
|
||||
return defaultMaterial;
|
||||
}
|
||||
set { base.material = value; }
|
||||
}
|
||||
|
||||
public float alphaHitTestMinimumThreshold { get; set; }
|
||||
#pragma warning restore IDE1006
|
||||
#pragma warning restore 1692
|
||||
|
||||
protected SlicedSlider()
|
||||
{
|
||||
useLegacyMeshGeneration = false;
|
||||
}
|
||||
|
||||
protected override void OnEnable()
|
||||
{
|
||||
base.OnEnable();
|
||||
TrackImage();
|
||||
}
|
||||
|
||||
protected override void OnDisable()
|
||||
{
|
||||
base.OnDisable();
|
||||
|
||||
if (m_Tracked)
|
||||
UnTrackImage();
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
protected override void OnValidate()
|
||||
{
|
||||
base.OnValidate();
|
||||
m_PixelsPerUnitMultiplier = Mathf.Max(0.01f, m_PixelsPerUnitMultiplier);
|
||||
}
|
||||
#endif
|
||||
|
||||
protected override void OnPopulateMesh(VertexHelper vh)
|
||||
{
|
||||
if (activeSprite == null)
|
||||
{
|
||||
base.OnPopulateMesh(vh);
|
||||
return;
|
||||
}
|
||||
|
||||
GenerateSlicedFilledSprite(vh);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update the renderer's material.
|
||||
/// </summary>
|
||||
protected override void UpdateMaterial()
|
||||
{
|
||||
base.UpdateMaterial();
|
||||
|
||||
// Check if this sprite has an associated alpha texture (generated when splitting RGBA = RGB + A as two textures without alpha)
|
||||
if (activeSprite == null)
|
||||
{
|
||||
canvasRenderer.SetAlphaTexture(null);
|
||||
return;
|
||||
}
|
||||
|
||||
Texture2D alphaTex = activeSprite.associatedAlphaSplitTexture;
|
||||
if (alphaTex != null)
|
||||
canvasRenderer.SetAlphaTexture(alphaTex);
|
||||
}
|
||||
|
||||
private void GenerateSlicedFilledSprite(VertexHelper vh)
|
||||
{
|
||||
vh.Clear();
|
||||
|
||||
if (m_FillAmount < 0.001f)
|
||||
return;
|
||||
|
||||
Rect rect = GetPixelAdjustedRect();
|
||||
Vector4 outer = Sprites.DataUtility.GetOuterUV(activeSprite);
|
||||
Vector4 padding = Sprites.DataUtility.GetPadding(activeSprite);
|
||||
|
||||
if (!hasBorder)
|
||||
{
|
||||
Vector2 size = activeSprite.rect.size;
|
||||
|
||||
int spriteW = Mathf.RoundToInt(size.x);
|
||||
int spriteH = Mathf.RoundToInt(size.y);
|
||||
|
||||
// Image's dimensions used for drawing. X = left, Y = bottom, Z = right, W = top.
|
||||
Vector4 vertices = new Vector4(
|
||||
rect.x + rect.width * (padding.x / spriteW),
|
||||
rect.y + rect.height * (padding.y / spriteH),
|
||||
rect.x + rect.width * ((spriteW - padding.z) / spriteW),
|
||||
rect.y + rect.height * ((spriteH - padding.w) / spriteH));
|
||||
|
||||
GenerateFilledSprite(vh, vertices, outer, m_FillAmount);
|
||||
return;
|
||||
}
|
||||
|
||||
Vector4 inner = Sprites.DataUtility.GetInnerUV(activeSprite);
|
||||
Vector4 border = GetAdjustedBorders(activeSprite.border / pixelsPerUnit, rect);
|
||||
|
||||
padding = padding / pixelsPerUnit;
|
||||
|
||||
s_SlicedVertices[0] = new Vector2(padding.x, padding.y);
|
||||
s_SlicedVertices[3] = new Vector2(rect.width - padding.z, rect.height - padding.w);
|
||||
|
||||
s_SlicedVertices[1].x = border.x;
|
||||
s_SlicedVertices[1].y = border.y;
|
||||
|
||||
s_SlicedVertices[2].x = rect.width - border.z;
|
||||
s_SlicedVertices[2].y = rect.height - border.w;
|
||||
|
||||
for (int i = 0; i < 4; ++i)
|
||||
{
|
||||
s_SlicedVertices[i].x += rect.x;
|
||||
s_SlicedVertices[i].y += rect.y;
|
||||
}
|
||||
|
||||
s_SlicedUVs[0] = new Vector2(outer.x, outer.y);
|
||||
s_SlicedUVs[1] = new Vector2(inner.x, inner.y);
|
||||
s_SlicedUVs[2] = new Vector2(inner.z, inner.w);
|
||||
s_SlicedUVs[3] = new Vector2(outer.z, outer.w);
|
||||
|
||||
float rectStartPos;
|
||||
float _1OverTotalSize;
|
||||
if (m_FillDirection == FillDirection.Left || m_FillDirection == FillDirection.Right)
|
||||
{
|
||||
rectStartPos = s_SlicedVertices[0].x;
|
||||
|
||||
float totalSize = (s_SlicedVertices[3].x - s_SlicedVertices[0].x);
|
||||
_1OverTotalSize = totalSize > 0f ? 1f / totalSize : 1f;
|
||||
}
|
||||
else
|
||||
{
|
||||
rectStartPos = s_SlicedVertices[0].y;
|
||||
|
||||
float totalSize = (s_SlicedVertices[3].y - s_SlicedVertices[0].y);
|
||||
_1OverTotalSize = totalSize > 0f ? 1f / totalSize : 1f;
|
||||
}
|
||||
|
||||
for (int x = 0; x < 3; x++)
|
||||
{
|
||||
int x2 = x + 1;
|
||||
|
||||
for (int y = 0; y < 3; y++)
|
||||
{
|
||||
if (!m_FillCenter && x == 1 && y == 1)
|
||||
continue;
|
||||
|
||||
int y2 = y + 1;
|
||||
|
||||
float sliceStart, sliceEnd;
|
||||
switch (m_FillDirection)
|
||||
{
|
||||
case FillDirection.Right:
|
||||
sliceStart = (s_SlicedVertices[x].x - rectStartPos) * _1OverTotalSize;
|
||||
sliceEnd = (s_SlicedVertices[x2].x - rectStartPos) * _1OverTotalSize;
|
||||
break;
|
||||
case FillDirection.Up:
|
||||
sliceStart = (s_SlicedVertices[y].y - rectStartPos) * _1OverTotalSize;
|
||||
sliceEnd = (s_SlicedVertices[y2].y - rectStartPos) * _1OverTotalSize;
|
||||
break;
|
||||
case FillDirection.Left:
|
||||
sliceStart = 1f - (s_SlicedVertices[x2].x - rectStartPos) * _1OverTotalSize;
|
||||
sliceEnd = 1f - (s_SlicedVertices[x].x - rectStartPos) * _1OverTotalSize;
|
||||
break;
|
||||
case FillDirection.Down:
|
||||
sliceStart = 1f - (s_SlicedVertices[y2].y - rectStartPos) * _1OverTotalSize;
|
||||
sliceEnd = 1f - (s_SlicedVertices[y].y - rectStartPos) * _1OverTotalSize;
|
||||
break;
|
||||
default: // Just there to get rid of the "Use of unassigned local variable" compiler error
|
||||
sliceStart = sliceEnd = 0f;
|
||||
break;
|
||||
}
|
||||
|
||||
if (sliceStart >= m_FillAmount)
|
||||
continue;
|
||||
|
||||
Vector4 vertices = new Vector4(s_SlicedVertices[x].x, s_SlicedVertices[y].y, s_SlicedVertices[x2].x, s_SlicedVertices[y2].y);
|
||||
Vector4 uvs = new Vector4(s_SlicedUVs[x].x, s_SlicedUVs[y].y, s_SlicedUVs[x2].x, s_SlicedUVs[y2].y);
|
||||
float fillAmount = (m_FillAmount - sliceStart) / (sliceEnd - sliceStart);
|
||||
|
||||
GenerateFilledSprite(vh, vertices, uvs, fillAmount);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private Vector4 GetAdjustedBorders(Vector4 border, Rect adjustedRect)
|
||||
{
|
||||
Rect originalRect = rectTransform.rect;
|
||||
|
||||
for (int axis = 0; axis <= 1; axis++)
|
||||
{
|
||||
float borderScaleRatio;
|
||||
|
||||
// The adjusted rect (adjusted for pixel correctness) may be slightly larger than the original rect.
|
||||
// Adjust the border to match the adjustedRect to avoid small gaps between borders (case 833201).
|
||||
if (originalRect.size[axis] != 0)
|
||||
{
|
||||
borderScaleRatio = adjustedRect.size[axis] / originalRect.size[axis];
|
||||
border[axis] *= borderScaleRatio;
|
||||
border[axis + 2] *= borderScaleRatio;
|
||||
}
|
||||
|
||||
// If the rect is smaller than the combined borders, then there's not room for the borders at their normal size.
|
||||
// In order to avoid artefacts with overlapping borders, we scale the borders down to fit.
|
||||
float combinedBorders = border[axis] + border[axis + 2];
|
||||
if (adjustedRect.size[axis] < combinedBorders && combinedBorders != 0)
|
||||
{
|
||||
borderScaleRatio = adjustedRect.size[axis] / combinedBorders;
|
||||
border[axis] *= borderScaleRatio;
|
||||
border[axis + 2] *= borderScaleRatio;
|
||||
}
|
||||
}
|
||||
|
||||
return border;
|
||||
}
|
||||
|
||||
private void GenerateFilledSprite(VertexHelper vh, Vector4 vertices, Vector4 uvs, float fillAmount)
|
||||
{
|
||||
if (m_FillAmount < 0.001f)
|
||||
return;
|
||||
|
||||
float uvLeft = uvs.x;
|
||||
float uvBottom = uvs.y;
|
||||
float uvRight = uvs.z;
|
||||
float uvTop = uvs.w;
|
||||
|
||||
if (fillAmount < 1f)
|
||||
{
|
||||
if (m_FillDirection == FillDirection.Left || m_FillDirection == FillDirection.Right)
|
||||
{
|
||||
if (m_FillDirection == FillDirection.Left)
|
||||
{
|
||||
vertices.x = vertices.z - (vertices.z - vertices.x) * fillAmount;
|
||||
uvLeft = uvRight - (uvRight - uvLeft) * fillAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
vertices.z = vertices.x + (vertices.z - vertices.x) * fillAmount;
|
||||
uvRight = uvLeft + (uvRight - uvLeft) * fillAmount;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (m_FillDirection == FillDirection.Down)
|
||||
{
|
||||
vertices.y = vertices.w - (vertices.w - vertices.y) * fillAmount;
|
||||
uvBottom = uvTop - (uvTop - uvBottom) * fillAmount;
|
||||
}
|
||||
else
|
||||
{
|
||||
vertices.w = vertices.y + (vertices.w - vertices.y) * fillAmount;
|
||||
uvTop = uvBottom + (uvTop - uvBottom) * fillAmount;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
s_Vertices[0] = new Vector3(vertices.x, vertices.y);
|
||||
s_Vertices[1] = new Vector3(vertices.x, vertices.w);
|
||||
s_Vertices[2] = new Vector3(vertices.z, vertices.w);
|
||||
s_Vertices[3] = new Vector3(vertices.z, vertices.y);
|
||||
|
||||
s_UVs[0] = new Vector2(uvLeft, uvBottom);
|
||||
s_UVs[1] = new Vector2(uvLeft, uvTop);
|
||||
s_UVs[2] = new Vector2(uvRight, uvTop);
|
||||
s_UVs[3] = new Vector2(uvRight, uvBottom);
|
||||
|
||||
int startIndex = vh.currentVertCount;
|
||||
|
||||
for (int i = 0; i < 4; i++)
|
||||
vh.AddVert(s_Vertices[i], color, s_UVs[i]);
|
||||
|
||||
vh.AddTriangle(startIndex, startIndex + 1, startIndex + 2);
|
||||
vh.AddTriangle(startIndex + 2, startIndex + 3, startIndex);
|
||||
}
|
||||
|
||||
int ILayoutElement.layoutPriority { get { return 0; } }
|
||||
float ILayoutElement.minWidth { get { return 0; } }
|
||||
float ILayoutElement.minHeight { get { return 0; } }
|
||||
float ILayoutElement.flexibleWidth { get { return -1; } }
|
||||
float ILayoutElement.flexibleHeight { get { return -1; } }
|
||||
|
||||
float ILayoutElement.preferredWidth
|
||||
{
|
||||
get
|
||||
{
|
||||
if (activeSprite == null)
|
||||
return 0;
|
||||
|
||||
return Sprites.DataUtility.GetMinSize(activeSprite).x / pixelsPerUnit;
|
||||
}
|
||||
}
|
||||
|
||||
float ILayoutElement.preferredHeight
|
||||
{
|
||||
get
|
||||
{
|
||||
if (activeSprite == null)
|
||||
return 0;
|
||||
|
||||
return Sprites.DataUtility.GetMinSize(activeSprite).y / pixelsPerUnit;
|
||||
}
|
||||
}
|
||||
|
||||
void ILayoutElement.CalculateLayoutInputHorizontal() { }
|
||||
void ILayoutElement.CalculateLayoutInputVertical() { }
|
||||
|
||||
bool ICanvasRaycastFilter.IsRaycastLocationValid(Vector2 screenPoint, Camera eventCamera)
|
||||
{
|
||||
if (alphaHitTestMinimumThreshold <= 0)
|
||||
return true;
|
||||
|
||||
if (alphaHitTestMinimumThreshold > 1)
|
||||
return false;
|
||||
|
||||
if (activeSprite == null)
|
||||
return true;
|
||||
|
||||
Vector2 local;
|
||||
if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(rectTransform, screenPoint, eventCamera, out local))
|
||||
return false;
|
||||
|
||||
Rect rect = GetPixelAdjustedRect();
|
||||
|
||||
// Convert to have lower left corner as reference point.
|
||||
local.x += rectTransform.pivot.x * rect.width;
|
||||
local.y += rectTransform.pivot.y * rect.height;
|
||||
|
||||
Rect spriteRect = activeSprite.rect;
|
||||
Vector4 border = activeSprite.border;
|
||||
Vector4 adjustedBorder = GetAdjustedBorders(border / pixelsPerUnit, rect);
|
||||
|
||||
for (int i = 0; i < 2; i++)
|
||||
{
|
||||
if (local[i] <= adjustedBorder[i])
|
||||
continue;
|
||||
|
||||
if (rect.size[i] - local[i] <= adjustedBorder[i + 2])
|
||||
{
|
||||
local[i] -= (rect.size[i] - spriteRect.size[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
float lerp = Mathf.InverseLerp(adjustedBorder[i], rect.size[i] - adjustedBorder[i + 2], local[i]);
|
||||
local[i] = Mathf.Lerp(border[i], spriteRect.size[i] - border[i + 2], lerp);
|
||||
}
|
||||
|
||||
// Normalize local coordinates.
|
||||
Rect textureRect = activeSprite.textureRect;
|
||||
Vector2 normalized = new Vector2(local.x / textureRect.width, local.y / textureRect.height);
|
||||
|
||||
// Convert to texture space.
|
||||
float x = Mathf.Lerp(textureRect.x, textureRect.xMax, normalized.x) / activeSprite.texture.width;
|
||||
float y = Mathf.Lerp(textureRect.y, textureRect.yMax, normalized.y) / activeSprite.texture.height;
|
||||
|
||||
switch (m_FillDirection)
|
||||
{
|
||||
case FillDirection.Right:
|
||||
if (x > m_FillAmount)
|
||||
return false;
|
||||
break;
|
||||
case FillDirection.Left:
|
||||
if (1f - x > m_FillAmount)
|
||||
return false;
|
||||
break;
|
||||
case FillDirection.Up:
|
||||
if (y > m_FillAmount)
|
||||
return false;
|
||||
break;
|
||||
case FillDirection.Down:
|
||||
if (1f - y > m_FillAmount)
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
return activeSprite.texture.GetPixelBilinear(x, y).a >= alphaHitTestMinimumThreshold;
|
||||
}
|
||||
catch (UnityException e)
|
||||
{
|
||||
Debug.LogError("Using alphaHitTestMinimumThreshold greater than 0 on Image whose sprite texture cannot be read. " + e.Message + " Also make sure to disable sprite packing for this sprite.", this);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
void ISerializationCallbackReceiver.OnBeforeSerialize() { }
|
||||
void ISerializationCallbackReceiver.OnAfterDeserialize()
|
||||
{
|
||||
m_FillAmount = Mathf.Clamp01(m_FillAmount);
|
||||
}
|
||||
|
||||
// Whether this is being tracked for Atlas Binding
|
||||
private bool m_Tracked = false;
|
||||
|
||||
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
||||
private static List<SlicedSlider> m_TrackedTexturelessImages = new List<SlicedSlider>();
|
||||
private static bool s_Initialized;
|
||||
#endif
|
||||
|
||||
private void TrackImage()
|
||||
{
|
||||
if (activeSprite != null && activeSprite.texture == null)
|
||||
{
|
||||
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
||||
if (!s_Initialized)
|
||||
{
|
||||
SpriteAtlasManager.atlasRegistered += RebuildImage;
|
||||
s_Initialized = true;
|
||||
}
|
||||
|
||||
m_TrackedTexturelessImages.Add(this);
|
||||
#endif
|
||||
m_Tracked = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void UnTrackImage()
|
||||
{
|
||||
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
||||
m_TrackedTexturelessImages.Remove(this);
|
||||
#endif
|
||||
m_Tracked = false;
|
||||
}
|
||||
|
||||
#if UNITY_2017_4 || UNITY_2018_2_OR_NEWER
|
||||
private static void RebuildImage(SpriteAtlas spriteAtlas)
|
||||
{
|
||||
for (int i = m_TrackedTexturelessImages.Count - 1; i >= 0; i--)
|
||||
{
|
||||
SlicedSlider image = m_TrackedTexturelessImages[i];
|
||||
if (spriteAtlas.CanBindTo(image.activeSprite))
|
||||
{
|
||||
image.SetAllDirty();
|
||||
m_TrackedTexturelessImages.RemoveAt(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
11
Assets/Architecture/Scripts/SlicedSlider.cs.meta
Normal file
11
Assets/Architecture/Scripts/SlicedSlider.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: b69b55aa2ac2e0e4592740cf1269d52c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
133
Assets/Architecture/Scripts/SystemController.cs
Normal file
133
Assets/Architecture/Scripts/SystemController.cs
Normal file
@@ -0,0 +1,133 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.SceneManagement;
|
||||
|
||||
/// <summary>
|
||||
/// SystemController singleton
|
||||
/// </summary>
|
||||
public class SystemController
|
||||
{
|
||||
/// <summary>
|
||||
/// The instance controlling the singleton
|
||||
/// </summary>
|
||||
private static SystemController instance = null;
|
||||
|
||||
/// <summary>
|
||||
/// Stack of the loaded scenes, used to easily go back to previous scenes
|
||||
/// </summary>
|
||||
private Stack<int> sceneStack = new Stack<int>();
|
||||
|
||||
/// <summary>
|
||||
/// Index of the previous loaded scene
|
||||
/// </summary>
|
||||
public int previousScene = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Index of the current loaded scene
|
||||
/// </summary>
|
||||
public int currentScene = -1;
|
||||
|
||||
/// <summary>
|
||||
/// Get the instance loaded by the singleton
|
||||
/// </summary>
|
||||
/// <returns>SystemController instance</returns>
|
||||
public static SystemController GetInstance()
|
||||
{
|
||||
// Create a new instance if non exists
|
||||
if (instance == null)
|
||||
{
|
||||
instance = new SystemController();
|
||||
instance.currentScene = SceneManager.GetActiveScene().buildIndex;
|
||||
instance.sceneStack.Push(instance.currentScene);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the number of passively 'active' scenes
|
||||
/// </summary>
|
||||
public int GetSceneStackSize() { return sceneStack.Count; }
|
||||
|
||||
/// <summary>
|
||||
/// Load the scene and push on the stack
|
||||
/// </summary>
|
||||
/// <param name="scenePath">Path of the scene</param>
|
||||
public void LoadNextScene(string scenePath)
|
||||
{
|
||||
LoadNextScene(SystemController.GetSceneIndex(scenePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the index of a given scene
|
||||
/// </summary>
|
||||
/// <param name="scenePath">Path of the scene</param>
|
||||
/// <returns></returns>
|
||||
public static int GetSceneIndex(string scenePath)
|
||||
{
|
||||
return SceneUtility.GetBuildIndexByScenePath(scenePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Load the scene and push on the stack
|
||||
/// </summary>
|
||||
/// <param name="sceneIndex">Buildindex of the scene</param>
|
||||
public void LoadNextScene(int sceneIndex)
|
||||
{
|
||||
previousScene = currentScene;
|
||||
currentScene = sceneIndex;
|
||||
|
||||
sceneStack.Push(currentScene);
|
||||
SceneManager.LoadScene(currentScene);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swap the current scene with the new scene on the stack
|
||||
/// </summary>
|
||||
/// <param name="scenePath">Path of the scene</param>
|
||||
public void SwapScene(string scenePath)
|
||||
{
|
||||
SwapScene(SystemController.GetSceneIndex(scenePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Swap the current scene with the new scene on the stack
|
||||
/// </summary>
|
||||
/// <param name="sceneIndex">Buildindex of the scene</param>
|
||||
public void SwapScene(int sceneIndex)
|
||||
{
|
||||
currentScene = sceneStack.Pop();
|
||||
LoadNextScene(sceneIndex);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Go back to the previous scene and unload the current scene
|
||||
/// </summary>
|
||||
public void BackToPreviousScene()
|
||||
{
|
||||
previousScene = sceneStack.Pop();
|
||||
if (sceneStack.Count > 0) SceneManager.LoadScene(currentScene = sceneStack.Peek());
|
||||
else Application.Quit();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Go back to a specific scene, unloading all the scenes on the way
|
||||
/// </summary>
|
||||
/// <param name="scenePath">Path of the scene</param>
|
||||
public void BackToScene(string scenePath)
|
||||
{
|
||||
BackToScene(SystemController.GetSceneIndex(scenePath));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Go back to a specific scene, unloading all the scene on the way
|
||||
/// </summary>
|
||||
/// <param name="sceneIndex">Buildindex of the scene</param>
|
||||
public void BackToScene(int sceneIndex)
|
||||
{
|
||||
previousScene = currentScene;
|
||||
while (0 < sceneStack.Count && sceneStack.Peek() != sceneIndex) sceneStack.Pop();
|
||||
|
||||
if (sceneStack.Count > 0) SceneManager.LoadScene(currentScene = sceneStack.Peek());
|
||||
else Application.Quit();
|
||||
}
|
||||
}
|
||||
11
Assets/Architecture/Scripts/SystemController.cs.meta
Normal file
11
Assets/Architecture/Scripts/SystemController.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bf5ea73aa43049e45a0ad926db15f315
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
25
Assets/Architecture/Scripts/ThemeIndex.cs
Normal file
25
Assets/Architecture/Scripts/ThemeIndex.cs
Normal file
@@ -0,0 +1,25 @@
|
||||
|
||||
/// <summary>
|
||||
/// Enum for easy indexing and checking if a course is of a certain kind
|
||||
/// </summary>
|
||||
public enum ThemeIndex
|
||||
{
|
||||
SIGN_ALPHABET,
|
||||
SIGN_BASICS,
|
||||
SIGN_CLOTHING,
|
||||
SIGN_ANIMALS,
|
||||
SIGN_FOOD,
|
||||
SIGN_HOBBIES,
|
||||
SIGN_HOUSE,
|
||||
SIGN_FAMILY,
|
||||
SPELLING_GEOGRAPY,
|
||||
SPELLING_BUILDINGS,
|
||||
SPELLING_SPORTS,
|
||||
SPELLING_BASICS,
|
||||
SPELLING_HOBBIES,
|
||||
SPELLING_PEOPLE,
|
||||
SPELLING_FRUIT,
|
||||
SPELLING_VEGGIES,
|
||||
SPELLING_WILD,
|
||||
SPELLING_FARM
|
||||
}
|
||||
11
Assets/Architecture/Scripts/ThemeIndex.cs.meta
Normal file
11
Assets/Architecture/Scripts/ThemeIndex.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 58e9afcf842bdfa48939e754bb39182a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user