Compare commits

..

No commits in common. "main" and "1.0.0" have entirely different histories.
main ... 1.0.0

37 changed files with 1407 additions and 2365 deletions

View file

@ -2,6 +2,8 @@
This package contains simple tools to use in your project. This package contains simple tools to use in your project.
This package will be updated once I find another useful tool or someone suggest me one.
## Features ## Features
- **AudioManager** with Play, Pause and most of the other basic things, as well as some effects like FadeIn or FadeOut. - **AudioManager** with Play, Pause and most of the other basic things, as well as some effects like FadeIn or FadeOut.
@ -10,8 +12,6 @@ This package contains simple tools to use in your project.
- Basic menu with **music and SFX sliders** as well as **resolution and quality dropdowns.** - Basic menu with **music and SFX sliders** as well as **resolution and quality dropdowns.**
- An **object pooler** with the ability to create pools with an undetermined size. - An **object pooler** with the ability to create pools with an undetermined size.
- A basic **scene manager** with a loading screen with progress bar. - A basic **scene manager** with a loading screen with progress bar.
- A simple **timer** that allows you to easily create clocks, countdowns and stopwatches with TextMeshPro
- An **auto-save** feature to reduce the chances of loosing data on crashes.
All of that comes with some editor menu items for creating all of that as fast as possible. All of that comes with some editor menu items for creating all of that as fast as possible.
@ -21,11 +21,11 @@ First install the TextMeshPro and Cinemachine into your Unity project
### Git Installation (Best way to get latest version) ### Git Installation (Best way to get latest version)
If you have git in your computer, you can open Package Manager inside Unity, select "Add package from Git url...", and paste link [https://github.com/GerardGascon/SimpleTools.git](https://github.com/GerardGascon/SimpleTools.git) If you have git in your computer, you can open Package Manager inside Unity, select "Add package from Git url...", and paste link [https://github.com/Geri8/SimpleTools.git](https://github.com/Geri8/SimpleTools.git)
or or
Open the manifest.json file of your Unity project. Add "com.geri.simpletools": "[https://github.com/GerardGascon/SimpleTools.git](https://github.com/GerardGascon/SimpleTools.git)" Open the manifest.json file of your Unity project. Add "com.geri.simpletools": "[https://github.com/Geri8/SimpleTools.git](https://github.com/Geri8/SimpleTools.git)"
### Manual Installation ### Manual Installation
@ -33,16 +33,13 @@ Download latest package from the Release section Import SimpleTools.unitypackage
## Usage ## Usage
### **AudioManager** ### AudioManager
```csharp ```csharp
using SimpleTools.AudioManager;
AudioManager.instance.Play("Name"); //Plays the sound with that name AudioManager.instance.Play("Name"); //Plays the sound with that name
AudioManager.instance.Play("Name", 1f); //Starts playing the sound "Name" in 1 second AudioManager.instance.Play("Name", 1f); //Starts playing the sound "Name" in 1 second
AudioManager.instance.PlayOneShot("Name"); //Plays one shot of that sound (Useful for repeated sounds) AudioManager.instance.PlayOneShot("Name"); //Plays one shot of that sound (Useful for repeated sounds)
AudioManager.instance.PlayWithIntro("Intro", "Loop"); //Plays the intro and then the loop AudioManager.instance.PlayWithIntro("Intro", "Loop"); //Plays the intro and then the loop
AudioManager.instance.PlayRandomSound("Name1", "Name2", "Name3"); // Plays one shot of a random sound
AudioManager.instance.Pause("Name"); //Pauses the sound AudioManager.instance.Pause("Name"); //Pauses the sound
AudioManager.instance.UnPause("Name"); //Unpauses the sound AudioManager.instance.UnPause("Name"); //Unpauses the sound
@ -60,13 +57,11 @@ AudioManager.instance.FadeMutedIn("Name", 1f); //Fade In a muted sound with a sp
AudioManager.instance.FadeMutedOut("Name", 1f); //Fade Out a sound without stopping it AudioManager.instance.FadeMutedOut("Name", 1f); //Fade Out a sound without stopping it
``` ```
### **ObjectPooler** ### ObjectPooler
The SpawnFromPool function always return a GameObject The SpawnFromPool function always return a GameObject
```csharp ```csharp
using SimpleTools.ObjectPooler;
Pool pool; //The pool scriptable object goes here Pool pool; //The pool scriptable object goes here
Pooler.CreatePools(pool); //Create the pool, without creating it you cannot spawn it Pooler.CreatePools(pool); //Create the pool, without creating it you cannot spawn it
Pool[] pools; Pool[] pools;
@ -81,72 +76,29 @@ Pooler.SpawnFromPool("Name", Vector3.zero, transform, true); //Spawn into a spec
Pooler.SpawnFromPool("Name", Vector3.zero, Quaternion.identity, transform, true); //Spawn into a specific position, rotation, parent and instantiate in worldSpace or not Pooler.SpawnFromPool("Name", Vector3.zero, Quaternion.identity, transform, true); //Spawn into a specific position, rotation, parent and instantiate in worldSpace or not
``` ```
### **Dialogue System** ### Dialogue System
The Dialogue function returns a bool (true if it's talking, false if it has ended) The Dialogue function returns a bool (true if it's talking, false if it has ended)
```csharp ```csharp
using SimpleTools.DialogueSystem;
Dialogue dialogue; //The dialogue scriptable object goes here Dialogue dialogue; //The dialogue scriptable object goes here
DialogueManager.instance.Dialogue(dialogue); //Start/Continue the dialogue DialogueSystem.instance.Dialogue(dialogue); //Start/Continue the dialogue
DialogueManager.instance.Dialogue(dialogue, "Sound1", "Sound2"); //Start/Continue the dialogue with a random set of sounds for the text reveal
``` ```
Text commands: ### SceneManager
```
<color=color></color> --> Sets font color within tags
<size=percentage></size> --> Sets font size within tags
<sprite=index> --> Draws a sprite from the TextMeshPro
<p:[tiny,short,normal,long,read]> --> Pauses during a period of time
<anim:[wobble,wave,rainbow,shake]></anim> --> Reproduces an animation
<sp:number></sp> --> Changes reveal speed
<snd:name> --> Plays a sound effect
<stopmsc:name,time> --> Fades a music out
<playmsc:name,time> --> Fades a music in
```
### **SceneManager**
```csharp ```csharp
using SimpleTools.SceneManagement;
Loader.Load(0); //Loads a scene with a specific build index Loader.Load(0); //Loads a scene with a specific build index
Loader.Load("Scene"); //Loads a scene with a specific name Loader.Load("Scene"); //Loads a scene with a specific name
``` ```
### **ScreenShake** ### ScreenShake
```csharp ```csharp
using SimpleTools.Cinemachine;
ScreenShake.Shake(1f, .25f); //Shakes the camera with an intensity and duration ScreenShake.Shake(1f, .25f); //Shakes the camera with an intensity and duration
``` ```
### **Timer** ### Editor
```csharp
using SimpleTools.Timer;
//Setup a stopwatch that updates at an unscaled time
Timer timer = textMeshProText.SetupTimer(TimerType.Stopwatch, TimerUpdate.UnscaledTime);
//Setup a clock
Timer timer = textMeshProText.SetupTimer(TimerType.Clock, TimerUpdate.UnscaledTime);
//Setup a countdown with the default time of 60 seconds
Timer timer = textMeshProText.SetupTimer(TimerType.Countdown, TimerUpdate.UnscaledTime, 60f);
timer.Play(); //Play or resume the timer
timer.Stop(); //Pause the timer
timer.ResetTimer(); //Pause and sets the time to the default one
timer.Restart(); //Restarts the timer
```
### **Auto-save**
To enable auto-save you have access the menu from the top bar, *Simple Tools>Auto Save Configuration.* You can auto-save every several minutes or auto-save every time you enter play mode.
### **Editor**
You can easily set up some things by right clicking in your Project Tab and then selecting Tools and clicking on the one you want to create. You can easily set up some things by right clicking in your Project Tab and then selecting Tools and clicking on the one you want to create.

View file

@ -2,24 +2,23 @@
using UnityEngine; using UnityEngine;
using System; using System;
namespace SimpleTools.AudioManager { public class AudioManager : MonoBehaviour{
public class AudioManager : MonoBehaviour {
public static AudioManager instance; public static AudioManager instance;
[SerializeField] Sounds soundList = default; [SerializeField] Sounds soundList = default;
void Awake() { void Awake(){
if (instance == null) { if(instance == null){
instance = this; instance = this;
} else { }else{
Destroy(gameObject); Destroy(gameObject);
return; return;
} }
DontDestroyOnLoad(gameObject); DontDestroyOnLoad(gameObject);
foreach (Sounds.List s in soundList.sounds) { foreach(Sounds.List s in soundList.sounds){
if (string.IsNullOrEmpty(s.name) || string.IsNullOrWhiteSpace(s.name)) { if(string.IsNullOrEmpty(s.name) || string.IsNullOrWhiteSpace(s.name)){
Debug.LogWarning("The name one sound is empty"); Debug.LogWarning("The name one sound is empty");
continue; continue;
} }
@ -28,7 +27,7 @@ namespace SimpleTools.AudioManager {
sound.transform.parent = transform; sound.transform.parent = transform;
s.source = sound.AddComponent<AudioSource>(); s.source = sound.AddComponent<AudioSource>();
if (soundList.mainMixer && soundList.sfxMixer) { if(soundList.mainMixer && soundList.sfxMixer){
if (s.type == Sounds.List.Type.Music) if (s.type == Sounds.List.Type.Music)
s.source.outputAudioMixerGroup = soundList.mainMixer; s.source.outputAudioMixerGroup = soundList.mainMixer;
else else
@ -47,10 +46,9 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to play a sound with a specific name /// <summary>Use this to play a sound with a specific name
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void Play(string name){
public void Play(string name) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if(s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
return; return;
} }
@ -61,11 +59,9 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to play a sound with a specific name and with a certain delay /// <summary>Use this to play a sound with a specific name and with a certain delay
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void Play(string name, float delay){
/// <param name="delay" type="float">The delay in seconds</param>
public void Play(string name, float delay) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
return; return;
} }
@ -76,10 +72,9 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to play one shot of a sound with a specific name /// <summary>Use this to play one shot of a sound with a specific name
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void PlayOneShot(string name){
public void PlayOneShot(string name) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
return; return;
} }
@ -90,11 +85,9 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to play an intro song and then start playing the song loop /// <summary>Use this to play an intro song and then start playing the song loop
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="intro" type="string">The name of the intro song</param> public void PlayWithIntro(string intro, string song){
/// <param name="song" type="string">The name of the song loop</param>
public void PlayWithIntro(string intro, string song) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == intro); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == intro);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + intro + " not found!"); Debug.LogWarning("Sound: " + intro + " not found!");
return; return;
} }
@ -105,23 +98,14 @@ namespace SimpleTools.AudioManager {
float introDuration = s.clip.length; float introDuration = s.clip.length;
Play(song, introDuration); Play(song, introDuration);
} }
/// <summary>Use this to play one shot of a random sound within a list
/// <para>They have to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary>
/// <param name="names" type="string[]">The names of the sounds</param>
public void PlayRandomSound(params string[] names) {
int random = UnityEngine.Random.Range(0, names.Length);
PlayOneShot(names[random]);
}
#endregion #endregion
#region Pause #region Pause
/// <summary>Use this to pause a sound with a specific name /// <summary>Use this to pause a sound with a specific name
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void Pause(string name){
public void Pause(string name) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
return; return;
} }
@ -132,10 +116,9 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to unpause a sound with a specific name /// <summary>Use this to unpause a sound with a specific name
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void UnPause(string name){
public void UnPause(string name) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
return; return;
} }
@ -148,10 +131,9 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to stop a sound with a specific name /// <summary>Use this to stop a sound with a specific name
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void Stop(string name){
public void Stop(string name) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
return; return;
} }
@ -162,9 +144,9 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to stop all the sounds /// <summary>Use this to stop all the sounds
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
public void StopAll() { public void StopAll(){
foreach (Sounds.List s in soundList.sounds) { foreach (Sounds.List s in soundList.sounds){
if (s.source) { if (s.source){
s.source.Stop(); s.source.Stop();
} }
} }
@ -173,11 +155,9 @@ namespace SimpleTools.AudioManager {
/// <summary>This function returns the AudioSource that contains a specific sound /// <summary>This function returns the AudioSource that contains a specific sound
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name">The name of the sound</param> public AudioSource GetSource(string name){
/// <returns>The AudioSource in the scene</returns>
public AudioSource GetSource(string name) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
return null; return null;
} }
@ -187,18 +167,16 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to start playing a sound with a fade in /// <summary>Use this to start playing a sound with a fade in
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void FadeIn(string name, float duration){
/// <param name="duration" type="float">The duration of the fade in</param>
public void FadeIn(string name, float duration) {
StartCoroutine(FadeInCoroutine(name, duration)); StartCoroutine(FadeInCoroutine(name, duration));
} }
IEnumerator FadeInCoroutine(string name, float fadeTime) { IEnumerator FadeInCoroutine(string name, float fadeTime){
AudioSource audioSource = GetSource(name); AudioSource audioSource = GetSource(name);
if (audioSource != null && !audioSource.isPlaying) { if (audioSource != null && !audioSource.isPlaying){
float volume = audioSource.volume; float volume = audioSource.volume;
audioSource.volume = 0; audioSource.volume = 0;
audioSource.Play(); audioSource.Play();
while (audioSource.volume < volume) { while (audioSource.volume < volume){
audioSource.volume += Time.deltaTime / fadeTime; audioSource.volume += Time.deltaTime / fadeTime;
yield return null; yield return null;
} }
@ -209,18 +187,16 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to stop playing a sound with a fade out /// <summary>Use this to stop playing a sound with a fade out
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void FadeOut(string name, float duration){
/// <param name="duration" type="float">The duration of the fade out</param>
public void FadeOut(string name, float duration) {
StartCoroutine(FadeOutCoroutine(name, duration)); StartCoroutine(FadeOutCoroutine(name, duration));
} }
IEnumerator FadeOutCoroutine(string name, float fadeTime) { IEnumerator FadeOutCoroutine(string name, float fadeTime){
AudioSource audioSource = GetSource(name); AudioSource audioSource = GetSource(name);
if (audioSource && audioSource.isPlaying) { if (audioSource && audioSource.isPlaying){
float startVolume = audioSource.volume; float startVolume = audioSource.volume;
while (audioSource.volume > 0) { while (audioSource.volume > 0){
audioSource.volume -= startVolume * Time.deltaTime / fadeTime; audioSource.volume -= startVolume * Time.deltaTime / fadeTime;
yield return null; yield return null;
} }
@ -233,10 +209,9 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to start playing a sound muted /// <summary>Use this to start playing a sound muted
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void PlayMuted(string name){
public void PlayMuted(string name) {
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
return; return;
} }
@ -248,19 +223,17 @@ namespace SimpleTools.AudioManager {
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// <para>WARNING: If the PlayMuted hasn't been called before, this function won't work</para> /// <para>WARNING: If the PlayMuted hasn't been called before, this function won't work</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void FadeMutedIn(string name, float duration){
/// <param name="duration">The duration of the fade in</param>
public void FadeMutedIn(string name, float duration) {
StartCoroutine(FadeMutedInCoroutine(name, duration)); StartCoroutine(FadeMutedInCoroutine(name, duration));
} }
IEnumerator FadeMutedInCoroutine(string name, float fadeTime) { IEnumerator FadeMutedInCoroutine(string name, float fadeTime){
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
yield break; yield break;
} }
while (s.source.volume < s.volume) { while (s.source.volume < s.volume){
s.source.volume += Time.deltaTime / fadeTime; s.source.volume += Time.deltaTime / fadeTime;
yield return null; yield return null;
} }
@ -269,24 +242,21 @@ namespace SimpleTools.AudioManager {
/// <summary>Use this to fade out a sound and keep playing that muted /// <summary>Use this to fade out a sound and keep playing that muted
/// <para>It has to be in the Sound asset referenced in the AudioManager instance</para> /// <para>It has to be in the Sound asset referenced in the AudioManager instance</para>
/// </summary> /// </summary>
/// <param name="name" type="string">The name of the sound</param> public void FadeMutedOut(string name, float duration){
/// <param name="duration">The duration of the fade out</param>
public void FadeMutedOut(string name, float duration) {
StartCoroutine(FadeMutedOutCoroutine(name, duration)); StartCoroutine(FadeMutedOutCoroutine(name, duration));
} }
IEnumerator FadeMutedOutCoroutine(string name, float fadeTime) { IEnumerator FadeMutedOutCoroutine(string name, float fadeTime){
Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name); Sounds.List s = Array.Find(soundList.sounds, sound => sound.name == name);
if (s == null) { if (s == null){
Debug.LogWarning("Sound: " + name + " not found!"); Debug.LogWarning("Sound: " + name + " not found!");
yield break; yield break;
} }
while (s.source.volume > 0) { while (s.source.volume > 0){
s.source.volume -= Time.deltaTime / fadeTime; s.source.volume -= Time.deltaTime / fadeTime;
yield return null; yield return null;
} }
s.source.volume = 0; s.source.volume = 0;
} }
#endregion #endregion
}
} }

View file

@ -1,9 +1,8 @@
using UnityEngine; using UnityEngine;
using UnityEngine.Audio; using UnityEngine.Audio;
namespace SimpleTools.AudioManager { [CreateAssetMenu(fileName = "Sounds", menuName = "Tools/Sounds", order = 0)]
[CreateAssetMenu(fileName = "Sounds", menuName = "Simple Tools/Sounds", order = 11)] public class Sounds : ScriptableObject{
public class Sounds : ScriptableObject {
[Tooltip("The music mixer.")] [Tooltip("The music mixer.")]
public AudioMixerGroup mainMixer = default; public AudioMixerGroup mainMixer = default;
@ -12,8 +11,7 @@ namespace SimpleTools.AudioManager {
public List[] sounds; public List[] sounds;
[System.Serializable] [System.Serializable] public class List{
public class List {
[Tooltip("Name of the sound. Each name has to be different between each other.")] [Tooltip("Name of the sound. Each name has to be different between each other.")]
public string name; public string name;
@ -34,20 +32,19 @@ namespace SimpleTools.AudioManager {
[HideInInspector] public AudioSource source; [HideInInspector] public AudioSource source;
float randomVolume; float randomVolume;
public float RandomVolume { public float RandomVolume{
get { get{
randomVolume = volume * (1f + Random.Range(-volumeVariance / 2f, volumeVariance / 2f)); randomVolume = volume * (1f + Random.Range(-volumeVariance / 2f, volumeVariance / 2f));
return randomVolume; return randomVolume;
} }
} }
float randomPitch; float randomPitch;
public float RandomPitch { public float RandomPitch{
get { get{
randomPitch = pitch * (1f + Random.Range(-pitchVariance / 2f, pitchVariance / 2f)); randomPitch = pitch * (1f + Random.Range(-pitchVariance / 2f, pitchVariance / 2f));
return randomPitch; return randomPitch;
} }
} }
} }
}
} }

View file

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: 2f2d8faa0dc23b34f9f347dc08bd85be
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,124 +0,0 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System;
using System.Threading;
using UnityEditor.SceneManagement;
using System.Threading.Tasks;
namespace SimpleTools.AutoSave {
public class AutoSaveConfig : EditorWindow {
[MenuItem("Simple Tools/Auto Save Configuration")]
public static void ShowWindow(){
EditorWindow w = GetWindow<AutoSaveConfig>("Auto-save Configuration");
w.position = new Rect(w.position.position, new Vector2(400, 150));
var data = EditorPrefs.GetString("AutoSave", JsonUtility.ToJson(w, false));
JsonUtility.FromJsonOverwrite(data, w);
}
[InitializeOnLoadMethod]
static void OnInitialize(){
int _index = EditorPrefs.GetInt("Index", 0);
bool _logging = EditorPrefs.GetBool("Logging", false);
ChangeAutoSaveMode(_index, _logging);
}
protected void OnEnable() {
OnInitialize();
}
protected void OnDisable() {
var data = JsonUtility.ToJson(this, false);
EditorPrefs.SetString("AutoSave", data);
EditorPrefs.SetInt("Index", index);
EditorPrefs.SetBool("Logging", logging);
}
readonly static string[] options = new string[] { "Disabled", "On Play", "1 Minute", "10 Minutes", "1 Hour" };
public static int index;
public static bool enabled;
public static bool logging;
void OnGUI() {
GUILayout.Label("Select auto-save mode:", EditorStyles.boldLabel);
int i = EditorGUILayout.Popup(index, options);
if (i != index) ChangeAutoSaveMode(i, logging);
GUILayout.Label("Log a message every time a the scene gets saved.");
if (logging) {
if (GUILayout.Button("Disable Logging")){
logging ^= true;
ChangeAutoSaveMode(i, logging);
}
} else {
if (GUILayout.Button("Enable Logging")) {
logging ^= true;
ChangeAutoSaveMode(i, logging);
}
}
}
static CancellationTokenSource _tokenSource;
static Task _task;
static int frequency;
static void ChangeAutoSaveMode(int mode, bool log){
index = mode;
logging = log;
CancelTask();
enabled = true;
EditorApplication.playModeStateChanged -= AutoSaveWhenPlayModeStarts;
switch(index){
case 0:
enabled = false;
return;
case 1:
EditorApplication.playModeStateChanged += AutoSaveWhenPlayModeStarts;
return;
case 2:
frequency = 1 * 60 * 1000;
break;
case 3:
frequency = 10 * 60 * 1000;
break;
case 4:
frequency = 60 * 60 * 1000;
break;
}
_tokenSource = new CancellationTokenSource();
_task = SaveInterval(_tokenSource.Token);
}
static void AutoSaveWhenPlayModeStarts(PlayModeStateChange state){
if(state == PlayModeStateChange.ExitingEditMode){
EditorSceneManager.SaveOpenScenes();
AssetDatabase.SaveAssets();
if (logging) Debug.Log($"Auto-saved at {DateTime.Now:h:mm:ss tt}");
}
}
static void CancelTask() {
if (_task == null) return;
_tokenSource.Cancel();
}
static async Task SaveInterval(CancellationToken token) {
while (!token.IsCancellationRequested) {
await Task.Delay(frequency, token);
if (token.IsCancellationRequested) break;
if (!enabled || Application.isPlaying || BuildPipeline.isBuildingPlayer || EditorApplication.isCompiling) return;
if (!UnityEditorInternal.InternalEditorUtility.isApplicationActive) return;
EditorSceneManager.SaveOpenScenes();
AssetDatabase.SaveAssets();
if (logging) Debug.Log($"Auto-saved at {DateTime.Now:h:mm:ss tt}");
}
}
}
}
#endif

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: e3f4095259fcc1f45991636604af9829
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,41 +1,38 @@
using UnityEngine; using UnityEngine;
using Cinemachine; using Cinemachine;
namespace SimpleTools.Cinemachine { public class CMCameraTrigger : MonoBehaviour{
public class CMCameraTrigger : MonoBehaviour {
CinemachineVirtualCamera vcam; CinemachineVirtualCamera vcam;
[SerializeField, Tooltip("Name of the collider's tag that will trigger the camera.")] string triggerTagName;
void Awake() { void Awake(){
vcam = GetComponentInChildren<CinemachineVirtualCamera>(true); vcam = GetComponentInChildren<CinemachineVirtualCamera>(true);
vcam.gameObject.SetActive(false); vcam.gameObject.SetActive(false);
} }
#region 3D #region 3D
void OnTriggerEnter(Collider col) { void OnTriggerEnter(Collider col){
if (col.CompareTag(triggerTagName)) { if (col.CompareTag("Player")){
vcam.gameObject.SetActive(true); vcam.gameObject.SetActive(true);
} }
} }
void OnTriggerExit(Collider col) { void OnTriggerExit(Collider col){
if (col.CompareTag(triggerTagName)) { if (col.CompareTag("Player")){
vcam.gameObject.SetActive(true); vcam.gameObject.SetActive(true);
} }
} }
#endregion #endregion
#region 2D #region 2D
void OnTriggerEnter2D(Collider2D col) { void OnTriggerEnter2D(Collider2D col){
if (col.CompareTag(triggerTagName)) { if (col.CompareTag("Player")){
vcam.gameObject.SetActive(true); vcam.gameObject.SetActive(true);
} }
} }
void OnTriggerExit2D(Collider2D col) { void OnTriggerExit2D(Collider2D col){
if (col.CompareTag(triggerTagName)) { if (col.CompareTag("Player")){
vcam.gameObject.SetActive(false); vcam.gameObject.SetActive(false);
} }
} }
#endregion #endregion
}
} }

View file

@ -1,8 +1,7 @@
using Cinemachine; using Cinemachine;
using UnityEngine; using UnityEngine;
namespace SimpleTools.Cinemachine { public static class ScreenShake{
public static class ScreenShake {
static CinemachineVirtualCamera vCam; static CinemachineVirtualCamera vCam;
static ScreenShakeUpdate shakeUpdate; static ScreenShakeUpdate shakeUpdate;
@ -12,8 +11,8 @@ namespace SimpleTools.Cinemachine {
[HideInInspector] public float shakeTimerTotal; [HideInInspector] public float shakeTimerTotal;
[HideInInspector] public float startingIntensity; [HideInInspector] public float startingIntensity;
void Update() { void Update(){
if (shakeTimer > 0) { if (shakeTimer > 0){
shakeTimer -= Time.deltaTime; shakeTimer -= Time.deltaTime;
CinemachineBasicMultiChannelPerlin multiChannelPerlin = vCam.GetCinemachineComponent<CinemachineBasicMultiChannelPerlin>(); CinemachineBasicMultiChannelPerlin multiChannelPerlin = vCam.GetCinemachineComponent<CinemachineBasicMultiChannelPerlin>();
multiChannelPerlin.m_AmplitudeGain = Mathf.Lerp(startingIntensity, 0f, 1 - (shakeTimer / shakeTimerTotal)); multiChannelPerlin.m_AmplitudeGain = Mathf.Lerp(startingIntensity, 0f, 1 - (shakeTimer / shakeTimerTotal));
@ -24,15 +23,14 @@ namespace SimpleTools.Cinemachine {
/// <summary>Shake the camera /// <summary>Shake the camera
/// <para>It needs a cinemachine camera with a noise profile in it.</para> /// <para>It needs a cinemachine camera with a noise profile in it.</para>
/// </summary> /// </summary>
public static void Shake(float intensity, float time) { public static void Shake(float intensity, float time){
if (vCam == null) { if(vCam == null){
vCam = Camera.main.GetComponent<CinemachineBrain>().ActiveVirtualCamera.VirtualCameraGameObject.GetComponent<CinemachineVirtualCamera>(); vCam = Camera.main.GetComponent<CinemachineBrain>().ActiveVirtualCamera.VirtualCameraGameObject.GetComponent<CinemachineVirtualCamera>();
} }
if (shakeUpdate == null) { if(shakeUpdate == null){
shakeUpdate = new GameObject("ShakeUpdate").AddComponent<ScreenShakeUpdate>(); shakeUpdate = new GameObject("ShakeUpdate").AddComponent<ScreenShakeUpdate>();
} }
shakeUpdate.startingIntensity = intensity; shakeUpdate.startingIntensity = intensity;
shakeUpdate.shakeTimer = shakeUpdate.shakeTimerTotal = time; shakeUpdate.shakeTimer = shakeUpdate.shakeTimerTotal = time;
} }
}
} }

View file

@ -1,16 +1,12 @@
using UnityEngine; using UnityEngine;
namespace SimpleTools.DialogueSystem { [CreateAssetMenu(fileName = "New Character", menuName = "Tools/Character", order = 0)]
[CreateAssetMenu(fileName = "New Dialogue", menuName = "Simple Tools/Dialogue", order = 11)] public class Dialogue : ScriptableObject{
public class Dialogue : ScriptableObject {
public DialogueBox[] sentences;
}
[System.Serializable]
public class DialogueBox {
public bool displayName; public bool displayName;
public string characterName; public string characterName;
[Space]
public Sprite characterImage; public Sprite characterImage;
[TextArea(5, 10)] public string sentence; [TextArea] public string[] sentences;
}
} }

View file

@ -1,126 +0,0 @@
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
namespace SimpleTools.DialogueSystem {
public class DialogueManager : MonoBehaviour {
DialogueVertexAnimator dialogueVertexAnimator;
Queue<string> sentences;
Queue<bool> displayNames;
Queue<string> characterNames;
Queue<Sprite> characterImages;
bool talking;
public DialogueManagerItems dialogueItems;
public static DialogueManager instance;
void Awake() {
instance = this;
sentences = new Queue<string>();
displayNames = new Queue<bool>();
characterNames = new Queue<string>();
characterImages = new Queue<Sprite>();
dialogueVertexAnimator = new DialogueVertexAnimator(dialogueItems.textBox);
}
/// <summary>
/// This is the main function to call to start a dialogue.
/// </summary>
/// <param name="dialogue">The dialogue to start.</param>
/// <returns>A bool that is false if the dialogue has finished and true if it hasn't.</returns>
public bool Dialogue(Dialogue dialogue) {
return Dialogue(dialogue, string.Empty);
}
/// <summary>
/// This is the main function to call to start a dialogue.
/// </summary>
/// <param name="dialogue">The dialogue to start.</param>
/// <param name="sounds">The sounds from the AudioManager that will be played on character reveal.</param>
/// <returns>A bool that is false if the dialogue has finished and true if it hasn't.</returns>
public bool Dialogue(Dialogue dialogue, params string[] sounds) {
dialogueVertexAnimator.SetAudioSourceGroup(sounds);
if (!talking) {
sentences.Clear();
if (dialogue.sentences.Length != 0) {
foreach (DialogueBox sentence in dialogue.sentences) {
sentences.Enqueue(sentence.sentence);
displayNames.Enqueue(sentence.displayName);
characterNames.Enqueue(sentence.characterName);
characterImages.Enqueue(sentence.characterImage);
}
} else {
sentences.Enqueue("I am error. No text has been added");
}
talking = true;
if (sentences.Count == 0) {
if (dialogueVertexAnimator.IsMessageAnimating())
return true;
talking = false;
return false;
}
string sentenceToShow = sentences.Peek();
bool displayName = displayNames.Peek();
string characterName = characterNames.Peek();
Sprite characterImage = characterImages.Peek();
if (PlayDialogue(sentenceToShow, displayName, characterName, characterImage)) {
sentences.Dequeue();
displayNames.Dequeue();
characterNames.Dequeue();
characterImages.Dequeue();
}
return true;
} else {
if (sentences.Count == 0) {
if (dialogueVertexAnimator.IsMessageAnimating())
return true;
talking = false;
return false;
}
string sentenceToShow = sentences.Peek();
bool displayName = displayNames.Peek();
string characterName = characterNames.Peek();
Sprite characterImage = characterImages.Peek();
if (PlayDialogue(sentenceToShow, displayName, characterName, characterImage)) {
sentences.Dequeue();
displayNames.Dequeue();
characterNames.Dequeue();
characterImages.Dequeue();
}
return true;
}
}
private Coroutine typeRoutine = null;
bool PlayDialogue(string message, bool displayName = false, string characterName = "", Sprite characterImage = null) {
if (dialogueVertexAnimator.IsMessageAnimating()) {
dialogueVertexAnimator.SkipToEndOfCurrentMessage();
return false; //Next message hasn't been shown because the current one is still animating.
}
this.EnsureCoroutineStopped(ref typeRoutine);
dialogueVertexAnimator.textAnimating = false;
List<DialogueCommand> commands = DialogueUtility.ProcessInputString(message, out string totalTextMessage);
typeRoutine = StartCoroutine(dialogueVertexAnimator.AnimateTextIn(commands, totalTextMessage, null));
dialogueItems.characterImage.sprite = characterImage;
dialogueItems.characterName.text = displayName ? characterName : "???";
return true; //Next message shown successfully
}
}
[System.Serializable]
public struct DialogueManagerItems {
public Image characterImage;
public TMP_Text characterName;
public TMP_Text textBox;
public Canvas canvas;
}
}

View file

@ -0,0 +1,75 @@
using System.Collections.Generic;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
public class DialogueSystem : MonoBehaviour{
public static DialogueSystem instance;
public GameObject nameField = default;
public TextMeshProUGUI nameText = default;
public TMP_Animated dialogue = default;
public Image faceImage = default;
Queue<string> sentences;
bool talking;
Animator anim;
void Awake(){
instance = this;
sentences = new Queue<string>();
anim = GetComponent<Animator>();
}
/// <summary>Start or continue the dialogue
/// <para>This function returns false if the dialogue has ended.</para>
/// </summary>
public bool Dialogue(Dialogue dialogue){
if(!talking){
if (dialogue.displayName){
nameText.text = dialogue.characterName;
nameField.SetActive(true);
nameText.gameObject.SetActive(true);
}else{
nameField.SetActive(false);
nameText.gameObject.SetActive(false);
}
if (dialogue.characterImage)
faceImage.sprite = dialogue.characterImage;
else
faceImage.sprite = null;
sentences.Clear();
if(dialogue.sentences.Length != 0){
foreach (string sentence in dialogue.sentences){
sentences.Enqueue(sentence);
}
}else{
sentences.Enqueue("I am error. No text has been added");
}
talking = true;
if(sentences.Count == 0){
talking = false;
return false;
}
string sentenceToShow = sentences.Dequeue();
this.dialogue.ReadText(sentenceToShow);
anim.SetBool("Talking", true);
return true;
}else{
if (sentences.Count == 0){
talking = false;
anim.SetBool("Talking", false);
return false;
}
string sentenceToShow = sentences.Dequeue();
this.dialogue.ReadText(sentenceToShow);
return true;
}
}
}

View file

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: dcef7fafd8716284392e9621424bfa6a guid: caad12703fd5c3349acc637253734ac9
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2

View file

@ -1,206 +0,0 @@
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
using System;
namespace SimpleTools.DialogueSystem {
public class DialogueUtility : MonoBehaviour {
// grab the remainder of the text until ">" or end of string
const string REMAINDER_REGEX = "(.*?((?=>)|(/|$)))";
const string PAUSE_REGEX_STRING = "<p:(?<pause>" + REMAINDER_REGEX + ")>";
static readonly Regex pauseRegex = new Regex(PAUSE_REGEX_STRING);
const string SOUND_REGEX_STRING = "<snd:(?<sound>" + REMAINDER_REGEX + ")>";
static readonly Regex soundRegex = new Regex(SOUND_REGEX_STRING);
const string PLAYMUSIC_REGEX_STRING = "<playmsc:(?<playmusic>" + REMAINDER_REGEX + ")>";
static readonly Regex playMusicRegex = new Regex(PLAYMUSIC_REGEX_STRING);
const string STOPMUSIC_REGEX_STRING = "<stopmsc:(?<stopmusic>" + REMAINDER_REGEX + ")>";
static readonly Regex stopMusicRegex = new Regex(STOPMUSIC_REGEX_STRING);
const string SPEED_REGEX_STRING = "<sp:(?<speed>" + REMAINDER_REGEX + ")>";
static readonly Regex speedRegex = new Regex(SPEED_REGEX_STRING);
const string ANIM_START_REGEX_STRING = "<anim:(?<anim>" + REMAINDER_REGEX + ")>";
static readonly Regex animStartRegex = new Regex(ANIM_START_REGEX_STRING);
const string ANIM_END_REGEX_STRING = "</anim>";
static readonly Regex animEndRegex = new Regex(ANIM_END_REGEX_STRING);
static readonly Dictionary<string, float> pauseDictionary = new Dictionary<string, float>{
{ "tiny", .1f },
{ "short", .25f },
{ "normal", 0.666f },
{ "long", 1f },
{ "read", 2f },
};
public static List<DialogueCommand> ProcessInputString(string message, out string processedMessage) {
List<DialogueCommand> result = new List<DialogueCommand>();
processedMessage = message;
processedMessage = HandlePauseTags(processedMessage, result);
processedMessage = HandleSoundTags(processedMessage, result);
processedMessage = HandlePlayMusicTags(processedMessage, result);
processedMessage = HandleStopMusicTags(processedMessage, result);
processedMessage = HandleSpeedTags(processedMessage, result);
processedMessage = HandleAnimStartTags(processedMessage, result);
processedMessage = HandleAnimEndTags(processedMessage, result);
return result;
}
static string HandleAnimEndTags(string processedMessage, List<DialogueCommand> result) {
MatchCollection animEndMatches = animEndRegex.Matches(processedMessage);
foreach (Match match in animEndMatches) {
result.Add(new DialogueCommand {
position = VisibleCharactersUpToIndex(processedMessage, match.Index),
type = DialogueCommandType.AnimEnd,
});
}
processedMessage = Regex.Replace(processedMessage, ANIM_END_REGEX_STRING, "");
return processedMessage;
}
static string HandleAnimStartTags(string processedMessage, List<DialogueCommand> result) {
MatchCollection animStartMatches = animStartRegex.Matches(processedMessage);
foreach (Match match in animStartMatches) {
string stringVal = match.Groups["anim"].Value;
result.Add(new DialogueCommand {
position = VisibleCharactersUpToIndex(processedMessage, match.Index),
type = DialogueCommandType.AnimStart,
textAnimValue = GetTextAnimationType(stringVal)
});
}
processedMessage = Regex.Replace(processedMessage, ANIM_START_REGEX_STRING, "");
return processedMessage;
}
static string HandleSpeedTags(string processedMessage, List<DialogueCommand> result) {
MatchCollection speedMatches = speedRegex.Matches(processedMessage);
foreach (Match match in speedMatches) {
string stringVal = match.Groups["speed"].Value;
if (!float.TryParse(stringVal, out float val)) {
val = 150f;
}
result.Add(new DialogueCommand {
position = VisibleCharactersUpToIndex(processedMessage, match.Index),
type = DialogueCommandType.TextSpeedChange,
floatValue = val
});
}
processedMessage = Regex.Replace(processedMessage, SPEED_REGEX_STRING, "");
return processedMessage;
}
static string HandlePauseTags(string processedMessage, List<DialogueCommand> result) {
MatchCollection pauseMatches = pauseRegex.Matches(processedMessage);
foreach (Match match in pauseMatches) {
string val = match.Groups["pause"].Value;
string pauseName = val;
Debug.Assert(pauseDictionary.ContainsKey(pauseName), "no pause registered for '" + pauseName + "'");
result.Add(new DialogueCommand {
position = VisibleCharactersUpToIndex(processedMessage, match.Index),
type = DialogueCommandType.Pause,
floatValue = pauseDictionary[pauseName]
});
}
processedMessage = Regex.Replace(processedMessage, PAUSE_REGEX_STRING, "");
return processedMessage;
}
static string HandleSoundTags(string processedMessage, List<DialogueCommand> result) {
MatchCollection soundMatches = soundRegex.Matches(processedMessage);
foreach (Match match in soundMatches) {
string val = match.Groups["sound"].Value;
string soundName = val;
result.Add(new DialogueCommand {
position = VisibleCharactersUpToIndex(processedMessage, match.Index),
type = DialogueCommandType.Sound,
stringValue = soundName
});
}
processedMessage = Regex.Replace(processedMessage, SOUND_REGEX_STRING, "");
return processedMessage;
}
static string HandlePlayMusicTags(string processedMessage, List<DialogueCommand> result) {
MatchCollection playMatches = playMusicRegex.Matches(processedMessage);
foreach (Match match in playMatches) {
string val = match.Groups["playmusic"].Value;
string functionName = val;
result.Add(new DialogueCommand {
position = VisibleCharactersUpToIndex(processedMessage, match.Index),
type = DialogueCommandType.PlayMusic,
stringValue = functionName
});
}
processedMessage = Regex.Replace(processedMessage, PLAYMUSIC_REGEX_STRING, "");
return processedMessage;
}
static string HandleStopMusicTags(string processedMessage, List<DialogueCommand> result) {
MatchCollection stopMatches = stopMusicRegex.Matches(processedMessage);
foreach (Match match in stopMatches) {
string val = match.Groups["stopmusic"].Value;
string functionName = val;
result.Add(new DialogueCommand {
position = VisibleCharactersUpToIndex(processedMessage, match.Index),
type = DialogueCommandType.StopMusic,
stringValue = functionName
});
}
processedMessage = Regex.Replace(processedMessage, STOPMUSIC_REGEX_STRING, "");
return processedMessage;
}
static TextAnimationType GetTextAnimationType(string stringVal) {
TextAnimationType result;
try {
result = (TextAnimationType)Enum.Parse(typeof(TextAnimationType), stringVal, true);
} catch (ArgumentException) {
Debug.LogError("Invalid Text Animation Type: " + stringVal);
result = TextAnimationType.none;
}
return result;
}
static int VisibleCharactersUpToIndex(string message, int index) {
int result = 0;
bool insideBrackets = false;
for (int i = 0; i < index; i++) {
if (message[i] == '<') {
insideBrackets = true;
} else if (message[i] == '>') {
insideBrackets = false;
result--;
}
if (!insideBrackets) {
result++;
} else if (i + 6 < index && message.Substring(i, 6) == "sprite") {
result++;
}
}
return result;
}
}
public struct DialogueCommand {
public int position;
public DialogueCommandType type;
public float floatValue;
public string stringValue;
public TextAnimationType textAnimValue;
}
public enum DialogueCommandType {
Pause,
TextSpeedChange,
AnimStart,
AnimEnd,
Sound,
PlayMusic,
StopMusic
}
public enum TextAnimationType {
none,
shake,
wave,
wobble,
rainbow,
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: d4649243ed65dff45b7891eed22eb4c6
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,277 +0,0 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using TMPro;
using UnityEngine;
namespace SimpleTools.DialogueSystem {
public class DialogueVertexAnimator {
public bool textAnimating = false;
bool stopAnimating = false;
readonly TMP_Text textBox;
string[] audioSourceGroup;
public void SetAudioSourceGroup(params string[] _audioSourceGroup) {
audioSourceGroup = _audioSourceGroup;
}
public DialogueVertexAnimator(TMP_Text _textBox) {
textBox = _textBox;
}
static readonly Color32 clear = new Color32(0, 0, 0, 0);
const float CHAR_ANIM_TIME = 0.07f;
static readonly Vector3 vecZero = Vector3.zero;
public IEnumerator AnimateTextIn(List<DialogueCommand> commands, string processedMessage, Action onFinish) {
textAnimating = true;
float secondsPerCharacter = 1f / 150f;
float timeOfLastCharacter = 0;
TextAnimInfo[] textAnimInfo = SeparateOutTextAnimInfo(commands);
TMP_TextInfo textInfo = textBox.textInfo;
for (int i = 0; i < textInfo.meshInfo.Length; i++) {
TMP_MeshInfo meshInfer = textInfo.meshInfo[i];
if (meshInfer.vertices != null) {
for (int j = 0; j < meshInfer.vertices.Length; j++) {
meshInfer.vertices[j] = vecZero;
}
}
}
textBox.text = processedMessage;
textBox.ForceMeshUpdate();
TMP_MeshInfo[] cachedMeshInfo = textInfo.CopyMeshInfoVertexData();
Color32[][] originalColors = new Color32[textInfo.meshInfo.Length][];
for (int i = 0; i < originalColors.Length; i++) {
Color32[] theColors = textInfo.meshInfo[i].colors32;
originalColors[i] = new Color32[theColors.Length];
Array.Copy(theColors, originalColors[i], theColors.Length);
}
int charCount = textInfo.characterCount;
float[] charAnimStartTimes = new float[charCount];
for (int i = 0; i < charCount; i++) {
charAnimStartTimes[i] = -1;
}
int visableCharacterIndex = 0;
while (true) {
if (stopAnimating) {
for (int i = visableCharacterIndex; i < charCount; i++) {
charAnimStartTimes[i] = Time.unscaledTime;
}
visableCharacterIndex = charCount;
FinishAnimating(onFinish);
}
if (ShouldShowNextCharacter(secondsPerCharacter, timeOfLastCharacter)) {
if (visableCharacterIndex <= charCount) {
ExecuteCommandsForCurrentIndex(commands, visableCharacterIndex, ref secondsPerCharacter, ref timeOfLastCharacter);
if (visableCharacterIndex < charCount && ShouldShowNextCharacter(secondsPerCharacter, timeOfLastCharacter)) {
charAnimStartTimes[visableCharacterIndex] = Time.unscaledTime;
PlayDialogueSound();
visableCharacterIndex++;
timeOfLastCharacter = Time.unscaledTime;
if (visableCharacterIndex == charCount) {
FinishAnimating(onFinish);
}
}
}
}
for (int j = 0; j < charCount; j++) {
TMP_CharacterInfo charInfo = textInfo.characterInfo[j];
if (charInfo.isVisible) {
int vertexIndex = charInfo.vertexIndex;
int materialIndex = charInfo.materialReferenceIndex;
Color32[] destinationColors = textInfo.meshInfo[materialIndex].colors32;
Color32 theColor = j < visableCharacterIndex ? originalColors[materialIndex][vertexIndex] : clear;
destinationColors[vertexIndex + 0] = theColor;
destinationColors[vertexIndex + 1] = theColor;
destinationColors[vertexIndex + 2] = theColor;
destinationColors[vertexIndex + 3] = theColor;
Vector3[] sourceVertices = cachedMeshInfo[materialIndex].vertices;
Vector3[] destinationVertices = textInfo.meshInfo[materialIndex].vertices;
float charSize = 0;
float charAnimStartTime = charAnimStartTimes[j];
if (charAnimStartTime >= 0) {
float timeSinceAnimStart = Time.unscaledTime - charAnimStartTime;
charSize = Mathf.Min(1, timeSinceAnimStart / CHAR_ANIM_TIME);
}
Vector3 animPosAdjustment = GetAnimPosAdjustment(textAnimInfo, j, textBox.fontSize, Time.unscaledTime);
Vector3 offset = (sourceVertices[vertexIndex + 0] + sourceVertices[vertexIndex + 2]) / 2;
destinationVertices[vertexIndex + 0] = ((sourceVertices[vertexIndex + 0] - offset) * charSize) + offset + animPosAdjustment;
destinationVertices[vertexIndex + 1] = ((sourceVertices[vertexIndex + 1] - offset) * charSize) + offset + animPosAdjustment;
destinationVertices[vertexIndex + 2] = ((sourceVertices[vertexIndex + 2] - offset) * charSize) + offset + animPosAdjustment;
destinationVertices[vertexIndex + 3] = ((sourceVertices[vertexIndex + 3] - offset) * charSize) + offset + animPosAdjustment;
for (int i = 0; i < 4; i++) {
Vector3 animVertexAdjustment = GetAnimVertexAdjustment(textAnimInfo, j, textBox.fontSize, Time.unscaledTime + i);
destinationVertices[vertexIndex + i] += animVertexAdjustment;
Color animColorAdjustment = GetAnimColorAdjustment(textAnimInfo, j, Time.unscaledTime + i, destinationVertices[vertexIndex + i]);
if (animColorAdjustment == Color.white)
continue;
destinationColors[vertexIndex + i] += animColorAdjustment;
}
}
}
textBox.UpdateVertexData(TMP_VertexDataUpdateFlags.Colors32);
for (int i = 0; i < textInfo.meshInfo.Length; i++) {
TMP_MeshInfo theInfo = textInfo.meshInfo[i];
theInfo.mesh.vertices = theInfo.vertices;
textBox.UpdateGeometry(theInfo.mesh, i);
}
yield return null;
}
}
void ExecuteCommandsForCurrentIndex(List<DialogueCommand> commands, int visableCharacterIndex, ref float secondsPerCharacter, ref float timeOfLastCharacter) {
for (int i = 0; i < commands.Count; i++) {
DialogueCommand command = commands[i];
if (command.position == visableCharacterIndex) {
switch (command.type) {
case DialogueCommandType.Pause:
timeOfLastCharacter = Time.unscaledTime + command.floatValue;
break;
case DialogueCommandType.TextSpeedChange:
secondsPerCharacter = 1f / command.floatValue;
break;
case DialogueCommandType.Sound:
AudioManager.AudioManager.instance.PlayOneShot(command.stringValue);
break;
case DialogueCommandType.PlayMusic:
string[] split0 = command.stringValue.Split(',');
AudioManager.AudioManager.instance.FadeIn(split0[0], float.Parse(split0[1], CultureInfo.InvariantCulture));
break;
case DialogueCommandType.StopMusic:
string[] split1 = command.stringValue.Split(',');
for (int j = 0; j < split1.Length; j++) {
Debug.Log(split1[j]);
}
AudioManager.AudioManager.instance.FadeOut(split1[0], float.Parse(split1[1], CultureInfo.InvariantCulture));
break;
}
commands.RemoveAt(i);
i--;
}
}
}
void FinishAnimating(Action onFinish) {
textAnimating = false;
stopAnimating = false;
onFinish?.Invoke();
}
const float NOISE_MAGNITUDE_ADJUSTMENT = 0.06f;
const float NOISE_FREQUENCY_ADJUSTMENT = 15f;
const float WAVE_MAGNITUDE_ADJUSTMENT = 0.06f;
const float WOBBLE_MAGNITUDE_ADJUSTMENT = 0.5f;
const float RAINBOW_LENGTH_ADJUSTMENT = .001f;
Vector3 GetAnimPosAdjustment(TextAnimInfo[] textAnimInfo, int charIndex, float fontSize, float time) {
float x = 0;
float y = 0;
for (int i = 0; i < textAnimInfo.Length; i++) {
TextAnimInfo info = textAnimInfo[i];
if (charIndex >= info.startIndex && charIndex < info.endIndex) {
if (info.type == TextAnimationType.shake) {
float scaleAdjust = fontSize * NOISE_MAGNITUDE_ADJUSTMENT;
x += (Mathf.PerlinNoise((charIndex + time) * NOISE_FREQUENCY_ADJUSTMENT, 0) - 0.5f) * scaleAdjust;
y += (Mathf.PerlinNoise((charIndex + time) * NOISE_FREQUENCY_ADJUSTMENT, 1000) - 0.5f) * scaleAdjust;
} else if (info.type == TextAnimationType.wave) {
y += Mathf.Sin((charIndex * 1.5f) + (time * 6)) * fontSize * WAVE_MAGNITUDE_ADJUSTMENT;
}
}
}
return new Vector3(x, y, 0);
}
Vector3 GetAnimVertexAdjustment(TextAnimInfo[] textAnimInfo, int charIndex, float fontSize, float time) {
float x = 0;
float y = 0;
for (int i = 0; i < textAnimInfo.Length; i++) {
TextAnimInfo info = textAnimInfo[i];
if (charIndex >= info.startIndex && charIndex < info.endIndex) {
if (info.type == TextAnimationType.wobble) {
float scaleAdjust = fontSize * NOISE_MAGNITUDE_ADJUSTMENT;
x = Mathf.Sin(time * 3.3f) * scaleAdjust * WOBBLE_MAGNITUDE_ADJUSTMENT;
y = Mathf.Cos(time * 2.5f) * scaleAdjust * WOBBLE_MAGNITUDE_ADJUSTMENT;
}
}
}
return new Vector3(x, y, 0);
}
Color GetAnimColorAdjustment(TextAnimInfo[] textAnimInfo, int charIndex, float time, Vector3 destinationVertice) {
Color color = Color.white;
for (int i = 0; i < textAnimInfo.Length; i++) {
TextAnimInfo info = textAnimInfo[i];
if (charIndex >= info.startIndex && charIndex < info.endIndex) {
if (info.type == TextAnimationType.rainbow) {
color = Color.HSVToRGB(Mathf.Repeat((time + destinationVertice.x * RAINBOW_LENGTH_ADJUSTMENT), 1f), .75f, 1);
}
}
}
return color;
}
static bool ShouldShowNextCharacter(float secondsPerCharacter, float timeOfLastCharacter) {
return (Time.unscaledTime - timeOfLastCharacter) > secondsPerCharacter;
}
public void SkipToEndOfCurrentMessage() {
if (textAnimating) {
stopAnimating = true;
}
}
public bool IsMessageAnimating() {
return textAnimating;
}
float timeUntilNextDialogueSound = 0;
float lastDialogueSound = 0;
void PlayDialogueSound() {
if (Time.unscaledTime - lastDialogueSound > timeUntilNextDialogueSound) {
timeUntilNextDialogueSound = UnityEngine.Random.Range(0.02f, 0.08f);
lastDialogueSound = Time.unscaledTime;
if (audioSourceGroup[0] != string.Empty)
AudioManager.AudioManager.instance.PlayRandomSound(audioSourceGroup);
}
}
TextAnimInfo[] SeparateOutTextAnimInfo(List<DialogueCommand> commands) {
List<TextAnimInfo> tempResult = new List<TextAnimInfo>();
List<DialogueCommand> animStartCommands = new List<DialogueCommand>();
List<DialogueCommand> animEndCommands = new List<DialogueCommand>();
for (int i = 0; i < commands.Count; i++) {
DialogueCommand command = commands[i];
if (command.type == DialogueCommandType.AnimStart) {
animStartCommands.Add(command);
commands.RemoveAt(i);
i--;
} else if (command.type == DialogueCommandType.AnimEnd) {
animEndCommands.Add(command);
commands.RemoveAt(i);
i--;
}
}
if (animStartCommands.Count != animEndCommands.Count) {
Debug.LogError("Unequal number of start and end animation commands. Start Commands: " + animStartCommands.Count + " End Commands: " + animEndCommands.Count);
} else {
for (int i = 0; i < animStartCommands.Count; i++) {
DialogueCommand startCommand = animStartCommands[i];
DialogueCommand endCommand = animEndCommands[i];
tempResult.Add(new TextAnimInfo {
startIndex = startCommand.position,
endIndex = endCommand.position,
type = startCommand.textAnimValue
});
}
}
return tempResult.ToArray();
}
}
public struct TextAnimInfo {
public int startIndex;
public int endIndex;
public TextAnimationType type;
}
}

View file

@ -0,0 +1,71 @@
using System.Collections;
using UnityEngine;
using UnityEngine.Events;
namespace TMPro{
[System.Serializable] public class TextRevealEvent : UnityEvent<char> { }
[System.Serializable] public class DialogueEvent : UnityEvent { }
public class TMP_Animated : TextMeshProUGUI{
float speed;
public TextRevealEvent onTextReveal;
public DialogueEvent onDialogueFinish;
public void ReadText(string newText){
text = string.Empty;
string[] subTexts = newText.Split('<', '>');
string displayText = "";
for (int i = 0; i < subTexts.Length; i++){
if (i % 2 == 0)
displayText += subTexts[i];
else if (!isCustomTag(subTexts[i].Replace(" ", "")))
displayText += $"<{subTexts[i]}>";
}
bool isCustomTag(string tag){
return tag.StartsWith("speed=") || tag.StartsWith("pause=");
}
text = displayText;
maxVisibleCharacters = 0;
StartCoroutine(Read());
IEnumerator Read(){
int subCounter = 0;
int visibleCounter = 0;
while(subCounter < subTexts.Length){
if(subCounter % 2 == 1){
yield return EvaluateTag(subTexts[subCounter].Replace(" ", ""));
}else{
while(visibleCounter < subTexts[subCounter].Length){
onTextReveal.Invoke(subTexts[subCounter][visibleCounter]);
visibleCounter++;
maxVisibleCharacters++;
yield return new WaitForSeconds(1f / speed);
}
visibleCounter = 0;
}
subCounter++;
}
yield return null;
WaitForSeconds EvaluateTag(string tag){
if (tag.Length > 0){
if (tag.StartsWith("speed=")){
speed = float.Parse(tag.Split('=')[1]);
}else if (tag.StartsWith("pause=")){
return new WaitForSeconds(float.Parse(tag.Split('=')[1]));
}
}
return null;
}
onDialogueFinish.Invoke();
}
}
}
}

View file

@ -1,11 +1,11 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: 23d6a059fd2bc464a9cba3a5ced1724d guid: f713d84a3ae882945800780459e26170
MonoImporter: MonoImporter:
externalObjects: {} externalObjects: {}
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []
executionOrder: 0 executionOrder: 0
icon: {instanceID: 0} icon: {fileID: 2800000, guid: 2fd6421f253b4ef1a19526541f9ffc0c, type: 3}
userData: userData:
assetBundleName: assetBundleName:
assetBundleVariant: assetBundleVariant:

View file

@ -1,4 +1,3 @@
#if UNITY_EDITOR
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
@ -11,21 +10,16 @@ using UnityEditor.SceneManagement;
using UnityEngine.EventSystems; using UnityEngine.EventSystems;
using UnityEditor.Experimental.SceneManagement; using UnityEditor.Experimental.SceneManagement;
using System; using System;
using SimpleTools.AudioManager;
using SimpleTools.DialogueSystem;
using SimpleTools.Cinemachine;
using SimpleTools.SceneManagement;
using SimpleTools.Menu;
public class ToolsEditor{ public class ToolsEditor{
[MenuItem("GameObject/Simple Tools/AudioManager", false, 10)] [MenuItem("GameObject/Tools/AudioManager", false, 10)]
static void CreateAudioManager(){ static void CreateAudioManager(){
GameObject audioManager = new GameObject("AudioManager"); GameObject audioManager = new GameObject("AudioManager");
audioManager.AddComponent<AudioManager>(); audioManager.AddComponent<AudioManager>();
} }
[MenuItem("GameObject/Simple Tools/Dialogue System", false, 10)] [MenuItem("GameObject/Tools/Dialogue System", false, 10)]
static void CreateDialogueSystem(){ static void CreateDialogueSystem(){
GameObject dialogueCanvas = new GameObject("DialogueCanvas"); GameObject dialogueCanvas = new GameObject("DialogueCanvas");
dialogueCanvas.AddComponent<RectTransform>(); dialogueCanvas.AddComponent<RectTransform>();
@ -34,9 +28,9 @@ public class ToolsEditor{
dialogueCanvas.AddComponent<CanvasScaler>(); dialogueCanvas.AddComponent<CanvasScaler>();
dialogueCanvas.AddComponent<GraphicRaycaster>(); dialogueCanvas.AddComponent<GraphicRaycaster>();
GameObject text = new GameObject("DialogueText"); GameObject text = new GameObject("TMP_Animated");
text.transform.SetParent(dialogueCanvas.transform); text.transform.SetParent(dialogueCanvas.transform);
text.AddComponent<TextMeshProUGUI>().text = "Dialogue"; text.AddComponent<TMP_Animated>().text = "New Text";
text.GetComponent<RectTransform>().anchoredPosition = Vector2.zero; text.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
GameObject name = new GameObject("NameText"); GameObject name = new GameObject("NameText");
@ -49,20 +43,14 @@ public class ToolsEditor{
image.AddComponent<Image>(); image.AddComponent<Image>();
image.GetComponent<RectTransform>().anchoredPosition = new Vector2(-150f, 25f); image.GetComponent<RectTransform>().anchoredPosition = new Vector2(-150f, 25f);
DialogueManager dialogueManager = dialogueCanvas.AddComponent<DialogueManager>(); DialogueSystem dialogueSystem = dialogueCanvas.AddComponent<DialogueSystem>();
Debug.Log(dialogueManager.dialogueItems); dialogueSystem.nameText = name.GetComponent<TextMeshProUGUI>();
dialogueManager.dialogueItems.textBox = text.GetComponent<TextMeshProUGUI>(); dialogueSystem.dialogue = text.GetComponent<TMP_Animated>();
dialogueManager.dialogueItems.characterName = name.GetComponent<TextMeshProUGUI>(); dialogueSystem.faceImage = image.GetComponent<Image>();
dialogueManager.dialogueItems.characterImage = image.GetComponent<Image>(); dialogueSystem.nameField = name;
dialogueManager.dialogueItems.canvas = canvas;
//DialogueSystem dialogueSystem = dialogueCanvas.AddComponent<DialogueSystem>();
//dialogueSystem.nameText = name.GetComponent<TextMeshProUGUI>();
//dialogueSystem.dialogue = text.GetComponent<TMP_Animated>();
//dialogueSystem.faceImage = image.GetComponent<Image>();
//dialogueSystem.nameField = name;
} }
[MenuItem("GameObject/Simple Tools/Camera Trigger/2D", false, 10)] [MenuItem("GameObject/Tools/Camera Trigger/2D", false, 10)]
static void CreateCameraTrigger2D(){ static void CreateCameraTrigger2D(){
GameObject cameraTrigger = new GameObject("CameraTrigger2D"); GameObject cameraTrigger = new GameObject("CameraTrigger2D");
cameraTrigger.AddComponent<BoxCollider2D>(); cameraTrigger.AddComponent<BoxCollider2D>();
@ -75,7 +63,7 @@ public class ToolsEditor{
cam.m_Lens.Orthographic = true; cam.m_Lens.Orthographic = true;
} }
[MenuItem("GameObject/Simple Tools/Camera Trigger/3D", false, 10)] [MenuItem("GameObject/Tools/Camera Trigger/3D", false, 10)]
static void CreateCameraTrigger3D(){ static void CreateCameraTrigger3D(){
GameObject cameraTrigger = new GameObject("CameraTrigger3D"); GameObject cameraTrigger = new GameObject("CameraTrigger3D");
cameraTrigger.AddComponent<BoxCollider>(); cameraTrigger.AddComponent<BoxCollider>();
@ -89,7 +77,7 @@ public class ToolsEditor{
} }
#if CINEMACHINE_271_OR_NEWER #if CINEMACHINE_271_OR_NEWER
[MenuItem("GameObject/Simple Tools/ScreenShake Camera/2D", false, 10)] [MenuItem("GameObject/Tools/ScreenShake Camera/2D", false, 10)]
static void CreateScreenShakeCamera2d(){ static void CreateScreenShakeCamera2d(){
GameObject screenShakeCamera = new GameObject("ScreenShakeCamera"); GameObject screenShakeCamera = new GameObject("ScreenShakeCamera");
CinemachineVirtualCamera vCam = screenShakeCamera.AddComponent<CinemachineVirtualCamera>(); CinemachineVirtualCamera vCam = screenShakeCamera.AddComponent<CinemachineVirtualCamera>();
@ -103,7 +91,7 @@ public class ToolsEditor{
shake.m_AmplitudeGain = 0f; shake.m_AmplitudeGain = 0f;
shake.m_FrequencyGain = 1f; shake.m_FrequencyGain = 1f;
} }
[MenuItem("GameObject/Simple Tools/ScreenShake Camera/3D", false, 10)] [MenuItem("GameObject/Tools/ScreenShake Camera/3D", false, 10)]
static void CreateScreenShakeCamera3d(){ static void CreateScreenShakeCamera3d(){
GameObject screenShakeCamera = new GameObject("ScreenShakeCamera"); GameObject screenShakeCamera = new GameObject("ScreenShakeCamera");
CinemachineVirtualCamera vCam = screenShakeCamera.AddComponent<CinemachineVirtualCamera>(); CinemachineVirtualCamera vCam = screenShakeCamera.AddComponent<CinemachineVirtualCamera>();
@ -118,7 +106,7 @@ public class ToolsEditor{
shake.m_FrequencyGain = 1f; shake.m_FrequencyGain = 1f;
} }
#else #else
[MenuItem("GameObject/Simple Tools/ScreenShake Camera", false, 10)] [MenuItem("GameObject/Tools/ScreenShake Camera", false, 10)]
static void CreateScreenShakeCamera2d(){ static void CreateScreenShakeCamera2d(){
GameObject screenShakeCamera = new GameObject("ScreenShakeCamera"); GameObject screenShakeCamera = new GameObject("ScreenShakeCamera");
CinemachineVirtualCamera vCam = screenShakeCamera.AddComponent<CinemachineVirtualCamera>(); CinemachineVirtualCamera vCam = screenShakeCamera.AddComponent<CinemachineVirtualCamera>();
@ -133,8 +121,7 @@ public class ToolsEditor{
} }
#endif #endif
[MenuItem("Assets/Create/Simple Tools/Create Loading Scene")] [MenuItem("Assets/Create/Tools/Create Loading Scene")]
[MenuItem("Simple Tools/Create Loading Scene")]
static void CreateLoadingScene(){ static void CreateLoadingScene(){
EditorSceneManager.SaveOpenScenes(); EditorSceneManager.SaveOpenScenes();
@ -175,7 +162,7 @@ public class ToolsEditor{
progressBarTransform.anchoredPosition = Vector2.zero; progressBarTransform.anchoredPosition = Vector2.zero;
progressBarTransform.sizeDelta = new Vector2Int(900, 20); progressBarTransform.sizeDelta = new Vector2Int(900, 20);
progressBar.sprite = (Sprite)AssetDatabase.LoadAssetAtPath("Packages/com.geri.simpletools/Simple Tools/Editor/Square.png", typeof(Sprite)); progressBar.sprite = (Sprite)AssetDatabase.LoadAssetAtPath("Packages/com.geri.simpletools/Tools/Editor/Square.png", typeof(Sprite));
progressBar.type = Image.Type.Filled; progressBar.type = Image.Type.Filled;
progressBar.fillMethod = Image.FillMethod.Horizontal; progressBar.fillMethod = Image.FillMethod.Horizontal;
progressBar.fillOrigin = (int)Image.OriginHorizontal.Left; progressBar.fillOrigin = (int)Image.OriginHorizontal.Left;
@ -184,8 +171,7 @@ public class ToolsEditor{
} }
#if UNITY_2019_3_OR_NEWER #if UNITY_2019_3_OR_NEWER
[MenuItem("Assets/Create/Simple Tools/Create Menu Scene")] [MenuItem("Assets/Create/Tools/Create Menu Scene")]
[MenuItem("Simple Tools/Create Menu Scene")]
static void CreateMenuScene(){ static void CreateMenuScene(){
EditorSceneManager.SaveOpenScenes(); EditorSceneManager.SaveOpenScenes();
@ -545,4 +531,3 @@ public class ToolsEditor{
#endregion #endregion
#endif #endif
} }
#endif

View file

@ -5,14 +5,13 @@ using UnityEngine.UI;
using TMPro; using TMPro;
using UnityEngine.Audio; using UnityEngine.Audio;
namespace SimpleTools.Menu { [System.Serializable] public class OnPlay : UnityEngine.Events.UnityEvent { }
[System.Serializable] public class OnPlay : UnityEngine.Events.UnityEvent { } public class MenuController : MonoBehaviour{
public class MenuController : MonoBehaviour {
[Header("Audio")] [Header("Audio")]
[SerializeField] AudioMixer mainMixer = default; [SerializeField] AudioMixer mainMixer = default;
[Tooltip("The music volume the first time you start the game")][SerializeField, Range(0, 1)] float defaultMusicValue = .75f; [Tooltip("The music volume the first time you start the game")] [SerializeField, Range(0, 1)] float defaultMusicValue = .75f;
[Tooltip("The SFX volume the first time you start the game")][SerializeField, Range(0, 1)] float defaultSfxValue = .75f; [Tooltip("The SFX volume the first time you start the game")] [SerializeField, Range(0, 1)] float defaultSfxValue = .75f;
public Slider musicSlider = default; public Slider musicSlider = default;
public Slider sfxSlider = default; public Slider sfxSlider = default;
@ -27,8 +26,8 @@ namespace SimpleTools.Menu {
[Space] [Space]
[SerializeField] OnPlay onPlay = default; [SerializeField] OnPlay onPlay = default;
void Awake() { void Awake(){
if (mainMixer) { if (mainMixer){
float musicVolume = PlayerPrefs.GetFloat("MusicVolume", defaultMusicValue); float musicVolume = PlayerPrefs.GetFloat("MusicVolume", defaultMusicValue);
float sfxVolume = PlayerPrefs.GetFloat("SFXVolume", defaultSfxValue); float sfxVolume = PlayerPrefs.GetFloat("SFXVolume", defaultSfxValue);
mainMixer.SetFloat("Master", Mathf.Log10(musicVolume <= .0001f ? .0001f : musicVolume) * 20); mainMixer.SetFloat("Master", Mathf.Log10(musicVolume <= .0001f ? .0001f : musicVolume) * 20);
@ -39,11 +38,12 @@ namespace SimpleTools.Menu {
resolutionDropdown.ClearOptions(); resolutionDropdown.ClearOptions();
List<string> options = new List<string>(); List<string> options = new List<string>();
for (int i = 0; i < resolutions.Length; i++) { for (int i = 0; i < resolutions.Length; i++){
string option = resolutions[i].width + "x" + resolutions[i].height; string option = resolutions[i].width + "x" + resolutions[i].height;
options.Add(option); options.Add(option);
if (resolutions[i].width == Screen.currentResolution.width && resolutions[i].height == Screen.currentResolution.height) { if (resolutions[i].width == Screen.currentResolution.width && resolutions[i].height == Screen.currentResolution.height)
{
currentResolutionIndex = i; currentResolutionIndex = i;
} }
} }
@ -56,7 +56,7 @@ namespace SimpleTools.Menu {
qualityDropdown.ClearOptions(); qualityDropdown.ClearOptions();
List<string> qualityNames = new List<string>(); List<string> qualityNames = new List<string>();
for (int i = 0; i < QualitySettings.names.Length; i++) { for (int i = 0; i < QualitySettings.names.Length; i++){
qualityNames.Add(QualitySettings.names[i]); qualityNames.Add(QualitySettings.names[i]);
} }
qualityDropdown.AddOptions(qualityNames); qualityDropdown.AddOptions(qualityNames);
@ -67,44 +67,43 @@ namespace SimpleTools.Menu {
qualityDropdown.RefreshShownValue(); qualityDropdown.RefreshShownValue();
} }
void OnValidate() { void OnValidate(){
if (musicSlider) musicSlider.minValue = musicSlider.minValue < .0001f ? .0001f : musicSlider.minValue; if (musicSlider) musicSlider.minValue = musicSlider.minValue < .0001f ? .0001f : musicSlider.minValue;
if (sfxSlider) sfxSlider.minValue = sfxSlider.minValue < .0001f ? .0001f : sfxSlider.minValue; if (sfxSlider) sfxSlider.minValue = sfxSlider.minValue < .0001f ? .0001f : sfxSlider.minValue;
} }
void Start() { void Start(){
musicSlider.value = PlayerPrefs.GetFloat("MusicVolume", defaultMusicValue); musicSlider.value = PlayerPrefs.GetFloat("MusicVolume", defaultMusicValue);
sfxSlider.value = PlayerPrefs.GetFloat("SFXVolume", defaultSfxValue); sfxSlider.value = PlayerPrefs.GetFloat("SFXVolume", defaultSfxValue);
} }
//Needs a slider between 0.0001 and 1 //Needs a slider between 0.0001 and 1
public void SetMusicVolume(float sliderValue) { public void SetMusicVolume(float sliderValue){
mainMixer.SetFloat("Master", Mathf.Log10(sliderValue) * 20); mainMixer.SetFloat("Master", Mathf.Log10(sliderValue) * 20);
PlayerPrefs.SetFloat("MusicVolume", sliderValue); PlayerPrefs.SetFloat("MusicVolume", sliderValue);
} }
//Needs a slider between 0.0001 and 1 //Needs a slider between 0.0001 and 1
public void SetSfxVolume(float sliderValue) { public void SetSfxVolume(float sliderValue){
mainMixer.SetFloat("SFX", Mathf.Log10(sliderValue) * 20); mainMixer.SetFloat("SFX", Mathf.Log10(sliderValue) * 20);
PlayerPrefs.SetFloat("SFXVolume", sliderValue); PlayerPrefs.SetFloat("SFXVolume", sliderValue);
} }
public void SetQuality(int qualityIndex) { public void SetQuality(int qualityIndex){
QualitySettings.SetQualityLevel(qualityIndex); QualitySettings.SetQualityLevel(qualityIndex);
PlayerPrefs.SetInt("QualitySelected", qualityIndex); PlayerPrefs.SetInt("QualitySelected", qualityIndex);
} }
public void SetResolution(int resolutionIndex) { public void SetResolution(int resolutionIndex){
Resolution resolution = resolutions[resolutionIndex]; Resolution resolution = resolutions[resolutionIndex];
Screen.SetResolution(resolution.width, resolution.height, Screen.fullScreen); Screen.SetResolution(resolution.width, resolution.height, Screen.fullScreen);
} }
public void Play() { public void Play(){
onPlay.Invoke(); onPlay.Invoke();
} }
public void Quit() { public void Quit(){
Application.Quit(); Application.Quit();
} }
}
} }

View file

@ -1,12 +0,0 @@
using UnityEngine;
namespace SimpleTools {
public static class MonobehaviourExtensions {
public static void EnsureCoroutineStopped(this MonoBehaviour value, ref Coroutine routine) {
if (routine != null) {
value.StopCoroutine(routine);
routine = null;
}
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 384cb39f98d5ca74f832bd42e32b3613
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,5 +1,3 @@
namespace SimpleTools.ObjectPooler { public interface IPooledObject{
public interface IPooledObject {
void OnObjectSpawn(); void OnObjectSpawn();
}
} }

View file

@ -1,13 +1,12 @@
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine; using UnityEngine;
namespace SimpleTools.ObjectPooler { [CreateAssetMenu(fileName = "New Pool", menuName = "Tools/Pool", order = 0)]
[CreateAssetMenu(fileName = "New Pool", menuName = "Simple Tools/Pool", order = 11)] public class Pool : ScriptableObject{
public class Pool : ScriptableObject {
public List<PoolPrefab> pools; public List<PoolPrefab> pools;
[System.Serializable] [System.Serializable]
public class PoolPrefab { public class PoolPrefab{
public string tag; public string tag;
public GameObject prefab; public GameObject prefab;
public bool undetermined; public bool undetermined;
@ -16,5 +15,4 @@ namespace SimpleTools.ObjectPooler {
[HideInInspector] public Queue<GameObject> determinedPool; [HideInInspector] public Queue<GameObject> determinedPool;
[HideInInspector] public List<GameObject> undeterminedPool; [HideInInspector] public List<GameObject> undeterminedPool;
} }
}
} }

View file

@ -2,8 +2,7 @@
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
namespace SimpleTools.ObjectPooler { public static class Pooler{
public static class Pooler {
class PoolChecker : MonoBehaviour { class PoolChecker : MonoBehaviour {
public string poolTag; public string poolTag;
@ -15,33 +14,33 @@ namespace SimpleTools.ObjectPooler {
/// <summary>Generate a scene with the objects of the pools in it /// <summary>Generate a scene with the objects of the pools in it
/// <para>If this isn't called, the pooler won't work</para> /// <para>If this isn't called, the pooler won't work</para>
/// </summary> /// </summary>
public static void CreatePools(Pool pool) { public static void CreatePools(Pool pool){
if (pool == null) { if(pool == null){
Debug.LogWarning("You have to provide a pool."); Debug.LogWarning("You have to provide a pool.");
return; return;
} }
poolDictionary = new Dictionary<string, Pool.PoolPrefab>(); poolDictionary = new Dictionary<string, Pool.PoolPrefab>();
if (SceneManager.GetSceneByName("PoolScene").IsValid()) { if (SceneManager.GetSceneByName("PoolScene").IsValid()){
poolScene = SceneManager.GetSceneByName("PoolScene"); poolScene = SceneManager.GetSceneByName("PoolScene");
} else { }else{
poolScene = SceneManager.CreateScene("PoolScene"); poolScene = SceneManager.CreateScene("PoolScene");
} }
foreach (Pool.PoolPrefab p in pool.pools) { foreach (Pool.PoolPrefab p in pool.pools){
if (!p.undetermined) { if (!p.undetermined){
if (p.determinedPool == null) { if(p.determinedPool == null){
p.determinedPool = new Queue<GameObject>(); p.determinedPool = new Queue<GameObject>();
} }
for (int i = 0; i < p.size; i++) { for (int i = 0; i < p.size; i++){
GameObject obj = Object.Instantiate(p.prefab); GameObject obj = Object.Instantiate(p.prefab);
obj.SetActive(false); obj.SetActive(false);
obj.AddComponent<PoolChecker>().poolTag = p.tag; obj.AddComponent<PoolChecker>().poolTag = p.tag;
SceneManager.MoveGameObjectToScene(obj, poolScene); SceneManager.MoveGameObjectToScene(obj, poolScene);
p.determinedPool.Enqueue(obj); p.determinedPool.Enqueue(obj);
} }
} else { }else{
if (p.undeterminedPool == null) { if(p.undeterminedPool == null){
p.undeterminedPool = new List<GameObject>(); p.undeterminedPool = new List<GameObject>();
} }
} }
@ -51,34 +50,34 @@ namespace SimpleTools.ObjectPooler {
/// <summary>Generate a scene with the objects of the pools in it /// <summary>Generate a scene with the objects of the pools in it
/// <para>If this isn't called, the pooler won't work</para> /// <para>If this isn't called, the pooler won't work</para>
/// </summary> /// </summary>
public static void CreatePools(Pool[] pools) { public static void CreatePools(Pool[] pools){
if (pools == null) { if (pools == null){
Debug.LogWarning("You have to provide a pool."); Debug.LogWarning("You have to provide a pool.");
return; return;
} }
poolDictionary = new Dictionary<string, Pool.PoolPrefab>(); poolDictionary = new Dictionary<string, Pool.PoolPrefab>();
if (SceneManager.GetSceneByName("PoolScene").IsValid()) { if (SceneManager.GetSceneByName("PoolScene").IsValid()){
poolScene = SceneManager.GetSceneByName("PoolScene"); poolScene = SceneManager.GetSceneByName("PoolScene");
} else { }else{
poolScene = SceneManager.CreateScene("PoolScene"); poolScene = SceneManager.CreateScene("PoolScene");
} }
for (int i = 0; i < pools.Length; i++) { for (int i = 0; i < pools.Length; i++){
foreach (Pool.PoolPrefab p in pools[i].pools) { foreach (Pool.PoolPrefab p in pools[i].pools){
if (!p.undetermined) { if (!p.undetermined){
if (p.determinedPool == null) { if (p.determinedPool == null){
p.determinedPool = new Queue<GameObject>(); p.determinedPool = new Queue<GameObject>();
} }
for (int j = 0; j < p.size; j++) { for (int j = 0; j < p.size; j++){
GameObject obj = Object.Instantiate(p.prefab); GameObject obj = Object.Instantiate(p.prefab);
obj.SetActive(false); obj.SetActive(false);
obj.AddComponent<PoolChecker>().poolTag = p.tag; obj.AddComponent<PoolChecker>().poolTag = p.tag;
SceneManager.MoveGameObjectToScene(obj, poolScene); SceneManager.MoveGameObjectToScene(obj, poolScene);
p.determinedPool.Enqueue(obj); p.determinedPool.Enqueue(obj);
} }
} else { }else{
if (p.undeterminedPool == null) { if (p.undeterminedPool == null){
p.undeterminedPool = new List<GameObject>(); p.undeterminedPool = new List<GameObject>();
} }
} }
@ -88,9 +87,9 @@ namespace SimpleTools.ObjectPooler {
} }
/// <summary>Destroy an object and return it to the pool scene /// <summary>Destroy an object and return it to the pool scene
/// </summary> /// </summary>
public static void Destroy(GameObject gameObject) { public static void Destroy(GameObject gameObject){
PoolChecker poolChecker = gameObject.GetComponent<PoolChecker>(); PoolChecker poolChecker = gameObject.GetComponent<PoolChecker>();
if (poolChecker == null) { if (poolChecker == null){
Debug.LogWarning("GameObject: " + gameObject + " isn't from a pool", gameObject); Debug.LogWarning("GameObject: " + gameObject + " isn't from a pool", gameObject);
return; return;
} }
@ -98,12 +97,12 @@ namespace SimpleTools.ObjectPooler {
gameObject.transform.SetParent(null); gameObject.transform.SetParent(null);
SceneManager.MoveGameObjectToScene(gameObject, poolScene); SceneManager.MoveGameObjectToScene(gameObject, poolScene);
if (poolDictionary.ContainsKey(poolChecker.poolTag)) { if (poolDictionary.ContainsKey(poolChecker.poolTag)){
Pool.PoolPrefab pool = poolDictionary[poolChecker.poolTag]; Pool.PoolPrefab pool = poolDictionary[poolChecker.poolTag];
if (pool.undetermined) { if (pool.undetermined){
gameObject.SetActive(false); gameObject.SetActive(false);
pool.undeterminedPool.Remove(gameObject); pool.undeterminedPool.Remove(gameObject);
} else { }else{
gameObject.SetActive(false); gameObject.SetActive(false);
} }
} }
@ -112,15 +111,15 @@ namespace SimpleTools.ObjectPooler {
/// <summary>Spawn an object into a specific position /// <summary>Spawn an object into a specific position
/// <para>The CreatePools function must have been called before.</para> /// <para>The CreatePools function must have been called before.</para>
/// </summary> /// </summary>
public static GameObject SpawnFromPool(string tag, Vector3 position) { public static GameObject SpawnFromPool(string tag, Vector3 position){
if (!poolDictionary.ContainsKey(tag)) { if (!poolDictionary.ContainsKey(tag)){
Debug.Log("Pool with tag " + tag + " doesn't exist."); Debug.Log("Pool with tag " + tag + " doesn't exist.");
return null; return null;
} }
Pool.PoolPrefab pool = poolDictionary[tag]; Pool.PoolPrefab pool = poolDictionary[tag];
GameObject objectToSpawn; GameObject objectToSpawn;
if (!pool.undetermined) { if (!pool.undetermined){
objectToSpawn = pool.determinedPool.Dequeue(); objectToSpawn = pool.determinedPool.Dequeue();
objectToSpawn.transform.position = position; objectToSpawn.transform.position = position;
@ -128,15 +127,15 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
pool.determinedPool.Enqueue(objectToSpawn); pool.determinedPool.Enqueue(objectToSpawn);
} else { }else{
if (pool.undeterminedPool.Count != 0) { if(pool.undeterminedPool.Count != 0){
int lastIndex = pool.undeterminedPool.Count - 1; int lastIndex = pool.undeterminedPool.Count - 1;
objectToSpawn = pool.undeterminedPool[lastIndex]; objectToSpawn = pool.undeterminedPool[lastIndex];
objectToSpawn.transform.position = position; objectToSpawn.transform.position = position;
objectToSpawn.transform.rotation = Quaternion.identity; objectToSpawn.transform.rotation = Quaternion.identity;
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
} else { }else{
objectToSpawn = Object.Instantiate(pool.prefab, position, Quaternion.identity); objectToSpawn = Object.Instantiate(pool.prefab, position, Quaternion.identity);
SceneManager.MoveGameObjectToScene(objectToSpawn, poolScene); SceneManager.MoveGameObjectToScene(objectToSpawn, poolScene);
objectToSpawn.AddComponent<PoolChecker>().poolTag = tag; objectToSpawn.AddComponent<PoolChecker>().poolTag = tag;
@ -144,7 +143,7 @@ namespace SimpleTools.ObjectPooler {
} }
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>(); IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if (pooledObj != null) { if(pooledObj != null){
pooledObj.OnObjectSpawn(); pooledObj.OnObjectSpawn();
} }
return objectToSpawn; return objectToSpawn;
@ -152,15 +151,15 @@ namespace SimpleTools.ObjectPooler {
/// <summary>Spawn an object into a specific position and parent /// <summary>Spawn an object into a specific position and parent
/// <para>The CreatePools function must have been called before.</para> /// <para>The CreatePools function must have been called before.</para>
/// </summary> /// </summary>
public static GameObject SpawnFromPool(string tag, Vector3 position, Transform parent) { public static GameObject SpawnFromPool(string tag, Vector3 position, Transform parent){
if (!poolDictionary.ContainsKey(tag)) { if (!poolDictionary.ContainsKey(tag)){
Debug.Log("Pool with tag " + tag + " doesn't exist."); Debug.Log("Pool with tag " + tag + " doesn't exist.");
return null; return null;
} }
Pool.PoolPrefab pool = poolDictionary[tag]; Pool.PoolPrefab pool = poolDictionary[tag];
GameObject objectToSpawn; GameObject objectToSpawn;
if (!pool.undetermined) { if (!pool.undetermined){
objectToSpawn = pool.determinedPool.Dequeue(); objectToSpawn = pool.determinedPool.Dequeue();
objectToSpawn.transform.position = position; objectToSpawn.transform.position = position;
@ -169,8 +168,8 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
pool.determinedPool.Enqueue(objectToSpawn); pool.determinedPool.Enqueue(objectToSpawn);
} else { }else{
if (pool.undeterminedPool.Count != 0) { if (pool.undeterminedPool.Count != 0){
int lastIndex = pool.undeterminedPool.Count - 1; int lastIndex = pool.undeterminedPool.Count - 1;
objectToSpawn = pool.undeterminedPool[lastIndex]; objectToSpawn = pool.undeterminedPool[lastIndex];
@ -178,14 +177,14 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.transform.rotation = Quaternion.identity; objectToSpawn.transform.rotation = Quaternion.identity;
objectToSpawn.transform.SetParent(parent); objectToSpawn.transform.SetParent(parent);
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
} else { }else{
objectToSpawn = Object.Instantiate(pool.prefab, position, Quaternion.identity, parent); objectToSpawn = Object.Instantiate(pool.prefab, position, Quaternion.identity, parent);
objectToSpawn.AddComponent<PoolChecker>().poolTag = tag; objectToSpawn.AddComponent<PoolChecker>().poolTag = tag;
} }
} }
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>(); IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if (pooledObj != null) { if (pooledObj != null){
pooledObj.OnObjectSpawn(); pooledObj.OnObjectSpawn();
} }
return objectToSpawn; return objectToSpawn;
@ -193,19 +192,19 @@ namespace SimpleTools.ObjectPooler {
/// <summary>Spawn an object into a specific position, parent and set if it's in world space or not /// <summary>Spawn an object into a specific position, parent and set if it's in world space or not
/// <para>The CreatePools function must have been called before.</para> /// <para>The CreatePools function must have been called before.</para>
/// </summary> /// </summary>
public static GameObject SpawnFromPool(string tag, Vector3 position, Transform parent, bool instantiateInWorldSpace) { public static GameObject SpawnFromPool(string tag, Vector3 position, Transform parent, bool instantiateInWorldSpace){
if (!poolDictionary.ContainsKey(tag)) { if (!poolDictionary.ContainsKey(tag)){
Debug.Log("Pool with tag " + tag + " doesn't exist."); Debug.Log("Pool with tag " + tag + " doesn't exist.");
return null; return null;
} }
if (!instantiateInWorldSpace) { if (!instantiateInWorldSpace){
SpawnFromPool(tag, position, parent); SpawnFromPool(tag, position, parent);
} }
Pool.PoolPrefab pool = poolDictionary[tag]; Pool.PoolPrefab pool = poolDictionary[tag];
GameObject objectToSpawn; GameObject objectToSpawn;
if (!pool.undetermined) { if (!pool.undetermined){
objectToSpawn = pool.determinedPool.Dequeue(); objectToSpawn = pool.determinedPool.Dequeue();
objectToSpawn.transform.localPosition = position; objectToSpawn.transform.localPosition = position;
@ -214,8 +213,8 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
pool.determinedPool.Enqueue(objectToSpawn); pool.determinedPool.Enqueue(objectToSpawn);
} else { }else{
if (pool.undeterminedPool.Count != 0) { if (pool.undeterminedPool.Count != 0){
int lastIndex = pool.undeterminedPool.Count - 1; int lastIndex = pool.undeterminedPool.Count - 1;
objectToSpawn = pool.undeterminedPool[lastIndex]; objectToSpawn = pool.undeterminedPool[lastIndex];
@ -223,7 +222,7 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.transform.localRotation = Quaternion.identity; objectToSpawn.transform.localRotation = Quaternion.identity;
objectToSpawn.transform.SetParent(parent); objectToSpawn.transform.SetParent(parent);
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
} else { }else{
objectToSpawn = Object.Instantiate(pool.prefab); objectToSpawn = Object.Instantiate(pool.prefab);
objectToSpawn.transform.localPosition = position; objectToSpawn.transform.localPosition = position;
objectToSpawn.transform.localRotation = Quaternion.identity; objectToSpawn.transform.localRotation = Quaternion.identity;
@ -233,7 +232,7 @@ namespace SimpleTools.ObjectPooler {
} }
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>(); IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if (pooledObj != null) { if (pooledObj != null){
pooledObj.OnObjectSpawn(); pooledObj.OnObjectSpawn();
} }
return objectToSpawn; return objectToSpawn;
@ -241,15 +240,15 @@ namespace SimpleTools.ObjectPooler {
/// <summary>Spawn an object into a specific position and rotation /// <summary>Spawn an object into a specific position and rotation
/// <para>The CreatePools function must have been called before.</para> /// <para>The CreatePools function must have been called before.</para>
/// </summary> /// </summary>
public static GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation) { public static GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation){
if (!poolDictionary.ContainsKey(tag)) { if (!poolDictionary.ContainsKey(tag)){
Debug.Log("Pool with tag " + tag + " doesn't exist."); Debug.Log("Pool with tag " + tag + " doesn't exist.");
return null; return null;
} }
Pool.PoolPrefab pool = poolDictionary[tag]; Pool.PoolPrefab pool = poolDictionary[tag];
GameObject objectToSpawn; GameObject objectToSpawn;
if (!pool.undetermined) { if (!pool.undetermined){
objectToSpawn = pool.determinedPool.Dequeue(); objectToSpawn = pool.determinedPool.Dequeue();
objectToSpawn.transform.position = position; objectToSpawn.transform.position = position;
@ -257,15 +256,15 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
pool.determinedPool.Enqueue(objectToSpawn); pool.determinedPool.Enqueue(objectToSpawn);
} else { }else{
if (pool.undeterminedPool.Count != 0) { if (pool.undeterminedPool.Count != 0){
int lastIndex = pool.undeterminedPool.Count - 1; int lastIndex = pool.undeterminedPool.Count - 1;
objectToSpawn = pool.undeterminedPool[lastIndex]; objectToSpawn = pool.undeterminedPool[lastIndex];
objectToSpawn.transform.position = position; objectToSpawn.transform.position = position;
objectToSpawn.transform.rotation = rotation; objectToSpawn.transform.rotation = rotation;
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
} else { }else{
objectToSpawn = Object.Instantiate(pool.prefab, position, rotation); objectToSpawn = Object.Instantiate(pool.prefab, position, rotation);
SceneManager.MoveGameObjectToScene(objectToSpawn, poolScene); SceneManager.MoveGameObjectToScene(objectToSpawn, poolScene);
objectToSpawn.AddComponent<PoolChecker>().poolTag = tag; objectToSpawn.AddComponent<PoolChecker>().poolTag = tag;
@ -273,7 +272,7 @@ namespace SimpleTools.ObjectPooler {
} }
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>(); IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if (pooledObj != null) { if (pooledObj != null){
pooledObj.OnObjectSpawn(); pooledObj.OnObjectSpawn();
} }
return objectToSpawn; return objectToSpawn;
@ -281,15 +280,15 @@ namespace SimpleTools.ObjectPooler {
/// <summary>Spawn an object into a specific position, rotation and parent /// <summary>Spawn an object into a specific position, rotation and parent
/// <para>The CreatePools function must have been called before.</para> /// <para>The CreatePools function must have been called before.</para>
/// </summary> /// </summary>
public static GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation, Transform parent) { public static GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation, Transform parent){
if (!poolDictionary.ContainsKey(tag)) { if (!poolDictionary.ContainsKey(tag)){
Debug.Log("Pool with tag " + tag + " doesn't exist."); Debug.Log("Pool with tag " + tag + " doesn't exist.");
return null; return null;
} }
Pool.PoolPrefab pool = poolDictionary[tag]; Pool.PoolPrefab pool = poolDictionary[tag];
GameObject objectToSpawn; GameObject objectToSpawn;
if (!pool.undetermined) { if (!pool.undetermined){
objectToSpawn = pool.determinedPool.Dequeue(); objectToSpawn = pool.determinedPool.Dequeue();
objectToSpawn.transform.position = position; objectToSpawn.transform.position = position;
@ -298,8 +297,8 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
pool.determinedPool.Enqueue(objectToSpawn); pool.determinedPool.Enqueue(objectToSpawn);
} else { }else{
if (pool.undeterminedPool.Count != 0) { if (pool.undeterminedPool.Count != 0){
int lastIndex = pool.undeterminedPool.Count - 1; int lastIndex = pool.undeterminedPool.Count - 1;
objectToSpawn = pool.undeterminedPool[lastIndex]; objectToSpawn = pool.undeterminedPool[lastIndex];
@ -307,14 +306,14 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.transform.rotation = rotation; objectToSpawn.transform.rotation = rotation;
objectToSpawn.transform.SetParent(parent); objectToSpawn.transform.SetParent(parent);
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
} else { }else{
objectToSpawn = Object.Instantiate(pool.prefab, position, rotation, parent); objectToSpawn = Object.Instantiate(pool.prefab, position, rotation, parent);
objectToSpawn.AddComponent<PoolChecker>().poolTag = tag; objectToSpawn.AddComponent<PoolChecker>().poolTag = tag;
} }
} }
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>(); IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if (pooledObj != null) { if (pooledObj != null){
pooledObj.OnObjectSpawn(); pooledObj.OnObjectSpawn();
} }
return objectToSpawn; return objectToSpawn;
@ -322,19 +321,19 @@ namespace SimpleTools.ObjectPooler {
/// <summary>Spawn an object into a specific position, rotation, parent and set if it's in world space or not /// <summary>Spawn an object into a specific position, rotation, parent and set if it's in world space or not
/// <para>The CreatePools function must have been called before.</para> /// <para>The CreatePools function must have been called before.</para>
/// </summary> /// </summary>
public static GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation, Transform parent, bool instantiateInWorldSpace) { public static GameObject SpawnFromPool(string tag, Vector3 position, Quaternion rotation, Transform parent, bool instantiateInWorldSpace){
if (!poolDictionary.ContainsKey(tag)) { if (!poolDictionary.ContainsKey(tag)){
Debug.Log("Pool with tag " + tag + " doesn't exist."); Debug.Log("Pool with tag " + tag + " doesn't exist.");
return null; return null;
} }
if (!instantiateInWorldSpace) { if (!instantiateInWorldSpace){
SpawnFromPool(tag, position, rotation, parent); SpawnFromPool(tag, position, rotation, parent);
} }
Pool.PoolPrefab pool = poolDictionary[tag]; Pool.PoolPrefab pool = poolDictionary[tag];
GameObject objectToSpawn; GameObject objectToSpawn;
if (!pool.undetermined) { if (!pool.undetermined){
objectToSpawn = pool.determinedPool.Dequeue(); objectToSpawn = pool.determinedPool.Dequeue();
objectToSpawn.transform.localPosition = position; objectToSpawn.transform.localPosition = position;
@ -343,8 +342,8 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
pool.determinedPool.Enqueue(objectToSpawn); pool.determinedPool.Enqueue(objectToSpawn);
} else { }else{
if (pool.undeterminedPool.Count != 0) { if (pool.undeterminedPool.Count != 0){
int lastIndex = pool.undeterminedPool.Count - 1; int lastIndex = pool.undeterminedPool.Count - 1;
objectToSpawn = pool.undeterminedPool[lastIndex]; objectToSpawn = pool.undeterminedPool[lastIndex];
@ -352,7 +351,7 @@ namespace SimpleTools.ObjectPooler {
objectToSpawn.transform.localRotation = rotation; objectToSpawn.transform.localRotation = rotation;
objectToSpawn.transform.SetParent(parent); objectToSpawn.transform.SetParent(parent);
objectToSpawn.SetActive(true); objectToSpawn.SetActive(true);
} else { }else{
objectToSpawn = Object.Instantiate(pool.prefab); objectToSpawn = Object.Instantiate(pool.prefab);
objectToSpawn.transform.localPosition = position; objectToSpawn.transform.localPosition = position;
objectToSpawn.transform.localRotation = rotation; objectToSpawn.transform.localRotation = rotation;
@ -362,10 +361,9 @@ namespace SimpleTools.ObjectPooler {
} }
IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>(); IPooledObject pooledObj = objectToSpawn.GetComponent<IPooledObject>();
if (pooledObj != null) { if (pooledObj != null){
pooledObj.OnObjectSpawn(); pooledObj.OnObjectSpawn();
} }
return objectToSpawn; return objectToSpawn;
} }
}
} }

View file

@ -3,8 +3,7 @@ using System.Collections;
using UnityEngine; using UnityEngine;
using UnityEngine.SceneManagement; using UnityEngine.SceneManagement;
namespace SimpleTools.SceneManagement { public static class Loader{
public static class Loader {
class LoadingMonoBehaviour : MonoBehaviour { } class LoadingMonoBehaviour : MonoBehaviour { }
@ -14,7 +13,7 @@ namespace SimpleTools.SceneManagement {
/// <summary>Load a scene with a loading scene /// <summary>Load a scene with a loading scene
/// <para>It requires a scene called "Loading" where the loading screen is located.</para> /// <para>It requires a scene called "Loading" where the loading screen is located.</para>
/// </summary> /// </summary>
public static void Load(int scene) { public static void Load(int scene){
onLoaderCallback = () => { onLoaderCallback = () => {
GameObject loadingGameObject = new GameObject("LoadingGameObject"); GameObject loadingGameObject = new GameObject("LoadingGameObject");
loadingGameObject.AddComponent<LoadingMonoBehaviour>().StartCoroutine(LoadSceneAsync(scene)); loadingGameObject.AddComponent<LoadingMonoBehaviour>().StartCoroutine(LoadSceneAsync(scene));
@ -25,7 +24,7 @@ namespace SimpleTools.SceneManagement {
/// <summary>Load a scene with a loading scene /// <summary>Load a scene with a loading scene
/// <para>It requires a scene called "Loading" where the loading screen is located.</para> /// <para>It requires a scene called "Loading" where the loading screen is located.</para>
/// </summary> /// </summary>
public static void Load(string scene) { public static void Load(string scene){
onLoaderCallback = () => { onLoaderCallback = () => {
GameObject loadingGameObject = new GameObject("LoadingGameObject"); GameObject loadingGameObject = new GameObject("LoadingGameObject");
loadingGameObject.AddComponent<LoadingMonoBehaviour>().StartCoroutine(LoadSceneAsync(scene)); loadingGameObject.AddComponent<LoadingMonoBehaviour>().StartCoroutine(LoadSceneAsync(scene));
@ -34,38 +33,37 @@ namespace SimpleTools.SceneManagement {
SceneManager.LoadScene("Loading"); SceneManager.LoadScene("Loading");
} }
static IEnumerator LoadSceneAsync(int scene) { static IEnumerator LoadSceneAsync(int scene){
yield return null; yield return null;
loadingAsyncOperation = SceneManager.LoadSceneAsync(scene); loadingAsyncOperation = SceneManager.LoadSceneAsync(scene);
while (!loadingAsyncOperation.isDone) { while (!loadingAsyncOperation.isDone){
yield return null; yield return null;
} }
} }
static IEnumerator LoadSceneAsync(string scene) { static IEnumerator LoadSceneAsync(string scene){
yield return null; yield return null;
loadingAsyncOperation = SceneManager.LoadSceneAsync(scene); loadingAsyncOperation = SceneManager.LoadSceneAsync(scene);
while (!loadingAsyncOperation.isDone) { while (!loadingAsyncOperation.isDone){
yield return null; yield return null;
} }
} }
/// <summary>Returns the loading progress /// <summary>Returns the loading progress
/// </summary> /// </summary>
public static float GetLoadingProgress() { public static float GetLoadingProgress(){
if (loadingAsyncOperation != null) { if(loadingAsyncOperation != null){
return loadingAsyncOperation.progress; return loadingAsyncOperation.progress;
} else { }else{
return 0f; return 0f;
} }
} }
public static void LoaderCallback() { public static void LoaderCallback(){
if (onLoaderCallback != null) { if(onLoaderCallback != null){
onLoaderCallback(); onLoaderCallback();
onLoaderCallback = null; onLoaderCallback = null;
} }
} }
}
} }

View file

@ -1,16 +1,14 @@
using UnityEngine; using UnityEngine;
namespace SimpleTools.SceneManagement { public class LoaderCallback : MonoBehaviour{
public class LoaderCallback : MonoBehaviour {
bool isFirstUpdate = true; bool isFirstUpdate = true;
// Update is called once per frame // Update is called once per frame
void Update() { void Update(){
if (isFirstUpdate) { if (isFirstUpdate){
isFirstUpdate = false; isFirstUpdate = false;
Loader.LoaderCallback(); Loader.LoaderCallback();
} }
} }
}
} }

View file

@ -1,19 +1,17 @@
using UnityEngine; using UnityEngine;
using UnityEngine.UI; using UnityEngine.UI;
namespace SimpleTools.SceneManagement { public class LoadingProgressBar : MonoBehaviour{
public class LoadingProgressBar : MonoBehaviour {
Image image; Image image;
// Start is called before the first frame update // Start is called before the first frame update
void Awake() { void Awake(){
image = transform.GetComponent<Image>(); image = transform.GetComponent<Image>();
} }
// Update is called once per frame // Update is called once per frame
void Update() { void Update(){
image.fillAmount = Loader.GetLoadingProgress(); image.fillAmount = Loader.GetLoadingProgress();
} }
}
} }

View file

@ -1,8 +0,0 @@
fileFormatVersion: 2
guid: b904c9938b1a3df4e83b1103e3085400
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,99 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using TMPro;
namespace SimpleTools.Timer{
public class Timer : MonoBehaviour{
float elapsedTime;
public float ElapsedTime { get { return elapsedTime; } }
bool isPaused;
public bool IsPaused { get { return isPaused; } }
TimeSpan timePlaying;
public TimeSpan TimePlaying { get { return timePlaying; } }
TMP_Text timer;
public TMP_Text TimerText { get { return timer; } }
TimerType timerType;
public TimerType TimerType { get { return timerType; } }
TimerUpdate timerUpdate;
public TimerUpdate TimerUpdate { get { return timerUpdate; } }
float defaultTime;
/// <summary>
/// Setup the timer
/// </summary>
public void Setup(float elapsedTime, bool isPaused, TimeSpan timePlaying, TMP_Text timer, TimerType timerType, TimerUpdate timerUpdate, string text){
this.elapsedTime = defaultTime = elapsedTime;
this.isPaused = isPaused;
this.timePlaying = timePlaying;
this.timer = timer;
this.timerType = timerType;
this.timerUpdate = timerUpdate;
timer.text = text;
}
IEnumerator UpdateTimer(){
while (!isPaused){
if(timerType == TimerType.Clock){
timer.text = DateTime.Now.ToString("HH:mm:ss");
}else{
switch (timerType){
case TimerType.Countdown:
elapsedTime -= timerUpdate == TimerUpdate.UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
if(elapsedTime < 0f){
elapsedTime = 0f;
isPaused = true;
}
break;
case TimerType.Stopwatch:
elapsedTime += timerUpdate == TimerUpdate.UnscaledTime ? Time.unscaledDeltaTime : Time.deltaTime;
break;
}
timePlaying = TimeSpan.FromSeconds(elapsedTime);
timer.text = timePlaying.ToString("m':'ss'.'ff");
}
yield return null;
}
}
/// <summary>
/// Play or resume the timer
/// </summary>
public void Play(){
isPaused = false;
StartCoroutine(UpdateTimer());
}
/// <summary>
/// Pause the timer
/// </summary>
public void Stop(){
isPaused = true;
}
/// <summary>
/// Pause and sets the time to the defaultOne
/// </summary>
public void ResetTimer(){
isPaused = true;
elapsedTime = defaultTime;
timePlaying = TimeSpan.FromSeconds(elapsedTime);
timer.text = timePlaying.ToString("m':'ss'.'ff");
}
/// <summary>
/// Restarts the timer
/// </summary>
public void Restart(){
isPaused = false;
elapsedTime = defaultTime;
timePlaying = TimeSpan.FromSeconds(elapsedTime);
timer.text = timePlaying.ToString("m':'ss'.'ff");
StopAllCoroutines();
StartCoroutine(UpdateTimer());
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 6daeed0a6935f484f85fc0ec1871344f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,7 +0,0 @@
namespace SimpleTools.Timer{
public enum TimerType{
Countdown,
Stopwatch,
Clock
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: f285456223780f946b49c6131d493c01
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,6 +0,0 @@
namespace SimpleTools.Timer{
public enum TimerUpdate{
ScaledTime,
UnscaledTime,
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 977b7b3a05b17c04da63124856e9ff6f
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,36 +0,0 @@
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System;
using TMPro;
namespace SimpleTools.Timer{
public static class TimerUtility {
/// <summary>
/// Setup the timer
/// </summary>
/// <param name="container">TMPro object that will contain the timer</param>
/// <param name="timerType">What type of timer will it be (Countdown, Stopwatch, Clock)</param>
/// <param name="countdownTime">The time that will have in case it is a countdown timer</param>
/// <returns></returns>
public static Timer SetupTimer(this TMP_Text container, TimerType timerType, TimerUpdate timerUpdate, float countdownTime = 60f){
Timer t = container.gameObject.AddComponent<Timer>();
float elapsedTime = 0f;
string text = string.Empty;
TimeSpan timePlaying = TimeSpan.Zero;
switch (timerType){
case TimerType.Countdown:
elapsedTime = countdownTime;
timePlaying = TimeSpan.FromSeconds(elapsedTime);
text = timePlaying.ToString("m':'ss'.'ff");
break;
case TimerType.Clock:
text = DateTime.Now.ToString("HH:mm:ss");
break;
}
t.Setup(elapsedTime, true, timePlaying, container, timerType, timerUpdate, text);
return t;
}
}
}

View file

@ -1,11 +0,0 @@
fileFormatVersion: 2
guid: 38076483429281e438cee653b26bb03d
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,6 +1,6 @@
{ {
"name": "com.geri.simpletools", "name": "com.geri.simpletools",
"version": "1.3.0", "version": "1.0.1",
"displayName": "Simple Tools", "displayName": "Simple Tools",
"description": "This package contains simple tools to use in your project.", "description": "This package contains simple tools to use in your project.",
"unity": "2018.4", "unity": "2018.4",