using UnityEngine; using UnityEditor; using UnityEditor.SceneManagement; namespace RayFire { [CanEditMultipleObjects] [CustomEditor (typeof(RayfireMan))] public class RayfireManEditor : Editor { Texture2D logo; Texture2D icon; RayfireMan man; /// ///////////////////////////////////////////////////////// /// Static /// ///////////////////////////////////////////////////////// static int space = 3; // Expand static bool expandDemolition; static bool expandMatPresets; static bool expandMatHeavyMetal; static bool expandMatLightMetal; static bool expandMatDenseRock; static bool expandMatPorousRock; static bool expandMatConcrete; static bool expandMatBrick; static bool expandMatGlass; static bool expandMatRubber; static bool expandMatIce; static bool expandMatWood; static GUIContent gui_ph_set = new GUIContent ("Set Gravity", "Sets custom gravity for simulated objects."); static GUIContent gui_ph_mul = new GUIContent (" Multiplier", "Custom gravity multiplier."); static GUIContent gui_ph_int = new GUIContent ("Interpolation", ""); static GUIContent gui_ph_cok = new GUIContent ("Cooking Options", "Mesh Collider cooking options."); static GUIContent gui_ph_col = new GUIContent ("Collider Size", "Minimum object size to get collider."); static GUIContent gui_ph_cop = new GUIContent ("Vertices Amount", "Used only when Planar Check enabled. All meshes with vertices amount less than defined value will perform planar check. If all vertices lay ALMOST on a plane then object will not get collider to avoid convex hull generation errors."); static GUIContent gui_col_mesh = new GUIContent ("Mesh", "Collision detection which will be used for simulated mesh objects."); static GUIContent gui_col_cls = new GUIContent ("Cluster", "Collision detection which will be used for Connected and Nested clusters."); static GUIContent gui_mat_min = new GUIContent ("Minimum Mass", "Minimum mass value which will be assigned to simulated object" + " if it's mass calculated by it's volume and density will be less than this value."); static GUIContent gui_mat_max = new GUIContent ("Maximum Mass", "Maximum mass value which will be assigned to simulated object" + " if it's mass calculated by it's volume and density will be higher than this value."); static GUIContent gui_mat_pres = new GUIContent ("Material Presets", "List of hardcoded materials with predefined simulation and demolition properties."); static GUIContent gui_mat_dest = new GUIContent ("Demolishable", "Makes object with this material demolishable in runtime."); static GUIContent gui_mat_sol = new GUIContent ("Solidity", "Global material solidity multiplier which used at collision to calculate if object should be demolished or not."); static GUIContent gui_mat_dens = new GUIContent ("Density", "Object mass depends on picked material density and collider volume."); static GUIContent gui_mat_drag = new GUIContent ("Drag", "Allows to decrease position velocity over time."); static GUIContent gui_mat_ang = new GUIContent ("Angular Drag", "Allows to decrease rotation velocity over time."); static GUIContent gui_mat_mat = new GUIContent ("Material", "Physic material which will be used for all objects with this material." + "If Material is not define then it will be created and defined here at Start using following Frictions and Bounciness properties."); static GUIContent gui_mat_dyn = new GUIContent ("Dynamic Friction", ""); static GUIContent gui_mat_stat = new GUIContent ("Static Friction", ""); static GUIContent gui_mat_bnc = new GUIContent ("Bounciness", ""); static GUIContent gui_act_par = new GUIContent ("Parent", "Object which will become parent of activated object"); static GUIContent gui_dml_sol = new GUIContent ("Global Solidity", "Global Solidity multiplier. Affect solidity of all simulated objects."); static GUIContent gui_dml_time = new GUIContent ("Time Quota", "Demolition time quota in milliseconds. Allows to prevent demolition at " + "the same frame if there was already another demolition " + "at the same frame and it took more time than Time Quota value."); static GUIContent gui_adv_expand = new GUIContent ("Advanced Properties", ""); static GUIContent gui_adv_parent = new GUIContent ("Parent", "Defines parent for all new fragments."); static GUIContent gui_adv_global = new GUIContent (" Global Parent", "Defines parent for all new fragments."); static GUIContent gui_adv_current = new GUIContent ("Current Amount", "Amount of created fragments."); static GUIContent gui_adv_amount = new GUIContent ("Maximum Amount", "Maximum amount of allowed fragments. Object won't be demolished if existing amount of fragments "+ "in scene higher that this value. Fading allows to decrease amount of fragments in scene."); static GUIContent gui_adv_bad = new GUIContent ("Bad Mesh Try", "Defines parent for all new fragments."); static GUIContent gui_adv_size = new GUIContent ("Size Threshold", "Disable Shadow Casting for all objects with size less than this value."); static GUIContent gui_pl_frg = new GUIContent ("Fragments", "Create gameobjects with MeshFilter, MeshRenderer and RayFireRigid components until Min Capacity value will be reached. Objects will be used for runtime fragments when needed"); static GUIContent gui_pl_prt = new GUIContent ("Particles", "Create gameobjects with Particle System until Min Capacity value will be reached. Objects will be used for Debris or Dust when needed."); static GUIContent gui_pl_bck = new GUIContent (" Reuse", "Do not destroy objects and send them back to pool until Max Capacity value will be reached"); static GUIContent gui_pl_min = new GUIContent (" Capacity Min", ""); static GUIContent gui_pl_max = new GUIContent (" Capacity Max", ""); /// ///////////////////////////////////////////////////////// /// Inspector /// ///////////////////////////////////////////////////////// public override void OnInspectorGUI() { man = target as RayfireMan; if (man == null) return; // Set new static instance if (RayfireMan.inst == null) RayfireMan.inst = man; GUILayout.Space (8); if (Application.isPlaying == true) { if (GUILayout.Button ("Destroy Storage Fragments", GUILayout.Height (20))) RayfireMan.inst.storage.DestroyAll(); GUILayout.Space (space); } UI_Physics(); GUILayout.Space (space); UI_Collision(); GUILayout.Space (space); UI_Materials(); GUILayout.Space (space); UI_Activation(); GUILayout.Space (space); UI_Demolition(); GUILayout.Space (space); UI_Pooling(); GUILayout.Space (space); UI_Info(); GUILayout.Space (space); UI_About(); GUILayout.Space (8); } /// ///////////////////////////////////////////////////////// /// Physics /// ///////////////////////////////////////////////////////// void UI_Physics() { GUILayout.Space (space); GUILayout.Label (" Physics", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.setGravity = EditorGUILayout.Toggle (gui_ph_set, man.setGravity); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); if (man.setGravity == true) { EditorGUI.BeginChangeCheck(); man.multiplier = EditorGUILayout.Slider (gui_ph_mul, man.multiplier, 0f, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); } EditorGUI.BeginChangeCheck(); man.interpolation = (RigidbodyInterpolation)EditorGUILayout.EnumPopup (gui_ph_int, man.interpolation); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); GUILayout.Label (" Collider", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.colliderSize = EditorGUILayout.Slider (gui_ph_col, man.colliderSize, 0f, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.coplanarVerts = EditorGUILayout.IntSlider (gui_ph_cop, man.coplanarVerts, 0, 999); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.cookingOptions = (MeshColliderCookingOptions)EditorGUILayout.EnumFlagsField (gui_ph_cok, man.cookingOptions); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); } /// ///////////////////////////////////////////////////////// /// Collision /// ///////////////////////////////////////////////////////// void UI_Collision() { GUILayout.Space (space); GUILayout.Label (" Collision Detection", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.meshCollision = (CollisionDetectionMode)EditorGUILayout.EnumPopup (gui_col_mesh, man.meshCollision); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.clusterCollision = (CollisionDetectionMode)EditorGUILayout.EnumPopup (gui_col_cls, man.clusterCollision); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); } /// ///////////////////////////////////////////////////////// /// Materials /// ///////////////////////////////////////////////////////// void UI_Materials() { GUILayout.Space (space); GUILayout.Label (" Materials", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.minimumMass = EditorGUILayout.Slider (gui_mat_min, man.minimumMass, 0f, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.maximumMass = EditorGUILayout.Slider (gui_mat_max, man.maximumMass, 0f, 4000f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); UI_Materials_Presets(); } void UI_Materials_Presets() { expandMatPresets = EditorGUILayout.Foldout (expandMatPresets, gui_mat_pres, true); if (expandMatPresets == true) { EditorGUI.indentLevel++; GUILayout.Space (space); UI_Material (man.materialPresets.heavyMetal, ref expandMatHeavyMetal, "Heavy Metal"); GUILayout.Space (space); UI_Material (man.materialPresets.lightMetal, ref expandMatLightMetal, "Light Metal"); GUILayout.Space (space); UI_Material (man.materialPresets.denseRock, ref expandMatDenseRock, "Dense Rock"); GUILayout.Space (space); UI_Material (man.materialPresets.porousRock, ref expandMatPorousRock, "Porous Rock"); GUILayout.Space (space); UI_Material (man.materialPresets.concrete, ref expandMatConcrete, "Concrete"); GUILayout.Space (space); UI_Material (man.materialPresets.brick, ref expandMatBrick, "Brick"); GUILayout.Space (space); UI_Material (man.materialPresets.glass, ref expandMatGlass, "Glass"); GUILayout.Space (space); UI_Material (man.materialPresets.rubber, ref expandMatRubber, "Rubber"); GUILayout.Space (space); UI_Material (man.materialPresets.ice, ref expandMatIce, "Ice"); GUILayout.Space (space); UI_Material (man.materialPresets.wood, ref expandMatWood, "Wood"); EditorGUI.indentLevel--; } } void UI_Material(RFMaterial mat, ref bool state, string cap) { state = EditorGUILayout.Foldout (state, cap, true); if (state == true) { GUILayout.Space (space); EditorGUI.indentLevel++; GUILayout.Label (" Demolition", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); mat.destructible = EditorGUILayout.Toggle (gui_mat_dest, mat.destructible); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); mat.solidity = EditorGUILayout.IntSlider (gui_mat_sol, mat.solidity, 0, 100); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Label (" Rigid Body", EditorStyles.boldLabel); EditorGUI.BeginChangeCheck(); mat.density = EditorGUILayout.Slider (gui_mat_dens, mat.density, 0.01f, 100f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); mat.drag = EditorGUILayout.Slider (gui_mat_drag, mat.drag, 0f, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); mat.angularDrag = EditorGUILayout.Slider (gui_mat_ang, mat.angularDrag, 0f, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Label (" Physic Material", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); mat.material = (PhysicMaterial)EditorGUILayout.ObjectField (gui_mat_mat, mat.material, typeof(PhysicMaterial), true); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); EditorGUI.BeginChangeCheck(); mat.dynamicFriction = EditorGUILayout.Slider (gui_mat_dyn, mat.dynamicFriction, 0.01f, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); mat.staticFriction = EditorGUILayout.Slider (gui_mat_stat, mat.staticFriction, 0.01f, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); mat.bounciness = EditorGUILayout.Slider (gui_mat_bnc, mat.bounciness, 0.01f, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); EditorGUI.indentLevel--; } } /// ///////////////////////////////////////////////////////// /// Activation /// ///////////////////////////////////////////////////////// void UI_Activation() { GUILayout.Space (space); GUILayout.Label (" Activation", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.parent = (GameObject)EditorGUILayout.ObjectField (gui_act_par, man.parent, typeof(GameObject), true); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); } /// ///////////////////////////////////////////////////////// /// Demolition /// ///////////////////////////////////////////////////////// void UI_Demolition() { GUILayout.Space (space); GUILayout.Label (" Demolition", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.globalSolidity = EditorGUILayout.Slider (gui_dml_sol, man.globalSolidity, 0f, 5f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.timeQuota = EditorGUILayout.Slider (gui_dml_time, man.timeQuota, 0f, 0.1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); UI_Demolition_Adv(); } void UI_Demolition_Adv() { expandDemolition = EditorGUILayout.Foldout (expandDemolition, gui_adv_expand, true); if (expandDemolition == true) { EditorGUI.indentLevel++; GUILayout.Space (space); GUILayout.Label (" Fragments", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.advancedDemolitionProperties.parent = (RFManDemolition.FragmentParentType)EditorGUILayout.EnumPopup (gui_adv_parent, man.advancedDemolitionProperties.parent); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); if (man.advancedDemolitionProperties.parent == RFManDemolition.FragmentParentType.GlobalParent) { EditorGUI.BeginChangeCheck(); man.advancedDemolitionProperties.globalParent = (Transform)EditorGUILayout.ObjectField (gui_adv_global, man.advancedDemolitionProperties.globalParent, typeof(Transform), true); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); } EditorGUI.BeginChangeCheck(); man.advancedDemolitionProperties.currentAmount = EditorGUILayout.IntField (gui_adv_current, man.advancedDemolitionProperties.currentAmount); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.advancedDemolitionProperties.maximumAmount = EditorGUILayout.IntField (gui_adv_amount, man.advancedDemolitionProperties.maximumAmount); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.advancedDemolitionProperties.badMeshTry = EditorGUILayout.IntSlider (gui_adv_bad, man.advancedDemolitionProperties.badMeshTry, 1, 10); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); GUILayout.Label (" Shadows", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.advancedDemolitionProperties.sizeThreshold = EditorGUILayout.Slider (gui_adv_size, man.advancedDemolitionProperties.sizeThreshold, 0, 1f); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); EditorGUI.indentLevel--; } } /// ///////////////////////////////////////////////////////// /// Pooling /// ///////////////////////////////////////////////////////// void UI_Pooling() { GUILayout.Space (space); GUILayout.Label (" Pooling", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.fragments.enable = EditorGUILayout.Toggle (gui_pl_frg, man.fragments.enable); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); if (man.fragments.enable == true) { GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.fragments.reuse = EditorGUILayout.Toggle (gui_pl_bck, man.fragments.reuse); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.fragments.minCap = EditorGUILayout.IntSlider (gui_pl_min, man.fragments.minCap, 0, 1000); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); if (man.fragments.reuse == true) { GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.fragments.maxCap = EditorGUILayout.IntSlider (gui_pl_max, man.fragments.maxCap, 0, 1000); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); } } GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.particles.enable = EditorGUILayout.Toggle (gui_pl_prt, man.particles.enable); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); if (man.particles.enable == true) { GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.particles.reuse = EditorGUILayout.Toggle (gui_pl_bck, man.particles.reuse); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.particles.minCap = EditorGUILayout.IntSlider (gui_pl_min, man.particles.minCap, 0, 1000); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); if (man.particles.reuse == true) { GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.particles.maxCap = EditorGUILayout.IntSlider (gui_pl_max, man.particles.maxCap, 0, 1000); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); } } } /// ///////////////////////////////////////////////////////// /// Info /// ///////////////////////////////////////////////////////// void UI_Info() { if (Application.isPlaying == true) { GUILayout.Label (" Info:", EditorStyles.boldLabel); if (man.fragments.enable == true && man.fragments.queue.Count > 0) GUILayout.Label ("Rigid Pool: " + man.fragments.queue.Count); if (man.particles.enable == true && man.particles.queue.Count > 0) GUILayout.Label ("Particles Pool: " + man.particles.queue.Count); if (man.advancedDemolitionProperties.currentAmount > 0) GUILayout.Label ("Fragments: " + man.advancedDemolitionProperties.currentAmount + "/" + man.advancedDemolitionProperties.maximumAmount); } } /// ///////////////////////////////////////////////////////// /// About /// ///////////////////////////////////////////////////////// void UI_About() { GUILayout.Space (space); GUILayout.Label (" About", EditorStyles.boldLabel); GUILayout.Space (space); EditorGUI.BeginChangeCheck(); man.debug = EditorGUILayout.Toggle ("Debug Messages", man.debug); if (EditorGUI.EndChangeCheck() == true) SetDirty (man); GUILayout.Space (space); GUILayout.Label ("Plugin build: " + RayfireMan.buildMajor + '.' + RayfireMan.buildMinor.ToString ("D2")); GUILayout.Space (space); // Logo TODO remove if component removed if (logo == null) logo = (Texture2D)AssetDatabase.LoadAssetAtPath ("Assets/RayFire/Info/Logo/logo_small.png", typeof(Texture2D)); if (logo != null) GUILayout.Box (logo, GUILayout.Width ((int)EditorGUIUtility.currentViewWidth - 19f), GUILayout.Height (64)); if (GUILayout.Button (" Changelog ", GUILayout.Height (20))) Application.OpenURL ("https://assetstore.unity.com/packages/tools/game-toolkits/rayfire-for-unity-148690#releases"); } /// ///////////////////////////////////////////////////////// /// Common /// ///////////////////////////////////////////////////////// void SetDirty (RayfireMan scr) { if (Application.isPlaying == false) { EditorUtility.SetDirty (scr); EditorSceneManager.MarkSceneDirty (scr.gameObject.scene); } } } }