├── .gitattributes
├── ScriptableObjects
├── Readme
├── EnemyBase.cs
├── Color SOs
│ ├── ColorData.cs
│ ├── PanelBackgroundColor.cs
│ └── ColorReference.cs
├── EnemyData.cs
├── EnemyManager.cs
└── EnemyControl.cs
├── Inspector Groups
├── Readme
├── Columns.cs
├── Tabs.cs
└── Grouping.cs
├── Custom Validator Scripts
├── Plant.cs
├── Plant.cs.meta
├── TestClass.cs.meta
├── PlantValidator.cs.meta
├── EmptyStringValidator.cs.meta
├── SpriteSizeAttribute.cs.meta
├── NeedsComponentAttribute.cs.meta
├── TestClass.cs
├── EmptyStringValidator.cs
├── NeedsComponentAttribute.cs
├── SpriteSizeAttribute.cs
└── PlantValidator.cs
├── First Custom Inspector
├── Readme.txt
└── GameManager.cs
├── AttributeDrawers
├── MyColorAttribute.cs
├── MyClass.cs
├── Vector2SliderAttribute.cs
└── Editor
│ ├── Vector2SliderAttributeDrawer.cs
│ └── MyColorAttributeDrawer.cs
├── Composite Attributes
├── PreFabAssetList.cs
├── PropertyOnly.cs
├── PropertyKeyWordExample.cs
├── TextureView.cs
├── StatsObject.cs
└── Stats.cs
├── Shorts
├── TabGroup.meta
├── Button Attribute.meta
├── Color Palette.meta
├── TabGroup
│ ├── CharacterTabExample.cs.meta
│ └── CharacterTabExample.cs
├── Color Palette
│ ├── ColorPaletteExamples.cs.meta
│ └── ColorPaletteExamples.cs
└── Button Attribute
│ ├── ButtonShortExamples.cs.meta
│ └── ButtonShortExamples.cs
├── README.md
├── Action Resolver
├── ActionButtonAttribute.cs
├── ActionButtonExample.cs
└── ActionButtonAttributeDrawer.cs
├── Struct Value Drawers
├── MyClass.cs
└── Editor
│ └── DateTimeDrawer.cs
├── 2D Character Creator
├── Editor
│ ├── CharacterEditor.cs.meta
│ └── CharacterEditor.cs
├── Character.cs
├── CharacterSpriteSettings.cs
└── CharacterSpriteData.cs
├── Custom Attribute Processors
├── Stats.cs
├── Character.cs
└── CharacterAttributeProcessor.cs
├── SFX Manager
├── PlaySFXExample.cs
├── SFXClip.cs
├── SFXManager.cs
└── SFX.cs
├── Class Value Drawers
├── MyClass.cs
└── Editor
│ └── MySubClassDrawer.cs
├── Value Resolver
├── ColorIfExample.cs
├── ColorIfAttributeDrawer.cs
└── ColorIfAttribute.cs
├── PropertyProcessors
├── SampleClass.cs
└── SamplePropertyProcessor.cs
├── The Manager Manager
├── ManagableAttribute.cs
└── Editor
│ ├── MBManager.cs
│ └── GUIUtils.cs
├── Data Manager
├── DataManager.cs
└── GUIUtils.cs
├── How I Use Odin
├── PlayerUnitValidator.cs
├── HelpfulButtons.cs
├── UnitUnlocakUpgradeWindow.cs
├── StatsUpgradeWindow.cs
├── ResourceSOCreator.cs
└── PatchNotes.cs
├── ScriptableObjectsWithOdin
├── EnemyData.cs
├── Editor
│ └── EnemyDataEditor.cs
└── EnemyControl.cs
├── Generic Matching
├── NPCBase.cs
└── NPCStats.cs
├── CustomGroups
└── MyClass.cs
└── THE Game Manager
└── TheGameManager.cs
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/ScriptableObjects/Readme:
--------------------------------------------------------------------------------
1 | These files are from the "scriptable object" tutorial video.
2 |
3 | Link: https://youtu.be/W5ECIJyoW80
4 |
--------------------------------------------------------------------------------
/Inspector Groups/Readme:
--------------------------------------------------------------------------------
1 | These files are from the "Creating Inspector Groups with Odin Inspector" video. The video can be found here: https://youtu.be/9AEEH67G-Vs
2 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/Plant.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | public class Plant : MonoBehaviour
6 | {
7 |
8 | }
9 |
--------------------------------------------------------------------------------
/First Custom Inspector/Readme.txt:
--------------------------------------------------------------------------------
1 | This folder contains the Game Manager script used in the "How to Create a Custom Inspector with Odin?"
2 |
3 | The video can be found at: https://youtu.be/UXYCTHf6MKY
--------------------------------------------------------------------------------
/AttributeDrawers/MyColorAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using System;
5 |
6 | public class MyColorAttribute : Attribute
7 | {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/Composite Attributes/PreFabAssetList.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector;
2 | using System;
3 |
4 | [IncludeMyAttributes]
5 | [AssetList(Path = "Prefabs")]
6 | public class PreFabAssetList : Attribute
7 | {
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/Shorts/TabGroup.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d68928357abcc2f4eb0de26edd8c30af
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Composite Attributes/PropertyOnly.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector;
2 | using System;
3 |
4 |
5 | [IncludeMyAttributes]
6 | [HideLabel]
7 | [InlineProperty]
8 | public class PropertyOnly : Attribute
9 | {
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/ScriptableObjects/EnemyBase.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | public abstract class EnemyBase : ScriptableObject
6 | {
7 | public abstract void DoTurn();
8 | }
9 |
--------------------------------------------------------------------------------
/Shorts/Button Attribute.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e95601394d742024897d2588f473e1af
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Shorts/Color Palette.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e4b05335151e4854bb850dc8e67cb65a
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Composite Attributes/PropertyKeyWordExample.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector;
2 | using System;
3 |
4 | [IncludeMyAttributes]
5 | [Title("@$property.NiceName")]
6 | public class PropertyKeyWordExample : Attribute
7 | {
8 |
9 | }
10 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | #SirenixTutorialFiles
2 |
3 | A collection of files used in recent (after Dec 19) Devdog Tutorial videos.
4 |
5 | All videos can be found on the Devdog YouTube channel.
6 |
7 | Link: https://www.youtube.com/channel/UCWpLqoOZdE5ZWZNonkBd9eA/
8 |
--------------------------------------------------------------------------------
/Action Resolver/ActionButtonAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | public class ActionButtonAttribute : Attribute
4 | {
5 | public string action;
6 |
7 | public ActionButtonAttribute (string action)
8 | {
9 | this.action = action;
10 | }
11 | }
12 |
13 |
14 |
--------------------------------------------------------------------------------
/Struct Value Drawers/MyClass.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using System;
5 | using Sirenix.OdinInspector;
6 |
7 | public class MyClass : MonoBehaviour
8 | {
9 | [ShowInInspector]
10 | public DateTime myDateTime;
11 | }
--------------------------------------------------------------------------------
/Composite Attributes/TextureView.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector;
2 | using System;
3 |
4 | [IncludeMyAttributes]
5 | [PreviewField(Alignment = ObjectFieldAlignment.Center, Height = 100)]
6 | [HideLabel]
7 | [AssetsOnly]
8 | public class TextureView : Attribute
9 | {
10 |
11 | }
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/ScriptableObjects/Color SOs/ColorData.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | [CreateAssetMenu(fileName = "ColorData", menuName = "My Game/Color Data")]
6 | public class ColorData : ScriptableObject
7 | {
8 | public Color colorValue;
9 | }
10 |
--------------------------------------------------------------------------------
/AttributeDrawers/MyClass.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | public class MyClass : MonoBehaviour
6 | {
7 | [Vector2Slider(0,20)]
8 | public Vector2 myVector2;
9 |
10 | [MyColor]
11 | public Color myColor;
12 |
13 | }
14 |
15 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/Plant.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 84300fa3fedec8a4bacd049071c208be
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/TestClass.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 2b9a587f5cf95594c926c0cbb3715cf7
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Shorts/TabGroup/CharacterTabExample.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ac620f805908f954d8de4a6abb20cfb9
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/PlantValidator.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: dcfa6de806f9a2d4db08d7125519b073
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Shorts/Color Palette/ColorPaletteExamples.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3160a361edb1c384c8fcf4a34dda9f82
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/2D Character Creator/Editor/CharacterEditor.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 8d4163024fba27c40b9911811df52184
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Custom Attribute Processors/Stats.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | [System.Serializable]
7 | public class Stats
8 | {
9 | public float stat1;
10 | public float stat2;
11 | public float stat3;
12 | public float stat4;
13 | }
14 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/EmptyStringValidator.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 17d0795dd5216f14d87bee7de63140cc
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/SpriteSizeAttribute.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b4e627cf8bd1d144e8198a7a6797863e
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/SFX Manager/PlaySFXExample.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | public class PlaySFXExample : MonoBehaviour
7 | {
8 | public SFX sfxToPlay;
9 |
10 | private void Start()
11 | {
12 | sfxToPlay.PlaySFX();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/Shorts/Button Attribute/ButtonShortExamples.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 895e6a275f11d7e4e9e98600446d3df0
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Composite Attributes/StatsObject.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | public class StatsObject : MonoBehaviour
7 | {
8 | [PropertyOnly]
9 | public Stats stats;
10 |
11 | [PreFabAssetList]
12 | public GameObject prefabList;
13 | }
14 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/NeedsComponentAttribute.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 48abf01db8c02a046aa131e684b8fd59
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Custom Attribute Processors/Character.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | public class Character : MonoBehaviour
6 | {
7 | public string characterName;
8 | public string description;
9 | public Texture2D icon;
10 | public GameObject prefab;
11 |
12 | public Stats stats;
13 | }
14 |
--------------------------------------------------------------------------------
/Class Value Drawers/MyClass.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 |
6 | public class MyClass : MonoBehaviour
7 | {
8 | public MySubClass mySubClass;
9 | }
10 |
11 | [System.Serializable]
12 | public class MySubClass
13 | {
14 | public string text;
15 | public int number;
16 | public Vector3 location;
17 | }
--------------------------------------------------------------------------------
/AttributeDrawers/Vector2SliderAttribute.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using System;
5 |
6 | public class Vector2SliderAttribute : Attribute
7 | {
8 | public float minValue;
9 | public float maxValue;
10 |
11 | public Vector2SliderAttribute(float min, float max)
12 | {
13 | this.minValue = min;
14 | this.maxValue = max;
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/Value Resolver/ColorIfExample.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | public class ColorIfExample : MonoBehaviour
7 | {
8 | [ColorIf("@Color.green", "HasEvenNumberOfCharacters")]
9 | public string greenIfEven;
10 |
11 | private bool HasEvenNumberOfCharacters()
12 | {
13 | return greenIfEven?.Length % 2 == 0;
14 | }
15 | }
16 |
17 |
18 |
--------------------------------------------------------------------------------
/Action Resolver/ActionButtonExample.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using Sirenix.OdinInspector;
3 |
4 | public class ActionButtonExample : MonoBehaviour
5 | {
6 | [ActionButton("DoAction")]
7 | public string someString;
8 |
9 | [ActionButton("@UnityEngine.Debug.Log(\"I did an action without a method!!!\")")]
10 | public string anotherString;
11 |
12 | private void DoAction()
13 | {
14 | Debug.Log("I did an action!");
15 | }
16 | }
17 |
18 |
19 |
20 |
--------------------------------------------------------------------------------
/PropertyProcessors/SampleClass.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | public class SampleClass : MonoBehaviour
6 | {
7 | public string top;
8 | public string middle;
9 | public string bottom;
10 |
11 | public int value1 = 1;
12 | public int value2 = 2;
13 | public int value3 = 3;
14 |
15 | }
16 |
17 | public enum MyEnum
18 | {
19 | zero,
20 | one,
21 | two,
22 | three,
23 | four
24 | }
25 |
--------------------------------------------------------------------------------
/ScriptableObjects/EnemyData.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | [CreateAssetMenu(fileName = "EnemyData", menuName = "My Game/Enemy Data")]
6 | public class EnemyData : ScriptableObject
7 | {
8 | public string enemyName;
9 | public string description;
10 | public GameObject enemyModel;
11 | public int health = 20;
12 | public float speed = 2f;
13 | public float detectRange = 10f;
14 | public int damage = 1;
15 | }
16 |
--------------------------------------------------------------------------------
/Inspector Groups/Columns.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | public class Columns : MonoBehaviour
7 | {
8 | [HorizontalGroup("Base", LabelWidth = 80)]
9 |
10 | [VerticalGroup("Base/Column 1")]
11 | public string a;
12 |
13 |
14 | [VerticalGroup("Base/Column 1")]
15 | public string b;
16 |
17 | [BoxGroup("Base/Column 2")]
18 | public string c;
19 | [BoxGroup("Base/Column 2")]
20 | public string d;
21 | }
22 |
--------------------------------------------------------------------------------
/The Manager Manager/ManagableAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | ///
4 | /// An attribute to mark monobehaviors so they
5 | /// can be imported into the MB manager editor window
6 | ///
7 | public class ManageableAttribute : Attribute
8 | {
9 | }
10 |
11 | ///
12 | /// An attribute to mark scriptable objects so they
13 | /// can be imported into the data manager editor window
14 | ///
15 | public class ManageableDataAttribute : Attribute
16 | {
17 | }
18 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/TestClass.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 | using UnityEngine.EventSystems;
6 |
7 | public class TestClass : MonoBehaviour
8 | {
9 | [NeedsComponent(typeof(Rigidbody))]
10 | public GameObject componentTest;
11 |
12 | [SpriteSize(100)]
13 | public Sprite sprite;
14 |
15 | [SpriteSize(SpriteSize.large)]
16 | public Sprite sprite2;
17 |
18 | //public List plantList = new List();
19 |
20 | }
21 |
22 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/EmptyStringValidator.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector.Editor.Validation;
2 |
3 | [assembly: RegisterValidator(typeof(EmptyStringValidator))]
4 |
5 | public class EmptyStringValidator : ValueValidator
6 | {
7 | protected override void Validate(ValidationResult result)
8 | {
9 | if (string.IsNullOrEmpty(this.ValueEntry.SmartValue))
10 | {
11 | result.ResultType = ValidationResultType.Warning;
12 | result.Message = "This string is empty! Are you sure that's correct?";
13 | }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ScriptableObjects/Color SOs/PanelBackgroundColor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 | using UnityEngine.UI;
6 |
7 | [RequireComponent(typeof(Image))]
8 | public class PanelBackgroundColor : MonoBehaviour
9 | {
10 | private Image panel;
11 | public ColorData color;
12 |
13 | private void AdjustColor(ColorReference _color)
14 | {
15 | if (panel == null)
16 | panel = this.GetComponent();
17 |
18 | panel.color = _color.Value;
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/Inspector Groups/Tabs.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | public class Tabs : MonoBehaviour
7 | {
8 | [TabGroup("Tab Group 1", "Tab 1")]
9 | public string A;
10 | [TabGroup("Tab Group 1", "Tab 1")]
11 | public string B;
12 |
13 | [TabGroup("Tab Group 1", "Tab 2")]
14 | public int C;
15 | [TabGroup("Tab Group 1", "Tab 2")]
16 | public int D;
17 |
18 | [BoxGroup("Box Group")]
19 | public int E;
20 |
21 | [BoxGroup("Tab Group 1/Tab 1/Sub Box Group")]
22 | public int F;
23 | }
24 |
--------------------------------------------------------------------------------
/SFX Manager/SFXClip.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | [CreateAssetMenu(menuName = "New SFX Clip", fileName = "NewSFXClip")]
7 | public class SFXClip : ScriptableObject
8 | {
9 | [Space]
10 | [Title("Audio Clip")]
11 | [Required]
12 | public AudioClip clip;
13 |
14 | [Title("Clip Settings")]
15 | [Range(0f, 1f)]
16 | public float volume = 1f;
17 | [Range(0f, 0.2f)]
18 | public float volumeVariation = 0.05f;
19 | [Range(0f, 2f)]
20 | public float pitch = 1f;
21 | [Range(0f, 0.2f)]
22 | public float pitchVariation = 0.05f;
23 | }
24 |
--------------------------------------------------------------------------------
/Shorts/Color Palette/ColorPaletteExamples.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using UnityEngine.UI;
5 | using Sirenix.OdinInspector;
6 |
7 | public class ColorPaletteExamples : MonoBehaviour
8 | {
9 | [OnValueChanged("AssignColor")]
10 | [ColorPalette(PaletteName = "MyColors")]
11 | public Color myColor;
12 |
13 | private SpriteRenderer mySprite;
14 |
15 | //[OnInspectorGUI]
16 | private void AssignColor()
17 | {
18 | if (mySprite == null)
19 | mySprite = this.GetComponent();
20 |
21 | mySprite.color = myColor;
22 |
23 | //force update in scene view
24 | UnityEditor.SceneView.RepaintAll();
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/Action Resolver/ActionButtonAttributeDrawer.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector.Editor;
2 | using Sirenix.OdinInspector.Editor.ActionResolvers;
3 | using UnityEngine;
4 |
5 | public class ActionButtonAttributeDrawer : OdinAttributeDrawer
6 | {
7 | private ActionResolver actionResolver;
8 |
9 | protected override void Initialize()
10 | {
11 | this.actionResolver = ActionResolver.Get(this.Property, this.Attribute.action);
12 | }
13 |
14 | protected override void DrawPropertyLayout (GUIContent label)
15 | {
16 | this.actionResolver.DrawError();
17 |
18 | if(GUILayout.Button("Perform Action"))
19 | {
20 | this.actionResolver.DoActionForAllSelectionIndices();
21 | }
22 |
23 | this.CallNextDrawer(label);
24 | }
25 | }
26 |
27 |
28 |
--------------------------------------------------------------------------------
/ScriptableObjects/EnemyManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 |
5 | public class EnemyManager : MonoBehaviour
6 | {
7 | public List enemyList = new List();
8 |
9 | private void DoEnemyTurns()
10 | {
11 | foreach (EnemyData enemy in enemyList)
12 | {
13 | if(enemy.enemyName == "Bob")
14 | {
15 | //do bob's turn
16 | }
17 | else if (enemy.enemyName == "Suzy")
18 | {
19 | //do suzy's turn
20 | }
21 | else if (enemy.enemyName == "Hank")
22 | {
23 | //do hank's turn
24 | }
25 | else if (enemy.enemyName == "WhyDidIDoItThisWay")
26 | {
27 | //do this guys's turn
28 | }
29 | }
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/NeedsComponentAttribute.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System;
3 | using Sirenix.OdinInspector.Editor.Validation;
4 |
5 | [assembly: RegisterValidator(typeof(NeedsComponentValidator))]
6 |
7 | public class NeedsComponentAttribute : Attribute
8 | {
9 | public Type type;
10 |
11 | public NeedsComponentAttribute(Type type)
12 | {
13 | this.type = type;
14 | }
15 | }
16 |
17 | public class NeedsComponentValidator : AttributeValidator
18 | {
19 | protected override void Validate(ValidationResult result)
20 | {
21 | if (this.ValueEntry.SmartValue == null)
22 | return;
23 |
24 | if (this.ValueEntry.SmartValue.GetComponent(this.Attribute.type) == null)
25 | {
26 | result.ResultType = ValidationResultType.Error;
27 | result.Message = "This Needs a " + this.Attribute.type.Name;
28 | }
29 | }
30 | }
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/Struct Value Drawers/Editor/DateTimeDrawer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.Utilities.Editor;
5 | using Sirenix.OdinInspector.Editor;
6 | using System;
7 |
8 | public class DateTimeDrawer : OdinValueDrawer
9 | {
10 | private string display;
11 | private object key = new object();
12 |
13 | protected override void DrawPropertyLayout(GUIContent label)
14 | {
15 | display = this.ValueEntry.SmartValue.ToString();
16 |
17 | SirenixEditorGUI.BeginShakeableGroup(key);
18 |
19 | display = SirenixEditorFields.TextField(label, display);
20 |
21 | if(DateTime.TryParse(display, out DateTime result))
22 | {
23 | this.ValueEntry.SmartValue = result;
24 | }
25 | else
26 | {
27 | SirenixEditorGUI.StartShakingGroup(key);
28 | }
29 |
30 | SirenixEditorGUI.EndShakeableGroup(key);
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/The Manager Manager/Editor/MBManager.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector.Editor;
2 | using System;
3 | using System.Linq;
4 | using UnityEditor;
5 |
6 | public class MBManager : OdinEditorWindow
7 | {
8 | private static Type[] typesToDisplay = TypeCache.GetTypesWithAttribute()
9 | .OrderBy(m => m.Name)
10 | .ToArray();
11 |
12 | private Type selectedType;
13 |
14 | [MenuItem("Tools/MB Manager")]
15 | private static void OpenEditor() => GetWindow();
16 |
17 | protected override void OnGUI()
18 | {
19 | GUIUtils.SelectButtonList(ref selectedType, typesToDisplay);
20 | base.OnGUI();
21 | }
22 |
23 | protected override object GetTarget()
24 | {
25 | if (selectedType == null && typesToDisplay.Length > 0)
26 | selectedType = typesToDisplay[0];
27 |
28 | if (selectedType == null)
29 | return null;
30 | else
31 | return FindObjectOfType(selectedType);
32 | }
33 | }
34 |
35 |
36 |
--------------------------------------------------------------------------------
/AttributeDrawers/Editor/Vector2SliderAttributeDrawer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.Utilities;
5 | using Sirenix.Utilities.Editor;
6 | using Sirenix.OdinInspector.Editor;
7 | using UnityEditor;
8 |
9 | public class Vector2SliderAttributeDrawer : OdinAttributeDrawer
10 | {
11 | protected override void DrawPropertyLayout(GUIContent label)
12 | {
13 | Rect rect = EditorGUILayout.GetControlRect();
14 |
15 | if(label != null)
16 | rect = EditorGUI.PrefixLabel(rect, label);
17 |
18 | Vector2 value = this.ValueEntry.SmartValue;
19 |
20 | GUIHelper.PushLabelWidth(20);
21 | value.x = EditorGUI.Slider(rect.AlignLeft(rect.width * 0.5f), "X", value.x,
22 | this.Attribute.minValue, this.Attribute.maxValue);
23 | value.y = EditorGUI.Slider(rect.AlignRight(rect.width * 0.5f), "Y", value.y,
24 | this.Attribute.minValue, this.Attribute.maxValue);
25 | GUIHelper.PopLabelWidth();
26 |
27 | this.ValueEntry.SmartValue = value;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Data Manager/DataManager.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector.Editor;
2 | using System;
3 | using System.Linq;
4 | using UnityEditor;
5 |
6 | public class DataManager : OdinMenuEditorWindow
7 | {
8 | private static Type[] typesToDisplay = TypeCache.GetTypesWithAttribute()
9 | .OrderBy(m => m.Name)
10 | .ToArray();
11 |
12 | private Type selectedType;
13 |
14 | [MenuItem("Tools/Data Manager")]
15 | private static void OpenEditor() => GetWindow();
16 |
17 | protected override void OnGUI()
18 | {
19 | //draw menu tree for SOs and other assets
20 | if (GUIUtils.SelectButtonList(ref selectedType, typesToDisplay))
21 | this.ForceMenuTreeRebuild();
22 |
23 | base.OnGUI();
24 | }
25 |
26 | protected override OdinMenuTree BuildMenuTree()
27 | {
28 | var tree = new OdinMenuTree();
29 | if(selectedType != null)
30 | tree.AddAllAssetsAtPath(selectedType.Name, "Assets/", selectedType, true, true);
31 | return tree;
32 | }
33 | }
34 |
35 |
36 |
37 |
--------------------------------------------------------------------------------
/Value Resolver/ColorIfAttributeDrawer.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using Sirenix.OdinInspector.Editor;
3 | using Sirenix.OdinInspector.Editor.ValueResolvers;
4 | using Sirenix.Utilities.Editor;
5 | public class ColorIfAttributeDrawer : OdinAttributeDrawer
6 | {
7 | private ValueResolver colorResolver;
8 | private ValueResolver conditionResolver;
9 |
10 | protected override void Initialize()
11 | {
12 | this.colorResolver = ValueResolver.Get(this.Property, this.Attribute.color, Color.white);
13 | this.conditionResolver = ValueResolver.Get(this.Property, this.Attribute.condition);
14 | }
15 |
16 | protected override void DrawPropertyLayout(GUIContent label)
17 | {
18 | ValueResolver.DrawErrors(this.colorResolver, this.conditionResolver);
19 |
20 | bool condition = this.conditionResolver.GetValue();
21 |
22 | if(condition)
23 | {
24 | GUIHelper.PushColor(this.colorResolver.GetValue());
25 | }
26 |
27 | this.CallNextDrawer(label);
28 |
29 | if(condition)
30 | {
31 | GUIHelper.PopColor();
32 | }
33 | }
34 | }
35 |
36 |
37 |
--------------------------------------------------------------------------------
/How I Use Odin/PlayerUnitValidator.cs:
--------------------------------------------------------------------------------
1 | #if UNITY_EDITOR
2 | using Sirenix.OdinInspector.Editor.Validation;
3 | using UnityEngine;
4 | using UnityEditor;
5 |
6 | [assembly: RegisterValidationRule(typeof(PlayerUnitValidator), Name = "PlayerUnitValidator")]
7 |
8 | public class PlayerUnitValidator : RootObjectValidator
9 | {
10 | protected override void Validate(ValidationResult result)
11 | {
12 | if (this.Object.gameObject.layer != 7 && this.Object.gameObject.layer != 9)
13 | result.AddError("Player Unit object is not on the player object layer.")
14 | .WithFix("Set Correct Layer =>", () => SetLayerToPlayerUnit(this.Object.gameObject), true);
15 |
16 | if (this.Object.GetComponent() == null)
17 | result.AddError("Player Unit does not have a collider.");
18 |
19 | if (this.Object.GetStat(Stat.sightDistance) <= 0.01f)
20 | result.AddError("Sight distance not set.")
21 | .WithFix(() => this.Object.GetStats().AddStat(Stat.sightDistance, 3f), true);
22 | }
23 |
24 | private void SetLayerToPlayerUnit(GameObject gameObject)
25 | {
26 | gameObject.layer = 7;
27 | }
28 | }
29 | #endif
30 |
31 |
32 |
--------------------------------------------------------------------------------
/Inspector Groups/Grouping.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | public class Grouping : MonoBehaviour
7 | {
8 | [HorizontalGroup("base", Width = 150)]
9 |
10 | [VerticalGroup("base/left")]
11 | [LabelWidth(90)]
12 | [HideLabel, Title("Enemy Name", Bold = false, HorizontalLine = false)]
13 | public string enemyName;
14 | [VerticalGroup("base/left")]
15 | [PreviewField(150)]
16 | [HideLabel]
17 | public Texture2D texture;
18 |
19 | [VerticalGroup("base/right")]
20 | [TextArea(5,5)]
21 | public string description;
22 |
23 | [HorizontalGroup("base/right/lower")]
24 |
25 | [VerticalGroup("base/right/lower/left")]
26 |
27 |
28 | [LabelWidth(50)]
29 | [Range(0,20)]
30 | public float stat1;
31 |
32 | [VerticalGroup("base/right/lower/left")]
33 |
34 | [LabelWidth(50)]
35 | [Range(0,20)]
36 | public float stat2;
37 |
38 | [VerticalGroup("base/right/lower/right")]
39 |
40 | [LabelWidth(50)]
41 | [Range(0,20)]
42 | public float stat3;
43 | [VerticalGroup("base/right/lower/right")]
44 | [LabelWidth(50)]
45 | [Range(0,20)]
46 | public float stat4;
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/Composite Attributes/Stats.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | [System.Serializable]
7 | public class Stats
8 | {
9 | [HorizontalGroup("base", Width = 150)]
10 |
11 | [VerticalGroup("base/left")]
12 | [LabelWidth(90)]
13 | [HideLabel, Title("Enemy Name", Bold = false, HorizontalLine = false)]
14 | public string enemyName;
15 | [VerticalGroup("base/left")]
16 | [PreviewField(150)]
17 | [HideLabel]
18 | public Texture2D texture;
19 |
20 | [VerticalGroup("base/right")]
21 | [TextArea(5,5)]
22 | [LabelText("@$property.Parent")]
23 | public string description;
24 |
25 | [HorizontalGroup("base/right/lower")]
26 |
27 | [VerticalGroup("base/right/lower/left")]
28 | [LabelWidth(50)]
29 | [Range(0,20)]
30 | public float stat1;
31 | [VerticalGroup("base/right/lower/left")]
32 | [LabelWidth(50)]
33 | [Range(0,20)]
34 | public float stat2;
35 | [VerticalGroup("base/right/lower/right")]
36 | [LabelWidth(50)]
37 | [Range(0,20)]
38 | public float stat3;
39 | [VerticalGroup("base/right/lower/right")]
40 | [LabelWidth(50)]
41 | [Range(0,20)]
42 | public float stat4;
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/ScriptableObjects/Color SOs/ColorReference.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | [System.Serializable]
7 | [InlineProperty]
8 | public class ColorReference
9 | {
10 | [HorizontalGroup("Color Reference",MaxWidth = 100)]
11 | [ValueDropdown("valueList")]
12 | [HideLabel]
13 | public bool useValue = true;
14 |
15 | [ShowIf("useValue", Animate = false)]
16 | [HorizontalGroup("Color Reference")]
17 | [HideLabel]
18 | public Color constantValue;
19 |
20 | [HideIf("useValue", Animate = false)]
21 | [HorizontalGroup("Color Reference")]
22 | [HideLabel]
23 | [Required]
24 | public ColorData variable;
25 |
26 | private ValueDropdownList valueList = new ValueDropdownList()
27 | {
28 | {"Value", true },
29 | {"Reference",false },
30 | };
31 |
32 | public Color Value
33 | {
34 | get
35 | {
36 | return useValue ? constantValue : variable.colorValue;
37 | }
38 | set
39 | {
40 | if (useValue)
41 | constantValue = value;
42 | else
43 | variable.colorValue = value;
44 | }
45 |
46 |
47 |
48 | }
49 |
50 |
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/ScriptableObjectsWithOdin/EnemyData.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | [CreateAssetMenu(fileName = "EnemyData", menuName = "My Game/Enemy Data")]
7 | [InlineEditor]
8 | public class EnemyData : ScriptableObject
9 | {
10 | [BoxGroup("Basic Info")]
11 | [LabelWidth(100)]
12 | public string enemyName;
13 | [BoxGroup("Basic Info")]
14 | [LabelWidth(100)]
15 | [TextArea]
16 | public string description;
17 |
18 | [HorizontalGroup("Game Data", 75)]
19 | [PreviewField(75)]
20 | [HideLabel]
21 | public GameObject enemyModel;
22 |
23 | [VerticalGroup("Game Data/Stats")]
24 | [LabelWidth(100)]
25 | [Range(20,100)]
26 | [GUIColor(0.5f,1f,0.5f)]
27 | public int health = 20;
28 | [VerticalGroup("Game Data/Stats")]
29 | [LabelWidth(100)]
30 | [Range(0.5f,5f)]
31 | [GUIColor(0.3f,0.5f,1f)]
32 | public float speed = 2f;
33 | [VerticalGroup("Game Data/Stats")]
34 | [LabelWidth(100)]
35 | [Range(5,30)]
36 | [GUIColor(1f,1f,0f)]
37 | public float detectRange = 10f;
38 | [VerticalGroup("Game Data/Stats")]
39 | [LabelWidth(100)]
40 | [Range(1,10)]
41 | [GUIColor(0.8f,0.4f,0.4f)]
42 | public int damage = 1;
43 | }
44 |
45 |
46 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/SpriteSizeAttribute.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System;
3 | using Sirenix.OdinInspector.Editor.Validation;
4 |
5 | [assembly: RegisterValidator(typeof(SpriteSizeValidator))]
6 | public class SpriteSizeValidator : AttributeValidator
7 | {
8 | protected override void Validate(ValidationResult result)
9 | {
10 | if (this.ValueEntry.SmartValue == null)
11 | return;
12 |
13 | int size = this.Attribute.size;
14 | int width = this.ValueEntry.SmartValue.texture.width;
15 |
16 | if (width != size)
17 | {
18 | result.ResultType = ValidationResultType.Warning;
19 | result.Message = "The Size of the sprite is NOT the desired size of " + width + " instead it is " + size;
20 | }
21 | }
22 | }
23 |
24 | public class SpriteSizeAttribute : Attribute
25 | {
26 | public int size;
27 |
28 | public SpriteSizeAttribute(int size)
29 | {
30 | this.size = size;
31 | }
32 |
33 | public SpriteSizeAttribute(SpriteSize spriteSize)
34 | {
35 | this.size = (int)spriteSize;
36 | }
37 | }
38 |
39 | public enum SpriteSize
40 | {
41 | small = 128,
42 | medium = 256,
43 | large = 512,
44 | extraLarge = 1024,
45 | huge = 2048
46 | }
47 |
48 |
49 |
--------------------------------------------------------------------------------
/How I Use Odin/HelpfulButtons.cs:
--------------------------------------------------------------------------------
1 |
2 | using Sirenix.OdinInspector;
3 | using Sirenix.OdinInspector.Editor;
4 | using UnityEditor;
5 | using UnityEditor.SceneManagement;
6 |
7 | public class HelpfulButtons : OdinEditorWindow
8 | {
9 | [MenuItem("Tools/Helpful Buttons")]
10 | private static void OpenWindow()
11 | {
12 | GetWindow().Show();
13 | }
14 |
15 | [ButtonGroup]
16 | private void StartScene()
17 | {
18 | LoadScene("Assets/Scenes/AlphaStartScene.unity");
19 | }
20 |
21 | [ButtonGroup]
22 | private void GameScene()
23 | {
24 | LoadScene("Assets/Scenes/Game Scene.unity");
25 | }
26 |
27 | [ButtonGroup]
28 | private void TestScene()
29 | {
30 | LoadScene("Assets/Scenes/Testing/Test Scene.unity");
31 | }
32 |
33 | private void LoadScene(string scenePath)
34 | {
35 | if (EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo())
36 | UnityEditor.SceneManagement.EditorSceneManager.OpenScene(scenePath);
37 | }
38 |
39 | [ButtonGroup]
40 | private void PatchNotes()
41 | {
42 | Selection.activeObject = AssetDatabase.LoadMainAssetAtPath("Assets/Prefabs/Patch Notes.asset");
43 | }
44 | }
45 |
46 |
47 |
--------------------------------------------------------------------------------
/Value Resolver/ColorIfAttribute.cs:
--------------------------------------------------------------------------------
1 | using System;
2 |
3 | public class ColorIfAttribute : Attribute
4 | {
5 | public string color;
6 | public string condition;
7 | public string myString;
8 |
9 | public ColorIfAttribute(string color, string condition)
10 | {
11 | this.color = color;
12 | this.condition = condition;
13 | }
14 | }
15 |
16 | //public class ColorIfAttributeDrawer : OdinAttributeDrawer
17 | //{
18 | // private ValueResolver colorResolver;
19 | // private ValueResolver conditionResolver;
20 |
21 | // protected override void Initialize()
22 | // {
23 | // this.colorResolver = ValueResolver.Get(this.Property, this.Attribute.color, Color.white);
24 | // this.conditionResolver = ValueResolver.Get(this.Property, this.Attribute.condition);
25 | // }
26 |
27 | // protected override void DrawPropertyLayout(GUIContent label)
28 | // {
29 | // ValueResolver.DrawErrors(this.colorResolver, this.conditionResolver);
30 |
31 | // bool condition = this.conditionResolver.GetValue();
32 |
33 | // if (condition)
34 | // {
35 | // GUIHelper.PushColor(this.colorResolver.GetValue());
36 | // }
37 |
38 | // this.CallNextDrawer(label);
39 |
40 | // if (condition)
41 | // {
42 | // GUIHelper.PopColor();
43 | // }
44 | // }
45 | //}
--------------------------------------------------------------------------------
/Shorts/Button Attribute/ButtonShortExamples.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 | using Sirenix.OdinInspector;
4 |
5 | public class ButtonShortExamples : MonoBehaviour
6 | {
7 | public int width;
8 | public int height;
9 | public GameObject gridItem;
10 | private List gridItemsList = new List();
11 |
12 | [ButtonGroup("GridButton")]
13 | private void GenerateGrid()
14 | {
15 | for (int i = 0; i < width; i++)
16 | {
17 | for (int j = 0; j < height; j++)
18 | {
19 | GameObject newGriditem
20 | = Instantiate(gridItem);
21 | newGriditem.transform.position
22 | = new Vector3(i, 0.25f, j) * 2;
23 | gridItemsList.Add(newGriditem);
24 | }
25 | }
26 | }
27 |
28 | [ButtonGroup("GridButton")]
29 | private void ClearGrid()
30 | {
31 | for (int i = 0; i < gridItemsList.Count; i++)
32 | {
33 | if (Application.isEditor)
34 | DestroyImmediate(gridItemsList[i]);
35 | else
36 | Destroy(gridItemsList[i]);
37 | }
38 | }
39 |
40 | private void SomeGeneric() where T : MonoBehaviour
41 | {
42 |
43 | }
44 |
45 | private void AnotherGeneric() where T : Component
46 | {
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/PropertyProcessors/SamplePropertyProcessor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 | using Sirenix.OdinInspector.Editor;
6 | using System;
7 |
8 | public class SamplePropertyProcessor : OdinPropertyProcessor where T : SampleClass
9 | {
10 | public override void ProcessMemberProperties(List propertyInfos)
11 | {
12 | for (int i = 0; i < propertyInfos.Count; i++)
13 | {
14 | if(propertyInfos[i].PropertyName == "bottom")
15 | {
16 | propertyInfos.Insert(0, propertyInfos[i]);
17 | propertyInfos.RemoveAt(i + 1);
18 | }
19 | }
20 |
21 | propertyInfos.AddDelegate("Print Hello", () => Debug.Log("Hello"), new BoxGroupAttribute("injected"));
22 |
23 | propertyInfos.AddValue("Injected Property",
24 | (ref SampleClass s) => s.value1 + s.value2 + s.value3,
25 | (ref SampleClass s, int sum) => { }, new BoxGroupAttribute("injected"));
26 |
27 | propertyInfos.AddValue("Injected Enum",
28 | (ref SampleClass s) => (MyEnum)s.value1,
29 | (ref SampleClass s, MyEnum myEnum) => s.value1 = (int)myEnum,
30 | new EnumToggleButtonsAttribute(),
31 | new BoxGroupAttribute("injected"));
32 |
33 | propertyInfos.Remove("value1");
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/The Manager Manager/Editor/GUIUtils.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.Utilities;
2 | using System;
3 | using UnityEditor;
4 | using UnityEngine;
5 | public static class GUIUtils
6 | {
7 | public static bool SelectButtonList(ref Type selectedType, Type[] typesToDisplay)
8 | {
9 | var rect = GUILayoutUtility.GetRect(0, 25);
10 |
11 | for (int i = 0; i < typesToDisplay.Length; i++)
12 | {
13 | var name = typesToDisplay[i].Name;
14 | var btnRect = rect.Split(i, typesToDisplay.Length);
15 |
16 | if (GUIUtils.SelectButton(btnRect, name, typesToDisplay[i] == selectedType))
17 | {
18 | selectedType = typesToDisplay[i];
19 | return true;
20 | }
21 | }
22 | return false;
23 | }
24 |
25 | public static bool SelectButton(Rect rect, string name, bool selected)
26 | {
27 | if (GUI.Button(rect, GUIContent.none, GUIStyle.none))
28 | return true;
29 |
30 | if (Event.current.type == EventType.Repaint)
31 | {
32 | var style = new GUIStyle(EditorStyles.miniButtonMid);
33 | style.stretchHeight = true;
34 | style.fixedHeight = rect.height;
35 | style.Draw(rect, new GUIContent(name), false, false, selected, false);
36 | }
37 | return false;
38 | }
39 |
40 | }
41 |
42 |
43 |
44 |
--------------------------------------------------------------------------------
/Data Manager/GUIUtils.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.Utilities;
2 | using System;
3 | using UnityEditor;
4 | using UnityEngine;
5 | using Sirenix.Utilities.Editor;
6 |
7 | public static class GUIUtils
8 | {
9 | public static bool SelectButtonList(ref Type selectedType, Type[] typesToDisplay)
10 | {
11 | var rect = GUILayoutUtility.GetRect(0, 25);
12 |
13 | for (int i = 0; i < typesToDisplay.Length; i++)
14 | {
15 | var name = typesToDisplay[i].Name;
16 | var btnRect = rect.Split(i, typesToDisplay.Length);
17 |
18 | if (GUIUtils.SelectButton(btnRect, name, typesToDisplay[i] == selectedType))
19 | {
20 | selectedType = typesToDisplay[i];
21 | return true;
22 | }
23 | }
24 | return false;
25 | }
26 |
27 | public static bool SelectButton(Rect rect, string name, bool selected)
28 | {
29 | if (GUI.Button(rect, GUIContent.none, GUIStyle.none))
30 | return true;
31 |
32 | if (Event.current.type == EventType.Repaint)
33 | {
34 | var style = new GUIStyle(EditorStyles.miniButtonMid);
35 | style.stretchHeight = true;
36 | style.fixedHeight = rect.height;
37 | style.Draw(rect, GUIHelper.TempContent(name), false, false, selected, false);
38 | }
39 |
40 |
41 | return false;
42 | }
43 |
44 | }
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Shorts/TabGroup/CharacterTabExample.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | public class CharacterTabExample : MonoBehaviour
7 | {
8 | [TabGroup("Character Details")]
9 | public CharacterInfo characterInfo;
10 |
11 | [TabGroup("Character Stats")]
12 | public CharacterStats stats;
13 |
14 | [TabGroup("Other")]
15 | public List inventory;
16 |
17 | [TabGroup("Other")]
18 | public List skillList;
19 | }
20 |
21 | [System.Serializable]
22 | public class Skill
23 | {
24 | //[TabGroup("Character Details")]
25 | //[TabGroup("Character Stats")]
26 | //[TabGroup("Other")]
27 | //[TabGroup("Skills")]
28 | public string skillName;
29 | public Sprite skillIcon;
30 | }
31 |
32 | [System.Serializable]
33 | public class CharacterStats
34 | {
35 | [Range(0,20)]
36 | public int strength;
37 | [Range(0,20)]
38 | public int vitality;
39 | [Range(0,20)]
40 | public int intelligence;
41 | [Range(0,20)]
42 | public int dexeterity;
43 | [Range(0,20)]
44 | public int charisma;
45 | }
46 |
47 | [System.Serializable]
48 | public class CharacterInfo
49 | {
50 | public string characterName;
51 | public string characterStory;
52 | public Sprite charcterImage;
53 | }
54 |
55 | [System.Serializable]
56 | public class InventoryObject
57 | {
58 | public Sprite icon;
59 | public string itemName;
60 | public string itemDescription;
61 | public ItemStats itemStats;
62 | }
63 |
64 | [System.Serializable]
65 | public class ItemStats
66 | {
67 | public int cost;
68 | public int weight;
69 | }
70 |
71 |
72 |
73 |
74 |
--------------------------------------------------------------------------------
/Custom Validator Scripts/PlantValidator.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using Sirenix.OdinInspector.Editor.Validation;
3 | using Sirenix.OdinInspector.Editor;
4 |
5 | [assembly: RegisterValidator(typeof(PlantValidator))]
6 | public class PlantValidator : ValueValidator
7 | {
8 | public override bool CanValidateProperty(InspectorProperty property)
9 | {
10 | return property.IsTreeRoot;
11 | }
12 |
13 | protected override void Validate(ValidationResult result)
14 | {
15 | if (this.ValueEntry.SmartValue == null)
16 | return;
17 |
18 | if(this.ValueEntry.SmartValue.transform.childCount == 0)
19 | {
20 | result.ResultType = ValidationResultType.Error;
21 | result.Message = "This Plant Doesn't Have a Child Object";
22 | }
23 | else
24 | {
25 | Transform child = this.ValueEntry.SmartValue.transform.GetChild(0);
26 |
27 | if (child.GetComponent() == null)
28 | {
29 | result.ResultType = ValidationResultType.Warning;
30 | result.Message = "The plant mesh is missing a collider";
31 | }
32 | else if (child.GetComponent() == null)
33 | {
34 | result.ResultType = ValidationResultType.Warning;
35 | result.Message = "The plant mesh is missing a rigidbody";
36 | }
37 | else if(!child.GetComponent().isKinematic)
38 | {
39 | result.ResultType = ValidationResultType.Warning;
40 | result.Message = "The plant rigidbody is not set to isKinematic";
41 | }
42 | }
43 | }
44 | }
45 |
46 |
47 |
48 |
49 |
--------------------------------------------------------------------------------
/Custom Attribute Processors/CharacterAttributeProcessor.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 | using Sirenix.OdinInspector.Editor;
6 | using Sirenix.Utilities;
7 | using System;
8 | using System.Reflection;
9 |
10 | public class CharacterAttributeProcessor : OdinAttributeProcessor where T : Character
11 | {
12 | public override void ProcessChildMemberAttributes(InspectorProperty parentProperty, MemberInfo member, List attributes)
13 | {
14 | attributes.Add(new LabelWidthAttribute(110));
15 |
16 | if(member.Name == "icon")
17 | {
18 | attributes.Add(new PropertyOrderAttribute(-1));
19 | attributes.Add(new HideLabelAttribute());
20 | attributes.Add(new HorizontalGroupAttribute("Character", 100));
21 | attributes.Add(new PreviewFieldAttribute(100, ObjectFieldAlignment.Center));
22 | }
23 |
24 | if(member.Name == "prefab")
25 | {
26 | attributes.Add(new VerticalGroupAttribute("Character/Right"));
27 | }
28 |
29 | if(member.GetReturnType() == typeof(string))
30 | {
31 | attributes.Add(new VerticalGroupAttribute("Character/Right"));
32 | }
33 |
34 | }
35 | }
36 |
37 | public class StatsAttributeProcessor : OdinAttributeProcessor
38 | {
39 | public override void ProcessChildMemberAttributes(InspectorProperty parentProperty, MemberInfo member, List attributes)
40 | {
41 | attributes.Add(new BoxGroupAttribute("Stats"));
42 | attributes.Add(new RangeAttribute(0, 20));
43 | }
44 |
45 | public override void ProcessSelfAttributes(InspectorProperty property, List attributes)
46 | {
47 | attributes.Add(new HideLabelAttribute());
48 | attributes.Add(new SpaceAttribute());
49 | }
50 | }
--------------------------------------------------------------------------------
/How I Use Odin/UnitUnlocakUpgradeWindow.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector;
2 | using Sirenix.OdinInspector.Editor;
3 | using UnityEditor;
4 | using UnityEngine;
5 |
6 | public class UnitUnlocakUpgradeWindow : OdinEditorWindow
7 | {
8 | [MenuItem("Tools/Unlock Unit Upgrade Creator")]
9 | private static void OpenWindow()
10 | {
11 | UnitUnlocakUpgradeWindow window = GetWindow();
12 | window.Show();
13 | window.path = PlayerPrefs.GetString("UnlockUnitPath", "");
14 | }
15 |
16 | private new void OnDestroy()
17 | {
18 | PlayerPrefs.SetString("UnlockUnitPath", path);
19 | base.OnDestroy();
20 | }
21 |
22 | [FolderPath, SerializeField, Required]
23 | private string path;
24 |
25 | [InlineEditor(Expanded = true)]
26 | public UnitUnlockUpgrade upgrade;
27 |
28 | [GUIColor(0.5f,1f,0.5f)]
29 | [ButtonGroup("")]
30 | private void SaveUpgrade()
31 | {
32 | upgrade.upgradeName = GenerateName();
33 | upgrade.description = GenerateDescription();
34 |
35 | if (string.IsNullOrEmpty(upgrade.upgradeName))
36 | return;
37 |
38 | AssetDatabase.CreateAsset(upgrade, path + "/" + upgrade.upgradeName + ".asset");
39 | AssetDatabase.SaveAssets();
40 | AssetDatabase.Refresh();
41 | NewUpgrade();
42 | }
43 |
44 | [GUIColor(0.5f,0.5f,1f)]
45 | [ButtonGroup("")]
46 | private void NewUpgrade()
47 | {
48 | upgrade = ScriptableObject.CreateInstance();
49 | upgrade.cost = new HexGame.Resources.ResourceAmount(HexGame.Resources.ResourceType.Research, 500);
50 | }
51 |
52 | [GUIColor(0.5f, 1f, 0.5f)]
53 | [ButtonGroup("")]
54 | private string GenerateName()
55 | {
56 | string name = "Unlock ";
57 |
58 | name += upgrade.buildingsToUnlock[0].ToNiceString();
59 |
60 | return name;
61 | }
62 |
63 | private string GenerateDescription()
64 | {
65 | return $"Unlocks {upgrade.buildingsToUnlock[0].ToNiceString()}";
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/ScriptableObjectsWithOdin/Editor/EnemyDataEditor.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using UnityEditor;
3 | using Sirenix.OdinInspector;
4 | using Sirenix.OdinInspector.Editor;
5 | using Sirenix.Utilities.Editor;
6 |
7 | public class EnemyDataEditor : OdinMenuEditorWindow
8 | {
9 | [MenuItem("Tools/Enemy Data")]
10 | private static void OpenWindow()
11 | {
12 | GetWindow().Show();
13 | }
14 |
15 | protected override OdinMenuTree BuildMenuTree()
16 | {
17 | var tree = new OdinMenuTree();
18 | tree.Selection.SupportsMultiSelect = false;
19 |
20 | tree.Add("Create New", new CreateNewEnemyData());
21 | tree.AddAllAssetsAtPath("Enemy Data", "Assets/Scripts", typeof(EnemyData));
22 | return tree;
23 | }
24 |
25 | public class CreateNewEnemyData
26 | {
27 | public CreateNewEnemyData()
28 | {
29 | enemyData = ScriptableObject.CreateInstance();
30 | enemyData.enemyName = "New Enemy Data";
31 | }
32 |
33 | [InlineEditor(Expanded = true)]
34 | public EnemyData enemyData;
35 |
36 | [Button("Add New Enemy SO")]
37 | private void CreateNewData()
38 | {
39 | AssetDatabase.CreateAsset(enemyData, "Assets/Scripts/" + enemyData.enemyName + ".asset");
40 | AssetDatabase.SaveAssets();
41 | }
42 | }
43 |
44 | protected override void OnBeginDrawEditors()
45 | {
46 | OdinMenuTreeSelection selected = this.MenuTree.Selection;
47 |
48 | SirenixEditorGUI.BeginHorizontalToolbar();
49 | {
50 | GUILayout.FlexibleSpace();
51 |
52 | if (SirenixEditorGUI.ToolbarButton("Delete Current"))
53 | {
54 | EnemyData asset = selected.SelectedValue as EnemyData;
55 | string path = AssetDatabase.GetAssetPath(asset);
56 | AssetDatabase.DeleteAsset(path);
57 | AssetDatabase.SaveAssets();
58 | }
59 |
60 | }
61 | SirenixEditorGUI.EndHorizontalToolbar();
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/ScriptableObjects/EnemyControl.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using UnityEngine.AI;
5 | using Sirenix.OdinInspector;
6 |
7 | [RequireComponent(typeof(NavMeshAgent))]
8 | public class EnemyControl : MonoBehaviour
9 | {
10 | private NavMeshAgent navAgent;
11 | private float wanderDistance = 3;
12 |
13 | public EnemyData data;
14 |
15 | private void Start()
16 | {
17 | if (navAgent == null)
18 | navAgent = this.GetComponent();
19 |
20 | if (data != null)
21 | LoadEnemy(data);
22 | }
23 |
24 | private void LoadEnemy(EnemyData _data)
25 | {
26 | //remove children objects i.e. visuals
27 | foreach (Transform child in this.transform)
28 | {
29 | if (Application.isEditor)
30 | DestroyImmediate(child.gameObject);
31 | else
32 | Destroy(child.gameObject);
33 | }
34 |
35 | //load current enemy visuals
36 | GameObject visuals = Instantiate(data.enemyModel);
37 | visuals.transform.SetParent(this.transform);
38 | visuals.transform.localPosition = Vector3.zero;
39 | visuals.transform.rotation = Quaternion.identity;
40 |
41 | //use stats data to set up enemy
42 | if (navAgent == null)
43 | navAgent = this.GetComponent();
44 |
45 | this.navAgent.speed = data.speed;
46 | }
47 |
48 | private void Update()
49 | {
50 | if (data == null)
51 | return;
52 |
53 | if (navAgent.remainingDistance < 1f)
54 | GetNewDestination();
55 | }
56 |
57 | private void GetNewDestination()
58 | {
59 | Vector3 nextDestination = this.transform.position;
60 | nextDestination += wanderDistance * new Vector3(Random.Range(-1f, 1f), 0f, Random.Range(-1f, 1f)).normalized;
61 |
62 | NavMeshHit hit;
63 | if (NavMesh.SamplePosition(nextDestination, out hit, 3f, NavMesh.AllAreas))
64 | navAgent.SetDestination(hit.position);
65 | }
66 |
67 | }
68 |
--------------------------------------------------------------------------------
/How I Use Odin/StatsUpgradeWindow.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector;
2 | using Sirenix.OdinInspector.Editor;
3 | using UnityEditor;
4 | using UnityEngine;
5 |
6 | public class StatsUpgradeWindow : OdinEditorWindow
7 | {
8 | [MenuItem("Tools/Stats Upgrade Creator")]
9 | private static void OpenWindow()
10 | {
11 | StatsUpgradeWindow window = GetWindow();
12 | window.Show();
13 | window.path = PlayerPrefs.GetString("StatsPath", "");
14 | }
15 | private new void OnDestroy()
16 | {
17 | PlayerPrefs.SetString("StatsPath", path);
18 | base.OnDestroy();
19 | }
20 |
21 | [FolderPath, SerializeField, Required]
22 | private string path;
23 |
24 | [InlineEditor(Expanded = true)]
25 | public StatsUpgrade upgrade;
26 |
27 | [GUIColor(0.5f,1f,0.5f)]
28 | [ButtonGroup("")]
29 | private void SaveUpgrade()
30 | {
31 | upgrade.upgradeName = GenerateName();
32 |
33 | if (string.IsNullOrEmpty(upgrade.upgradeName))
34 | return;
35 |
36 | AssetDatabase.CreateAsset(upgrade, path + "/" + upgrade.upgradeName + ".asset");
37 | AssetDatabase.SaveAssets();
38 | AssetDatabase.Refresh();
39 | NewUpgrade();
40 | }
41 |
42 | [GUIColor(0.5f,0.5f,1f)]
43 | [ButtonGroup("")]
44 | private void NewUpgrade()
45 | {
46 | upgrade = ScriptableObject.CreateInstance();
47 | upgrade.cost = new HexGame.Resources.ResourceAmount(HexGame.Resources.ResourceType.Research, 500);
48 | }
49 |
50 | [GUIColor(0.5f, 1f, 0.5f)]
51 | [ButtonGroup("")]
52 | private string GenerateName()
53 | {
54 | string name;
55 | name = upgrade.unitsToUpgrade[0].name;
56 | name = name.Replace("Stats", "");
57 |
58 | foreach (var upgrade in upgrade.upgradeToApply)
59 | {
60 | if (upgrade.Value > 0)
61 | name += "Plus";
62 | else
63 | name += "Minus";
64 |
65 | name += $" {Mathf.Abs(upgrade.Value)} {upgrade.Key}";
66 | }
67 |
68 | return name;
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/ScriptableObjectsWithOdin/EnemyControl.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using UnityEngine.AI;
5 | using Sirenix.OdinInspector;
6 |
7 | [RequireComponent(typeof(NavMeshAgent))]
8 | public class EnemyControl : MonoBehaviour
9 | {
10 | private NavMeshAgent navAgent;
11 | private float wanderDistance = 3;
12 |
13 | [OnValueChanged("LoadEnemy")]
14 | [InlineEditor]
15 | public EnemyData data;
16 |
17 | private void Start()
18 | {
19 | if (navAgent == null)
20 | navAgent = this.GetComponent();
21 |
22 | if (data != null)
23 | LoadEnemy(data);
24 | }
25 |
26 | private void LoadEnemy(EnemyData _data)
27 | {
28 | //remove children objects i.e. visuals
29 | foreach (Transform child in this.transform)
30 | {
31 | if (Application.isEditor)
32 | DestroyImmediate(child.gameObject);
33 | else
34 | Destroy(child.gameObject);
35 | }
36 |
37 | //load current enemy visuals
38 | GameObject visuals = Instantiate(data.enemyModel);
39 | visuals.transform.SetParent(this.transform);
40 | visuals.transform.localPosition = Vector3.zero;
41 | visuals.transform.rotation = Quaternion.identity;
42 |
43 | //use stats data to set up enemy
44 | if (navAgent == null)
45 | navAgent = this.GetComponent();
46 |
47 | this.navAgent.speed = data.speed;
48 | }
49 |
50 | private void Update()
51 | {
52 | if (data == null)
53 | return;
54 |
55 | if (navAgent.remainingDistance < 1f)
56 | GetNewDestination();
57 | }
58 |
59 | private void GetNewDestination()
60 | {
61 | Vector3 nextDestination = this.transform.position;
62 | nextDestination += wanderDistance * new Vector3(Random.Range(-1f, 1f), 0f, Random.Range(-1f, 1f)).normalized;
63 |
64 | NavMeshHit hit;
65 | if (NavMesh.SamplePosition(nextDestination, out hit, 3f, NavMesh.AllAreas))
66 | navAgent.SetDestination(hit.position);
67 | }
68 |
69 | }
70 |
--------------------------------------------------------------------------------
/AttributeDrawers/Editor/MyColorAttributeDrawer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.Utilities;
5 | using Sirenix.Utilities.Editor;
6 | using Sirenix.OdinInspector.Editor;
7 | using UnityEditor;
8 |
9 | public class MyColorAttributeDrawer : OdinAttributeDrawer
10 | {
11 | protected override void DrawPropertyLayout(GUIContent label)
12 | {
13 | Rect rect = EditorGUILayout.GetControlRect();
14 | Color tempColor = this.ValueEntry.SmartValue;
15 | string hexCode = ColorUtility.ToHtmlStringRGB(tempColor);
16 |
17 | if (label != null)
18 | rect = EditorGUI.PrefixLabel(rect, label);
19 |
20 | rect = EditorGUILayout.GetControlRect();
21 | tempColor = SirenixEditorFields.ColorField(rect.AlignLeft(rect.width * 0.75f), tempColor);
22 |
23 | //hexcode
24 | hexCode = SirenixEditorFields.TextField(rect.AlignRight(rect.width * 0.25f), "#" + hexCode);
25 | if(ColorUtility.TryParseHtmlString(hexCode, out tempColor))
26 | {
27 | this.ValueEntry.SmartValue = tempColor;
28 | }
29 |
30 | //rgb values
31 | rect = EditorGUILayout.GetControlRect();
32 |
33 | GUIHelper.PushLabelWidth(15);
34 | tempColor.r = EditorGUI.Slider(rect.AlignLeft(rect.width * 0.3f), "R", tempColor.r, 0f, 1f);
35 | tempColor.g = EditorGUI.Slider(rect.AlignCenter(rect.width * 0.3f), "G", tempColor.g, 0f, 1f);
36 | tempColor.b = EditorGUI.Slider(rect.AlignRight(rect.width * 0.3f), "B", tempColor.b, 0f, 1f);
37 | GUIHelper.PopLabelWidth();
38 |
39 | //hsv values
40 | Color.RGBToHSV(tempColor, out float h, out float s, out float v);
41 | rect = EditorGUILayout.GetControlRect();
42 |
43 | GUIHelper.PushLabelWidth(15);
44 | h = EditorGUI.Slider(rect.AlignLeft(rect.width * 0.3f), "H", h, 0f, 1f);
45 | s = EditorGUI.Slider(rect.AlignCenter(rect.width * 0.3f), "S", s, 0f, 1f);
46 | v = EditorGUI.Slider(rect.AlignRight(rect.width * 0.3f), "V", v, 0f, 1f);
47 | GUIHelper.PopLabelWidth();
48 |
49 | tempColor = Color.HSVToRGB(h, s, v);
50 |
51 | this.ValueEntry.SmartValue = tempColor;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/2D Character Creator/Character.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | public class Character : MonoBehaviour
7 | {
8 | [OnValueChanged("SetSprites")]
9 | [InlineEditor(InlineEditorObjectFieldModes.Foldout, Expanded = true)]
10 | [OnValueChanged("SetSprites", true)] //will only update if SO changed in character inspector
11 | [TabGroup("Sprites")]
12 | public CharacterSpriteData spriteData;
13 |
14 | //Sprite Renderers
15 | //these correspond to the sprites in the SO
16 |
17 | [Title("Head")]
18 | [TabGroup("Sprite Renderers")]
19 | public SpriteRenderer head;
20 | [TabGroup("Sprite Renderers")]
21 | public SpriteRenderer face;
22 | [TabGroup("Sprite Renderers")]
23 | public SpriteRenderer beard;
24 | [TabGroup("Sprite Renderers")]
25 | public SpriteRenderer hair;
26 | [TabGroup("Sprite Renderers")]
27 | public SpriteRenderer hat;
28 |
29 | [Title("Body")]
30 | [TabGroup("Sprite Renderers")]
31 | public SpriteRenderer body;
32 | [TabGroup("Sprite Renderers")]
33 | public SpriteRenderer rightHand;
34 | [TabGroup("Sprite Renderers")]
35 | public SpriteRenderer leftHand;
36 | [TabGroup("Sprite Renderers")]
37 | public SpriteRenderer rightLeg;
38 | [TabGroup("Sprite Renderers")]
39 | public SpriteRenderer leftLeg;
40 |
41 | [Title("Weapons")]
42 | [TabGroup("Sprite Renderers")]
43 | public SpriteRenderer rightHandItem;
44 | [TabGroup("Sprite Renderers")]
45 | public SpriteRenderer leftHandItem;
46 |
47 | private void SetSprites()
48 | {
49 | if (spriteData == null)
50 | return;
51 |
52 | body.sprite = spriteData.body;
53 | head.sprite = spriteData.head;
54 | face.sprite = spriteData.face;
55 | beard.sprite = spriteData.beard;
56 | hair.sprite = spriteData.hair;
57 | hat.sprite = spriteData.hat;
58 | rightHand.sprite = spriteData.rightHand;
59 | rightHandItem.sprite = spriteData.rightHandItem;
60 | leftHand.sprite = spriteData.leftHand;
61 | leftHandItem.sprite = spriteData.leftHandItem;
62 | rightLeg.sprite = spriteData.rightLeg;
63 | leftLeg.sprite = spriteData.leftLeg;
64 | }
65 | }
66 |
--------------------------------------------------------------------------------
/SFX Manager/SFXManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using System.Linq;
5 | using Sirenix.OdinInspector;
6 |
7 | public class SFXManager : MonoBehaviour
8 | {
9 | private static SFXManager _instance;
10 | public static SFXManager instance
11 | {
12 | get
13 | {
14 | if (_instance == null)
15 | _instance = FindObjectOfType();
16 |
17 | return _instance;
18 | }
19 | }
20 |
21 | [HorizontalGroup("AudioSource")]
22 | [SerializeField]
23 | private AudioSource defaultAudioSource;
24 |
25 | [TabGroup("UI")]
26 | [AssetList(Path = "/Audio/UI SFX", AutoPopulate = true)]
27 | public List uiSFX;
28 | [TabGroup("Ambient")]
29 | [AssetList(Path = "/Audio/Ambient SFX", AutoPopulate = true)]
30 | public List ambientSFX;
31 | [TabGroup("Weapons")]
32 | [AssetList(Path = "/Audio/Weapon SFX", AutoPopulate = true)]
33 | public List weaponSFX;
34 |
35 | public static void PlaySFX(SFXClip sfx, bool waitToFinish = true, AudioSource audioSource = null)
36 | {
37 | if (audioSource == null)
38 | audioSource = SFXManager.instance.defaultAudioSource;
39 |
40 | if (audioSource == null)
41 | {
42 | Debug.LogError("You forgot to add a default audio source!");
43 | return;
44 | }
45 |
46 | if (!audioSource.isPlaying || !waitToFinish)
47 | {
48 | audioSource.clip = sfx.clip;
49 | audioSource.volume = sfx.volume + Random.Range(-sfx.volumeVariation, sfx.volumeVariation);
50 | audioSource.pitch = sfx.pitch + Random.Range(-sfx.pitchVariation, sfx.pitchVariation);
51 | audioSource.Play();
52 | }
53 | }
54 |
55 | [HorizontalGroup("AudioSource")]
56 | [ShowIf("@defaultAudioSource == null")]
57 | [GUIColor(1f,0.5f,0.5f,1f)]
58 | [Button]
59 | private void AddAudioSource()
60 | {
61 | defaultAudioSource = this.gameObject.GetComponent();
62 |
63 | if (defaultAudioSource == null)
64 | defaultAudioSource = this.gameObject.AddComponent();
65 | }
66 |
67 | public enum SFXType
68 | {
69 | UI,
70 | Ambient,
71 | Weapons
72 | }
73 | }
74 |
75 |
76 |
77 |
78 |
79 |
--------------------------------------------------------------------------------
/Generic Matching/NPCBase.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.Utilities.Editor;
5 | using Sirenix.OdinInspector.Editor;
6 | using UnityEditor;
7 |
8 | public class NPCBase : MonoBehaviour
9 | {
10 | public BaseStats stats;
11 |
12 | public MagicStats magicStats;
13 |
14 | public List NPCStatsList = new List();
15 | }
16 |
17 | //public interface IResettable
18 | //{
19 | // void Reset();
20 | //}
21 |
22 | //public class AddBoxToStatsDrawer : OdinValueDrawer where T : BaseStats
23 | //{
24 | // protected override void DrawPropertyLayout(GUIContent label)
25 | // {
26 | // SirenixEditorGUI.BeginBox();
27 | // this.CallNextDrawer(label);
28 | // SirenixEditorGUI.EndBox();
29 | // }
30 | //}
31 |
32 | //public class ResetContextMenuDrawer : OdinValueDrawer, IDefinesGenericMenuItems where T : IResettable
33 | //{
34 |
35 | // protected override void Initialize()
36 | // {
37 | // this.SkipWhenDrawing = true;
38 | // }
39 |
40 | // public void PopulateGenericMenu(InspectorProperty property, GenericMenu genericMenu)
41 | // {
42 | // genericMenu.AddItem(new GUIContent("Reset Stats"), false, Reset);
43 | // }
44 |
45 | // private void Reset()
46 | // {
47 | // this.Property.RecordForUndo("Resetting values using IResettable");
48 |
49 | // foreach (var value in this.ValueEntry.Values)
50 | // {
51 | // value.Reset();
52 | // }
53 | // }
54 | //}
55 |
56 | //public class ResetListDrawr : OdinValueDrawer, IDefinesGenericMenuItems where TList : IList
57 | // where TElement : IResettable
58 | //{
59 | // protected override void Initialize()
60 | // {
61 | // this.SkipWhenDrawing = true;
62 | // }
63 |
64 | // public void PopulateGenericMenu(InspectorProperty property, GenericMenu genericMenu)
65 | // {
66 | // genericMenu.AddItem(new GUIContent("Reset List"), false, ResetList);
67 | // }
68 |
69 | // private void ResetList()
70 | // {
71 | // this.Property.RecordForUndo("Resetting List using IResettable");
72 |
73 | // foreach (var list in this.ValueEntry.Values)
74 | // {
75 | // foreach (var element in list)
76 | // {
77 | // element.Reset();
78 | // }
79 | // }
80 | // }
81 | //}
82 |
--------------------------------------------------------------------------------
/Generic Matching/NPCStats.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections.Generic;
3 | using Sirenix.Utilities.Editor;
4 | using Sirenix.OdinInspector.Editor;
5 | using UnityEditor;
6 |
7 | [System.Serializable]
8 | public class BaseStats : IResettable
9 | {
10 | public int health;
11 | public int gold;
12 |
13 | public void Reset()
14 | {
15 | health = 100;
16 | gold = 100;
17 | }
18 | }
19 |
20 | [System.Serializable]
21 | public class MagicStats : BaseStats
22 | {
23 | public int mana;
24 | public int manaRecharge;
25 | }
26 |
27 | public interface IResettable
28 | {
29 | void Reset();
30 | }
31 |
32 | public class AddBoxToStatsDrawer : OdinValueDrawer where T : BaseStats
33 | {
34 | protected override void DrawPropertyLayout(GUIContent label)
35 | {
36 | SirenixEditorGUI.BeginBox();
37 | this.CallNextDrawer(label);
38 | SirenixEditorGUI.EndBox();
39 | }
40 | }
41 |
42 | public class ResetContextMenuDrawer : OdinValueDrawer, IDefinesGenericMenuItems where T : IResettable
43 | {
44 | protected override void Initialize()
45 | {
46 | this.SkipWhenDrawing = true;
47 | }
48 |
49 | public void PopulateGenericMenu(InspectorProperty property, GenericMenu genericMenu)
50 | {
51 | genericMenu.AddItem(new GUIContent("Reset Stats"), false, Reset);
52 | }
53 |
54 | private void Reset()
55 | {
56 | this.Property.RecordForUndo("Reset Stats with IResettable");
57 |
58 | foreach (var value in this.ValueEntry.Values)
59 | {
60 | value.Reset();
61 | }
62 | }
63 | }
64 |
65 | public class ResetListDrawer : OdinValueDrawer, IDefinesGenericMenuItems where TList : IList
66 | where TElement : IResettable
67 | {
68 |
69 | protected override void Initialize()
70 | {
71 | this.SkipWhenDrawing = true;
72 | }
73 |
74 | public void PopulateGenericMenu(InspectorProperty property, GenericMenu genericMenu)
75 | {
76 | genericMenu.AddItem(new GUIContent("Reset List"), false, ResetList);
77 | }
78 |
79 | private void ResetList()
80 | {
81 | this.Property.RecordForUndo("Reset List with IResettable");
82 |
83 | foreach (var list in this.ValueEntry.Values)
84 | {
85 | foreach (var element in list)
86 | {
87 | element.Reset();
88 | }
89 | }
90 | }
91 | }
--------------------------------------------------------------------------------
/Class Value Drawers/Editor/MySubClassDrawer.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.Utilities.Editor;
5 | using Sirenix.OdinInspector.Editor;
6 | using Sirenix.Utilities;
7 | using UnityEditor;
8 |
9 |
10 | public class MySubClassDrawer : OdinValueDrawer
11 | {
12 | private InspectorProperty text;
13 | private InspectorProperty number;
14 | private InspectorProperty location;
15 |
16 | protected override void Initialize()
17 | {
18 | text = this.Property.Children["text"];
19 | number = this.Property.Children["number"];
20 | location = this.Property.Children["location"];
21 | }
22 |
23 | protected override void DrawPropertyLayout(GUIContent label)
24 | {
25 | Rect rect = EditorGUILayout.GetControlRect();
26 |
27 | if (label != null)
28 | rect = EditorGUI.PrefixLabel(rect, label);
29 |
30 | rect = EditorGUILayout.GetControlRect();
31 |
32 | GUIHelper.PushLabelWidth(75);
33 | text.ValueEntry.WeakSmartValue = SirenixEditorFields.TextField(rect.Split(0, 2),
34 | "Text", (string)text.ValueEntry.WeakSmartValue);
35 | number.ValueEntry.WeakSmartValue = SirenixEditorFields.IntField(rect.Split(1, 2),
36 | "Number", (int)number.ValueEntry.WeakSmartValue);
37 | location.Draw();
38 | GUIHelper.PopLabelWidth();
39 | }
40 | }
41 |
42 | public class MySubClassDrawer_WrongWay : OdinValueDrawer
43 | {
44 | private InspectorProperty text;
45 | private InspectorProperty number;
46 | private InspectorProperty location;
47 |
48 | protected override void Initialize()
49 | {
50 | text = this.Property.Children["text"];
51 | number = this.Property.Children["number"];
52 | location = this.Property.Children["location"];
53 | }
54 |
55 | protected override void DrawPropertyLayout(GUIContent label)
56 | {
57 | string text = this.ValueEntry.SmartValue.text;
58 | int number = this.ValueEntry.SmartValue.number;
59 | Vector3 location = this.ValueEntry.SmartValue.location;
60 |
61 | Rect rect = EditorGUILayout.GetControlRect();
62 |
63 | if (label != null)
64 | rect = EditorGUI.PrefixLabel(rect, label);
65 |
66 | rect = EditorGUILayout.GetControlRect();
67 |
68 | GUIHelper.PushLabelWidth(75);
69 | text = SirenixEditorFields.TextField(rect.Split(0, 2), "Text", text);
70 | number = SirenixEditorFields.IntField(rect.Split(1, 2), "Number", number);
71 | location = SirenixEditorFields.Vector3Field("Location", location);
72 | GUIHelper.PopLabelWidth();
73 |
74 | this.ValueEntry.SmartValue.text = text;
75 | this.ValueEntry.SmartValue.number = number;
76 | this.ValueEntry.SmartValue.location = location;
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/SFX Manager/SFX.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | [System.Serializable]
7 | public class SFX
8 | {
9 | [LabelText("SFX Type")]
10 | [LabelWidth(100)]
11 | [OnValueChanged("SFXChange")]
12 | [InlineButton("PlaySFX")]
13 | public SFXManager.SFXType sfxType = SFXManager.SFXType.UI;
14 |
15 | [LabelText("$sfxLabel")]
16 | [LabelWidth(100)]
17 | [ValueDropdown("SFXType")]
18 | [OnValueChanged("SFXChange")]
19 | [InlineButton("SelectSFX")]
20 | public SFXClip sfxToPlay;
21 | private string sfxLabel = "SFX";
22 |
23 | [SerializeField]
24 | private bool showSettings = false;
25 |
26 | [ShowIf("showSettings")]
27 | [SerializeField]
28 | private bool editSettings = false;
29 |
30 | [InlineEditor(InlineEditorObjectFieldModes.Hidden)]
31 | [ShowIf("showSettings")]
32 | [EnableIf("editSettings")]
33 | [SerializeField]
34 | private SFXClip _sfxBase;
35 |
36 | [Title("Audio Source")]
37 | [ShowIf("showSettings")]
38 | [EnableIf("editSettings")]
39 | [SerializeField]
40 | private bool waitToPlay = true;
41 |
42 | [ShowIf("showSettings")]
43 | [EnableIf("editSettings")]
44 | [SerializeField]
45 | private bool useDefault = true;
46 |
47 | [DisableIf("useDefault")]
48 | [ShowIf("showSettings")]
49 | [EnableIf("editSettings")]
50 | [SerializeField]
51 | private AudioSource audiosource;
52 |
53 | private void SFXChange()
54 | {
55 | //keep the label up to date
56 | sfxLabel = sfxType.ToString() + " SFX";
57 |
58 | //keep the displayed "SFX clip" up to date
59 | _sfxBase = sfxToPlay;
60 | }
61 |
62 |
63 | private void SelectSFX()
64 | {
65 | UnityEditor.Selection.activeObject = sfxToPlay;
66 | }
67 |
68 | //Get's list of SFX from manager, used in the inspector
69 | private List SFXType()
70 | {
71 | List sfxList;
72 |
73 | switch (sfxType)
74 | {
75 | case SFXManager.SFXType.UI:
76 | sfxList = SFXManager.instance.uiSFX;
77 | break;
78 | case SFXManager.SFXType.Ambient:
79 | sfxList = SFXManager.instance.ambientSFX;
80 | break;
81 | case SFXManager.SFXType.Weapons:
82 | sfxList = SFXManager.instance.weaponSFX;
83 | break;
84 | default:
85 | sfxList = SFXManager.instance.uiSFX;
86 | break;
87 | }
88 |
89 | return sfxList;
90 | }
91 |
92 | public void PlaySFX()
93 | {
94 | if (useDefault || audiosource == null)
95 | SFXManager.PlaySFX(sfxToPlay, waitToPlay, null);
96 | else
97 | SFXManager.PlaySFX(sfxToPlay, waitToPlay, audiosource);
98 | }
99 | }
100 |
--------------------------------------------------------------------------------
/CustomGroups/MyClass.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 | using Sirenix.OdinInspector.Editor;
6 | using Sirenix.Utilities.Editor;
7 | using System;
8 |
9 | public class MyClass : MonoBehaviour
10 | {
11 |
12 |
13 | [ColorFoldoutGroup("group1", 1f,0f,0f)]
14 | public int first = 1;
15 | [ColorFoldoutGroup("group1")]
16 | public int second = 2;
17 | [ColorFoldoutGroup("group1")]
18 | public int third = 3;
19 |
20 | [ColorFoldoutGroup("group2", 0f, 1f, 0f)]
21 | public string down;
22 | [ColorFoldoutGroup("group2")]
23 | public string up;
24 | [ColorFoldoutGroup("group2")]
25 | public string strange;
26 |
27 | [ColorFoldoutGroup("group3", 0f, 0f, 0.7f)]
28 | public Vector3 charm = new Vector3(1,0,0);
29 | [ColorFoldoutGroup("group3")]
30 | public Vector3 bottom = new Vector3(0, -1, 0);
31 | [ColorFoldoutGroup("group3")]
32 | public Vector3 top = new Vector3(0, 0, 0);
33 | }
34 |
35 | public class ColorFoldoutGroupAttribute : PropertyGroupAttribute
36 | {
37 | public float R, G, B, A;
38 |
39 | public ColorFoldoutGroupAttribute(string path) : base (path)
40 | {
41 |
42 | }
43 |
44 | public ColorFoldoutGroupAttribute(string path, float r, float g, float b, float a = 1f) : base(path)
45 | {
46 | this.R = r;
47 | this.G = g;
48 | this.B = b;
49 | this.A = a;
50 | }
51 |
52 | protected override void CombineValuesWith(PropertyGroupAttribute other)
53 | {
54 | var otherAttr = (ColorFoldoutGroupAttribute)other;
55 |
56 | this.R = Math.Max(otherAttr.R, this.R);
57 | this.G = Math.Max(otherAttr.G, this.G);
58 | this.B = Math.Max(otherAttr.B, this.B);
59 | this.A = Math.Max(otherAttr.A, this.A);
60 | }
61 | }
62 |
63 | public class ColorFoldoutGroupAttributeDrawer : OdinGroupDrawer
64 | {
65 | private LocalPersistentContext isExpanded;
66 |
67 | protected override void Initialize()
68 | {
69 | this.isExpanded = this.GetPersistentValue("ColorFoldoutGroupAttributeDrawer.isExpanded",
70 | GeneralDrawerConfig.Instance.ExpandFoldoutByDefault);
71 | }
72 |
73 | protected override void DrawPropertyLayout(GUIContent label)
74 | {
75 | GUIHelper.PushColor(new Color(this.Attribute.R, this.Attribute.G, this.Attribute.B, this.Attribute.A));
76 | SirenixEditorGUI.BeginBox();
77 | SirenixEditorGUI.BeginBoxHeader();
78 | GUIHelper.PopColor();
79 |
80 | this.isExpanded.Value = SirenixEditorGUI.Foldout(this.isExpanded.Value, label);
81 | SirenixEditorGUI.EndBoxHeader();
82 |
83 | if (SirenixEditorGUI.BeginFadeGroup(this, this.isExpanded.Value))
84 | {
85 | for (int i = 0; i < this.Property.Children.Count; i++)
86 | {
87 | this.Property.Children[i].Draw();
88 | }
89 | }
90 | SirenixEditorGUI.EndFadeGroup();
91 | SirenixEditorGUI.EndBox();
92 | }
93 | }
--------------------------------------------------------------------------------
/How I Use Odin/ResourceSOCreator.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector;
2 | using Sirenix.OdinInspector.Editor;
3 | using UnityEditor;
4 | using UnityEngine;
5 | using HexGame.Resources;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 |
9 | public class ResourceSOCreator : OdinEditorWindow
10 | {
11 | [MenuItem("Tools/Resource Creator")]
12 | private static void OpenWindow()
13 | {
14 | ResourceSOCreator window = GetWindow();
15 | window.Show();
16 | window.path = PlayerPrefs.GetString("Resource SO Path", "");
17 | }
18 | private new void OnDestroy()
19 | {
20 | PlayerPrefs.SetString("Resource SO Path", path);
21 | base.OnDestroy();
22 | }
23 |
24 | [SerializeField]
25 | [OnValueChanged("FindTemplate")]
26 | private ResourceType resourceType;
27 |
28 | [FolderPath, SerializeField, Required]
29 | private string path;
30 |
31 | [InlineEditor(Expanded = true)]
32 | public ResourceTemplate resource;
33 |
34 | [GUIColor(0.5f,1f,0.5f)]
35 | [ButtonGroup("")]
36 | private void SaveResourceTemplate()
37 | {
38 | if (string.IsNullOrEmpty(resource.resourceName))
39 | return;
40 |
41 | if(!AssetDatabase.Contains(resource))
42 | AssetDatabase.CreateAsset(resource, path + "/" + resource.resourceName + ".asset");
43 | AssetDatabase.SaveAssets();
44 | AssetDatabase.Refresh();
45 | NewUpgrade();
46 | }
47 |
48 | [GUIColor(0.5f,0.5f,1f)]
49 | [ButtonGroup("")]
50 | private void NewUpgrade()
51 | {
52 | resource = ScriptableObject.CreateInstance();
53 | }
54 |
55 | [GUIColor(0.5f, 1f, 0.5f)]
56 | [ButtonGroup("")]
57 | private void CreateRemainingTypes()
58 | {
59 | List templates = HelperFunctions.GetScriptableObjects(path);
60 |
61 | foreach (var rt in System.Enum.GetValues(typeof(ResourceType)))
62 | {
63 | ResourceTemplate resourceTemplate = templates.Where(x => x.type == (ResourceType)rt).FirstOrDefault();
64 | if(resourceTemplate == null)
65 | {
66 | NewUpgrade();
67 | resource.type = (ResourceType)rt;
68 | SaveResourceTemplate();
69 | }
70 | }
71 | }
72 |
73 | private void FindTemplate()
74 | {
75 | if (resource != null)
76 | SaveResourceTemplate();
77 |
78 | Debug.Log("Looking for template");
79 | List templates = HelperFunctions.GetScriptableObjects(path);
80 | ResourceTemplate resourceTemplate = null;
81 |
82 | if(templates != null && templates.Count > 0)
83 | resourceTemplate = templates.Where(x => x.type == resourceType).FirstOrDefault();
84 |
85 | if(resourceTemplate == null)
86 | {
87 | NewUpgrade();
88 | resource.type = (ResourceType)resourceType;
89 | }
90 | else
91 | {
92 | resource = resourceTemplate;
93 | }
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/How I Use Odin/PatchNotes.cs:
--------------------------------------------------------------------------------
1 | using Sirenix.OdinInspector;
2 | using System.Collections.Generic;
3 | using System.Collections.ObjectModel;
4 | using System.Linq;
5 | using UnityEngine;
6 |
7 | [CreateAssetMenu(fileName = "Patch Notes", menuName = "Create New Patch Notes")]
8 | public class PatchNotes : SerializedScriptableObject
9 | {
10 | [SerializeField]
11 | public Dictionary patchNotes = new Dictionary();
12 |
13 | [Title("Add New Notes")]
14 | [SerializeField]
15 | [OnValueChanged("LoadNotesToEdit")]
16 | private float version;
17 | [TextArea(10, 20)]
18 | [SerializeField]
19 | [OnValueChanged("AddNotes")]
20 | private string notes;
21 | [SerializeField]
22 | [TextArea(5, 10)]
23 | public string knownIssues;
24 |
25 | public NoteContainer GetNotes(float version)
26 | {
27 | patchNotes.TryGetValue(version, out NoteContainer notes);
28 | return notes;
29 | }
30 | public void SaveNotes(float version, string note)
31 | {
32 | patchNotes.TryGetValue(version, out NoteContainer notes);
33 | if (notes == null)
34 | patchNotes.Add(version, new NoteContainer(version, note));
35 | else
36 | notes.notes = note;
37 | }
38 |
39 | [GUIColor(0.6f, 1f, 0.6f)]
40 | [ButtonGroup("Buttons")]
41 | private void AddNotes()
42 | {
43 | SaveNotes(version, notes);
44 | }
45 |
46 | [GUIColor(1f, 0.6f, 0.6f)]
47 | [ButtonGroup("Buttons")]
48 | private void ResetRead()
49 | {
50 | foreach (KeyValuePair note in patchNotes)
51 | ES3.Save(note.Key.ToString() + " has been read", false, "patchnotes.es3");
52 | }
53 | public void SetLatestAsRead()
54 | {
55 | ES3.Save(GetLatestVersion().ToString() + " has been read", true, "patchnotes.es3");
56 | }
57 | public bool IsLatestRead()
58 | {
59 | if (!ES3.FileExists("patchnotes.es3"))
60 | return false;
61 |
62 | return ES3.Load(GetLatestVersion().ToString() + " has been read", "patchnotes.es3");
63 | }
64 | private void LoadNotesToEdit()
65 | {
66 | if (patchNotes.TryGetValue(version, out NoteContainer notes))
67 | this.notes = notes.notes;
68 | }
69 | public float GetLatestVersion()
70 | {
71 | float latestVersion = 0f;
72 |
73 | foreach (KeyValuePair note in patchNotes)
74 | {
75 | if (note.Key > latestVersion)
76 | latestVersion = note.Key;
77 | }
78 |
79 | return latestVersion;
80 | }
81 | public ReadOnlyCollection GetAllNotes(bool newestFirst = true)
82 | {
83 | List notes = new List();
84 | foreach (var version in patchNotes.Keys)
85 | {
86 | notes.Add(GetNotes(version));
87 | }
88 |
89 | if (newestFirst)
90 | notes = notes.OrderByDescending(x => x.version).ToList();
91 |
92 | return notes.AsReadOnly();
93 | }
94 | [SerializeField]
95 | public class NoteContainer
96 | {
97 | public NoteContainer(float version, string notes)
98 | {
99 | this.version = version;
100 | this.notes = notes;
101 | }
102 |
103 | public float version;
104 | [TextArea]
105 | public string notes;
106 | }
107 | }
108 |
--------------------------------------------------------------------------------
/First Custom Inspector/GameManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections.Generic;
2 | using UnityEngine;
3 | using Sirenix.OdinInspector;
4 |
5 | public class GameManager : MonoBehaviour
6 | {
7 | [BoxGroup("Game State Info")]
8 | [EnumToggleButtons]
9 | [OnValueChanged("StateChange")]
10 | [ShowInInspector]
11 | public static GameState gameState;
12 |
13 | [BoxGroup("Game State Info")]
14 | [ShowInInspector]
15 | public static int turnsRemaining = 3;
16 |
17 | //UI elements
18 | [TabGroup("UI")]
19 | [SceneObjectsOnly]
20 | [Required]
21 | [InlineButton("SelectCanvas","Select")]
22 | public Canvas startButtons;
23 | [TabGroup("UI")]
24 | [SceneObjectsOnly,Required]
25 | [InlineButton("SelectCanvas","Select")]
26 | public Canvas pauseMenu;
27 | [TabGroup("UI")]
28 | [SceneObjectsOnly,Required]
29 | [InlineButton("SelectCanvas","Select")]
30 | public Canvas HUD;
31 |
32 | //background music
33 | [TabGroup("Music")]
34 | public AudioSource musicSource;
35 |
36 | [Space]
37 | [ShowInInspector]
38 | [ValueDropdown("musicList")]
39 | [TabGroup("Music")]
40 | [InlineButton("PlayMusic")]
41 | private AudioClip currentMusicClip;
42 | [TabGroup("Music")]
43 | [InlineEditor(InlineEditorModes.SmallPreview)]
44 | public List musicList;
45 |
46 | //sfx
47 | [TabGroup("SFX")]
48 | public AudioSource sfxSource;
49 | [TabGroup("SFX")]
50 | [InlineButton("PlaySFX","Test")]
51 | public AudioClip uiClick;
52 | [TabGroup("SFX")]
53 | [InlineButton("PlaySFX","Test")]
54 | public AudioClip weaponShoot;
55 | [TabGroup("SFX")]
56 | [InlineButton("PlaySFX","Test")]
57 | public AudioClip weaponHit;
58 | [TabGroup("SFX")]
59 | [InlineButton("PlaySFX","Test")]
60 | public AudioClip enemySpawn;
61 |
62 | //enemies
63 | [TabGroup("Enemies", "Enemy Data")]
64 | [AssetsOnly]
65 | public GameObject enemyPrefab;
66 | [TabGroup("Enemies", "Enemy Data")]
67 | [InlineEditor(InlineEditorModes.GUIOnly)]
68 | [AssetsOnly]
69 | public List enemyList;
70 |
71 | //spawn points
72 | [TabGroup("Enemies","Spawn Points")]
73 | [SceneObjectsOnly]
74 | public List spawnPoints;
75 |
76 | private void PlaySFX(AudioClip sfx)
77 | {
78 | if (sfxSource != null && !sfxSource.isPlaying)
79 | sfxSource.PlayOneShot(sfx);
80 | }
81 |
82 | public void PlayMusic(AudioClip music)
83 | {
84 | if (musicSource != null && music != null)
85 | {
86 | musicSource.clip = music;
87 | musicSource.Play();
88 | }
89 | }
90 |
91 | [Button(ButtonSizes.Medium)]
92 | [TabGroup("Enemies","Enemy Data")]
93 | [GUIColor(0.6f,1f,0.6f)]
94 | public void SpawnRandomEnemy()
95 | {
96 | if (enemyList.Count == 0 || spawnPoints.Count == 0)
97 | return;
98 |
99 | GameObject enemyToSpawn = Instantiate(enemyPrefab);
100 |
101 | //inject data
102 | EnemyData data = enemyList[Random.Range(0, enemyList.Count)];
103 | enemyToSpawn.GetComponent().SetEnemyData(data);
104 |
105 | //set location
106 | enemyToSpawn.transform.position = spawnPoints[Random.Range(0, spawnPoints.Count)].position;
107 | }
108 |
109 | public void StateChange()
110 | {
111 | switch (gameState)
112 | {
113 | case GameState.startScene:
114 | break;
115 | case GameState.gamePlay:
116 | break;
117 | case GameState.paused:
118 | break;
119 | case GameState.complete:
120 | break;
121 | default:
122 | break;
123 | }
124 | }
125 |
126 | private void SelectCanvas(Canvas _object)
127 | {
128 | if(_object)
129 | UnityEditor.Selection.activeObject = _object.gameObject;
130 | }
131 | }
132 |
133 | public enum GameState
134 | {
135 | startScene,
136 | gamePlay,
137 | paused,
138 | complete
139 | }
140 |
--------------------------------------------------------------------------------
/2D Character Creator/Editor/CharacterEditor.cs:
--------------------------------------------------------------------------------
1 | using UnityEngine;
2 | using System.Collections.Generic;
3 | using UnityEditor;
4 | using Sirenix.OdinInspector;
5 | using Sirenix.OdinInspector.Editor;
6 | using Sirenix.Utilities.Editor;
7 |
8 | public class CharacterEditor : OdinMenuEditorWindow
9 | {
10 | private static CharacterSpriteSettings sprites;
11 |
12 | [MenuItem("Tools/2D Character Creator")]
13 | public static void OpenWindow()
14 | {
15 | GetWindow().Show();
16 | if (sprites == null)
17 | sprites = AssetDatabase.LoadAssetAtPath("Assets/Scripts/2D Character Creator/SpriteSettings.asset", typeof(CharacterSpriteSettings)) as CharacterSpriteSettings;
18 | }
19 |
20 | protected override OdinMenuTree BuildMenuTree()
21 | {
22 | var tree = new OdinMenuTree();
23 | tree.Selection.SupportsMultiSelect = false;
24 |
25 | tree.Add("Create New", new CreateNewCharcacterData());
26 | tree.AddAllAssetsAtPath("Enemy Data", "Assets/Scripts/2D Character Creator/Characters", typeof(CharacterSpriteData));
27 | if(sprites != null)
28 | tree.Add("Set Up Sprites", sprites);
29 | return tree;
30 | }
31 |
32 | protected override void OnBeginDrawEditors()
33 | {
34 | OdinMenuTreeSelection selected = this.MenuTree.Selection;
35 |
36 | SirenixEditorGUI.BeginHorizontalToolbar();
37 | {
38 | GUILayout.FlexibleSpace();
39 |
40 | if (SirenixEditorGUI.ToolbarButton("Delete Current"))
41 | {
42 | CharacterSpriteData asset = selected.SelectedValue as CharacterSpriteData;
43 | string path = AssetDatabase.GetAssetPath(asset);
44 | AssetDatabase.DeleteAsset(path);
45 | AssetDatabase.SaveAssets();
46 | }
47 | }
48 | SirenixEditorGUI.EndHorizontalToolbar();
49 | }
50 |
51 | public class CreateNewCharcacterData
52 | {
53 | public CreateNewCharcacterData()
54 | {
55 | characterSpriteData = ScriptableObject.CreateInstance();
56 | characterSpriteData.characterName = "New Character Data";
57 | }
58 |
59 | [InlineEditor(Expanded = true)]
60 | public CharacterSpriteData characterSpriteData;
61 |
62 | [GUIColor(0.7f,1f,0.7f)]
63 | [ButtonGroup("CreateButtons")]
64 | private void CreateCharacterData()
65 | {
66 | AssetDatabase.CreateAsset(characterSpriteData, "Assets/Scripts/2D Character Creator/Characters/" + characterSpriteData.characterName + ".asset");
67 | AssetDatabase.SaveAssets();
68 | }
69 |
70 | [GUIColor(0.7f,0.7f,1f)]
71 | [ButtonGroup("CreateButtons")]
72 | private void RandomizeSprites()
73 | {
74 | CharacterSpriteSettings sprites = AssetDatabase.LoadAssetAtPath("Assets/Scripts/2D Character Creator/SpriteSettings.asset", typeof(CharacterSpriteSettings)) as CharacterSpriteSettings;
75 |
76 | if (sprites == null)
77 | return;
78 |
79 | characterSpriteData.body = sprites.bodySprites[Random.Range(0, sprites.bodySprites.Count)];
80 | characterSpriteData.head = sprites.headSprites[Random.Range(0, sprites.headSprites.Count)];
81 | characterSpriteData.face = sprites.faceSprites[Random.Range(0, sprites.faceSprites.Count)];
82 | characterSpriteData.beard = sprites.beardSprites[Random.Range(0, sprites.beardSprites.Count)];
83 | characterSpriteData.hair = sprites.hairSprites[Random.Range(0, sprites.hairSprites.Count)];
84 | characterSpriteData.hat = sprites.hatSprites[Random.Range(0, sprites.hatSprites.Count)];
85 | characterSpriteData.rightHand = sprites.rightHandSprites[Random.Range(0, sprites.rightHandSprites.Count)];
86 | characterSpriteData.rightHandItem = sprites.weaponSprites[Random.Range(0, sprites.weaponSprites.Count)];
87 | characterSpriteData.leftHand = sprites.leftHandSprites[Random.Range(0, sprites.leftHandSprites.Count)];
88 | characterSpriteData.leftHandItem = sprites.weaponSprites[Random.Range(0, sprites.weaponSprites.Count)];
89 | characterSpriteData.rightLeg = sprites.rightLegSprites[Random.Range(0, sprites.rightLegSprites.Count)];
90 | characterSpriteData.leftLeg = sprites.leftLegSprites[Random.Range(0, sprites.leftLegSprites.Count)];
91 | }
92 | }
93 | }
94 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/2D Character Creator/CharacterSpriteSettings.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 |
6 | ///
7 | /// This holds all the project wide sprite data
8 | /// these fields can be accessed in the editor
9 | /// and the Character Data SO
10 | ///
11 |
12 | [CreateAssetMenu(fileName = "SpriteSettings", menuName = "Create Sprite Settings SO")]
13 | public class CharacterSpriteSettings : ScriptableObject
14 | {
15 | [Title("Asset Locations")]
16 | [FolderPath]
17 | public List spriteFolders;
18 | [FolderPath]
19 | public List otherSpriteFolders;
20 |
21 | [Title("Head")]
22 | [SerializeField]
23 | private string headIdentifier;
24 | public List headSprites = new List();
25 | [SerializeField]
26 | private string faceIdentifier;
27 | public List faceSprites = new List();
28 | [SerializeField]
29 | private string beardIdentifier;
30 | public List beardSprites = new List();
31 | [SerializeField]
32 | private string hairIdentifier;
33 | public List hairSprites = new List();
34 | [SerializeField]
35 | private string hatIdentifier;
36 | public List hatSprites = new List();
37 |
38 | [Title("Body")]
39 | [SerializeField]
40 | private string bodyIdentifier;
41 | public List bodySprites = new List();
42 | [SerializeField]
43 | private string rightHandIdentifier;
44 | public List rightHandSprites = new List();
45 | [SerializeField]
46 | private string leftHandIdentifier;
47 | public List leftHandSprites = new List();
48 | [SerializeField]
49 | private string rightLegIdentifier;
50 | public List rightLegSprites = new List();
51 | [SerializeField]
52 | private string leftLegIdentifier;
53 | public List leftLegSprites = new List();
54 |
55 | [Title("Weapons")]
56 | [SerializeField]
57 | private string weaponIndentifier;
58 | [VerticalGroup("Character/Weapons")]
59 | public List weaponSprites = new List();
60 |
61 | [Button]
62 | public void FindSpritesInAssets()
63 | {
64 | if (spriteFolders == null || spriteFolders.Count == 0)
65 | return;
66 |
67 | FindSpritesAddToList(bodyIdentifier, bodySprites);
68 | FindSpritesAddToList(headIdentifier, headSprites);
69 | FindSpritesAddToList(faceIdentifier, faceSprites);
70 | FindSpritesAddToList(beardIdentifier, beardSprites);
71 | FindSpritesAddToList(hairIdentifier, hairSprites);
72 | FindSpritesAddToList(hatIdentifier, hatSprites);
73 | FindSpritesAddToList(rightHandIdentifier, rightHandSprites);
74 | FindSpritesAddToList(leftHandIdentifier, leftHandSprites);
75 | FindSpritesAddToList(rightLegIdentifier, rightLegSprites);
76 | FindSpritesAddToList(leftLegIdentifier, leftLegSprites);
77 |
78 | if (otherSpriteFolders == null || otherSpriteFolders.Count == 0)
79 | return;
80 |
81 | FindUnidentifiedSpritesAddToList(weaponSprites);
82 | }
83 |
84 | private void FindSpritesAddToList(string identifier, List spriteList)
85 | {
86 | spriteList.Clear();
87 | string[] folders = spriteFolders.ToArray();
88 | string[] spriteGUIDs = UnityEditor.AssetDatabase.FindAssets(identifier + " t:sprite", folders);
89 |
90 | foreach (string GUID in spriteGUIDs)
91 | {
92 | string spritePath = UnityEditor.AssetDatabase.GUIDToAssetPath(GUID);
93 | Sprite foundSprite = UnityEditor.AssetDatabase.LoadAssetAtPath(spritePath);
94 |
95 | if (foundSprite != null)
96 | spriteList.Add(foundSprite);
97 | }
98 | }
99 |
100 | private void FindUnidentifiedSpritesAddToList(List spriteList)
101 | {
102 | spriteList.Clear();
103 | string[] folders = otherSpriteFolders.ToArray();
104 | string[] spriteGUIDs = UnityEditor.AssetDatabase.FindAssets("t:sprite", folders);
105 |
106 | foreach (string GUID in spriteGUIDs)
107 | {
108 | string spritePath = UnityEditor.AssetDatabase.GUIDToAssetPath(GUID);
109 | Sprite foundSprite = UnityEditor.AssetDatabase.LoadAssetAtPath(spritePath);
110 |
111 | if (foundSprite != null)
112 | spriteList.Add(foundSprite);
113 | }
114 | }
115 | }
116 |
--------------------------------------------------------------------------------
/2D Character Creator/CharacterSpriteData.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using Sirenix.OdinInspector;
5 | using Sirenix.Utilities.Editor;
6 | using Sirenix.OdinInspector.Editor;
7 |
8 | ///
9 | /// This holds all the sprite data for the character
10 | ///
11 |
12 |
13 | [CreateAssetMenu(fileName = "New Character Sprites", menuName = "Create New Character Sprite SO")]
14 | public class CharacterSpriteData : SerializedScriptableObject
15 | {
16 | [LabelWidth(125)]
17 | public string characterName;
18 |
19 | //sprites
20 | [Title("Head")]
21 | [HorizontalGroup("Character", LabelWidth = 100)]
22 | [VerticalGroup("Character/Head")]
23 | [ValueDropdown("@GetBodySprites(spriteSettings.hatSprites)")]
24 | public Sprite hat;
25 | [VerticalGroup("Character/Head")]
26 | [ValueDropdown("@GetBodySprites(spriteSettings.hairSprites)")]
27 | public Sprite hair;
28 | [VerticalGroup("Character/Head")]
29 | [ValueDropdown("@GetBodySprites(spriteSettings.headSprites)")]
30 | public Sprite head;
31 | [VerticalGroup("Character/Head")]
32 | [ValueDropdown("@GetBodySprites(spriteSettings.faceSprites)")]
33 | public Sprite face;
34 | [VerticalGroup("Character/Head")]
35 | [ValueDropdown("@GetBodySprites(spriteSettings.beardSprites)")]
36 | public Sprite beard;
37 |
38 | [Title("Body")]
39 | [VerticalGroup("Character/Body")]
40 | [ValueDropdown("@GetBodySprites(spriteSettings.bodySprites)")]
41 | public Sprite body;
42 | [VerticalGroup("Character/Body")]
43 | [ValueDropdown("@GetBodySprites(spriteSettings.rightHandSprites)")]
44 | public Sprite rightHand;
45 | [VerticalGroup("Character/Body")]
46 | [ValueDropdown("@GetBodySprites(spriteSettings.leftHandSprites)")]
47 | public Sprite leftHand;
48 | [VerticalGroup("Character/Body")]
49 | [ValueDropdown("@GetBodySprites(spriteSettings.rightLegSprites)")]
50 | public Sprite rightLeg;
51 | [VerticalGroup("Character/Body")]
52 | [ValueDropdown("@GetBodySprites(spriteSettings.leftLegSprites)")]
53 | public Sprite leftLeg;
54 |
55 |
56 | [Title("Weapons")]
57 | [VerticalGroup("Character/Weapons")]
58 | [ValueDropdown("@GetBodySprites(spriteSettings.weaponSprites)")]
59 | public Sprite rightHandItem;
60 | [VerticalGroup("Character/Weapons")]
61 | [ValueDropdown("@GetBodySprites(spriteSettings.weaponSprites)")]
62 | public Sprite leftHandItem;
63 |
64 | private static CharacterSpriteSettings spriteSettings;
65 |
66 | //I'm leaving this in as a simpler visualization option
67 | //it also shows up one more Odin feature
68 |
69 | //[SerializeField]
70 | //[TableMatrix(SquareCells = true)]
71 | //private Sprite[,] spriteArray;
72 |
73 | //private void OnValidate()
74 | //{
75 | // DrawCharacterInArray();
76 | //}
77 |
78 | //[OnInspectorInit]
79 | //public void DrawCharacterInArray()
80 | //{
81 | // spriteArray = new Sprite[5, 4]
82 | // {
83 | // {null,null,rightHandItem,null},
84 | // {null,beard,rightHand,rightLeg},
85 | // {hat,face,body,null},
86 | // {null,head,leftHand,leftLeg},
87 | // {null,null,leftHandItem,null}
88 | // };
89 | //}
90 |
91 | [OnInspectorInit]
92 | private void GetSpriteSettings()
93 | {
94 | if (spriteSettings == null)
95 | spriteSettings = UnityEditor.AssetDatabase.LoadAssetAtPath("Assets/Scripts/2D Character Creator/SpriteSettings.asset", typeof(CharacterSpriteSettings)) as CharacterSpriteSettings;
96 | }
97 |
98 | private IEnumerable GetBodySprites(List spriteList)
99 | {
100 | List dropDownItemList = new List();
101 |
102 | dropDownItemList.Add(new ValueDropdownItem("none", null)); //adding a null value to dropdown
103 |
104 | for (int i = 0; i < spriteList.Count; i++)
105 | {
106 | ValueDropdownItem dropdownItem = new ValueDropdownItem(spriteList[i].name + " " + i, spriteList[i]);
107 | dropDownItemList.Add(dropdownItem);
108 | }
109 |
110 | return dropDownItemList;
111 | }
112 |
113 | [OnInspectorGUI]
114 | private void DrawPreview()
115 | {
116 | var rect = GUILayoutUtility.GetRect(300, 200);
117 | Rect newRect;
118 |
119 | if (rightHand != null) //all the if's seem horrible
120 | {
121 | newRect = PositionSprite(rect, -10, 120, rightHand);
122 | GUI.DrawTexture(newRect, rightHand.texture, ScaleMode.ScaleToFit);
123 | }
124 |
125 | if (leftLeg != null)
126 | {
127 | newRect = PositionSprite(rect, 10, 150, leftLeg);
128 | GUI.DrawTexture(newRect, leftLeg.texture, ScaleMode.ScaleToFit);
129 | }
130 |
131 | if (rightLeg != null)
132 | {
133 | newRect = PositionSprite(rect, -10, 150, rightLeg);
134 | GUI.DrawTexture(newRect, rightLeg.texture, ScaleMode.ScaleToFit);
135 | }
136 |
137 | if (body != null)
138 | {
139 | newRect = PositionSprite(rect, -5, 135, body);
140 | GUI.DrawTexture(newRect, body.texture, ScaleMode.ScaleToFit);
141 | }
142 |
143 | if (head != null)
144 | {
145 | newRect = PositionSprite(rect, 0, 105, head);
146 | GUI.DrawTexture(newRect, head.texture, ScaleMode.ScaleToFit);
147 | }
148 |
149 | if (face != null)
150 | {
151 | newRect = PositionSprite(rect, 0, 65, face);
152 | GUI.DrawTexture(newRect, face.texture, ScaleMode.ScaleToFit);
153 | }
154 |
155 | if (hair != null)
156 | {
157 | newRect = PositionSprite(rect, 0, 100, hair);
158 | GUI.DrawTexture(newRect, hair.texture, ScaleMode.ScaleToFit);
159 | }
160 |
161 | if (hat != null)
162 | {
163 | newRect = PositionSprite(rect, 0, 105, hat);
164 | GUI.DrawTexture(newRect, hat.texture, ScaleMode.ScaleToFit);
165 | }
166 |
167 | if (leftHand != null)
168 | {
169 | newRect = PositionSprite(rect, 10, 120, leftHand);
170 | GUI.DrawTexture(newRect, leftHand.texture, ScaleMode.ScaleToFit);
171 | }
172 |
173 | if (rightHandItem != null)
174 | {
175 | newRect = PositionSprite(rect, -30, 135, rightHandItem);
176 | GUI.DrawTexture(newRect, rightHandItem.texture, ScaleMode.ScaleToFit);
177 | }
178 |
179 | if (leftHandItem != null)
180 | {
181 | newRect = PositionSprite(rect, 12, 145, leftHandItem);
182 | GUI.DrawTexture(newRect, leftHandItem.texture, ScaleMode.ScaleToFit);
183 | }
184 | }
185 |
186 | private Rect PositionSprite(Rect rect, float x, float y, Sprite sprite)
187 | {
188 | float width = sprite.texture.width;
189 | float height = sprite.texture.height;
190 |
191 | float xPos = rect.x + x - sprite.pivot.x;//no width needed?
192 | xPos += rect.width / 2; //centering
193 | float yPos = rect.y + y + sprite.pivot.y - height; //why does the height matter?
194 |
195 | return new Rect(xPos, yPos, width, height);
196 | }
197 | }
198 |
--------------------------------------------------------------------------------
/THE Game Manager/TheGameManager.cs:
--------------------------------------------------------------------------------
1 | using System.Collections;
2 | using System.Collections.Generic;
3 | using UnityEngine;
4 | using UnityEditor;
5 | using Sirenix.OdinInspector;
6 | using Sirenix.OdinInspector.Editor;
7 | using Sirenix.Utilities.Editor;
8 |
9 | public class TheGameManager : OdinMenuEditorWindow
10 | {
11 | [OnValueChanged("StateChange")]
12 | [LabelText("Manager View")]
13 | [LabelWidth(100f)]
14 | [EnumToggleButtons]
15 | [ShowInInspector]
16 | private ManagerState managerState;
17 | private int enumIndex = 0;
18 | private bool treeRebuild = false;
19 |
20 | private DrawUniverse drawUniverse = new DrawUniverse();
21 | private DrawNPC drawNPC = new DrawNPC();
22 | private DrawSFX drawSFX = new DrawSFX();
23 |
24 | private DrawSelected drawModules = new DrawSelected();
25 | private DrawSelected drawColors = new DrawSelected();
26 | private DrawSelected drawItems = new DrawSelected();
27 | private DrawSelected drawRecipes = new DrawSelected();
28 |
29 | //paths to SOs in project
30 | private string modulePath = "Assets/Prefabs/Ships/Module/ModuleData";
31 | private string colorPath = "Assets/Resources/ColorData";
32 | private string itemPath = "Assets/Resources/Items";
33 | private string recipePath = "Assets/Scripts/Industry/Recipe Data";
34 |
35 | [MenuItem("Tools/The Game Manager")]
36 | public static void OpenWindow()
37 | {
38 | GetWindow().Show();
39 | }
40 |
41 | private void StateChange()
42 | {
43 | treeRebuild = true;
44 | }
45 |
46 | protected override void Initialize()
47 | {
48 | drawModules.SetPath(modulePath);
49 | drawColors.SetPath(colorPath);
50 | drawItems.SetPath(itemPath);
51 | drawRecipes.SetPath(recipePath);
52 |
53 | drawUniverse.FindMyObject();
54 | drawNPC.FindMyObject();
55 | drawSFX.FindMyObject();
56 | }
57 |
58 | protected override void OnGUI()
59 | {
60 | if(treeRebuild && Event.current.type == EventType.Layout)
61 | {
62 | ForceMenuTreeRebuild();
63 | treeRebuild = false;
64 | }
65 |
66 | SirenixEditorGUI.Title("The Game Manager", "Because every hobby game is overscoped", TextAlignment.Center, true);
67 | EditorGUILayout.Space();
68 |
69 | switch (managerState)
70 | {
71 |
72 | case ManagerState.modules:
73 | case ManagerState.items:
74 | case ManagerState.recipes:
75 | case ManagerState.color:
76 | DrawEditor(enumIndex);
77 | break;
78 | default:
79 | break;
80 | }
81 | EditorGUILayout.Space();
82 |
83 | base.OnGUI();
84 | }
85 |
86 | protected override void DrawEditors()
87 | {
88 | switch (managerState)
89 | {
90 | case ManagerState.universe:
91 | DrawEditor(enumIndex);
92 | break;
93 | case ManagerState.modules:
94 | drawModules.SetSelected(this.MenuTree.Selection.SelectedValue);
95 | break;
96 | case ManagerState.npc:
97 | DrawEditor(enumIndex);
98 | break;
99 | case ManagerState.items:
100 | drawItems.SetSelected(this.MenuTree.Selection.SelectedValue);
101 | break;
102 | case ManagerState.recipes:
103 | drawRecipes.SetSelected(this.MenuTree.Selection.SelectedValue);
104 | break;
105 | case ManagerState.color:
106 | drawColors.SetSelected(this.MenuTree.Selection.SelectedValue);
107 | break;
108 | case ManagerState.sfx:
109 | DrawEditor(enumIndex);
110 | break;
111 | default:
112 | break;
113 | }
114 |
115 | DrawEditor((int)managerState);
116 | }
117 |
118 | protected override IEnumerable