├── README.md.meta
├── Scripts
├── Audio
│ ├── MusicStack.meta
│ ├── MusicStack
│ │ ├── MusicStack.cs.meta
│ │ ├── AudioClipMusicAsset.cs.meta
│ │ ├── SceneBackgroundMusic.cs.meta
│ │ ├── SmoothLoopMusicAsset.cs.meta
│ │ ├── BasicMusicStackElement.cs.meta
│ │ ├── SceneBackgroundMusic.cs
│ │ ├── BasicMusicStackElement.cs
│ │ ├── SmoothLoopMusicAsset.cs
│ │ ├── AudioClipMusicAsset.cs
│ │ └── MusicStack.cs
│ ├── MusicPlayer.cs.meta
│ ├── SoundPlayer.cs.meta
│ ├── AmbientSounds.cs.meta
│ ├── FadeOutAudioSource.cs.meta
│ ├── SmoothLoopAudioClip.cs.meta
│ ├── SmoothLoopAudioSource.cs.meta
│ ├── SmoothLoopAudioClip.cs
│ ├── FadeOutAudioSource.cs
│ ├── SmoothLoopAudioSource.cs
│ ├── MusicPlayer.cs
│ ├── AmbientSounds.cs
│ └── SoundPlayer.cs
├── Audio.meta
├── Editor.meta
├── Physics.meta
├── Timer.meta
├── Extensions.meta
├── Services.meta
├── Singleton.meta
├── ExportableScene.meta
├── ExportableScene
│ ├── Editor.meta
│ ├── ExportableScene.cs.meta
│ ├── Editor
│ │ ├── ExportableScenePropertyDrawer.cs.meta
│ │ └── ExportableScenePropertyDrawer.cs
│ └── ExportableScene.cs
├── Asserts.cs.meta
├── CameraShake.cs.meta
├── RandomRange.cs.meta
├── Timer
│ ├── Timer.cs.meta
│ ├── TimerManager.cs.meta
│ ├── TimerExtensions.cs.meta
│ ├── TimerExtensions.cs
│ ├── TimerManager.cs
│ └── Timer.cs
├── Vector2Int.cs.meta
├── CheatCodeDetector.cs.meta
├── CleanUpParticles.cs.meta
├── EnumFlagAttribute.cs.meta
├── PrioritySortingKey.cs.meta
├── WireSphereGizmo.cs.meta
├── Editor
│ ├── CustomMenuItems.cs.meta
│ ├── KeywordReplacer.cs.meta
│ ├── RandomRangeDrawer.cs.meta
│ ├── EnumFlagPropertyDrawer.cs.meta
│ ├── InspectorNavigator.cs.meta
│ ├── KeywordReplacer.cs
│ ├── RandomRangeDrawer.cs
│ ├── EnumFlagPropertyDrawer.cs
│ ├── InspectorNavigator.cs
│ └── CustomMenuItems.cs
├── EnumFlagAttribute.cs
├── Physics
│ ├── PhysicsMovement.cs.meta
│ ├── StabilizeTorque.cs.meta
│ ├── StandUpStraight.cs.meta
│ ├── NavigatorMovement.cs.meta
│ ├── StabilizeTorque.cs
│ ├── StandUpStraight.cs
│ ├── NavigatorMovement.cs
│ └── PhysicsMovement.cs
├── Services
│ ├── ServiceLocator.cs.meta
│ ├── ServiceMonoBehaviour.cs.meta
│ ├── ServiceMonoBehaviour.cs
│ └── ServiceLocator.cs
├── Singleton
│ ├── Singleton.cs.meta
│ ├── SceneSingleton.cs.meta
│ ├── ResourceSingletonAttribute.cs.meta
│ ├── ResourceSingletonAttribute.cs
│ ├── SceneSingleton.cs
│ └── Singleton.cs
├── TimeScaleController.cs.meta
├── TrackerCameraMovement.cs.meta
├── TriggerCollidersTracker.cs.meta
├── Extensions
│ ├── QuickUnityExtensions.cs.meta
│ ├── QuickUnityMathExtensions.cs.meta
│ ├── QuickUnityMathExtensions.cs
│ └── QuickUnityExtensions.cs
├── EventList.cs.meta
├── WireSphereGizmo.cs
├── RandomRange.cs
├── CleanUpParticles.cs
├── EventList.cs
├── Asserts.cs
├── TriggerCollidersTracker.cs
├── CheatCodeDetector.cs
├── PrioritySortingKey.cs
├── TimeScaleController.cs
├── Vector2Int.cs
├── CameraShake.cs
└── TrackerCameraMovement.cs
├── Resources
├── MusicPlayer.prefab.meta
├── MusicStack.prefab.meta
├── SoundPlayer.prefab.meta
├── InControlManager.prefab.meta
├── MusicStack.prefab
├── MusicPlayer.prefab
├── InControlManager.prefab
└── SoundPlayer.prefab
├── Resources.meta
├── Scripts.meta
├── .gitignore
└── README.md
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e8bb8c5e06c93fe4284afa2d323eaee7
3 | timeCreated: 1450127766
4 | licenseType: Free
5 | DefaultImporter:
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8584a91d0342a0a44b285f16c4359406
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Resources/MusicPlayer.prefab.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b053506bd7975f74b8fe2281d9bdad1a
3 | timeCreated: 1450215009
4 | licenseType: Free
5 | NativeFormatImporter:
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Resources/MusicStack.prefab.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 41308c390179b6e469618a8b3be2e238
3 | timeCreated: 1450215009
4 | licenseType: Free
5 | NativeFormatImporter:
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Resources/SoundPlayer.prefab.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0c372e0fd7fb3b8489342af6a50a2327
3 | timeCreated: 1450133544
4 | licenseType: Free
5 | NativeFormatImporter:
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Resources.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bee93a86a9ab83f4ca3e28ec4e5002c3
3 | folderAsset: yes
4 | timeCreated: 1454097959
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Resources/InControlManager.prefab.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bbe22400a0ad2fc4e9d46726507a1acc
3 | timeCreated: 1454125742
4 | licenseType: Free
5 | NativeFormatImporter:
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Scripts.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a62a20f8847b03f469aebfe151e5fbf7
3 | folderAsset: yes
4 | timeCreated: 1450128518
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/Audio.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 858abbca84eee314c9b2a25e7c49a567
3 | folderAsset: yes
4 | timeCreated: 1450140351
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 772a169d2b4d6b3438521ea7435d1fa7
3 | folderAsset: yes
4 | timeCreated: 1458948878
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/Physics.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 823af75b9840da040b61d5055b2c3020
3 | folderAsset: yes
4 | timeCreated: 1454122070
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/Timer.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 04bbc6a22624ad043bccfa8d1454e95a
3 | folderAsset: yes
4 | timeCreated: 1450128529
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/Extensions.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 615bb0f82c1a87a488cd387629f924dd
3 | folderAsset: yes
4 | timeCreated: 1450130937
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/Services.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 11e463743ec1df64fbe6b5537959d5c5
3 | folderAsset: yes
4 | timeCreated: 1511283283
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/Singleton.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a20c0020464447d47beb82947a4a3ec0
3 | folderAsset: yes
4 | timeCreated: 1450129737
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/ExportableScene.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 427a34ad507b04a46aeeb82ac22ce793
3 | folderAsset: yes
4 | timeCreated: 1454094860
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/ExportableScene/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0f44ad36eb1c10d40ad71ca834f39ee7
3 | folderAsset: yes
4 | timeCreated: 1454094852
5 | licenseType: Free
6 | DefaultImporter:
7 | userData:
8 | assetBundleName:
9 | assetBundleVariant:
10 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/MusicStack.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 92ec81ff692086c458fc2e96242b11ea
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Scripts/Asserts.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 79e3444fe5bfd654998bb1e40e188585
3 | timeCreated: 1507766112
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/AudioClipMusicAsset.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 63eb07f36aef94b4bbbabf68ff582e01
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/SceneBackgroundMusic.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f13443b5f8d41a749b492814a3cf8e54
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/SmoothLoopMusicAsset.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8db6f165c62b77942bf7e1f394dacb21
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Scripts/CameraShake.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 23690bdcbcda53c4fab48258975110e7
3 | timeCreated: 1449944241
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/RandomRange.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a88c7c2725974e44fabdf1da1196dde2
3 | timeCreated: 1459027254
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Timer/Timer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b6dcdabb99651a14391958bcead3d55d
3 | timeCreated: 1449941199
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Vector2Int.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f8a91afe2295fec4cad0369475ae0c2f
3 | timeCreated: 1454094884
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicPlayer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 10da20cb8d3d60a4eb7500cbe9b7bf05
3 | timeCreated: 1450140186
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/BasicMusicStackElement.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 62e4a2834bd078446b000b16f4d9d4ff
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Scripts/Audio/SoundPlayer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0ac27dde6773e2048a3af87551f31828
3 | timeCreated: 1450126781
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/CheatCodeDetector.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2be00708972437842b247e59ae179ff8
3 | timeCreated: 1459904989
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/CleanUpParticles.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 751b0a58eaa9f2346aedd36bac2a8e46
3 | timeCreated: 1449951287
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/EnumFlagAttribute.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 74ee393729f60ba4f99f8482891a7cfb
3 | timeCreated: 1513997800
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/PrioritySortingKey.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 66b13f1b112399c44b77a5b716d6f615
3 | timeCreated: 1513021834
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Timer/TimerManager.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: aed8fc0eb4ac22847b0c4cee99254275
3 | timeCreated: 1449941199
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/WireSphereGizmo.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 554b83a4b61965e498cdbf9c69496db4
3 | timeCreated: 1454175674
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Audio/AmbientSounds.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: adab7e3f85f17c045949a02f087ab71b
3 | timeCreated: 1515447441
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Editor/CustomMenuItems.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f6107f6848a4e6b489afb3a75a509604
3 | timeCreated: 1458948869
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Editor/KeywordReplacer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4b0640a141e28cf4c8674885c77a19ce
3 | timeCreated: 1503510259
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/EnumFlagAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | public class EnumFlagAttribute : PropertyAttribute {
6 | public string enumName;
7 |
8 | public EnumFlagAttribute() { }
9 |
10 | public EnumFlagAttribute(string name) {
11 | enumName = name;
12 | }
13 | }
--------------------------------------------------------------------------------
/Scripts/Physics/PhysicsMovement.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: fe28afd5924ee694b9ddaa4cf6580263
3 | timeCreated: 1454124656
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Physics/StabilizeTorque.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 01ca4bc8524b8ef4abe45a4119fdce04
3 | timeCreated: 1454167722
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Physics/StandUpStraight.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bfb5008ee5be3d14c99b8036006182f8
3 | timeCreated: 1454167722
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Services/ServiceLocator.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 30a640e26ef926540b7ac3d50ea7a280
3 | timeCreated: 1511209578
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Singleton/Singleton.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 335cc2883a276244da368f7d3fbac766
3 | timeCreated: 1449956159
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/TimeScaleController.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c594e214e99e17e45bd975f92f875e49
3 | timeCreated: 1449956137
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Timer/TimerExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c6076695697fa5d4da6f6a6bd7c97393
3 | timeCreated: 1449941199
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/TrackerCameraMovement.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dec6a06b7981c4d4eb332a8cdc76c459
3 | timeCreated: 1454168073
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/TriggerCollidersTracker.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 38cf00cafcec11b4781abac75c60f93e
3 | timeCreated: 1460305845
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Audio/FadeOutAudioSource.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bd8d4212d60602e4e818efaaaee64605
3 | timeCreated: 1450140475
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Audio/SmoothLoopAudioClip.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0916717ac71643b4dac82db1c88a7860
3 | timeCreated: 1502924398
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Audio/SmoothLoopAudioSource.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0a8731744aa8dc947997ef5e310ba3f0
3 | timeCreated: 1502918664
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Editor/RandomRangeDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 23ec05976adfc4942bb5a944462dca0b
3 | timeCreated: 1459026938
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Physics/NavigatorMovement.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b3fb46f18f2807f47972d07869286721
3 | timeCreated: 1459024086
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Singleton/SceneSingleton.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 4026e5559279e3b448c8a2db1d0a1b18
3 | timeCreated: 1449948596
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Editor/EnumFlagPropertyDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ef7ca956c9187224cb4ab34993dfe221
3 | timeCreated: 1513997544
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/ExportableScene/ExportableScene.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 47df75b20ca59e441ba4e06c79dde6f7
3 | timeCreated: 1454094872
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Extensions/QuickUnityExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 20b4a83efeb977c41ab11ab8937633d2
3 | timeCreated: 1449937700
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Services/ServiceMonoBehaviour.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1c928a493f60aad4f99f2918d51a1c0f
3 | timeCreated: 1511215392
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/EventList.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d8af5c388f5dcd84aaece79caad251ff
3 | timeCreated: 1522269848
4 | licenseType: Free
5 | MonoImporter:
6 | externalObjects: {}
7 | serializedVersion: 2
8 | defaultReferences: []
9 | executionOrder: 0
10 | icon: {instanceID: 0}
11 | userData:
12 | assetBundleName:
13 | assetBundleVariant:
14 |
--------------------------------------------------------------------------------
/Scripts/Extensions/QuickUnityMathExtensions.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 981faf9218be6004fad37c404a75b25f
3 | timeCreated: 1454094251
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/Singleton/ResourceSingletonAttribute.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 0a845c01d07e6b64f85246708f22e146
3 | timeCreated: 1449956169
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | [Ll]ibrary/
2 | [Tt]emp/
3 | [Oo]bj/
4 | [Bb]uild/
5 |
6 | # Autogenerated VS/MD solution and project files
7 | *.csproj
8 | *.unityproj
9 | *.sln
10 | *.suo
11 | *.tmp
12 | *.user
13 | *.userprefs
14 | *.pidb
15 | *.booproj
16 |
17 | # Unity3D generated meta files
18 | *.pidb.meta
19 |
20 | # Unity3D Generated File On Crash Reports
21 | sysinfo.txt
22 |
--------------------------------------------------------------------------------
/Scripts/Timer/TimerExtensions.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | public static class TimerExtensions {
5 | public static Timer RegisterTimer(this MonoBehaviour owner, float duration, Action onComplete, bool isLooped = false, bool useUnscaledTime = false) {
6 | return Timer.Register(duration, onComplete, isLooped, useUnscaledTime, owner);
7 | }
8 | }
--------------------------------------------------------------------------------
/Scripts/Editor/InspectorNavigator.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 1aad66bd125102b49bd5a6383102a3f9
3 | timeCreated: 1523309883
4 | licenseType: Free
5 | MonoImporter:
6 | externalObjects: {}
7 | serializedVersion: 2
8 | defaultReferences: []
9 | executionOrder: 0
10 | icon: {instanceID: 0}
11 | userData:
12 | assetBundleName:
13 | assetBundleVariant:
14 |
--------------------------------------------------------------------------------
/Scripts/ExportableScene/Editor/ExportableScenePropertyDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9d235b5f5020ce94e8d00b1ef7ce1a43
3 | timeCreated: 1454094869
4 | licenseType: Free
5 | MonoImporter:
6 | serializedVersion: 2
7 | defaultReferences: []
8 | executionOrder: 0
9 | icon: {instanceID: 0}
10 | userData:
11 | assetBundleName:
12 | assetBundleVariant:
13 |
--------------------------------------------------------------------------------
/Scripts/WireSphereGizmo.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | public class WireSphereGizmo : MonoBehaviour {
5 |
6 | public Color color = Color.red;
7 | public float radius = 1f;
8 |
9 | private void OnDrawGizmos() {
10 | Gizmos.color = this.color;
11 | Gizmos.DrawWireSphere(this.transform.position, this.radius);
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/Scripts/RandomRange.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 |
5 | [Serializable]
6 | public struct RandomRange {
7 | public float min;
8 | public float max;
9 |
10 | public RandomRange(float min, float max) {
11 | this.max = max;
12 | this.min = min;
13 | }
14 |
15 | public float Random() {
16 | return UnityEngine.Random.Range(this.min, this.max);
17 | }
18 | }
--------------------------------------------------------------------------------
/Scripts/Singleton/ResourceSingletonAttribute.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 |
5 | ///
6 | /// Add this attribute to a Singleton class and it will load the Singleton from the Resources folder.
7 | ///
8 | [AttributeUsage(AttributeTargets.Class)]
9 | public class ResourceSingletonAttribute : Attribute {
10 | public readonly string resourceFilePath;
11 |
12 | public ResourceSingletonAttribute(string path) {
13 | this.resourceFilePath = path;
14 | }
15 | }
--------------------------------------------------------------------------------
/Scripts/Audio/SmoothLoopAudioClip.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | namespace QuickUnityTools.Audio {
6 | ///
7 | /// An audio clip and metadata required for smooth looping.
8 | ///
9 | [CreateAssetMenu]
10 | public class SmoothLoopAudioClip : ScriptableObject {
11 | public AudioClip clip;
12 | public float introMeasures = 1;
13 | public float beatsPerMeasure = 4;
14 | public float beatsPerMinute = 130;
15 | public float length { get { return clip.length; } }
16 | }
17 | }
--------------------------------------------------------------------------------
/Scripts/CleanUpParticles.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | ///
5 | /// Creates a specified number of particles and cleans up the object after.
6 | ///
7 | /// NOTE: This will override Emission settings on the system.
8 | ///
9 | [RequireComponent(typeof(ParticleSystem))]
10 | public class CleanUpParticles : MonoBehaviour {
11 |
12 | private ParticleSystem system;
13 |
14 | void Start () {
15 | this.system = this.GetComponent();
16 | }
17 |
18 | void Update () {
19 | if (!this.system.IsAlive()) {
20 | GameObject.Destroy(this.gameObject);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | I'm retiring this repo after making so many different branches of this locally.
2 | I might create a new version of this at some point.
3 |
4 | # QuickUnityTools
5 |
6 | A bunch of scripts I use when working with Unity to do things faster! (Handy for game jams!)
7 |
8 | It's about time I finally made a submodule out of all the scripts I have lying around...
9 | Feel free to use any of these scripts in your games. A reference would be appreciated but it's not necessary.
10 |
11 | This stuff might change without notice as I add new tools and improve any APIs...
12 | I'll be creating documention whenever it's convenient, but feel free to ask me about these scripts on Twitter: @adamgryu
13 |
14 | Happy Game Development :)
15 |
--------------------------------------------------------------------------------
/Scripts/Services/ServiceMonoBehaviour.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEngine;
5 |
6 | ///
7 | /// Classes that inherit from this can be found globally using the ServiceLocator class.
8 | /// This behaviour also ensures that there is only one service per scene.
9 | ///
10 | public abstract class ServiceMonoBehaviour : MonoBehaviour {
11 |
12 | protected virtual void OnEnable() {
13 | var sceneObjects = gameObject.scene.FindComponentsOfTypeInScene(GetType());
14 |
15 | if (sceneObjects.AtLeast(2)) {
16 | Debug.LogError("[ServiceMonoBehaviour] " + GetType().Name + ": Multiple instances of this service in this scene.");
17 | }
18 | }
19 | }
--------------------------------------------------------------------------------
/Scripts/Physics/StabilizeTorque.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | [RequireComponent(typeof(Rigidbody))]
5 | public class StabilizeTorque : MonoBehaviour {
6 |
7 | public Vector3 upDirection;
8 | public float upTorque;
9 |
10 | public Vector3 forwardDirection;
11 | public float forwardTorque;
12 |
13 | private Rigidbody body;
14 |
15 | void Start() {
16 | this.body = this.GetComponent();
17 | }
18 |
19 | void FixedUpdate() {
20 | Vector3 torque = Vector3.Cross(this.transform.up, upDirection) * this.upTorque;
21 | this.body.AddTorque(torque);
22 | torque = Vector3.Cross(this.transform.forward, forwardDirection) * this.forwardTorque;
23 | this.body.AddTorque(torque);
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/Scripts/EventList.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using System;
4 |
5 | public class EventList : IEnumerable {
6 |
7 | public event Action onModified;
8 |
9 | private List list;
10 |
11 | public EventList() {
12 | this.list = new List();
13 | }
14 |
15 | public void Add(T item) {
16 | list.Add(item);
17 | if (onModified != null) {
18 | onModified();
19 | }
20 | }
21 |
22 | public void Remove(T item) {
23 | list.Remove(item);
24 | if (onModified != null) {
25 | onModified();
26 | }
27 | }
28 |
29 | public IEnumerator GetEnumerator() {
30 | return list.GetEnumerator();
31 | }
32 |
33 | IEnumerator IEnumerable.GetEnumerator() {
34 | return list.GetEnumerator();
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/SceneBackgroundMusic.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using UnityEngine.SceneManagement;
4 | using System;
5 |
6 | namespace QuickUnityTools.Audio {
7 |
8 | ///
9 | /// Music that plays in the background of the scene. It is added to the MusicStack for the
10 | /// scene's lifetime.
11 | ///
12 | public class SceneBackgroundMusic : MonoBehaviour {
13 |
14 | public BasicMusicStackElement musicConfig;
15 |
16 | private PrioritySortingKey musicStackKey;
17 |
18 | private void Start() {
19 | musicStackKey = MusicStack.instance.AddToMusicStack(musicConfig);
20 | }
21 |
22 | private void OnDestroy() {
23 | if (MusicStack.instance != null) {
24 | MusicStack.instance.RemoveFromMusicStack(musicStackKey);
25 | }
26 | }
27 | }
28 | }
--------------------------------------------------------------------------------
/Scripts/Physics/StandUpStraight.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | [RequireComponent(typeof(Rigidbody))]
5 | public class StandUpStraight : MonoBehaviour {
6 |
7 | public enum UpVector {
8 | Up,
9 | Forward,
10 | Right,
11 | }
12 |
13 | public float standUpTorue = 10f;
14 | public UpVector upVector = UpVector.Up;
15 | private Rigidbody body;
16 |
17 | void Start() {
18 | this.body = this.GetComponent();
19 | }
20 |
21 | void FixedUpdate() {
22 | Vector3 myUp = Vector3.up;
23 | switch (upVector) {
24 | case UpVector.Up: myUp = transform.up; break;
25 | case UpVector.Right: myUp = transform.right; break;
26 | case UpVector.Forward: myUp = transform.forward; break;
27 | }
28 | Vector3 torque = Vector3.Cross(myUp, Vector3.up) * this.standUpTorue;
29 | this.body.AddTorque(torque);
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Scripts/Audio/FadeOutAudioSource.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | namespace QuickUnityTools.Audio {
5 |
6 | public class FadeOutAudioSource : MonoBehaviour {
7 |
8 | public float fadeOutTime = 1f;
9 | public bool destroyGameObjectOnFinish = true;
10 |
11 | private Timer fadeOutTimer;
12 | private AudioSource audioSource;
13 | private float startVolume;
14 |
15 | private void Start() {
16 | audioSource = GetComponent();
17 | startVolume = audioSource.volume;
18 | fadeOutTimer = this.RegisterTimer(fadeOutTime, () => {
19 | if (destroyGameObjectOnFinish) {
20 | GameObject.Destroy(gameObject);
21 | }
22 | });
23 | }
24 |
25 | private void Update() {
26 | audioSource.volume = Mathf.Lerp(startVolume, 0, fadeOutTimer.GetPercentageComplete());
27 | }
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Scripts/Asserts.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using UnityEngine;
6 |
7 | public static class Asserts {
8 | public static void NotNull(object obj, string failureMessage = "") {
9 | if (obj == null) {
10 | throw new NullReferenceException("Not Null Assertion failed: " + failureMessage);
11 | }
12 | }
13 |
14 | public static void Null(object obj, string failureMessage = "") {
15 | if (obj != null) {
16 | throw new Exception("Null Assertion failed: " + failureMessage);
17 | }
18 | }
19 |
20 | public static void AssertTrue(bool expression, string failureMessage) {
21 | if (!expression) {
22 | throw new Exception("Assertion failed: " + failureMessage);
23 | }
24 | }
25 |
26 | public static void WeakAssertTrue(bool expression, string failureMessage) {
27 | if (!expression) {
28 | Debug.LogError("Weak Assertion failed: " + failureMessage);
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Scripts/Editor/KeywordReplacer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using UnityEditor;
5 | using UnityEngine;
6 |
7 | namespace QuickUnityTools.Editor {
8 | public class KeywordReplace : UnityEditor.AssetModificationProcessor {
9 |
10 | public static void OnWillCreateAsset(string path) {
11 | path = path.Replace(".meta", "");
12 | int index = path.LastIndexOf(".");
13 | if (index < 0)
14 | return;
15 |
16 | string file = path.Substring(index);
17 | if (file != ".cs" && file != ".js" && file != ".boo")
18 | return;
19 |
20 | index = Application.dataPath.LastIndexOf("Assets");
21 | path = Application.dataPath.Substring(0, index) + path;
22 | if (!System.IO.File.Exists(path))
23 | return;
24 |
25 | string fileContent = System.IO.File.ReadAllText(path);
26 | fileContent = fileContent.Replace("#NAMESPACE#", GetNamespaceForPath(path));
27 |
28 | System.IO.File.WriteAllText(path, fileContent);
29 | AssetDatabase.Refresh();
30 | }
31 |
32 | public static string GetNamespaceForPath(string path) {
33 | return Application.productName;
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/Scripts/ExportableScene/Editor/ExportableScenePropertyDrawer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using UnityEditor;
4 |
5 | [CustomPropertyDrawer(typeof(ExportableScene))]
6 | public class ExportableSceneDrawer : PropertyDrawer {
7 |
8 | private bool verified = false;
9 |
10 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
11 | label = EditorGUI.BeginProperty(position, label, property);
12 | Rect contentPosition = EditorGUI.PrefixLabel(position, label);
13 |
14 | var sceneReference = property.FindPropertyRelative("sceneReference");
15 | Object lastSceneObj = sceneReference.objectReferenceValue;
16 | Object sceneObj = EditorGUI.ObjectField(contentPosition, sceneReference.objectReferenceValue, typeof(SceneAsset), false);
17 | sceneReference.objectReferenceValue = sceneObj;
18 |
19 | EditorGUI.EndProperty();
20 |
21 | if (lastSceneObj != sceneObj || !verified) {
22 | verified = true;
23 |
24 | // Update the scene name.
25 | string name = sceneObj == null ? "" : sceneObj.name;
26 | var sceneNameProperty = property.FindPropertyRelative("sceneName");
27 | if (sceneNameProperty.stringValue != name) {
28 | Debug.Log("Setting the exportable scene from " + sceneNameProperty.stringValue + " to " + name);
29 | sceneNameProperty.stringValue = name;
30 | }
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/BasicMusicStackElement.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 |
5 | namespace QuickUnityTools.Audio {
6 |
7 | [Serializable]
8 | public class BasicMusicStackElement : IMusicStackElement {
9 |
10 | public AudioClip music;
11 | public SmoothLoopAudioClip smoothLoopMusic;
12 | public MusicStackPriorty priority = MusicStackPriorty.Low;
13 | public MusicStack.Transition transitionIn = MusicStack.Transition.CROSS_FADE;
14 | public MusicStack.Transition transitionOut = MusicStack.Transition.CROSS_FADE;
15 | public float desiredVolume = 1;
16 |
17 | public BasicMusicStackElement(AudioClip music) {
18 | this.music = music;
19 | }
20 |
21 | public MusicStack.IMusicAsset GetMusicAsset() {
22 | if (smoothLoopMusic != null) {
23 | return new SmoothLoopMusicAsset(smoothLoopMusic);
24 | }
25 | return music != null ? new AudioClipMusicAsset(music) : null;
26 | }
27 |
28 | public MusicStack.Transition GetReleaseControlTransition() {
29 | return transitionOut;
30 | }
31 |
32 | public MusicStack.Transition GetTakeControlTransition() {
33 | return transitionIn;
34 | }
35 |
36 | public float GetDesiredVolume() {
37 | return desiredVolume;
38 | }
39 |
40 | public MusicStackPriorty GetPriority() {
41 | return priority;
42 | }
43 | }
44 | }
--------------------------------------------------------------------------------
/Scripts/Editor/RandomRangeDrawer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 | using UnityEditor;
5 |
6 | [CustomPropertyDrawer(typeof(RandomRange))]
7 | public class RandomRangeDrawer : PropertyDrawer {
8 |
9 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
10 | // Using BeginProperty / EndProperty on the parent property means that
11 | // prefab override logic works on the entire property.
12 | EditorGUI.BeginProperty(position, label, property);
13 |
14 | // Draw label
15 | position = EditorGUI.PrefixLabel(position, GUIUtility.GetControlID(FocusType.Passive), label);
16 |
17 | // Don't make child fields be indented
18 | var indent = EditorGUI.indentLevel;
19 | EditorGUI.indentLevel = 0;
20 |
21 | // Calculate rects
22 | var amountRect = new Rect(position.x, position.y, position.width / 2, position.height);
23 | var unitRect = new Rect(position.x + position.width / 2, position.y, position.width / 2, position.height);
24 |
25 | // Draw fields - pass GUIContent.none to each so they are drawn without labels
26 | EditorGUI.PropertyField(amountRect, property.FindPropertyRelative("min"), GUIContent.none);
27 | EditorGUI.PropertyField(unitRect, property.FindPropertyRelative("max"), GUIContent.none);
28 |
29 | // Set indent back to what it was
30 | EditorGUI.indentLevel = indent;
31 |
32 | EditorGUI.EndProperty();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/Scripts/ExportableScene/ExportableScene.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 | using System.Linq;
5 |
6 | #if UNITY_EDITOR
7 | using UnityEditor;
8 | #endif
9 |
10 | [Serializable]
11 | public class ExportableScene {
12 | [SerializeField]
13 | private UnityEngine.Object sceneReference; // These are SceneAsset objects that disappear in an actual build.
14 |
15 | [SerializeField]
16 | private string sceneName = "";
17 |
18 | ///
19 | /// Please call this in MonoBehaviours where this is used.
20 | ///
21 | public void Validate(MonoBehaviour dirtyTarget) {
22 | string name = sceneReference != null ? sceneReference.name : "";
23 | if (sceneName != name) {
24 | Debug.LogWarning("Click here to go to the object and fix outdated ExportableScene reference for " + dirtyTarget.gameObject.name, dirtyTarget);
25 | }
26 |
27 | #if UNITY_EDITOR
28 | if (!EditorBuildSettings.scenes.Any(s => s.path == AssetDatabase.GetAssetPath(sceneReference))) {
29 | Debug.LogWarning("The referenced scene is not included in the build settings!");
30 | }
31 | #endif
32 | }
33 |
34 | public string GetSceneName() {
35 | if (sceneReference != null) {
36 | if (sceneReference.name != sceneName) {
37 | Debug.LogError("An ExportableScene reference is out of date: " + sceneName + " -> " + sceneReference.name);
38 | }
39 | // NOTE: Cannot verify that the scene name is NULL when the object reference is null.
40 | }
41 | return sceneName;
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/Scripts/Timer/TimerManager.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 |
7 | ///
8 | /// Provide scene-local access to the TimerManager using a service locator.
9 | ///
10 | public class TimerServiceLocator : ServiceLocator {
11 |
12 | public TimerManager timerManager { get { return LocateOrCreateServiceInActiveScene(); } }
13 |
14 | public class TimerManager : ServiceMonoBehaviour {
15 |
16 | private List timers = new List();
17 | private List timersToAddBuffer = new List();
18 |
19 | private void Update() {
20 | UpdateAllRegisteredTimers();
21 | }
22 |
23 | private void OnDestroy() {
24 | CancelAllRegisteredTimers();
25 | }
26 |
27 | public void AddTimer(Timer timer) {
28 | timersToAddBuffer.Add(timer);
29 | }
30 |
31 | private void UpdateAllRegisteredTimers() {
32 | timers.AddRange(timersToAddBuffer);
33 | if (timersToAddBuffer.Count > 0) {
34 | timersToAddBuffer.Clear();
35 | }
36 |
37 | bool anyDone = false;
38 | foreach (Timer timer in timers) {
39 | timer.Update();
40 | anyDone |= timer.IsDone();
41 | }
42 |
43 | if (anyDone) {
44 | timers.RemoveAll(t => t.IsDone());
45 | }
46 | }
47 |
48 | private void CancelAllRegisteredTimers() {
49 | foreach (Timer timer in timers) {
50 | timer.Cancel();
51 | }
52 |
53 | timers.Clear();
54 | }
55 | }
56 | }
--------------------------------------------------------------------------------
/Resources/MusicStack.prefab:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!1 &129508
4 | GameObject:
5 | m_ObjectHideFlags: 0
6 | m_PrefabParentObject: {fileID: 0}
7 | m_PrefabInternal: {fileID: 100100000}
8 | serializedVersion: 5
9 | m_Component:
10 | - component: {fileID: 433064}
11 | - component: {fileID: 114330149919376814}
12 | m_Layer: 0
13 | m_Name: MusicStack
14 | m_TagString: Untagged
15 | m_Icon: {fileID: 0}
16 | m_NavMeshLayer: 0
17 | m_StaticEditorFlags: 0
18 | m_IsActive: 1
19 | --- !u!4 &433064
20 | Transform:
21 | m_ObjectHideFlags: 1
22 | m_PrefabParentObject: {fileID: 0}
23 | m_PrefabInternal: {fileID: 100100000}
24 | m_GameObject: {fileID: 129508}
25 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
26 | m_LocalPosition: {x: -109.49736, y: 60.066124, z: -8.0625}
27 | m_LocalScale: {x: 1, y: 1, z: 1}
28 | m_Children: []
29 | m_Father: {fileID: 0}
30 | m_RootOrder: 0
31 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
32 | --- !u!1001 &100100000
33 | Prefab:
34 | m_ObjectHideFlags: 1
35 | serializedVersion: 2
36 | m_Modification:
37 | m_TransformParent: {fileID: 0}
38 | m_Modifications: []
39 | m_RemovedComponents: []
40 | m_ParentPrefab: {fileID: 0}
41 | m_RootGameObject: {fileID: 129508}
42 | m_IsPrefabParent: 1
43 | --- !u!114 &114330149919376814
44 | MonoBehaviour:
45 | m_ObjectHideFlags: 1
46 | m_PrefabParentObject: {fileID: 0}
47 | m_PrefabInternal: {fileID: 100100000}
48 | m_GameObject: {fileID: 129508}
49 | m_Enabled: 1
50 | m_EditorHideFlags: 0
51 | m_Script: {fileID: 11500000, guid: 92ec81ff692086c458fc2e96242b11ea, type: 3}
52 | m_Name:
53 | m_EditorClassIdentifier:
54 | mixerGroup: {fileID: 243763981611373278, guid: 8fd65192e26cb5b44b53cdcec90e6088,
55 | type: 2}
56 |
--------------------------------------------------------------------------------
/Resources/MusicPlayer.prefab:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!1 &129508
4 | GameObject:
5 | m_ObjectHideFlags: 0
6 | m_PrefabParentObject: {fileID: 0}
7 | m_PrefabInternal: {fileID: 100100000}
8 | serializedVersion: 5
9 | m_Component:
10 | - component: {fileID: 433064}
11 | - component: {fileID: 11494380}
12 | m_Layer: 0
13 | m_Name: MusicPlayer
14 | m_TagString: Untagged
15 | m_Icon: {fileID: 0}
16 | m_NavMeshLayer: 0
17 | m_StaticEditorFlags: 0
18 | m_IsActive: 1
19 | --- !u!4 &433064
20 | Transform:
21 | m_ObjectHideFlags: 1
22 | m_PrefabParentObject: {fileID: 0}
23 | m_PrefabInternal: {fileID: 100100000}
24 | m_GameObject: {fileID: 129508}
25 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
26 | m_LocalPosition: {x: -109.49736, y: 60.066124, z: -8.0625}
27 | m_LocalScale: {x: 1, y: 1, z: 1}
28 | m_Children: []
29 | m_Father: {fileID: 0}
30 | m_RootOrder: 0
31 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
32 | --- !u!114 &11494380
33 | MonoBehaviour:
34 | m_ObjectHideFlags: 1
35 | m_PrefabParentObject: {fileID: 0}
36 | m_PrefabInternal: {fileID: 100100000}
37 | m_GameObject: {fileID: 129508}
38 | m_Enabled: 1
39 | m_EditorHideFlags: 0
40 | m_Script: {fileID: 11500000, guid: 10da20cb8d3d60a4eb7500cbe9b7bf05, type: 3}
41 | m_Name:
42 | m_EditorClassIdentifier:
43 | musicMixerGroup: {fileID: 243763981611373278, guid: 8fd65192e26cb5b44b53cdcec90e6088,
44 | type: 2}
45 | fadeInRate: 0.25
46 | fadeOutRate: 0.5
47 | --- !u!1001 &100100000
48 | Prefab:
49 | m_ObjectHideFlags: 1
50 | serializedVersion: 2
51 | m_Modification:
52 | m_TransformParent: {fileID: 0}
53 | m_Modifications: []
54 | m_RemovedComponents: []
55 | m_ParentPrefab: {fileID: 0}
56 | m_RootGameObject: {fileID: 129508}
57 | m_IsPrefabParent: 1
58 |
--------------------------------------------------------------------------------
/Resources/InControlManager.prefab:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!1 &121382
4 | GameObject:
5 | m_ObjectHideFlags: 0
6 | m_PrefabParentObject: {fileID: 0}
7 | m_PrefabInternal: {fileID: 100100000}
8 | serializedVersion: 5
9 | m_Component:
10 | - component: {fileID: 440894}
11 | - component: {fileID: 11439814}
12 | m_Layer: 8
13 | m_Name: InControlManager
14 | m_TagString: Untagged
15 | m_Icon: {fileID: 0}
16 | m_NavMeshLayer: 0
17 | m_StaticEditorFlags: 0
18 | m_IsActive: 1
19 | --- !u!4 &440894
20 | Transform:
21 | m_ObjectHideFlags: 1
22 | m_PrefabParentObject: {fileID: 0}
23 | m_PrefabInternal: {fileID: 100100000}
24 | m_GameObject: {fileID: 121382}
25 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
26 | m_LocalPosition: {x: 0, y: 1.37, z: 0}
27 | m_LocalScale: {x: 1, y: 1, z: 1}
28 | m_Children: []
29 | m_Father: {fileID: 0}
30 | m_RootOrder: 0
31 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
32 | --- !u!114 &11439814
33 | MonoBehaviour:
34 | m_ObjectHideFlags: 1
35 | m_PrefabParentObject: {fileID: 0}
36 | m_PrefabInternal: {fileID: 100100000}
37 | m_GameObject: {fileID: 121382}
38 | m_Enabled: 1
39 | m_EditorHideFlags: 0
40 | m_Script: {fileID: 11500000, guid: c7b5e8de77c5b4597ae7fbfb49a95e22, type: 3}
41 | m_Name:
42 | m_EditorClassIdentifier:
43 | logDebugInfo: 0
44 | invertYAxis: 0
45 | enableXInput: 1
46 | useFixedUpdate: 0
47 | dontDestroyOnLoad: 1
48 | customProfiles:
49 | - KeyboardAndMouseProfile
50 | --- !u!1001 &100100000
51 | Prefab:
52 | m_ObjectHideFlags: 1
53 | serializedVersion: 2
54 | m_Modification:
55 | m_TransformParent: {fileID: 0}
56 | m_Modifications: []
57 | m_RemovedComponents: []
58 | m_ParentPrefab: {fileID: 0}
59 | m_RootGameObject: {fileID: 121382}
60 | m_IsPrefabParent: 1
61 |
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/SmoothLoopMusicAsset.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using UnityEngine.Audio;
4 |
5 | namespace QuickUnityTools.Audio {
6 | public class SmoothLoopMusicAsset : MusicStack.IMusicAsset {
7 |
8 | private SmoothLoopAudioClip clip;
9 |
10 | public SmoothLoopMusicAsset(SmoothLoopAudioClip clip) {
11 | this.clip = clip;
12 | }
13 |
14 | public MusicStack.IMusicPlayer CreatePlayer() {
15 | return new SmoothLoopMusicPlayer(clip);
16 | }
17 |
18 | public int GetMusicID() {
19 | return clip.GetInstanceID();
20 | }
21 | }
22 |
23 | public class SmoothLoopMusicPlayer : MusicStack.IMusicPlayer {
24 | private SmoothLoopAudioSource source;
25 |
26 | public SmoothLoopMusicPlayer(SmoothLoopAudioClip clip) {
27 | GameObject obj = new GameObject("SmoothLoopMusicPlayer (" + clip + ")");
28 | SmoothLoopAudioSource source = obj.AddComponent();
29 | source.music = clip;
30 | this.source = source;
31 | UnityEngine.Object.DontDestroyOnLoad(obj);
32 | }
33 |
34 | public AudioMixerGroup outputAudioMixerGroup {
35 | set { source.mixerGroup = value; }
36 | }
37 |
38 | public float volume {
39 | get { return source.volume; }
40 | set { source.volume = value; }
41 | }
42 |
43 | public bool isPlaying { get { return source.isPlaying; } }
44 |
45 | public void CleanUp() {
46 | GameObject.Destroy(source.gameObject);
47 | }
48 |
49 | public void Play() {
50 | source.Play();
51 | }
52 |
53 | public void Stop() {
54 | source.Stop();
55 | }
56 | }
57 | }
--------------------------------------------------------------------------------
/Scripts/Editor/EnumFlagPropertyDrawer.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Reflection;
5 | using UnityEditor;
6 | using UnityEngine;
7 |
8 | ///
9 | /// From the Unity wiki.
10 | ///
11 | [CustomPropertyDrawer(typeof(EnumFlagAttribute))]
12 | public class EnumFlagDrawer : PropertyDrawer {
13 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) {
14 | EnumFlagAttribute flagSettings = (EnumFlagAttribute)attribute;
15 | Enum targetEnum = GetBaseProperty(property);
16 |
17 | string propName = flagSettings.enumName;
18 | if (string.IsNullOrEmpty(propName))
19 | propName = property.name;
20 |
21 | EditorGUI.BeginProperty(position, label, property);
22 | Enum enumNew = EditorGUI.EnumFlagsField(position, ObjectNames.NicifyVariableName(propName), targetEnum);
23 | property.intValue = (int)Convert.ChangeType(enumNew, targetEnum.GetType());
24 | EditorGUI.EndProperty();
25 | }
26 |
27 | static T GetBaseProperty(SerializedProperty prop) {
28 | // Separate the steps it takes to get to this property
29 | string[] separatedPaths = prop.propertyPath.Split('.');
30 |
31 | // Go down to the root of this serialized property
32 | System.Object reflectionTarget = prop.serializedObject.targetObject as object;
33 | // Walk down the path to get the target object
34 | foreach (var path in separatedPaths) {
35 | FieldInfo fieldInfo = reflectionTarget.GetType().GetField(path);
36 | reflectionTarget = fieldInfo.GetValue(reflectionTarget);
37 | }
38 | return (T)reflectionTarget;
39 | }
40 | }
--------------------------------------------------------------------------------
/Scripts/Extensions/QuickUnityMathExtensions.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 |
5 | public static class QuickUnityMathExtensions {
6 |
7 | public static Vector3 Round(this Vector3 vector) {
8 | return new Vector3(Mathf.Round(vector.x), Mathf.Round(vector.y), Mathf.Round(vector.z));
9 | }
10 |
11 | public static Vector3 Clamp(this Vector3 v, float length) {
12 | float m = v.magnitude;
13 | if (m > length) {
14 | return (v / m) * length;
15 | }
16 | return v;
17 | }
18 |
19 | public static Vector3 Snap(this Vector3 v, float cellSize) {
20 | v = (v / cellSize);
21 | return new Vector3((int)v.x, (int)v.y, (int)v.z) * cellSize;
22 | }
23 |
24 | public static Vector3 SetX(this Vector3 vector, float x) {
25 | return new Vector3(x, vector.y, vector.z);
26 | }
27 |
28 | public static Vector3 SetY(this Vector3 vector, float y) {
29 | return new Vector3(vector.x, y, vector.z);
30 | }
31 |
32 | public static Vector3 SetZ(this Vector3 vector, float z) {
33 | return new Vector3(vector.x, vector.y, z);
34 | }
35 |
36 | public static Vector2 SetX(this Vector2 vector, float x) {
37 | return new Vector2(x, vector.y);
38 | }
39 |
40 | public static Vector2 SetY(this Vector2 vector, float y) {
41 | return new Vector2(vector.x, y);
42 | }
43 |
44 | public static Vector3 TransformComponents(this Vector3 vector, Func transformation) {
45 | return new Vector3(transformation(vector.x), transformation(vector.y), transformation(vector.z));
46 | }
47 |
48 | public static int Mod(this int x, int m) {
49 | return (x % m + m) % m;
50 | }
51 |
52 | public static float Sqr(this float v) {
53 | return v * v;
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/Scripts/TriggerCollidersTracker.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | public abstract class TriggerCollidersTracker : MonoBehaviour {
6 |
7 | public int objectsInsideCount { get { return this.collidersInside.Count; } }
8 | protected List collidersInside;
9 |
10 | protected virtual void Start() {
11 | this.collidersInside = new List();
12 | }
13 |
14 | protected virtual void Update() {
15 | for (int i = collidersInside.Count - 1; i >= 0; i--) {
16 | var collider = collidersInside[i];
17 | if (collider == null || !collider.enabled || !collider.gameObject.activeInHierarchy) {
18 | this.MarkColliderRemoved(collider);
19 | }
20 | }
21 | }
22 |
23 | private void OnTriggerEnter(Collider collider) {
24 | if (collider.GetComponent() == null) {
25 | return;
26 | }
27 | if (!this.collidersInside.Contains(collider)) {
28 | this.collidersInside.Add(collider);
29 | if (this.collidersInside.Count == 1) {
30 | this.OnAtLeastOneCollider();
31 | }
32 | }
33 | this.OnColliderEnter(collider);
34 | }
35 |
36 | private void OnTriggerExit(Collider collider) {
37 | this.MarkColliderRemoved(collider);
38 | }
39 |
40 | private void MarkColliderRemoved(Collider collider) {
41 | if (this.collidersInside.Contains(collider)) {
42 | this.collidersInside.Remove(collider);
43 | this.OnColliderExit(collider);
44 | if (this.collidersInside.Count == 0) {
45 | this.OnNoColliders();
46 | }
47 | }
48 | }
49 |
50 | protected virtual void OnAtLeastOneCollider() { }
51 |
52 | protected virtual void OnNoColliders() { }
53 |
54 | protected virtual void OnColliderEnter(Collider collider) { }
55 |
56 | protected virtual void OnColliderExit(Collider collider) { }
57 | }
58 |
59 |
--------------------------------------------------------------------------------
/Scripts/Singleton/SceneSingleton.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | ///
5 | /// Represents a single-instance object that is placed in scenes.
6 | /// This will not create the singleton, it just provides quick access to the Singleton.
7 | ///
8 | /// I think this class is still kind of buggy in some situations, I'll fix it later.
9 | ///
10 | [Obsolete("SceneSingletons aren't really singletons. Use the ServiceLocator instead.")]
11 | public class SceneSingleton : MonoBehaviour where T : MonoBehaviour {
12 | private static T _instance;
13 |
14 | public static T instance {
15 | get {
16 | // HACK: Search for a new one if the current is disabled; this is needed for my current project.
17 | if (_instance != null && !_instance.isActiveAndEnabled) {
18 | _instance = null;
19 | Debug.Log("[SceneSingleton] The current instance of " + typeof(T) + " is inactive. Searching for an active one...");
20 | }
21 |
22 | if (_instance == null) {
23 | _instance = (T)GameObject.FindObjectOfType(typeof(T));
24 |
25 | if (GameObject.FindObjectsOfType(typeof(T)).Length > 1) {
26 | Debug.LogError("[SceneSingleton] Something went really wrong - there should never be more than 1 singleton! Reopening the scene might fix it.");
27 | return _instance;
28 | }
29 |
30 | if (_instance == null) {
31 | Debug.LogWarning("[SceneSingleton] An instance of " + typeof(T) + " is needed in the scene, but none exists!");
32 | } else {
33 | Debug.Log("[SceneSingleton] Using instance already created: " + _instance.gameObject.name);
34 | }
35 | }
36 |
37 | return _instance;
38 | }
39 | }
40 |
41 | protected virtual void Awake() {
42 | // Placeholder.
43 | }
44 |
45 | protected virtual void OnDestroy() {
46 | _instance = null;
47 | }
48 | }
--------------------------------------------------------------------------------
/Scripts/CheatCodeDetector.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System;
5 |
6 | public abstract class CheatCodeDetector : MonoBehaviour {
7 |
8 | private class Cheat {
9 | public string cheatCode { get; private set; }
10 | private Action onActivate;
11 | private int cheatTypeIndex;
12 | private CheatCodeDetector controller;
13 |
14 | public Cheat(string cheatCode, Action onActivate, CheatCodeDetector controller) {
15 | this.cheatCode = cheatCode;
16 | this.onActivate = onActivate;
17 | this.cheatTypeIndex = 0;
18 | this.controller = controller;
19 | }
20 |
21 | public void Update() {
22 | if (Input.inputString != "") {
23 | if (Input.inputString[0] == this.cheatCode[this.cheatTypeIndex]) {
24 | this.cheatTypeIndex++;
25 | if (this.cheatTypeIndex == this.cheatCode.Length) {
26 | this.cheatTypeIndex = 0;
27 | Activate();
28 | }
29 | } else {
30 | this.cheatTypeIndex = 0;
31 | }
32 | }
33 | }
34 |
35 | public void Activate() {
36 | this.onActivate();
37 | this.controller.OnCheatActivation();
38 | }
39 | }
40 |
41 | private List cheats = new List();
42 |
43 | protected virtual void Update() {
44 | foreach (Cheat cheat in this.cheats) {
45 | cheat.Update();
46 | }
47 | }
48 |
49 | public void RegisterCheat(string cheatCode, Action onActivate) {
50 | this.cheats.Add(new Cheat(cheatCode, onActivate, this));
51 | }
52 |
53 | public void TriggerCheat(string name) {
54 | var cheat = cheats.FirstOrDefault(c => c.cheatCode == name);
55 | if (cheat != null) {
56 | cheat.Activate();
57 | }
58 | }
59 |
60 | protected virtual void OnCheatActivation() {
61 | // Triggers on every cheat activation.
62 | }
63 | }
--------------------------------------------------------------------------------
/Resources/SoundPlayer.prefab:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!1 &185932
4 | GameObject:
5 | m_ObjectHideFlags: 0
6 | m_PrefabParentObject: {fileID: 0}
7 | m_PrefabInternal: {fileID: 100100000}
8 | serializedVersion: 5
9 | m_Component:
10 | - component: {fileID: 492442}
11 | - component: {fileID: 11456836}
12 | m_Layer: 0
13 | m_Name: SoundPlayer
14 | m_TagString: Untagged
15 | m_Icon: {fileID: 0}
16 | m_NavMeshLayer: 0
17 | m_StaticEditorFlags: 0
18 | m_IsActive: 1
19 | --- !u!4 &492442
20 | Transform:
21 | m_ObjectHideFlags: 1
22 | m_PrefabParentObject: {fileID: 0}
23 | m_PrefabInternal: {fileID: 100100000}
24 | m_GameObject: {fileID: 185932}
25 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
26 | m_LocalPosition: {x: 0.14774781, y: -0.8848554, z: 0}
27 | m_LocalScale: {x: 1, y: 1, z: 1}
28 | m_Children: []
29 | m_Father: {fileID: 0}
30 | m_RootOrder: 0
31 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
32 | --- !u!114 &11456836
33 | MonoBehaviour:
34 | m_ObjectHideFlags: 1
35 | m_PrefabParentObject: {fileID: 0}
36 | m_PrefabInternal: {fileID: 100100000}
37 | m_GameObject: {fileID: 185932}
38 | m_Enabled: 1
39 | m_EditorHideFlags: 0
40 | m_Script: {fileID: 11500000, guid: 0ac27dde6773e2048a3af87551f31828, type: 3}
41 | m_Name:
42 | m_EditorClassIdentifier:
43 | soundMixerGroup: {fileID: 243265969154359278, guid: 8fd65192e26cb5b44b53cdcec90e6088,
44 | type: 2}
45 | --- !u!1001 &100100000
46 | Prefab:
47 | m_ObjectHideFlags: 1
48 | serializedVersion: 2
49 | m_Modification:
50 | m_TransformParent: {fileID: 0}
51 | m_Modifications:
52 | - target: {fileID: 0}
53 | propertyPath: soundMixerGroup
54 | value:
55 | objectReference: {fileID: 24378234, guid: d9e41bc711dbe3e40b3a332b205a6329,
56 | type: 2}
57 | - target: {fileID: 0}
58 | propertyPath: musicMixerGroup
59 | value:
60 | objectReference: {fileID: 24315298, guid: d9e41bc711dbe3e40b3a332b205a6329,
61 | type: 2}
62 | m_RemovedComponents: []
63 | m_ParentPrefab: {fileID: 0}
64 | m_RootGameObject: {fileID: 185932}
65 | m_IsPrefabParent: 1
66 |
--------------------------------------------------------------------------------
/Scripts/PrioritySortingKey.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 |
6 | ///
7 | /// For use with SortedList.
8 | /// Sorts the items by priority, with using time as a tiebreaker.
9 | ///
10 | public class PrioritySortingKey : IComparable {
11 | private static int uniqueConsecutiveTimeOrderIds = int.MinValue;
12 |
13 | private int priority;
14 | private int timestamp;
15 |
16 | public PrioritySortingKey(int priority) : this(priority, GetUniqueTime()) { }
17 |
18 | public PrioritySortingKey(int priority, int timestamp) {
19 | this.priority = priority;
20 | this.timestamp = timestamp;
21 | }
22 |
23 | public int CompareTo(object obj) {
24 | int compare = -1 * this.priority.CompareTo(((PrioritySortingKey)obj).priority);
25 | if (compare == 0) {
26 | return -1 * this.timestamp.CompareTo(((PrioritySortingKey)obj).timestamp);
27 | }
28 | return compare;
29 | }
30 |
31 | public override string ToString() {
32 | return "(Priority: " + priority + ", Time: " + timestamp + ")";
33 | }
34 |
35 | public static int GetUniqueTime() {
36 | uniqueConsecutiveTimeOrderIds++;
37 | return uniqueConsecutiveTimeOrderIds;
38 | }
39 | }
40 |
41 | ///
42 | /// For use with SortedList where the list represents an ordered stack that manages some global state
43 | /// that users have to register themselves with to modify.
44 | ///
45 | public class StackResourceSortingKey : PrioritySortingKey {
46 |
47 | private Action releaseResource;
48 |
49 | public StackResourceSortingKey(int priority, Action releaseResource) : base(priority) {
50 | Asserts.NotNull(releaseResource);
51 | this.releaseResource = releaseResource;
52 | }
53 |
54 | public void ReleaseResource() {
55 | releaseResource(this);
56 | }
57 |
58 | public static void Release(StackResourceSortingKey key) {
59 | if (key != null) {
60 | key.ReleaseResource();
61 | }
62 | }
63 | }
--------------------------------------------------------------------------------
/Scripts/Audio/MusicStack/AudioClipMusicAsset.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using UnityEngine.Audio;
4 |
5 | namespace QuickUnityTools.Audio {
6 |
7 | ///
8 | /// An adapter for so they can be used as a music stack asset.
9 | ///
10 | public class AudioClipMusicAsset : MusicStack.IMusicAsset {
11 |
12 | private AudioClip clip;
13 |
14 | public AudioClipMusicAsset(AudioClip clip) {
15 | this.clip = clip;
16 | }
17 |
18 | public int GetMusicID() {
19 | return clip.GetInstanceID();
20 | }
21 |
22 | public MusicStack.IMusicPlayer CreatePlayer() {
23 | return new AudioClipMusicPlayer(clip);
24 | }
25 |
26 | ///
27 | /// Creates an audio source to play the related audio clip on the music stack.
28 | ///
29 | public class AudioClipMusicPlayer : MusicStack.IMusicPlayer {
30 |
31 | private AudioSource source;
32 |
33 | public AudioClipMusicPlayer(AudioClip clip) {
34 | GameObject obj = new GameObject("AudioClipMusicPlayer (" + clip + ")");
35 | AudioSource source = obj.AddComponent();
36 | source.clip = clip;
37 | source.loop = true;
38 | this.source = source;
39 | UnityEngine.Object.DontDestroyOnLoad(obj);
40 | }
41 |
42 | public float volume {
43 | get { return source.volume; }
44 | set { source.volume = value; }
45 | }
46 |
47 | public bool isPlaying { get { return source.isPlaying; } }
48 |
49 | public AudioMixerGroup outputAudioMixerGroup {
50 | set { source.outputAudioMixerGroup = value; }
51 | }
52 |
53 | public void CleanUp() {
54 | GameObject.Destroy(source.gameObject);
55 | }
56 |
57 | public void Play() {
58 | source.Play();
59 | }
60 |
61 | public void Stop() {
62 | source.Stop();
63 | }
64 | }
65 | }
66 | }
--------------------------------------------------------------------------------
/Scripts/TimeScaleController.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 |
5 | public class TimeScaleController : Singleton {
6 |
7 | private const float TIME_SCALE_CHANGE_SPEED = 1000;
8 |
9 | public float baseTimeScale { get; set; }
10 |
11 | private float slowMoScale;
12 | private float slowMoDuration;
13 |
14 | private float timeScaleChangeSpeed = TIME_SCALE_CHANGE_SPEED;
15 | private float initalFixedDeltaTime;
16 |
17 | private SortedList timeScaleAdjustments = new SortedList();
18 | private IList timeScaleListCache;
19 |
20 | private void Awake() {
21 | initalFixedDeltaTime = Time.fixedDeltaTime;
22 | timeScaleListCache = timeScaleAdjustments.Values;
23 | baseTimeScale = 1;
24 | }
25 |
26 | private void Update() {
27 | float realDeltaTime = Time.unscaledDeltaTime;
28 |
29 | if (slowMoDuration > 0) {
30 | // Apply the slow mo.
31 | slowMoDuration = Mathf.MoveTowards(slowMoDuration, 0, realDeltaTime);
32 | Time.timeScale = Mathf.MoveTowards(Time.timeScale, slowMoScale, timeScaleChangeSpeed * realDeltaTime);
33 | Time.fixedDeltaTime = Mathf.LerpUnclamped(0, initalFixedDeltaTime, Time.timeScale);
34 | } else {
35 | // Return to normal speed.
36 | float desiredTimeScale = baseTimeScale;
37 | if (timeScaleAdjustments.Count > 0) {
38 | desiredTimeScale *= timeScaleListCache[0];
39 | }
40 |
41 | if (Time.timeScale != desiredTimeScale) {
42 | Time.timeScale = Mathf.MoveTowards(Time.timeScale, desiredTimeScale, timeScaleChangeSpeed * realDeltaTime);
43 | if (Time.timeScale == desiredTimeScale) {
44 | // Once back to speed, return the the default change speed.
45 | timeScaleChangeSpeed = TIME_SCALE_CHANGE_SPEED;
46 | }
47 | }
48 |
49 | // Update the fixed time to match the timescale.
50 | float fixedDeltaTime = Mathf.Min(initalFixedDeltaTime, Mathf.LerpUnclamped(0, initalFixedDeltaTime, Time.timeScale));
51 | if (Time.fixedDeltaTime != fixedDeltaTime) {
52 | Time.fixedDeltaTime = fixedDeltaTime;
53 | }
54 | }
55 | }
56 |
57 | ///
58 | /// Adjusts the timescale. The returned key must be used to unregister the adjustment and return it to normal.
59 | ///
60 | public StackResourceSortingKey AdjustTimeScale(float timeScale) {
61 | var resourceKey = new StackResourceSortingKey(0, key => timeScaleAdjustments.Remove(key));
62 | timeScaleAdjustments.Add(resourceKey, timeScale);
63 | return resourceKey;
64 | }
65 |
66 | ///
67 | /// Slows down time for a some realtime seconds.
68 | ///
69 | public void SlowMo(float slowTimeScale, float duration, float? timeChangeSpeed = null) {
70 | slowMoScale = slowTimeScale;
71 | slowMoDuration = duration;
72 | if (timeChangeSpeed.HasValue) {
73 | timeScaleChangeSpeed = timeChangeSpeed.Value;
74 | }
75 | }
76 | }
77 |
--------------------------------------------------------------------------------
/Scripts/Timer/Timer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System;
3 | using System.Linq;
4 | using System.Collections;
5 | using System.Collections.Generic;
6 |
7 | public class Timer {
8 |
9 | public bool isLooped { get; set; }
10 | public bool isPaused { get; set; }
11 |
12 | public float duration { get; private set; }
13 | public bool isCancelled { get; private set; }
14 | public bool isCompleted { get; private set; }
15 |
16 | private float accumulatedTime;
17 |
18 | private Action onComplete;
19 | private bool usesUnscaledTime;
20 | private bool hasAutoDestroyOwner;
21 | private UnityEngine.Object autoDestroyOwner;
22 |
23 | private Timer(float duration, Action onComplete, bool isLooped, bool useUnscaledTime) {
24 | this.duration = duration;
25 | this.onComplete = onComplete;
26 |
27 | this.isLooped = isLooped;
28 | this.isCancelled = false;
29 | this.usesUnscaledTime = useUnscaledTime;
30 |
31 | this.accumulatedTime = 0;
32 | }
33 |
34 | private float GetDeltaTime() {
35 | if (this.usesUnscaledTime) {
36 | return Time.unscaledDeltaTime;
37 | } else {
38 | return Time.deltaTime;
39 | }
40 | }
41 |
42 | public void SetAutoDestroyOwner(UnityEngine.Object owner) {
43 | this.autoDestroyOwner = owner;
44 | this.hasAutoDestroyOwner = owner != null;
45 | }
46 |
47 | public bool IsDone() {
48 | return this.isCompleted || this.isCancelled || (this.hasAutoDestroyOwner && this.autoDestroyOwner == null);
49 | }
50 |
51 | public void Cancel() {
52 | this.isCancelled = true;
53 | }
54 |
55 | public void Update() {
56 | if (this.IsDone() || this.isPaused) {
57 | return;
58 | }
59 |
60 | this.accumulatedTime += this.GetDeltaTime();
61 | if (this.accumulatedTime >= this.duration) {
62 | this.onComplete();
63 |
64 | if (this.isLooped) {
65 | this.accumulatedTime = 0;
66 | } else {
67 | this.isCompleted = true;
68 | }
69 | }
70 | }
71 |
72 | public float GetTimeRemaining() {
73 | return this.IsDone() ? 0 : this.duration - this.accumulatedTime;
74 | }
75 |
76 | public float GetTime() {
77 | return this.accumulatedTime;
78 | }
79 |
80 | public float GetPercentageComplete() {
81 | if (this.isCompleted) {
82 | return 1;
83 | }
84 | return this.accumulatedTime / this.duration;
85 | }
86 |
87 | public static Timer Register(float duration, Action onComplete, bool isLooped = false, bool useUnscaledTime = false, UnityEngine.Object autoCancelObj = null) {
88 | Timer timer = new Timer(duration, onComplete, isLooped, useUnscaledTime);
89 | timer.SetAutoDestroyOwner(autoCancelObj);
90 | if (TimerServiceLocator.instance != null && TimerServiceLocator.instance.timerManager != null) {
91 | TimerServiceLocator.instance.timerManager.AddTimer(timer);
92 | }
93 | return timer;
94 | }
95 |
96 | public static void Cancel(Timer timer) {
97 | if (timer != null) {
98 | timer.Cancel();
99 | }
100 | }
101 |
102 | public static void FinishImmediately(Timer timer) {
103 | if (timer == null) {
104 | return;
105 | }
106 | if (timer.IsDone()) {
107 | return;
108 | }
109 | timer.onComplete();
110 | timer.isCompleted = true;
111 | }
112 | }
--------------------------------------------------------------------------------
/Scripts/Editor/InspectorNavigator.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 | using System.Collections;
4 | using System.Collections.Generic;
5 | using System;
6 | using System.Linq;
7 |
8 | public class InspectorNavigator : EditorWindow {
9 |
10 | private static InspectorNavigator openedInstance;
11 |
12 | private List backList = new List();
13 | private List forwardList = new List();
14 |
15 | private int[] previousSelection;
16 | private bool isGoingBack;
17 | private bool isGoingForward;
18 |
19 | [MenuItem("Window/Inspector Navigator/Open")]
20 | private static void Create() {
21 | if (openedInstance) {
22 | Debug.LogWarning("The inspector navigator is already open! Restarting the window...");
23 | openedInstance.Close();
24 | openedInstance = null;
25 | }
26 |
27 | InspectorNavigator window = (InspectorNavigator)GetWindow(typeof(InspectorNavigator));
28 | window.Show();
29 | window.titleContent = new GUIContent("Navigator");
30 | window.minSize = new Vector2(10f, EditorGUIUtility.singleLineHeight + 5f);
31 |
32 | openedInstance = window;
33 | }
34 |
35 | [MenuItem("Window/Inspector Navigator/Back %LEFT")]
36 | private static void BackShortcut() {
37 | if (!openedInstance) {
38 | Debug.LogWarning("Open the navigator window first...");
39 | return;
40 | }
41 | openedInstance.Back();
42 | }
43 |
44 | [MenuItem("Window/Inspector Navigator/Forward %RIGHT")]
45 | private static void ForwardShortcut() {
46 | if (!openedInstance) {
47 | Debug.LogWarning("Open the navigator window first...");
48 | return;
49 | }
50 | openedInstance.Forward();
51 | }
52 |
53 | private void OnSelectionChange() {
54 | if (Selection.instanceIDs != previousSelection) {
55 | if (isGoingBack && backList.Count > 0) {
56 | if (previousSelection != null) {
57 | forwardList.Add(previousSelection);
58 | }
59 | backList.RemoveAt(backList.Count - 1);
60 | } else if (isGoingForward && forwardList.Count > 0) {
61 | if (previousSelection != null) {
62 | backList.Add(previousSelection);
63 | }
64 | forwardList.RemoveAt(forwardList.Count - 1);
65 | } else if (previousSelection != null) {
66 | backList.Add(previousSelection);
67 | forwardList.Clear();
68 | }
69 | }
70 |
71 | if (backList.Count > 64) {
72 | backList.RemoveAt(0);
73 | }
74 |
75 | isGoingBack = false;
76 | isGoingForward = false;
77 | previousSelection = Selection.instanceIDs;
78 | }
79 |
80 | private void OnDestroy() {
81 | openedInstance = null;
82 | }
83 |
84 | protected virtual void OnGUI() {
85 | GUILayout.BeginHorizontal();
86 | DrawGUIToolbar();
87 | GUILayout.EndHorizontal();
88 | }
89 |
90 | protected virtual void DrawGUIToolbar() {
91 | if (GUILayout.Button("◄")) {
92 | Back();
93 | }
94 | if (GUILayout.Button("►")) {
95 | Forward();
96 | }
97 | }
98 |
99 | private void Forward() {
100 | if (forwardList.Count == 0) {
101 | Debug.LogWarning("Nothing to go forward to...");
102 | return;
103 | }
104 |
105 | isGoingForward = true;
106 | Selection.instanceIDs = forwardList.Last();
107 | }
108 |
109 | private void Back() {
110 | if (backList.Count == 0) {
111 | Debug.LogWarning("Nothing to go back to...");
112 | return;
113 | }
114 |
115 | isGoingBack = true;
116 | Selection.instanceIDs = backList.Last();
117 | }
118 | }
--------------------------------------------------------------------------------
/Scripts/Services/ServiceLocator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using UnityEngine;
5 | using UnityEngine.SceneManagement;
6 |
7 | ///
8 | /// Provides controlled access to services that exist locally within a scene. Concrete classes should
9 | /// provide getters for various services and use the Locate() method to find and cache the service
10 | /// reference. The cache is cleared when the active scene changes to point to the services in the new
11 | /// scene.
12 | ///
13 | /// The concrete type that is used for singleton access.
14 | public abstract class ServiceLocator : Singleton where TMyType : MonoBehaviour {
15 |
16 | private static bool applicationIsQuitting = false;
17 |
18 | protected Dictionary cachedSceneServices = new Dictionary();
19 |
20 |
21 | protected virtual void Awake() {
22 | SceneManager.activeSceneChanged += OnActiveSceneChange;
23 | }
24 |
25 | protected virtual void OnApplicationQuit() {
26 | applicationIsQuitting = true;
27 | }
28 |
29 | private void OnActiveSceneChange(Scene oldScene, Scene newScene) {
30 | Log("Clearing the cached scene services.");
31 | cachedSceneServices.Clear();
32 | }
33 |
34 | ///
35 | /// Looks for a service that exists as a MonoBehaviour in the current scene.
36 | ///
37 | protected TService LocateServiceInActiveScene() where TService : ServiceMonoBehaviour {
38 | var service = LocateServiceInActiveSceneWithoutErrors();
39 | if (service == null) {
40 | LogError(typeof(TService), "Service is not present in this scene!");
41 | }
42 | return service;
43 | }
44 |
45 | public TService LocateServiceInActiveSceneWithoutErrors() where TService : ServiceMonoBehaviour {
46 | // Try and find a cached version of the service.
47 | Type serviceType = typeof(TService);
48 | if (cachedSceneServices.ContainsKey(serviceType)) {
49 | var cached = (TService)cachedSceneServices[serviceType];
50 | if (cached != null) {
51 | return cached;
52 | } else {
53 | Log(serviceType, "The cached service was null! Hopefully it was destroyed in a scene transition?");
54 | }
55 | }
56 |
57 | TService foundService = SceneManager.GetActiveScene().FindComponentsOfTypeInScene().FirstOrDefault();
58 | if (foundService == null) {
59 | return null;
60 | }
61 |
62 | Log(serviceType, "Located service and caching it.");
63 | cachedSceneServices[serviceType] = foundService;
64 | return foundService;
65 | }
66 |
67 | protected TService LocateOrCreateServiceInActiveScene() where TService : ServiceMonoBehaviour {
68 | TService service = LocateServiceInActiveSceneWithoutErrors();
69 | if (service != null) {
70 | return service;
71 | }
72 |
73 | if (applicationIsQuitting) {
74 | return null;
75 | }
76 |
77 | Type serviceType = typeof(TService);
78 | Log(serviceType, "Created a new service in the scene.");
79 | GameObject obj = new GameObject("(Created Service) " + serviceType.Name);
80 | service = obj.AddComponent();
81 | cachedSceneServices[serviceType] = service;
82 | return service;
83 | }
84 |
85 | private void Log(string message) {
86 | Log(null, message);
87 | }
88 |
89 | private void Log(Type service, string message) {
90 | string serviceText = service != null ? service.Name + ": " : "";
91 | Debug.Log("[" + GetType().Name + "] " + serviceText + message);
92 | }
93 |
94 | private void LogError(Type service, string warning) {
95 | string serviceText = service != null ? service.Name + ": " : "";
96 | Debug.LogError("[" + GetType().Name + "] " + serviceText + warning);
97 | }
98 | }
--------------------------------------------------------------------------------
/Scripts/Vector2Int.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System;
3 | using System.Text;
4 |
5 | public struct Vector2Int {
6 |
7 | public static readonly Vector2Int[] MAIN_DIRECTIONS = new Vector2Int[] { new Vector2Int(1, 0), new Vector2Int(-1, 0), new Vector2Int(0, 1), new Vector2Int(0, -1) };
8 | public static readonly Vector2Int[] ALL_DIRECTIONS = new Vector2Int[] { new Vector2Int(1, 0), new Vector2Int(-1, 0), new Vector2Int(0, 1), new Vector2Int(0, -1), new Vector2Int(1, 1), new Vector2Int(-1, 1), new Vector2Int(1, -1), new Vector2Int(-1, -1) };
9 | public static readonly Vector2Int zero = new Vector2Int(0, 0);
10 | public static readonly Vector2Int unitX = new Vector2Int(1, 0);
11 | public static readonly Vector2Int unitY = new Vector2Int(0, 1);
12 |
13 | public int x;
14 | public int y;
15 |
16 | public Vector2Int(int x, int y) {
17 | this.x = x;
18 | this.y = y;
19 | }
20 |
21 | public bool IsNeighbors(Vector2Int other) {
22 | return Math.Abs(other.x - this.x) <= 1 && Math.Abs(other.y - this.y) <= 1;
23 | }
24 |
25 | public Vector3 ToV3() {
26 | return new Vector3(x, y, 0);
27 | }
28 |
29 | public Vector2 ToV2() {
30 | return new Vector2(x, y);
31 | }
32 |
33 | public override bool Equals(object obj) {
34 | return (obj is Vector2Int) ? this == ((Vector2Int)obj) : false;
35 | }
36 |
37 | public bool Equals(Vector2Int other) {
38 | return this == other;
39 | }
40 |
41 | public override int GetHashCode() {
42 | return this.x + this.y;
43 | }
44 |
45 | public Vector2Int TurnClockwise() {
46 | return new Vector2Int(-y, x);
47 | }
48 |
49 | public override string ToString() {
50 | StringBuilder sb = new StringBuilder(24);
51 | sb.Append("{X:");
52 | sb.Append(this.x);
53 | sb.Append(" Y:");
54 | sb.Append(this.y);
55 | sb.Append("}");
56 | return sb.ToString();
57 | }
58 |
59 | #region operators
60 |
61 | public static Vector2Int operator -(Vector2Int value) {
62 | value.x = -value.x;
63 | value.y = -value.y;
64 | return value;
65 | }
66 |
67 |
68 | public static bool operator ==(Vector2Int value1, Vector2Int value2) {
69 | return value1.x == value2.x && value1.y == value2.y;
70 | }
71 |
72 |
73 | public static bool operator !=(Vector2Int value1, Vector2Int value2) {
74 | return value1.x != value2.x || value1.y != value2.y;
75 | }
76 |
77 |
78 | public static Vector2Int operator +(Vector2Int value1, Vector2Int value2) {
79 | value1.x += value2.x;
80 | value1.y += value2.y;
81 | return value1;
82 | }
83 |
84 |
85 | public static Vector2Int operator -(Vector2Int value1, Vector2Int value2) {
86 | value1.x -= value2.x;
87 | value1.y -= value2.y;
88 | return value1;
89 | }
90 |
91 |
92 | public static Vector2Int operator *(Vector2Int value1, Vector2Int value2) {
93 | value1.x *= value2.x;
94 | value1.y *= value2.y;
95 | return value1;
96 | }
97 |
98 |
99 | public static Vector2Int operator *(Vector2Int value, int scaleFactor) {
100 | value.x *= scaleFactor;
101 | value.y *= scaleFactor;
102 | return value;
103 | }
104 |
105 |
106 | public static Vector2Int operator *(int scaleFactor, Vector2Int value) {
107 | value.x *= scaleFactor;
108 | value.y *= scaleFactor;
109 | return value;
110 | }
111 |
112 |
113 | public static Vector2Int operator /(Vector2Int value1, Vector2Int value2) {
114 | value1.x /= value2.x;
115 | value1.y /= value2.y;
116 | return value1;
117 | }
118 |
119 |
120 | public static Vector2Int operator /(Vector2Int value1, int divider) {
121 | float factor = 1 / divider;
122 | value1.x = (int)(value1.x * factor);
123 | value1.y = (int)(value1.y * factor);
124 | return value1;
125 | }
126 |
127 | #endregion Operators
128 | }
129 |
--------------------------------------------------------------------------------
/Scripts/CameraShake.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System;
4 | using System.Collections.Generic;
5 |
6 | ///
7 | /// Adds a shaking effect to the camera which can be triggered through code. A random vector is
8 | /// added to the camera position on OnPreRender() if a shake is occuring.
9 | ///
10 | [RequireComponent(typeof(Camera))]
11 | public class CameraShake : MonoBehaviour {
12 |
13 | [Serializable]
14 | public class ShakeConfiguration {
15 | [Tooltip("The maximum distance the camera can move from its normal position while shaking.")]
16 | public float maxShakeDistance = 0.3f;
17 |
18 | [Tooltip("The time (in seconds) it takes for the camera to stop shaking.")]
19 | public float shakeTime = 1;
20 |
21 | [Tooltip("The strength of the camera shake over the course of its cooldown time.")]
22 | public AnimationCurve shakeDistanceOverTime = AnimationCurve.EaseInOut(0, 0, 1, 1);
23 | }
24 |
25 | public enum Intensity {
26 | Tiny,
27 | Gentle,
28 | Moderate,
29 | Heavy,
30 | Extreme,
31 | }
32 |
33 | public ShakeConfiguration tinyShake;
34 | public ShakeConfiguration gentleShake;
35 | public ShakeConfiguration moderateShake;
36 | public ShakeConfiguration heavyShake;
37 | public ShakeConfiguration extremeShake;
38 |
39 | public bool isShaking { get { return this.shakeCooldown > 0.05f; } }
40 |
41 | private Dictionary shakeConfigs;
42 | private Intensity lastIntensity;
43 | private ShakeConfiguration shakeConfig;
44 |
45 | private float shakeCooldown;
46 | private Vector3 lastShakeVector;
47 |
48 | private void Awake() {
49 | shakeConfigs = new Dictionary();
50 | shakeConfigs[Intensity.Tiny] = tinyShake;
51 | shakeConfigs[Intensity.Gentle] = gentleShake;
52 | shakeConfigs[Intensity.Moderate] = moderateShake;
53 | shakeConfigs[Intensity.Heavy] = heavyShake;
54 | shakeConfigs[Intensity.Extreme] = extremeShake;
55 | }
56 |
57 | ///
58 | /// Shakes the camera.
59 | ///
60 | public void Shake(Intensity intensity) {
61 | if (!isShaking || intensity > lastIntensity) {
62 | lastIntensity = intensity;
63 | shakeConfig = shakeConfigs[intensity];
64 | shakeCooldown = shakeConfig.shakeTime;
65 | }
66 | }
67 |
68 | ///
69 | /// Shakes all cameras in the scene.
70 | ///
71 | public static void ShakeAllCameras(Intensity intensity) {
72 | foreach (Camera camera in Camera.allCameras) {
73 | CameraShake shake = camera.GetComponent();
74 | if (shake != null) {
75 | shake.Shake(intensity);
76 | }
77 | }
78 | }
79 |
80 | private void Update() {
81 | if (isShaking) {
82 | shakeCooldown = Mathf.MoveTowards(shakeCooldown, 0, Time.unscaledDeltaTime);
83 | }
84 |
85 | // Debug shakes by holding R, T, Y, and then pressing a number from 1 to 5.
86 | if (Input.GetKey(KeyCode.R) && Input.GetKey(KeyCode.T) && Input.GetKey(KeyCode.Y)) {
87 | for (KeyCode key = KeyCode.Alpha1; key <= KeyCode.Alpha5; key++) {
88 | if (Input.GetKeyDown(key)) {
89 | Shake((Intensity)(int)(key - KeyCode.Alpha1));
90 | }
91 | }
92 | }
93 | }
94 |
95 | private void OnPreRender() {
96 | if (isShaking) {
97 | float shakePercent = shakeCooldown / shakeConfig.shakeTime;
98 | this.lastShakeVector = UnityEngine.Random.insideUnitSphere
99 | * shakeConfig.shakeDistanceOverTime.Evaluate(shakePercent)
100 | * shakeConfig.maxShakeDistance;
101 | this.transform.position += this.lastShakeVector;
102 | }
103 | }
104 |
105 | private void OnPostRender() {
106 | if (isShaking) {
107 | this.transform.position -= this.lastShakeVector;
108 | }
109 | }
110 | }
111 |
--------------------------------------------------------------------------------
/Scripts/Audio/SmoothLoopAudioSource.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using UnityEngine;
5 | using UnityEngine.Audio;
6 | using UnityEngine.SceneManagement;
7 |
8 | namespace QuickUnityTools.Audio {
9 |
10 | ///
11 | /// A special audio source that allows an audio clip to smoothly loop from some point other than the beginning of the song.
12 | ///
13 | public class SmoothLoopAudioSource : MonoBehaviour {
14 |
15 | private const int SECONDS_IN_MINUTE = 60;
16 |
17 | public SmoothLoopAudioClip music;
18 |
19 | public AudioMixerGroup mixerGroup {
20 | get { return _mixerGroup; }
21 | set {
22 | _mixerGroup = value;
23 | if (audioSources != null) {
24 | for (int i = 0; i < audioSources.Length; i++) {
25 | audioSources[i].outputAudioMixerGroup = mixerGroup;
26 | }
27 | }
28 | }
29 | }
30 | private AudioMixerGroup _mixerGroup;
31 |
32 | public float volume {
33 | get { return _volume; }
34 | set {
35 | _volume = value;
36 | if (audioSources != null) {
37 | foreach (AudioSource source in audioSources) { source.volume = value; }
38 | }
39 | }
40 | }
41 | private float _volume = 1;
42 |
43 | public bool isPlaying { get; private set; }
44 |
45 | private AudioSource[] audioSources;
46 | private float introTime { get { return ((music.beatsPerMeasure * music.introMeasures) / music.beatsPerMinute) * SECONDS_IN_MINUTE; } }
47 | private float loopTime { get { return music.length - introTime; } }
48 |
49 | private double startDpsTime;
50 | private int nextAudioSourceIndex;
51 | private int numberOfLoopsScheduled;
52 | private Timer loopTimer;
53 |
54 | private void Start() {
55 | audioSources = new AudioSource[2];
56 | for (int i = 0; i < audioSources.Length; i++) {
57 | audioSources[i] = gameObject.AddComponent();
58 | audioSources[i].clip = music.clip;
59 | audioSources[i].outputAudioMixerGroup = mixerGroup;
60 | audioSources[i].volume = volume;
61 | }
62 | }
63 |
64 | public void Play() {
65 | // Reset the play state.
66 | Stop();
67 | startDpsTime = AudioSettings.dspTime;
68 | isPlaying = true;
69 |
70 | // Play the full track once.
71 | audioSources[0].Play();
72 |
73 | // Schedule the track to play again from its looping position.
74 | audioSources[1].PlayScheduled(startDpsTime + music.length);
75 | audioSources[1].time = introTime;
76 |
77 | nextAudioSourceIndex = 0;
78 | numberOfLoopsScheduled = 1;
79 |
80 | // After the first run of the track finishes, schedule the second loop while the first loop is playing.
81 | loopTimer = this.RegisterTimer(music.length, ScheduleNextLoop);
82 | }
83 |
84 | public void Stop() {
85 | for (int i = 0; i < audioSources.Length; i++) {
86 | audioSources[i].Stop();
87 | }
88 | if (loopTimer != null) {
89 | loopTimer.Cancel();
90 | }
91 | isPlaying = false;
92 | }
93 |
94 | ///
95 | /// Schedules the next loop to play. When this function executes, the last scheduled loop
96 | /// should just be beginning to play.
97 | ///
98 | /// This method will call itself to schedule another loop after each loop finishes.
99 | ///
100 | private void ScheduleNextLoop() {
101 | audioSources[nextAudioSourceIndex].PlayScheduled(startDpsTime + music.length + loopTime * numberOfLoopsScheduled);
102 | audioSources[nextAudioSourceIndex].time = introTime;
103 |
104 | nextAudioSourceIndex = (nextAudioSourceIndex + 1) % audioSources.Length;
105 | numberOfLoopsScheduled++;
106 |
107 | loopTimer = this.RegisterTimer(loopTime, ScheduleNextLoop);
108 | }
109 | }
110 | }
--------------------------------------------------------------------------------
/Scripts/Audio/MusicPlayer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using UnityEngine.Audio;
4 | using System;
5 |
6 | namespace QuickUnityTools.Audio {
7 | ///
8 | /// A class for managing the currently playing song.
9 | ///
10 | [ResourceSingleton("MusicPlayer")]
11 | [Obsolete("The MusicPlayerStack is the newer version of this class.")]
12 | public class MusicPlayer : Singleton {
13 |
14 | public AudioSource currentAudio { get; private set; }
15 | private AudioSource fadeOutAudio = null;
16 | private bool isFadingOutAudioClip { get { return this.fadeOutAudio != null; } }
17 |
18 | public AudioMixerGroup musicMixerGroup;
19 | public float fadeInRate = 0.25f;
20 | public float fadeOutRate = 0.5f;
21 | public float musicVolume {
22 | get { return this._musicVolume; }
23 | set {
24 | this._musicVolume = value;
25 | this.currentAudio.volume = this._musicVolume;
26 | this.fadeOutAudio.volume = 0;
27 | }
28 | }
29 | private float _musicVolume = 0.45f;
30 |
31 | private void Update() {
32 | if (this.fadeOutAudio != null) {
33 | // If the old audio is not null, fade it out.
34 | if (this.fadeOutAudio.volume > 0.1f * this.musicVolume) {
35 | this.fadeOutAudio.volume -= fadeOutRate * this.musicVolume * Time.deltaTime;
36 | } else {
37 | // Destroy audio once we are done fading it out.
38 | GameObject.Destroy(fadeOutAudio);
39 | this.fadeOutAudio = null;
40 | }
41 | }
42 |
43 | if (this.currentAudio != null) {
44 | // If the current audio is low volume, turn it up!
45 | if (this.currentAudio.volume < this.musicVolume) {
46 | this.currentAudio.volume = Mathf.MoveTowards(this.currentAudio.volume, this.musicVolume, this.fadeInRate * Time.deltaTime);
47 | }
48 | }
49 | }
50 |
51 | ///
52 | /// Pass null to fade out current music.
53 | ///
54 | public void TransitionToMusic(AudioClip newMusic) {
55 | // Don't transition if the music is the same.
56 | if (this.currentAudio != null && this.currentAudio.clip == newMusic) {
57 | return;
58 | }
59 |
60 | // Always fade out the current music.
61 | bool musicWasPlayingBeforeTransition = this.currentAudio != null;
62 | if (this.currentAudio != null) {
63 | this.BeginMusicFadeOut();
64 | }
65 |
66 | // Don't play any new music if none is specified.
67 | if (newMusic == null) {
68 | return;
69 | }
70 |
71 | // Play the new audio.
72 | this.currentAudio = this.gameObject.AddComponent();
73 | this.currentAudio.clip = newMusic;
74 | this.currentAudio.Play();
75 | this.currentAudio.outputAudioMixerGroup = musicMixerGroup;
76 | this.currentAudio.loop = true;
77 |
78 | if (musicWasPlayingBeforeTransition) {
79 | // Fade in the new music.
80 | this.currentAudio.volume = 0.1f * this.musicVolume;
81 | }
82 | }
83 |
84 | ///
85 | /// Fades out the current music.
86 | ///
87 | public void FadeOutMusic() {
88 | this.TransitionToMusic(null);
89 | }
90 |
91 | ///
92 | /// Stops the current music without fading it out.
93 | ///
94 | public void StopMusic() {
95 | if (this.currentAudio != null) {
96 | GameObject.Destroy(this.currentAudio);
97 | this.currentAudio = null;
98 | }
99 | if (this.isFadingOutAudioClip) {
100 | // Destroy the previous audio clip that hasn't finished fading out.
101 | GameObject.Destroy(this.fadeOutAudio);
102 | this.fadeOutAudio = null;
103 | }
104 | }
105 |
106 | private void BeginMusicFadeOut() {
107 | if (this.isFadingOutAudioClip) {
108 | // Destroy the previous audio clip that hasn't finished fading out.
109 | GameObject.Destroy(this.fadeOutAudio);
110 | this.fadeOutAudio = null;
111 | }
112 | this.fadeOutAudio = this.currentAudio;
113 | this.currentAudio = null;
114 | }
115 | }
116 | }
117 |
--------------------------------------------------------------------------------
/Scripts/Singleton/Singleton.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 |
4 | ///
5 | /// Global Singletons are created when needed.
6 | /// They are never initially present in a scene, and are lazily spawned.
7 | /// They belong to DontDestroyOnLoad and persist forever.
8 | ///
9 | public class Singleton : MonoBehaviour where T : MonoBehaviour {
10 | private static T _instance;
11 |
12 | private static object _lock = new object();
13 |
14 | public static T instance {
15 | get {
16 | if (applicationIsQuitting) {
17 | Debug.LogWarning("[Singleton] Instance '" + typeof(T) +
18 | "' already destroyed on application quit." +
19 | " Won't create again - returning null.");
20 | return null;
21 | }
22 |
23 | lock (_lock) {
24 | if (_instance == null) {
25 | _instance = (T)FindObjectOfType(typeof(T));
26 |
27 | if (FindObjectsOfType(typeof(T)).Length > 1) {
28 | Debug.LogError("[Singleton] Something went really wrong " +
29 | " - there should never be more than 1 singleton!" +
30 | " Reopening the scene might fix it.");
31 | return _instance;
32 | }
33 |
34 | if (_instance == null) {
35 | // Check if the ResourceSingletonAttribute is present...
36 | ResourceSingletonAttribute resource = null;
37 | object[] attributes = typeof(T).GetCustomAttributes(false);
38 | foreach (System.Attribute attribute in attributes) {
39 | resource = attribute as ResourceSingletonAttribute;
40 | if (resource != null) {
41 | break;
42 | }
43 | }
44 |
45 | if (resource != null) {
46 | // Load a prefab that contains this singleton.
47 | GameObject prefab = Resources.Load(resource.resourceFilePath);
48 | if (prefab == null) {
49 | Debug.LogError("The Resource Singleton " + typeof(T) + " was not found in any resources folder!");
50 | return null;
51 | }
52 | GameObject singleton = GameObject.Instantiate(prefab);
53 | singleton.name = "(Resource Global Singleton) " + singleton.name;
54 | _instance = singleton.GetComponent();
55 | if (_instance == null) {
56 | Debug.LogError("A prefab was loaded for the singleton, but the component was not on it!");
57 | } else {
58 | DontDestroyOnLoad(singleton);
59 | Debug.Log("[Singleton] An instance of " + typeof(T) +
60 | " is needed in the scene, so '" + singleton +
61 | "' was loaded as a prefab with DontDestroyOnLoad.");
62 | }
63 | } else {
64 | // Create a singleton component in the world.
65 | GameObject singleton = new GameObject();
66 | _instance = singleton.AddComponent();
67 | singleton.name = "(Global Singleton) " + typeof(T).ToString();
68 | DontDestroyOnLoad(singleton);
69 | Debug.Log("[Singleton] An instance of " + typeof(T) +
70 | " is needed in the scene, so '" + singleton +
71 | "' was created with DontDestroyOnLoad.");
72 | }
73 | } else {
74 | Debug.Log("[Singleton] Using instance already created: " +
75 | _instance.gameObject.name);
76 | }
77 | }
78 |
79 | return _instance;
80 | }
81 | }
82 | }
83 |
84 | private static bool applicationIsQuitting = false;
85 | ///
86 | /// When Unity quits, it destroys objects in a random order.
87 | /// In principle, a Singleton is only destroyed when application quits.
88 | /// If any script calls Instance after it have been destroyed,
89 | /// it will create a buggy ghost object that will stay on the Editor scene
90 | /// even after stopping playing the Application. Really bad!
91 | /// So, this was made to be sure we're not creating that buggy ghost object.
92 | ///
93 | public void OnDestroy() {
94 | applicationIsQuitting = true;
95 | }
96 | }
--------------------------------------------------------------------------------
/Scripts/TrackerCameraMovement.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System;
6 |
7 | ///
8 | /// Moves the camera to track multiple targets.
9 | ///
10 | public class TrackerCameraMovement : MonoBehaviour {
11 |
12 | protected static List EMPTY_LIST = new List();
13 |
14 | // Inspector Fields
15 | public float minDistanceBetweenPlayers = 3f;
16 | public float maxDistanceBetweenPlayers = 20f;
17 |
18 | public float minCameraSize = 5;
19 | public float maxCameraSize = 10;
20 |
21 | public float minDistanceFromWorld = 20;
22 | public float maxDistanceFromWorld = 50;
23 |
24 | public float cameraDriftLerp = 1f;
25 | public float acceleration = 12;
26 |
27 | public Vector3 cameraOffset;
28 | public List additionalCameraTargets;
29 |
30 | // Public Properties
31 | public Func limitCameraMovement;
32 | public float speed { get; set; }
33 |
34 | // Private / Protected Properties
35 | protected Camera myCamera;
36 | protected Transform lockedTransform;
37 | protected bool isLocked;
38 |
39 |
40 | protected virtual void Awake() {
41 | this.myCamera = this.GetComponent();
42 | }
43 |
44 | protected virtual void FixedUpdate() {
45 | float desiredSize = this.myCamera.orthographicSize;
46 | Vector3 desired = this.transform.position;
47 |
48 | // Find the desired position for the camera...
49 | if (this.GetGameObjectsToTrack().Count() > 0 || this.additionalCameraTargets.Count > 0) {
50 | desired = this.CalculatePlayerFocusCameraSettings(out desiredSize);
51 | }
52 | if (this.limitCameraMovement != null) {
53 | desired = this.limitCameraMovement(desired);
54 | }
55 | if (this.isLocked) {
56 | desired = this.lockedTransform.position;
57 | }
58 |
59 | // Clamp the desired movement by the speed and handle acceleration.
60 | Vector3 desiredMovement = (desired - this.transform.position) * cameraDriftLerp;
61 | if (desiredMovement.sqrMagnitude > this.speed.Sqr()) {
62 | float length = desiredMovement.magnitude;
63 | speed = Mathf.MoveTowards(this.speed, length, this.acceleration * Time.fixedDeltaTime);
64 | desiredMovement = desiredMovement * speed / length;
65 | } else {
66 | speed = desiredMovement.magnitude;
67 | }
68 |
69 | // Change the camera movement.
70 | this.transform.position += desiredMovement * Time.fixedDeltaTime;
71 | this.myCamera.orthographicSize += (desiredSize - this.myCamera.orthographicSize) * this.cameraDriftLerp * Time.fixedDeltaTime;
72 | }
73 |
74 | public virtual IEnumerable GetGameObjectsToTrack() {
75 | return EMPTY_LIST;
76 | }
77 |
78 | public Vector3 CalculateDesiredPosition() {
79 | float _orthoSize;
80 | return CalculatePlayerFocusCameraSettings(out _orthoSize);
81 | }
82 |
83 | public virtual void LockTransform(Transform lockedTransform, bool snap = false) {
84 | this.isLocked = true;
85 | this.lockedTransform = lockedTransform;
86 | if (snap) {
87 | this.transform.position = lockedTransform.transform.position;
88 | this.transform.rotation = lockedTransform.transform.rotation;
89 | }
90 | }
91 |
92 | public virtual void UnlockTransform() {
93 | this.isLocked = false;
94 | }
95 |
96 | private Vector3 CalculatePlayerFocusCameraSettings(out float orthoSize) {
97 | IEnumerable ps = this.GetGameObjectsToTrack().Concat(this.additionalCameraTargets);
98 | if (ps.Count() == 0) {
99 | orthoSize = this.GetComponent().orthographicSize;
100 | return this.transform.position;
101 | }
102 |
103 | Vector3 min = new Vector3(ps.Min(p => p.transform.position.x),
104 | ps.Min(p => p.transform.position.y),
105 | ps.Min(p => p.transform.position.z));
106 | Vector3 max = new Vector3(ps.Max(p => p.transform.position.x),
107 | ps.Max(p => p.transform.position.y),
108 | ps.Max(p => p.transform.position.z));
109 |
110 | float dist = (min - max).magnitude;
111 | float percentDistance = Mathf.InverseLerp(minDistanceBetweenPlayers, maxDistanceBetweenPlayers, dist);
112 |
113 | float useDist = Mathf.Lerp(minDistanceFromWorld, maxDistanceFromWorld, percentDistance);
114 | orthoSize = Mathf.Lerp(minCameraSize, maxCameraSize, percentDistance);
115 |
116 | Vector3 center = (min + max) / 2;
117 | return center - this.transform.forward * useDist + this.cameraOffset;
118 | }
119 | }
120 |
--------------------------------------------------------------------------------
/Scripts/Audio/AmbientSounds.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using UnityEngine;
6 | using UnityEngine.Audio;
7 | using UnityEngine.SceneManagement;
8 |
9 | namespace QuickUnityTools.Audio {
10 | public class AmbientSounds : ServiceMonoBehaviour {
11 |
12 | [Serializable]
13 | public class AmbientSound {
14 | public AudioClip clip;
15 | public float volume = 1;
16 | public bool fadeIn = true;
17 | public AudioSource existingSource;
18 | }
19 |
20 | public AmbientSound[] soundsInScene;
21 | public AudioMixerGroup mixerGroup;
22 |
23 | private void Awake() {
24 | AmbientSoundManager.instance.Initalize(this);
25 | }
26 |
27 | protected override void OnEnable() {
28 | base.OnEnable();
29 | AmbientSoundManager.instance.UpdateSounds(soundsInScene);
30 | }
31 |
32 | public void SetSounds(AmbientSound[] sounds) {
33 | soundsInScene = sounds;
34 | AmbientSoundManager.instance.UpdateSounds(sounds);
35 | }
36 |
37 | private class AmbientSoundManager : Singleton {
38 | private AudioMixerGroup mixerGroup;
39 | private float fadeTime = 1f;
40 | private Dictionary playingSounds = new Dictionary();
41 | private List soundFades = new List();
42 | private bool initalized = false;
43 |
44 | public void Initalize(AmbientSounds soundGroup) {
45 | if (!initalized) {
46 | mixerGroup = soundGroup.mixerGroup;
47 | UpdateSounds(soundGroup.soundsInScene);
48 | initalized = true;
49 | }
50 | }
51 |
52 | /**
53 | * This is the old way of triggering
54 | private void Awake() {
55 | SceneManager.activeSceneChanged += OnActiveSceneChanged;
56 | }
57 |
58 | private void OnActiveSceneChanged(Scene oldScene, Scene newScene) {
59 | var soundGroups = GameObject.FindObjectsOfType();
60 | if (soundGroups.Length > 1) {
61 | Debug.LogWarning("Duplicate ambient sounds in this scene! There should only be one.");
62 | }
63 | var sounds = soundGroups.FirstOrDefault();
64 | UpdateSounds(sounds != null ? sounds.soundsInScene : new AmbientSound[0]);
65 | }
66 | */
67 |
68 | public void UpdateSounds(AmbientSound[] newSounds) {
69 | CancelPreviousFades();
70 |
71 | // Create sources or update sources for the sounds in the new set.
72 | foreach (AmbientSound sound in newSounds) {
73 | if (!playingSounds.ContainsKey(sound.clip)) {
74 | var newSource = sound.existingSource != null ? sound.existingSource : new GameObject(sound.clip.name).AddComponent();
75 | newSource.transform.parent = this.transform;
76 | newSource.clip = sound.clip;
77 | newSource.volume = sound.fadeIn ? 0 : sound.volume;
78 | newSource.loop = true;
79 | newSource.outputAudioMixerGroup = mixerGroup;
80 | newSource.Play();
81 | playingSounds[sound.clip] = newSource;
82 | }
83 | var source = playingSounds[sound.clip];
84 | if (source.volume != sound.volume) {
85 | FadeTowardsVolume(source, sound.volume);
86 | }
87 | }
88 |
89 | // Remove sounds that are not in the new set.
90 | var soundsNotInScene = playingSounds.Where(playingSound => !newSounds.Any(newSound => newSound.clip == playingSound.Key)).Select(s => s.Value);
91 | foreach (AudioSource source in soundsNotInScene.ToArray()) {
92 | source.gameObject.AddComponent();
93 | playingSounds.Remove(source.clip);
94 | }
95 | }
96 |
97 | private void FadeTowardsVolume(AudioSource source, float volume) {
98 | soundFades.Add(StartCoroutine(FadeSourceVolumeRoutine(source, volume, fadeTime)));
99 | }
100 |
101 | private IEnumerator FadeSourceVolumeRoutine(AudioSource source, float targetVolume, float fadeTime) {
102 | float originalVolume = source.volume;
103 | float startTime = Time.time;
104 | while (Time.time - startTime < fadeTime) {
105 | source.volume = Mathf.Lerp(originalVolume, targetVolume, (Time.time - startTime) / fadeTime);
106 | yield return null;
107 | }
108 | source.volume = targetVolume;
109 | }
110 |
111 | private void CancelPreviousFades() {
112 | foreach (var fade in soundFades) {
113 | StopCoroutine(fade);
114 | }
115 | }
116 | }
117 | }
118 | }
--------------------------------------------------------------------------------
/Scripts/Audio/SoundPlayer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using System.Collections.Generic;
4 | using UnityEngine.Audio;
5 | using System;
6 |
7 | namespace QuickUnityTools.Audio {
8 |
9 | ///
10 | /// A class for quickly importing and playing one-off sounds.
11 | ///
12 | [ResourceSingleton("SoundPlayer")]
13 | public class SoundPlayer : Singleton {
14 |
15 | public AudioMixerGroup soundMixerGroup;
16 |
17 | private Dictionary loadedSounds = new Dictionary();
18 |
19 | public AudioSource PlayVaried(AudioClip soundName, float spread = 0.3f) {
20 | AudioSource source = this.Play(soundName);
21 | source.pitch += UnityEngine.Random.Range(-spread / 2, spread / 2);
22 | return source;
23 | }
24 |
25 | public AudioSource Play(AudioClip clip, float volume = 1) {
26 | return this.Play(clip, this.transform.position, volume);
27 | }
28 |
29 | public AudioSource Play(AudioClip clip, Vector3 position, float volume = 1, float spatialBlend = 0) {
30 | return this.PlayOneOff(clip, position, volume, spatialBlend);
31 | }
32 |
33 | public AudioSource PlayLooped(AudioClip clip, Vector3 position) {
34 | AudioSource source = this.CreateAudioObject(clip, position);
35 | source.loop = true;
36 | source.Play();
37 | return source;
38 | }
39 |
40 | private AudioSource PlayOneOff(AudioClip clip, Vector3 position, float volume = 1, float spatialBlend = 0) {
41 | if (clip == null) {
42 | Debug.LogWarning("Audio clip is not assigned to a value!");
43 | return null;
44 | }
45 |
46 | AudioSource audioSource = this.CreateAudioObject(clip, position);
47 | audioSource.volume = volume;
48 | audioSource.spatialBlend = spatialBlend;
49 | audioSource.outputAudioMixerGroup = this.soundMixerGroup;
50 |
51 | audioSource.Play();
52 |
53 | Timer.Register(clip.length + 0.1f, () => {
54 | if (audioSource != null) {
55 | GameObject.Destroy(audioSource.gameObject);
56 | }
57 | }, false, true);
58 | return audioSource;
59 | }
60 |
61 | private AudioSource CreateAudioObject(AudioClip clip, Vector3 position) {
62 | GameObject soundGameObject = new GameObject("AudioSource (Temp)");
63 | soundGameObject.transform.position = position;
64 | AudioSource audioSource = soundGameObject.AddComponent();
65 | audioSource.clip = clip;
66 | return audioSource;
67 | }
68 |
69 | [Obsolete]
70 | public AudioSource Play(string soundName) {
71 | return this.Play(this.LookUpAudioClip(soundName));
72 | }
73 |
74 | [Obsolete]
75 | public AudioSource PlayVaried(string soundName, float spread = 0.3f) {
76 | return this.PlayVaried(this.LookUpAudioClip(soundName), spread);
77 | }
78 |
79 | ///
80 | /// Looks up an audio clip and loads it into memory.
81 | /// Currently, there's no way of unloading this clip in the API.
82 | ///
83 | private AudioClip LookUpAudioClip(string soundName) {
84 | if (loadedSounds.ContainsKey(soundName)) {
85 | return this.loadedSounds[soundName];
86 | } else {
87 | AudioClip clip = Resources.Load(soundName);
88 | if (clip == null) {
89 | Debug.LogWarning("Tried to play sound from string, but failed: " + soundName);
90 | return null;
91 | } else {
92 | this.loadedSounds.Add(soundName, clip);
93 | return clip;
94 | }
95 | }
96 | }
97 | }
98 |
99 | public static class Volume {
100 |
101 | public enum Channel {
102 | Master,
103 | Music,
104 | Ambience,
105 | SoundEffects,
106 | }
107 |
108 | private static float GetDefaultChannelDB(Channel channel) {
109 | switch (channel) {
110 | case Channel.Master: return -6;
111 | case Channel.Music: return -5;
112 | }
113 | return 0;
114 | }
115 |
116 | public static void SetVolume(Channel channel, float percent) {
117 | float normal = GetDefaultChannelDB(channel);
118 | SetVolume(channel.ToString() + "Volume", percent, normal);
119 | }
120 |
121 | private static void SetVolume(string parameter, float percent, float normal) {
122 | float a = (-80 - normal) / Mathf.Log(0.01f);
123 | float db = a * Mathf.Log(Mathf.Max(0.01f, percent)) + normal;
124 | SoundPlayer.instance.soundMixerGroup.audioMixer.SetFloat(parameter, db);
125 | }
126 |
127 | public static float GetVolume(Channel channel) {
128 | string parameter = channel.ToString() + "Volume";
129 |
130 | float db;
131 | SoundPlayer.instance.soundMixerGroup.audioMixer.GetFloat(parameter, out db);
132 |
133 | float normal = GetDefaultChannelDB(channel);
134 | float a = (-80 - normal) / Mathf.Log(0.01f);
135 | float percent = Mathf.Exp((db - normal) / a);
136 | return percent;
137 | }
138 | }
139 |
140 | public static class SoundPlayerExtensions {
141 | public static AudioSource Play(this AudioClip clip) {
142 | return SoundPlayer.instance.Play(clip);
143 | }
144 | }
145 | }
--------------------------------------------------------------------------------
/Scripts/Physics/NavigatorMovement.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections;
3 | using UnityEngine.AI;
4 | using System;
5 |
6 | ///
7 | /// A physics movement rigidbody that follows the nav mesh.
8 | ///
9 | public class NavigatorMovement : PhysicsMovement {
10 |
11 | private NavMeshNavigator navigator;
12 |
13 | private void Start() {
14 | navigator = gameObject.AddComponent();
15 | }
16 |
17 | public void SetGoal(Vector3 goal) {
18 | navigator.SetGoal(goal);
19 | }
20 |
21 | public override Vector3 GetDesiredMovementVector() {
22 | return navigator.GetMovementDirection();
23 | }
24 | }
25 |
26 | ///
27 | /// Uses the nav mesh to calculate the direction the object should move.
28 | /// This direction can be retrieved by calling .
29 | ///
30 | public class NavMeshNavigator : MonoBehaviour {
31 | public float successDistance = 0.7f;
32 | public bool enableMovement = true;
33 | public RandomRange repathTimeout = new RandomRange(0.25f, 1f);
34 |
35 | public bool hasGoal { get { return this.goal.HasValue; } }
36 | public bool hasValidPath { get { return this.currentPath != null && this.currentPath.status != UnityEngine.AI.NavMeshPathStatus.PathInvalid; } }
37 | public Vector3 destinationNode { get { return this.currentPath.corners[pathNode]; } }
38 | public Vector3? goal { get; private set; }
39 | public event Action onGoalReached;
40 | public event Action onBeforeCalculationTimeout;
41 |
42 | protected NavMeshPath currentPath { get; private set; }
43 | protected int pathNode { get; private set; }
44 | private float recalculateTimer = 0.1f;
45 | private NavMeshPath cachedReusablePath;
46 |
47 | private void Awake() {
48 | cachedReusablePath = new NavMeshPath();
49 | }
50 |
51 | protected virtual void Update() {
52 | if (this.enableMovement) {
53 | this.recalculateTimer -= Time.deltaTime;
54 | if (this.recalculateTimer <= 0) {
55 | this.OnCalculationTimeout();
56 | this.recalculateTimer = this.GetRecalculationTime(); // Distribute pathfinding more evenly.
57 | }
58 |
59 | if (this.hasGoal) {
60 | if (this.hasValidPath) {
61 | float distToGoal = (this.destinationNode - this.transform.position).SetY(0).magnitude;
62 | if (distToGoal < this.successDistance) {
63 | this.SelectNextNode();
64 | }
65 | } else if ((this.goal.Value - this.transform.position).SetY(0).magnitude < this.successDistance) {
66 | this.ReachGoal();
67 | }
68 | }
69 | }
70 | }
71 |
72 | protected virtual void OnCalculationTimeout() {
73 | if (onBeforeCalculationTimeout != null) {
74 | onBeforeCalculationTimeout();
75 | }
76 | if (this.hasGoal) {
77 | this.RecalculatePath();
78 | }
79 | }
80 |
81 | ///
82 | /// Returns the direction this object should move to follow the path.
83 | ///
84 | public Vector3 GetMovementDirection() {
85 | if (this.hasValidPath) {
86 | return (this.destinationNode - this.transform.position).SetY(0).normalized;
87 | }
88 | return Vector3.zero;
89 | }
90 |
91 | ///
92 | /// Paths to the given goal on the goal update event.
93 | ///
94 | public void SetGoal(Vector3 goal) {
95 | this.goal = goal;
96 | }
97 |
98 | ///
99 | /// Paths to the given goal and immediately repaths.
100 | ///
101 | public void SetGoalImmediately(Vector3 goal) {
102 | SetGoal(goal);
103 | RecalculatePath();
104 | }
105 |
106 | public void ClearGoal() {
107 | this.goal = null;
108 | this.currentPath = null;
109 | }
110 |
111 | private void ReachGoal() {
112 | ClearGoal();
113 | if (onGoalReached != null) {
114 | onGoalReached();
115 | }
116 | }
117 |
118 | public float GetDistanceToGoal() {
119 | if (!hasValidPath) {
120 | return 0;
121 | }
122 |
123 | float distance = (transform.position - destinationNode).magnitude;
124 | for (int i = pathNode; i < currentPath.corners.Length - 1; i++) {
125 | distance += (currentPath.corners[i + 1] - currentPath.corners[i]).magnitude;
126 | }
127 | return distance;
128 | }
129 |
130 | private void SelectNextNode() {
131 | this.pathNode++;
132 | if (this.pathNode >= this.currentPath.corners.Length) {
133 | this.ReachGoal();
134 | }
135 | }
136 |
137 | private void RecalculatePath() {
138 | NavMesh.CalculatePath(this.transform.position, goal.Value, int.MaxValue, cachedReusablePath);
139 | this.currentPath = cachedReusablePath;
140 | this.pathNode = Mathf.Min(1, currentPath.corners.Length - 1);
141 | }
142 |
143 | private float GetRecalculationTime() {
144 | return repathTimeout.Random();
145 | }
146 |
147 | protected virtual void OnDrawGizmos() {
148 | if (this.hasValidPath) {
149 | for (int i = 1; i < this.currentPath.corners.Length; i++) {
150 | Gizmos.DrawLine(this.currentPath.corners[i - 1], this.currentPath.corners[i]);
151 | }
152 | Gizmos.color = Color.red;
153 | Gizmos.DrawWireSphere(this.destinationNode, this.successDistance);
154 | }
155 |
156 | if (this.hasGoal) {
157 | Gizmos.color = Color.green;
158 | Gizmos.DrawWireCube(this.goal.Value, Vector3.one * 1.4f);
159 | }
160 | }
161 | }
--------------------------------------------------------------------------------
/Scripts/Editor/CustomMenuItems.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 | using System.Linq;
4 | using System.Collections.Generic;
5 |
6 | ///
7 | /// A collection of useful shortcuts for manipulating the hierarchy.
8 | /// Some of this was written by me, some of it was collected from random Unity
9 | /// forums and StackOverflow posts.
10 | ///
11 | public class CustomMenuItems {
12 | [MenuItem("GameObject/Hierarchy/Select First Child Each", false, 10)]
13 | private static void SelectChildren() {
14 | Object[] newSelection = Selection.gameObjects.Select(obj => obj.transform.childCount > 0 ? obj.transform.GetChild(0).gameObject : obj).Cast