Compare commits

...

18 commits
1.1.2 ... main

Author SHA1 Message Date
Gerard Gascón
672856770f
Updated version 2022-10-10 23:33:21 +02:00
Gerard Gascón
8857a11038
Added auto-save 2022-10-10 23:32:15 +02:00
Gerard Gascón
09973676e1
Update package.json 2022-09-25 12:07:36 +02:00
Gerard Gascón
629841b912
Update README.md 2022-09-25 12:06:48 +02:00
Gerard Gascón
c6fe332009
Add files via upload 2022-09-25 12:04:28 +02:00
Gerard Gascón
ff9831ed0b
Update README.md 2022-09-23 09:13:16 +02:00
Gerard Gascón
10cccc9b70
Added in-dialogue sounds 2022-09-22 13:52:08 +02:00
Gerard Gascón
1fde00e811 Revert "Add files via upload"
This reverts commit 1df7a33ab0.
2022-09-22 13:50:33 +02:00
Gerard Gascón
5dc6b69d49 Revert "Revert "Update README.md""
This reverts commit 0837786d01.
2022-09-22 13:50:23 +02:00
Gerard Gascón
0837786d01 Revert "Update README.md"
This reverts commit 4151df9226.
2022-09-22 13:49:54 +02:00
Gerard Gascón
5575d911c8
Update README.md 2022-09-22 13:44:49 +02:00
Gerard Gascón
1df7a33ab0
Add files via upload 2022-09-22 13:43:53 +02:00
Gerard Gascón
4151df9226
Update README.md 2022-09-15 17:59:54 +02:00
Gerard Gascón
99892e8b04
Add files via upload 2022-09-15 17:49:28 +02:00
Gerard Gascón
505584b91e
Bugfix
Small bug prevented text from showing without sound
2022-09-15 17:43:49 +02:00
Gerard Gascón
9f9dedba98
Removed old scripts 2022-09-15 17:32:04 +02:00
Gerard Gascón
0e8b8b1835
Reworked the dialogue system
Now the dialogue can use tags to add special effects
Reorganized project structure, updating may require adding some using statements
2022-09-15 17:27:28 +02:00
Gerard Gascón
95bad523b9
Update README.md 2022-03-13 22:23:46 +01:00
30 changed files with 2159 additions and 1430 deletions

View file

@ -2,8 +2,6 @@
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
- **AudioManager** with Play, Pause and most of the other basic things, as well as some effects like FadeIn or FadeOut.
@ -12,6 +10,8 @@ This package will be updated once I find another useful tool or someone suggest
- 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.
- 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.
@ -33,13 +33,16 @@ Download latest package from the Release section Import SimpleTools.unitypackage
## Usage
### AudioManager
### **AudioManager**
```csharp
using SimpleTools.AudioManager;
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.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.PlayRandomSound("Name1", "Name2", "Name3"); // Plays one shot of a random sound
AudioManager.instance.Pause("Name"); //Pauses the sound
AudioManager.instance.UnPause("Name"); //Unpauses the sound
@ -57,11 +60,13 @@ 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
```
### ObjectPooler
### **ObjectPooler**
The SpawnFromPool function always return a GameObject
```csharp
using SimpleTools.ObjectPooler;
Pool pool; //The pool scriptable object goes here
Pooler.CreatePools(pool); //Create the pool, without creating it you cannot spawn it
Pool[] pools;
@ -76,29 +81,50 @@ 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
```
### Dialogue System
### **Dialogue System**
The Dialogue function returns a bool (true if it's talking, false if it has ended)
```csharp
using SimpleTools.DialogueSystem;
Dialogue dialogue; //The dialogue scriptable object goes here
DialogueSystem.instance.Dialogue(dialogue); //Start/Continue the dialogue
DialogueManager.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
```
### SceneManager
Text commands:
```
<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
using SimpleTools.SceneManagement;
Loader.Load(0); //Loads a scene with a specific build index
Loader.Load("Scene"); //Loads a scene with a specific name
```
### ScreenShake
### **ScreenShake**
```csharp
using SimpleTools.Cinemachine;
ScreenShake.Shake(1f, .25f); //Shakes the camera with an intensity and duration
```
### Timer
### **Timer**
```csharp
using SimpleTools.Timer;
@ -116,7 +142,11 @@ timer.ResetTimer(); //Pause and sets the time to the default one
timer.Restart(); //Restarts the timer
```
### Editor
### **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.

View file

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

View file

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

8
Tools/AutoSave.meta Normal file
View file

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

View file

@ -0,0 +1,124 @@
#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,5 +1,5 @@
fileFormatVersion: 2
guid: caad12703fd5c3349acc637253734ac9
guid: e3f4095259fcc1f45991636604af9829
MonoImporter:
externalObjects: {}
serializedVersion: 2

View file

@ -1,38 +1,41 @@
using UnityEngine;
using Cinemachine;
public class CMCameraTrigger : MonoBehaviour{
namespace SimpleTools.Cinemachine {
public class CMCameraTrigger : MonoBehaviour {
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.gameObject.SetActive(false);
}
#region 3D
void OnTriggerEnter(Collider col){
if (col.CompareTag("Player")){
void OnTriggerEnter(Collider col) {
if (col.CompareTag(triggerTagName)) {
vcam.gameObject.SetActive(true);
}
}
void OnTriggerExit(Collider col){
if (col.CompareTag("Player")){
void OnTriggerExit(Collider col) {
if (col.CompareTag(triggerTagName)) {
vcam.gameObject.SetActive(true);
}
}
#endregion
#region 2D
void OnTriggerEnter2D(Collider2D col){
if (col.CompareTag("Player")){
void OnTriggerEnter2D(Collider2D col) {
if (col.CompareTag(triggerTagName)) {
vcam.gameObject.SetActive(true);
}
}
void OnTriggerExit2D(Collider2D col){
if (col.CompareTag("Player")){
void OnTriggerExit2D(Collider2D col) {
if (col.CompareTag(triggerTagName)) {
vcam.gameObject.SetActive(false);
}
}
#endregion
}
}

View file

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

View file

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

View file

@ -0,0 +1,126 @@
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

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

View file

@ -1,75 +0,0 @@
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

@ -0,0 +1,206 @@
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

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

View file

@ -0,0 +1,277 @@
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,11 @@
fileFormatVersion: 2
guid: dcef7fafd8716284392e9621424bfa6a
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View file

@ -1,78 +0,0 @@
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 = 20;
public TextRevealEvent onTextReveal;
public DialogueEvent onDialogueFinish;
void Update(){
/*if(Application.isPlaying)
this.Animate();*/
}
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=") || tag.StartsWith("wave") || tag.StartsWith("rainbow") || tag.StartsWith("shake");
}
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++;
//this.Animate();
yield return new WaitForSeconds(text[maxVisibleCharacters - 1] == ' ' ? 0 : (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

@ -11,6 +11,11 @@ using UnityEditor.SceneManagement;
using UnityEngine.EventSystems;
using UnityEditor.Experimental.SceneManagement;
using System;
using SimpleTools.AudioManager;
using SimpleTools.DialogueSystem;
using SimpleTools.Cinemachine;
using SimpleTools.SceneManagement;
using SimpleTools.Menu;
public class ToolsEditor{
@ -29,9 +34,9 @@ public class ToolsEditor{
dialogueCanvas.AddComponent<CanvasScaler>();
dialogueCanvas.AddComponent<GraphicRaycaster>();
GameObject text = new GameObject("TMP_Animated");
GameObject text = new GameObject("DialogueText");
text.transform.SetParent(dialogueCanvas.transform);
text.AddComponent<TMP_Animated>().text = "New Text";
text.AddComponent<TextMeshProUGUI>().text = "Dialogue";
text.GetComponent<RectTransform>().anchoredPosition = Vector2.zero;
GameObject name = new GameObject("NameText");
@ -44,11 +49,17 @@ public class ToolsEditor{
image.AddComponent<Image>();
image.GetComponent<RectTransform>().anchoredPosition = new Vector2(-150f, 25f);
DialogueSystem dialogueSystem = dialogueCanvas.AddComponent<DialogueSystem>();
dialogueSystem.nameText = name.GetComponent<TextMeshProUGUI>();
dialogueSystem.dialogue = text.GetComponent<TMP_Animated>();
dialogueSystem.faceImage = image.GetComponent<Image>();
dialogueSystem.nameField = name;
DialogueManager dialogueManager = dialogueCanvas.AddComponent<DialogueManager>();
Debug.Log(dialogueManager.dialogueItems);
dialogueManager.dialogueItems.textBox = text.GetComponent<TextMeshProUGUI>();
dialogueManager.dialogueItems.characterName = name.GetComponent<TextMeshProUGUI>();
dialogueManager.dialogueItems.characterImage = image.GetComponent<Image>();
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)]

View file

@ -5,13 +5,14 @@ using UnityEngine.UI;
using TMPro;
using UnityEngine.Audio;
[System.Serializable] public class OnPlay : UnityEngine.Events.UnityEvent { }
public class MenuController : MonoBehaviour{
namespace SimpleTools.Menu {
[System.Serializable] public class OnPlay : UnityEngine.Events.UnityEvent { }
public class MenuController : MonoBehaviour {
[Header("Audio")]
[SerializeField] AudioMixer mainMixer = default;
[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 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;
public Slider musicSlider = default;
public Slider sfxSlider = default;
@ -26,8 +27,8 @@ public class MenuController : MonoBehaviour{
[Space]
[SerializeField] OnPlay onPlay = default;
void Awake(){
if (mainMixer){
void Awake() {
if (mainMixer) {
float musicVolume = PlayerPrefs.GetFloat("MusicVolume", defaultMusicValue);
float sfxVolume = PlayerPrefs.GetFloat("SFXVolume", defaultSfxValue);
mainMixer.SetFloat("Master", Mathf.Log10(musicVolume <= .0001f ? .0001f : musicVolume) * 20);
@ -38,12 +39,11 @@ public class MenuController : MonoBehaviour{
resolutionDropdown.ClearOptions();
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;
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;
}
}
@ -56,7 +56,7 @@ public class MenuController : MonoBehaviour{
qualityDropdown.ClearOptions();
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]);
}
qualityDropdown.AddOptions(qualityNames);
@ -67,43 +67,44 @@ public class MenuController : MonoBehaviour{
qualityDropdown.RefreshShownValue();
}
void OnValidate(){
void OnValidate() {
if (musicSlider) musicSlider.minValue = musicSlider.minValue < .0001f ? .0001f : musicSlider.minValue;
if (sfxSlider) sfxSlider.minValue = sfxSlider.minValue < .0001f ? .0001f : sfxSlider.minValue;
}
void Start(){
void Start() {
musicSlider.value = PlayerPrefs.GetFloat("MusicVolume", defaultMusicValue);
sfxSlider.value = PlayerPrefs.GetFloat("SFXVolume", defaultSfxValue);
}
//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);
PlayerPrefs.SetFloat("MusicVolume", sliderValue);
}
//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);
PlayerPrefs.SetFloat("SFXVolume", sliderValue);
}
public void SetQuality(int qualityIndex){
public void SetQuality(int qualityIndex) {
QualitySettings.SetQualityLevel(qualityIndex);
PlayerPrefs.SetInt("QualitySelected", qualityIndex);
}
public void SetResolution(int resolutionIndex){
public void SetResolution(int resolutionIndex) {
Resolution resolution = resolutions[resolutionIndex];
Screen.SetResolution(resolution.width, resolution.height, Screen.fullScreen);
}
public void Play(){
public void Play() {
onPlay.Invoke();
}
public void Quit(){
public void Quit() {
Application.Quit();
}
}
}

View file

@ -0,0 +1,12 @@
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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -75,7 +75,7 @@ namespace SimpleTools.Timer{
}
/// <summary>
/// Pause and sets the time to the default one
/// Pause and sets the time to the defaultOne
/// </summary>
public void ResetTimer(){
isPaused = true;

View file

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