├── TagSelector ├── Scripts │ ├── TagSelectorAttribute.cs │ └── Editor │ │ └── TagSelectorPropertyDrawer.cs └── Demo │ ├── Scripts │ └── TagSelectorDemoScript.cs │ └── TagSelectorDemoScene.unity ├── LICENSE.md └── README.md /TagSelector/Scripts/TagSelectorAttribute.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------- // 2 | // Author : William Whitehouse / WSWhitehouse // 3 | // GitHub : github.com/WSWhitehouse // 4 | // Created : 30/06/2019 // 5 | // Edited : 25/02/2020 // 6 | // ------------------------------------------- // 7 | 8 | using UnityEngine; 9 | 10 | namespace WSWhitehouse.TagSelector 11 | { 12 | public class TagSelectorAttribute : PropertyAttribute 13 | { 14 | public bool UseDefaultTagFieldDrawer = false; 15 | } 16 | } -------------------------------------------------------------------------------- /TagSelector/Demo/Scripts/TagSelectorDemoScript.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------- // 2 | // Author : William Whitehouse / WSWhitehouse // 3 | // GitHub : github.com/WSWhitehouse // 4 | // Created : 25/02/2020 // 5 | // Edited : 25/02/2020 // 6 | // ------------------------------------------- // 7 | 8 | using UnityEngine; 9 | 10 | namespace WSWhitehouse.TagSelector.Demo 11 | { 12 | public class TagSelectorDemoScript : MonoBehaviour 13 | { 14 | [TagSelector] public string tagOne; 15 | 16 | [TagSelector(UseDefaultTagFieldDrawer = true)] 17 | public string tagTwo; 18 | } 19 | } -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | 2 | The MIT License (MIT) 3 | 4 | Copyright (c) 2020 William Whitehouse 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Unity Tag Selector 2 | 3 | Simple attribute that turns a normal string field into a dropdown of all available Tags in the inspector. Never misspell the name of a tag ever again. 4 | 5 | [![Image from Gyazo](https://i.gyazo.com/084e5e63cce91a10e6b65bf985c7a102.gif)](https://gyazo.com/084e5e63cce91a10e6b65bf985c7a102) 6 | 7 | ## Installing & Using the Attribute 8 | 9 | - Download the source code or check the [releases on this repository](https://github.com/WSWhitehouse/Unity-Tag-Selector/releases) for a specific Unity Package download or download the [Latest Unity Package](https://github.com/WSWhitehouse/Unity-Tag-Selector/releases/latest) 10 | - If you downloaded the Unity Package you will need to import it. `Assets -> Import Package -> Custom Package` and select the Unity Package you just downloaded 11 | - Put a `[TagSelector]` attribute in front of any string field. Optional bool value to change the dropdown to the default Unity Tag Dropdown 12 | 13 | [![Image from Gyazo](https://i.gyazo.com/809dc931cc89430d02347916646b47fc.png)](https://gyazo.com/809dc931cc89430d02347916646b47fc) 14 | 15 | - Done! You will now have a dropdown selector which includes all of the available Tags. 16 | -------------------------------------------------------------------------------- /TagSelector/Scripts/Editor/TagSelectorPropertyDrawer.cs: -------------------------------------------------------------------------------- 1 | // ------------------------------------------- // 2 | // Author : William Whitehouse / WSWhitehouse // 3 | // GitHub : github.com/WSWhitehouse // 4 | // Created : 30/06/2019 // 5 | // Edited : 25/02/2020 // 6 | // ------------------------------------------- // 7 | 8 | using UnityEngine; 9 | using UnityEditor; 10 | using System.Collections.Generic; 11 | using UnityEditorInternal; 12 | 13 | namespace WSWhitehouse.TagSelector 14 | { 15 | [CustomPropertyDrawer(typeof(TagSelectorAttribute))] 16 | public class TagSelectorPropertyDrawer : PropertyDrawer 17 | { 18 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label) 19 | { 20 | if (property.propertyType == SerializedPropertyType.String) 21 | { 22 | EditorGUI.BeginProperty(position, label, property); 23 | 24 | TagSelectorAttribute selectorAttribute = attribute as TagSelectorAttribute; 25 | 26 | if (selectorAttribute.UseDefaultTagFieldDrawer) 27 | { 28 | property.stringValue = EditorGUI.TagField(position, label, property.stringValue); 29 | } 30 | else 31 | { 32 | List tagList = new List {""}; 33 | tagList.AddRange(InternalEditorUtility.tags); 34 | string propertyString = property.stringValue; 35 | int index = -1; 36 | if (propertyString == "") 37 | { 38 | index = 0; 39 | } 40 | else 41 | { 42 | for (int i = 1; i < tagList.Count; i++) 43 | { 44 | if (tagList[i] != propertyString) 45 | { 46 | continue; 47 | } 48 | 49 | index = i; 50 | break; 51 | } 52 | } 53 | 54 | index = EditorGUI.Popup(position, label.text, index, tagList.ToArray()); 55 | 56 | if (index == 0) 57 | { 58 | property.stringValue = ""; 59 | } 60 | else if (index >= 1) 61 | { 62 | property.stringValue = tagList[index]; 63 | } 64 | else 65 | { 66 | property.stringValue = ""; 67 | } 68 | } 69 | 70 | EditorGUI.EndProperty(); 71 | } 72 | else 73 | { 74 | EditorGUI.PropertyField(position, property, label); 75 | } 76 | } 77 | } 78 | } -------------------------------------------------------------------------------- /TagSelector/Demo/TagSelectorDemoScene.unity: -------------------------------------------------------------------------------- 1 | %YAML 1.1 2 | %TAG !u! tag:unity3d.com,2011: 3 | --- !u!29 &1 4 | OcclusionCullingSettings: 5 | m_ObjectHideFlags: 0 6 | serializedVersion: 2 7 | m_OcclusionBakeSettings: 8 | smallestOccluder: 5 9 | smallestHole: 0.25 10 | backfaceThreshold: 100 11 | m_SceneGUID: 00000000000000000000000000000000 12 | m_OcclusionCullingData: {fileID: 0} 13 | --- !u!104 &2 14 | RenderSettings: 15 | m_ObjectHideFlags: 0 16 | serializedVersion: 9 17 | m_Fog: 0 18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1} 19 | m_FogMode: 3 20 | m_FogDensity: 0.01 21 | m_LinearFogStart: 0 22 | m_LinearFogEnd: 300 23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1} 24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1} 25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1} 26 | m_AmbientIntensity: 1 27 | m_AmbientMode: 0 28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1} 29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0} 30 | m_HaloStrength: 0.5 31 | m_FlareStrength: 1 32 | m_FlareFadeSpeed: 3 33 | m_HaloTexture: {fileID: 0} 34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0} 35 | m_DefaultReflectionMode: 0 36 | m_DefaultReflectionResolution: 128 37 | m_ReflectionBounces: 1 38 | m_ReflectionIntensity: 1 39 | m_CustomReflection: {fileID: 0} 40 | m_Sun: {fileID: 0} 41 | m_IndirectSpecularColor: {r: 0, g: 0, b: 0, a: 1} 42 | m_UseRadianceAmbientProbe: 0 43 | --- !u!157 &3 44 | LightmapSettings: 45 | m_ObjectHideFlags: 0 46 | serializedVersion: 11 47 | m_GIWorkflowMode: 1 48 | m_GISettings: 49 | serializedVersion: 2 50 | m_BounceScale: 1 51 | m_IndirectOutputScale: 1 52 | m_AlbedoBoost: 1 53 | m_EnvironmentLightingMode: 0 54 | m_EnableBakedLightmaps: 1 55 | m_EnableRealtimeLightmaps: 1 56 | m_LightmapEditorSettings: 57 | serializedVersion: 12 58 | m_Resolution: 2 59 | m_BakeResolution: 40 60 | m_AtlasSize: 1024 61 | m_AO: 0 62 | m_AOMaxDistance: 1 63 | m_CompAOExponent: 1 64 | m_CompAOExponentDirect: 0 65 | m_ExtractAmbientOcclusion: 0 66 | m_Padding: 2 67 | m_LightmapParameters: {fileID: 0} 68 | m_LightmapsBakeMode: 1 69 | m_TextureCompression: 1 70 | m_FinalGather: 0 71 | m_FinalGatherFiltering: 1 72 | m_FinalGatherRayCount: 256 73 | m_ReflectionCompression: 2 74 | m_MixedBakeMode: 2 75 | m_BakeBackend: 1 76 | m_PVRSampling: 1 77 | m_PVRDirectSampleCount: 32 78 | m_PVRSampleCount: 512 79 | m_PVRBounces: 2 80 | m_PVREnvironmentSampleCount: 256 81 | m_PVREnvironmentReferencePointCount: 2048 82 | m_PVRFilteringMode: 1 83 | m_PVRDenoiserTypeDirect: 1 84 | m_PVRDenoiserTypeIndirect: 1 85 | m_PVRDenoiserTypeAO: 1 86 | m_PVRFilterTypeDirect: 0 87 | m_PVRFilterTypeIndirect: 0 88 | m_PVRFilterTypeAO: 0 89 | m_PVREnvironmentMIS: 1 90 | m_PVRCulling: 1 91 | m_PVRFilteringGaussRadiusDirect: 1 92 | m_PVRFilteringGaussRadiusIndirect: 5 93 | m_PVRFilteringGaussRadiusAO: 2 94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5 95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2 96 | m_PVRFilteringAtrousPositionSigmaAO: 1 97 | m_ExportTrainingData: 0 98 | m_TrainingDataDestination: TrainingData 99 | m_LightingDataAsset: {fileID: 0} 100 | m_UseShadowmask: 1 101 | --- !u!196 &4 102 | NavMeshSettings: 103 | serializedVersion: 2 104 | m_ObjectHideFlags: 0 105 | m_BuildSettings: 106 | serializedVersion: 2 107 | agentTypeID: 0 108 | agentRadius: 0.5 109 | agentHeight: 2 110 | agentSlope: 45 111 | agentClimb: 0.4 112 | ledgeDropHeight: 0 113 | maxJumpAcrossDistance: 0 114 | minRegionArea: 2 115 | manualCellSize: 0 116 | cellSize: 0.16666667 117 | manualTileSize: 0 118 | tileSize: 256 119 | accuratePlacement: 0 120 | debug: 121 | m_Flags: 0 122 | m_NavMeshData: {fileID: 0} 123 | --- !u!1 &967071190 124 | GameObject: 125 | m_ObjectHideFlags: 0 126 | m_CorrespondingSourceObject: {fileID: 0} 127 | m_PrefabInstance: {fileID: 0} 128 | m_PrefabAsset: {fileID: 0} 129 | serializedVersion: 6 130 | m_Component: 131 | - component: {fileID: 967071192} 132 | - component: {fileID: 967071191} 133 | m_Layer: 0 134 | m_Name: DEMO OBJECT 135 | m_TagString: Untagged 136 | m_Icon: {fileID: 0} 137 | m_NavMeshLayer: 0 138 | m_StaticEditorFlags: 0 139 | m_IsActive: 1 140 | --- !u!114 &967071191 141 | MonoBehaviour: 142 | m_ObjectHideFlags: 0 143 | m_CorrespondingSourceObject: {fileID: 0} 144 | m_PrefabInstance: {fileID: 0} 145 | m_PrefabAsset: {fileID: 0} 146 | m_GameObject: {fileID: 967071190} 147 | m_Enabled: 1 148 | m_EditorHideFlags: 0 149 | m_Script: {fileID: 11500000, guid: 600cce9ca0e597e4d869505c0400625c, type: 3} 150 | m_Name: 151 | m_EditorClassIdentifier: 152 | tagOne: MainCamera 153 | tagTwo: EditorOnly 154 | --- !u!4 &967071192 155 | Transform: 156 | m_ObjectHideFlags: 0 157 | m_CorrespondingSourceObject: {fileID: 0} 158 | m_PrefabInstance: {fileID: 0} 159 | m_PrefabAsset: {fileID: 0} 160 | m_GameObject: {fileID: 967071190} 161 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 162 | m_LocalPosition: {x: 0, y: 0, z: 0} 163 | m_LocalScale: {x: 1, y: 1, z: 1} 164 | m_Children: [] 165 | m_Father: {fileID: 0} 166 | m_RootOrder: 2 167 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 168 | --- !u!1 &1114830373 169 | GameObject: 170 | m_ObjectHideFlags: 0 171 | m_CorrespondingSourceObject: {fileID: 0} 172 | m_PrefabInstance: {fileID: 0} 173 | m_PrefabAsset: {fileID: 0} 174 | serializedVersion: 6 175 | m_Component: 176 | - component: {fileID: 1114830375} 177 | - component: {fileID: 1114830374} 178 | m_Layer: 0 179 | m_Name: Directional Light 180 | m_TagString: Untagged 181 | m_Icon: {fileID: 0} 182 | m_NavMeshLayer: 0 183 | m_StaticEditorFlags: 0 184 | m_IsActive: 1 185 | --- !u!108 &1114830374 186 | Light: 187 | m_ObjectHideFlags: 0 188 | m_CorrespondingSourceObject: {fileID: 0} 189 | m_PrefabInstance: {fileID: 0} 190 | m_PrefabAsset: {fileID: 0} 191 | m_GameObject: {fileID: 1114830373} 192 | m_Enabled: 1 193 | serializedVersion: 9 194 | m_Type: 1 195 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1} 196 | m_Intensity: 1 197 | m_Range: 10 198 | m_SpotAngle: 30 199 | m_InnerSpotAngle: 21.80208 200 | m_CookieSize: 10 201 | m_Shadows: 202 | m_Type: 2 203 | m_Resolution: -1 204 | m_CustomResolution: -1 205 | m_Strength: 1 206 | m_Bias: 0.05 207 | m_NormalBias: 0.4 208 | m_NearPlane: 0.2 209 | m_CullingMatrixOverride: 210 | e00: 1 211 | e01: 0 212 | e02: 0 213 | e03: 0 214 | e10: 0 215 | e11: 1 216 | e12: 0 217 | e13: 0 218 | e20: 0 219 | e21: 0 220 | e22: 1 221 | e23: 0 222 | e30: 0 223 | e31: 0 224 | e32: 0 225 | e33: 1 226 | m_UseCullingMatrixOverride: 0 227 | m_Cookie: {fileID: 0} 228 | m_DrawHalo: 0 229 | m_Flare: {fileID: 0} 230 | m_RenderMode: 0 231 | m_CullingMask: 232 | serializedVersion: 2 233 | m_Bits: 4294967295 234 | m_RenderingLayerMask: 1 235 | m_Lightmapping: 4 236 | m_LightShadowCasterMode: 0 237 | m_AreaSize: {x: 1, y: 1} 238 | m_BounceIntensity: 1 239 | m_ColorTemperature: 6570 240 | m_UseColorTemperature: 0 241 | m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0} 242 | m_UseBoundingSphereOverride: 0 243 | m_ShadowRadius: 0 244 | m_ShadowAngle: 0 245 | --- !u!4 &1114830375 246 | Transform: 247 | m_ObjectHideFlags: 0 248 | m_CorrespondingSourceObject: {fileID: 0} 249 | m_PrefabInstance: {fileID: 0} 250 | m_PrefabAsset: {fileID: 0} 251 | m_GameObject: {fileID: 1114830373} 252 | m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261} 253 | m_LocalPosition: {x: 0, y: 3, z: 0} 254 | m_LocalScale: {x: 1, y: 1, z: 1} 255 | m_Children: [] 256 | m_Father: {fileID: 0} 257 | m_RootOrder: 1 258 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0} 259 | --- !u!1 &1702096245 260 | GameObject: 261 | m_ObjectHideFlags: 0 262 | m_CorrespondingSourceObject: {fileID: 0} 263 | m_PrefabInstance: {fileID: 0} 264 | m_PrefabAsset: {fileID: 0} 265 | serializedVersion: 6 266 | m_Component: 267 | - component: {fileID: 1702096248} 268 | - component: {fileID: 1702096247} 269 | - component: {fileID: 1702096246} 270 | m_Layer: 0 271 | m_Name: Main Camera 272 | m_TagString: MainCamera 273 | m_Icon: {fileID: 0} 274 | m_NavMeshLayer: 0 275 | m_StaticEditorFlags: 0 276 | m_IsActive: 1 277 | --- !u!81 &1702096246 278 | AudioListener: 279 | m_ObjectHideFlags: 0 280 | m_CorrespondingSourceObject: {fileID: 0} 281 | m_PrefabInstance: {fileID: 0} 282 | m_PrefabAsset: {fileID: 0} 283 | m_GameObject: {fileID: 1702096245} 284 | m_Enabled: 1 285 | --- !u!20 &1702096247 286 | Camera: 287 | m_ObjectHideFlags: 0 288 | m_CorrespondingSourceObject: {fileID: 0} 289 | m_PrefabInstance: {fileID: 0} 290 | m_PrefabAsset: {fileID: 0} 291 | m_GameObject: {fileID: 1702096245} 292 | m_Enabled: 1 293 | serializedVersion: 2 294 | m_ClearFlags: 1 295 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0} 296 | m_projectionMatrixMode: 1 297 | m_GateFitMode: 2 298 | m_FOVAxisMode: 0 299 | m_SensorSize: {x: 36, y: 24} 300 | m_LensShift: {x: 0, y: 0} 301 | m_FocalLength: 50 302 | m_NormalizedViewPortRect: 303 | serializedVersion: 2 304 | x: 0 305 | y: 0 306 | width: 1 307 | height: 1 308 | near clip plane: 0.3 309 | far clip plane: 1000 310 | field of view: 60 311 | orthographic: 0 312 | orthographic size: 5 313 | m_Depth: -1 314 | m_CullingMask: 315 | serializedVersion: 2 316 | m_Bits: 4294967295 317 | m_RenderingPath: -1 318 | m_TargetTexture: {fileID: 0} 319 | m_TargetDisplay: 0 320 | m_TargetEye: 3 321 | m_HDR: 1 322 | m_AllowMSAA: 1 323 | m_AllowDynamicResolution: 0 324 | m_ForceIntoRT: 0 325 | m_OcclusionCulling: 1 326 | m_StereoConvergence: 10 327 | m_StereoSeparation: 0.022 328 | --- !u!4 &1702096248 329 | Transform: 330 | m_ObjectHideFlags: 0 331 | m_CorrespondingSourceObject: {fileID: 0} 332 | m_PrefabInstance: {fileID: 0} 333 | m_PrefabAsset: {fileID: 0} 334 | m_GameObject: {fileID: 1702096245} 335 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} 336 | m_LocalPosition: {x: 0, y: 1, z: -10} 337 | m_LocalScale: {x: 1, y: 1, z: 1} 338 | m_Children: [] 339 | m_Father: {fileID: 0} 340 | m_RootOrder: 0 341 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} 342 | --------------------------------------------------------------------------------