├── .gitattributes ├── .gitignore ├── CHANGELOG.md ├── CHANGELOG.md.meta ├── CODEOWNERS ├── CODEOWNERS.meta ├── LICENSE ├── LICENSE.meta ├── README.md ├── README.md.meta ├── TCS PhysicsDropper.meta ├── TCS PhysicsDropper ├── Editor.meta ├── Editor │ ├── PhysicsDropToolbarButton.cs │ ├── PhysicsDropToolbarButton.cs.meta │ ├── PhysicsDropper.cs │ ├── PhysicsDropper.cs.meta │ ├── PhysicsDropperObject.cs │ ├── PhysicsDropperObject.cs.meta │ ├── PhysicsDropperOverlay.cs │ ├── PhysicsDropperOverlay.cs.meta │ ├── PhysicsDropperWindow.cs │ ├── PhysicsDropperWindow.cs.meta │ ├── TCS.PhysicsDropper.asmdef │ ├── TCS.PhysicsDropper.asmdef.meta │ ├── Utils.meta │ └── Utils │ │ ├── Logger.cs │ │ └── Logger.cs.meta ├── Runtime.meta └── Runtime │ ├── PhysicsDropperComponent.cs │ ├── PhysicsDropperComponent.cs.meta │ ├── TCS.PhysicsDropper.asmdef │ └── TCS.PhysicsDropper.asmdef.meta ├── docs~ ├── images.meta └── images │ ├── ExampleGif_1.gif │ ├── ExampleGif_1.gif.meta │ ├── ExampleGif_2.gif │ ├── ExampleGif_2.gif.meta │ ├── ExampleGif_3.gif │ ├── ExampleGif_4.gif │ ├── IconImage.png │ └── InfoPanel.png ├── package.json └── package.json.meta /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # This .gitignore file should be placed at the root of your Unity project directory 2 | # 3 | # Get latest from https://github.com/github/gitignore/blob/main/Unity.gitignore 4 | # 5 | /[Ll]ibrary/ 6 | /[Tt]emp/ 7 | /[Oo]bj/ 8 | /[Bb]uild/ 9 | /[Bb]uilds/ 10 | /[Ll]ogs/ 11 | /[Uu]ser[Ss]ettings/ 12 | 13 | # MemoryCaptures can get excessive in size. 14 | # They also could contain extremely sensitive data 15 | /[Mm]emoryCaptures/ 16 | 17 | # Recordings can get excessive in size 18 | /[Rr]ecordings/ 19 | 20 | # Uncomment this line if you wish to ignore the asset store tools plugin 21 | # /[Aa]ssets/AssetStoreTools* 22 | 23 | # Autogenerated Jetbrains Rider plugin 24 | /[Aa]ssets/Plugins/Editor/JetBrains* 25 | 26 | # Visual Studio cache directory 27 | .vs/ 28 | 29 | # Gradle cache directory 30 | .gradle/ 31 | 32 | # Autogenerated VS/MD/Consulo solution and project files 33 | ExportedObj/ 34 | .consulo/ 35 | *.csproj 36 | *.unityproj 37 | *.sln 38 | *.suo 39 | *.tmp 40 | *.user 41 | *.userprefs 42 | *.pidb 43 | *.booproj 44 | *.svd 45 | *.pdb 46 | *.mdb 47 | *.opendb 48 | *.VC.db 49 | 50 | # Unity3D generated meta files 51 | *.pidb.meta 52 | *.pdb.meta 53 | *.mdb.meta 54 | 55 | # Unity3D generated file on crash reports 56 | sysinfo.txt 57 | 58 | # Builds 59 | *.apk 60 | *.aab 61 | *.unitypackage 62 | *.app 63 | 64 | # Crashlytics generated file 65 | crashlytics-build.properties 66 | 67 | # Packed Addressables 68 | /[Aa]ssets/[Aa]ddressable[Aa]ssets[Dd]ata/*/*.bin* 69 | 70 | # Temporary auto-generated Android Assets 71 | /[Aa]ssets/[Ss]treamingAssets/aa.meta 72 | /[Aa]ssets/[Ss]treamingAssets/aa/* 73 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## [1.0.9] - 2024-11-21 2 | - Removed: Linq for optimization 3 | 4 | ## [1.0.8] - 2024-11-21 5 | - Enhancement: Changed to TryGet from GetComponent for optimization. 6 | 7 | ## [1.0.7] - 2024-11-21 8 | - Update: Fixed issue where all rigid bodies caught in simulation. 9 | 10 | ## [1.0.6] - 2024-11-20 11 | - Update: added 'Logger.cs' and updated log methods 12 | - Hotfix: added Default icon to soft fix the issue of the icon not showing up in the scene view. 13 | - Hotfix: just used unity default icon to save myself all this hassle. 14 | 15 | ## [1.0.5] - 2024-11-20 16 | - Hotfix: fixed issue were scene view needed a refresh to show the icon from the resource folder. 17 | - Hotfix: Adjusted the toggle to reflected having no game object selected 18 | 19 | ## [1.0.4] - 2024-11-19 20 | - Hotfix: fixed typo on icon image for resource folder. 21 | 22 | ## [1.0.3] - 2024-11-08 23 | - Updated to store collider IsTrigger value and reset it after the object is dropped. 24 | 25 | ## [1.0.2] - 2024-11-07 26 | - Updated added components to only give the parent a rigidbody if it doesn't already have one. 27 | 28 | ## [1.0.1] - 2024-11-06 29 | -Updating the package to include the missing `TCS-PhysicsDropper` folder. 30 | 31 | ## [1.0.0] 32 | ### Initial Release and Additions 33 | - Introduced foundational package contents. -------------------------------------------------------------------------------- /CHANGELOG.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6671f06be4f6d814e9aabcba036f1593 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | # You (repo owner) as the Code Owner for the whole repository 2 | * @Ddemon26 3 | -------------------------------------------------------------------------------- /CODEOWNERS.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 6e5a6a0b158e49f4bb41db5174f56bc4 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 Damon Fedorick 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /LICENSE.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ed80a8ee88ae647429bb092989895b87 3 | DefaultImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Physics Dropper Overlay for Unity 2 | Physics Dropper in ActionPhysics Dropper in Action 3 | 4 | Physics Dropper in ActionPhysics Dropper in Action 5 | 6 | [![Join our Discord](https://img.shields.io/badge/Discord-Join%20Us-7289DA?logo=discord&logoColor=white)](https://discord.gg/knwtcq3N2a) 7 | ![Discord](https://img.shields.io/discord/1047781241010794506) 8 | ![GitHub Forks](https://img.shields.io/github/forks/Ddemon26/TCS-PhysicsDropper) 9 | ![GitHub Contributors](https://img.shields.io/github/contributors/Ddemon26/TCS-PhysicsDropper) 10 | ![GitHub Stars](https://img.shields.io/github/stars/Ddemon26/TCS-PhysicsDropper) 11 | ![GitHub Repo Size](https://img.shields.io/github/repo-size/Ddemon26/TCS-PhysicsDropper) 12 | 13 | ## Overview 14 | 15 | The **Physics Dropper Overlay** is a tool for Unity developers that allows efficient, physics-based placement of GameObjects in Unity's SceneView. By using simulated physics, this tool streamlines the positioning process, enabling natural placements without manual adjustments. 16 | 17 | Using the Physics Dropper Overlay adds realism to your scene by leveraging Unity's physics engine. It is especially useful for creating dynamic environments, setting up test cases, or managing multiple objects, speeding up development while maintaining precision. 18 | 19 | ## Key Features 20 | 21 | - **SceneView Integration**: Provides a seamless overlay within Unity's SceneView, allowing quick access to the dropper tool. 22 | - **Toolbar Access**: Access the dropper via a dedicated toolbar button. 23 | - **Configurable Stopping Criteria**: Choose when the simulation should stop based on time elapsed or velocity threshold. 24 | - **Automatic Component Management**: Automatically adds necessary physics components like Colliders and Rigidbodies if absent. 25 | - **MeshCollider Convex Settings Support**: Adjusts MeshColliders to be compatible with dynamic physics simulations. 26 | - **Max Simulation Time Setting**: Allows users to define a maximum simulation duration to avoid endless simulations. 27 | 28 | ## How It Works 29 | 30 | The **Physics Dropper Overlay** simplifies arranging GameObjects in Unity by using simulated physics within the editor. It ensures that each selected GameObject is equipped with necessary physics components and manages the simulation process in real time. 31 | 32 | Workflow steps: 33 | 34 | 1. **Select GameObjects**: Highlight the GameObjects in the SceneView that you want to drop. 35 | 2. **Activate Dropper**: Click the custom toolbar button to initiate the dropper. This starts the physics simulation. 36 | 3. **Simulation Criteria**: The drop continues until one of the stopping criteria is satisfied: 37 | - **Time After Impact**: The simulation persists for a set time after the first contact. 38 | - **Velocity Threshold**: The simulation stops when the velocity falls below a predefined threshold. 39 | 4. **Automatic Cleanup**: The tool reverts any temporary components to return the GameObjects to their original state once the simulation is complete. 40 | 41 | ## Installation 42 | 43 | ``` 44 | https://github.com/Ddemon26/TCS-PhysicsDropper.git 45 | ``` 46 | 47 | To install the Physics Dropper Overlay: 48 | 49 | 1. Clone or download this repository. 50 | 2. Add the `PhysicsDropperOverlay.cs` script to your Unity project's `Editor` directory. 51 | 3. Launch Unity, and the Physics Dropper Overlay will be available within the SceneView. 52 | 53 | ## Usage 54 | 55 | To use the Physics Dropper Overlay: 56 | 57 | 1. **Select GameObjects**: In the SceneView, select the GameObjects to drop. 58 | 2. **Click the Toolbar Button**: Locate and click the `PhysicsDropToolbarButton` to open the dropper interface. 59 | 3. **Configure Drop Settings**: 60 | - **Stopping Criteria**: Set criteria for ending the simulation: 61 | - **Time After Impact**: Duration after landing. 62 | - **Velocity Threshold**: Velocity below which the simulation stops. 63 | - **Maximum Simulation Time**: Set a time limit for the simulation. 64 | 4. **Start Simulation**: Click to initiate the drop. The objects will fall and interact naturally based on physics. 65 | 66 | ### Example Scenario 67 | 68 | For designing a forest environment, instead of manually adjusting rocks and branches on uneven terrain, use the Physics Dropper tool to simulate realistic drops. 69 | 70 | ## Physics Dropper in Action Toolbar Button and Interface 71 | 72 | - **PhysicsDropToolbarButton**: The primary way to interact with the Physics Dropper. The button in Unity's SceneView toolbar allows you to start, configure, and stop the physics simulation. 73 | - **PhysicsDropperWindow**: A popup window for modifying parameters like stopping criteria and maximum simulation time. 74 | 75 | ## Contributing 76 | 77 | Contributions to improve the Physics Dropper Overlay are welcome. If you have feature suggestions or optimizations, feel free to fork the repository, make changes, and submit a pull request. 78 | 79 | ### Local Development 80 | 81 | 1. Fork this repository. 82 | 2. Create a new branch (`git checkout -b feature/NewFeature`). 83 | 3. Commit your changes (`git commit -m 'Add new feature'`). 84 | 4. Push to the branch (`git push origin feature/NewFeature`). 85 | 5. Open a Pull Request for review. 86 | 87 | ## Support 88 | 89 | If you encounter issues or have questions, join our Discord community using the link at the top of this README. 90 | 91 | ## License 92 | 93 | This project is licensed under the MIT License, allowing free use, modification, and distribution. 94 | 95 | --- 96 | 97 | For more information, refer to the comments within the codebase or create an issue in the GitHub repository. Happy coding! 98 | -------------------------------------------------------------------------------- /README.md.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 13bf1fee41f1e354bab436ec696163ee 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /TCS PhysicsDropper.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 575f2adb42e84354a8101ef627d2a9df 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 38eb617b0001932468cea173508c432a 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropToolbarButton.cs: -------------------------------------------------------------------------------- 1 | using UnityEditor; 2 | using UnityEditor.Toolbars; 3 | using UnityEngine; 4 | using UnityEngine.UIElements; 5 | using PopupWindow = UnityEditor.PopupWindow; 6 | namespace TCS.PhysicsDropper { 7 | [EditorToolbarElement(ID, typeof(SceneView))] 8 | internal sealed class PhysicsDropToolbarButton : EditorToolbarDropdownToggle, IAccessContainerWindow { 9 | public const string ID = "PhysicsDropToolbarButton"; 10 | readonly PhysicsDropper m_physicsDropper = new(); 11 | public EditorWindow containerWindow { get; set; } 12 | 13 | static readonly Texture2D PreloadedIcon = EditorGUIUtility 14 | .IconContent("ConstantForce Icon").image as Texture2D; 15 | 16 | public PhysicsDropToolbarButton() { 17 | viewDataKey = ID; 18 | icon = PreloadedIcon; 19 | if (!icon) { 20 | Logger.LogError("Sprite 'ConstantForceRed' not found."); 21 | } 22 | name = "PhysicsDropToolbarButton"; 23 | tooltip = L10n.Tr("Physics Dropper"); 24 | dropdownClicked += () => PopupWindow.Show(worldBound, new PhysicsDropperWindow(m_physicsDropper)); 25 | this.RegisterValueChangedCallback(evt => OnToggleChanged(evt.newValue)); 26 | RegisterCallback(new EventCallback(OnAttachedToPanel)); 27 | RegisterCallback(new EventCallback(OnDetachFromPanel)); 28 | 29 | m_physicsDropper.SendFalseBool += OnToggleChanged; 30 | } 31 | void OnToggleChanged(bool evtNewValue) { 32 | value = evtNewValue; 33 | if (evtNewValue) { 34 | m_physicsDropper.DropSelectedObjects(); 35 | } 36 | else { 37 | m_physicsDropper.StopDropping(); 38 | } 39 | } 40 | void OnAttachedToPanel(AttachToPanelEvent evt) { 41 | //NO-OP 42 | //Debug.Log("Element attached to panel"); 43 | } 44 | void OnDetachFromPanel(DetachFromPanelEvent evt) { 45 | //NO-OP 46 | //Debug.Log("Element detached from panel"); 47 | } 48 | } 49 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropToolbarButton.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 864a40d5a46b4d63861c04d7a29c8bec -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropper.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using UnityEditor; 4 | using UnityEngine; 5 | using Object = UnityEngine.Object; 6 | 7 | namespace TCS.PhysicsDropper { 8 | internal enum StoppingCriteria { 9 | TimeAfterImpact, 10 | VelocityThreshold, 11 | } 12 | 13 | internal sealed class PhysicsDropper { 14 | public float TimeAfterImpact = 1.0f; 15 | public float VelocityThreshold = 0.001f; 16 | public float MaxSimulationTime = 20f; 17 | public StoppingCriteria StoppingCriteria = StoppingCriteria.TimeAfterImpact; 18 | public Action SendFalseBool; 19 | 20 | readonly List m_droppingObjects = new(); 21 | readonly List m_nonSelectedRigidbodies = new(); 22 | bool m_isDropping; 23 | SimulationMode m_prevSimulationMode; 24 | 25 | public void DropSelectedObjects() { 26 | GameObject[] selectedObjects = Selection.gameObjects; 27 | 28 | if (selectedObjects.Length == 0) { 29 | Logger.LogError("No GameObjects selected!"); 30 | SendFalseBool?.Invoke(false); 31 | return; 32 | } 33 | 34 | // Check for at least one MeshRenderer in selected objects or their children 35 | var hasAtLeastOneMeshRenderer = false; 36 | foreach (var obj in selectedObjects) { 37 | 38 | if (!HasMeshRenderer(obj)) continue; 39 | hasAtLeastOneMeshRenderer = true; 40 | break; 41 | } 42 | 43 | if (!hasAtLeastOneMeshRenderer) { 44 | Logger.LogError("At least one selected GameObject or its children must have a MeshRenderer component."); 45 | return; 46 | } 47 | 48 | m_droppingObjects.Clear(); 49 | m_nonSelectedRigidbodies.Clear(); 50 | 51 | // Collect all rigidbodies in the scene that are not selected 52 | CollectNonSelectedRigidbodies(selectedObjects); 53 | 54 | // Disable non-selected rigidbodies 55 | DisableNonSelectedRigidbodies(); 56 | 57 | foreach (var obj in selectedObjects) { 58 | if (!obj) { 59 | Logger.LogError("One of the selected GameObjects is null!"); 60 | continue; 61 | } 62 | 63 | var transform = obj.transform; 64 | var originalPosition = transform.position; 65 | var originalRotation = transform.rotation; 66 | 67 | // Register Undo for the transform (captures position and rotation) 68 | Undo.RegisterCompleteObjectUndo(transform, "Drop Objects"); 69 | 70 | bool hadRigidbody; 71 | var rb = obj.GetComponent(); 72 | var originalCollisionDetectionMode = CollisionDetectionMode.Discrete; 73 | var originalIsKinematic = true; 74 | 75 | if (rb) { 76 | hadRigidbody = true; 77 | originalCollisionDetectionMode = rb.collisionDetectionMode; 78 | originalIsKinematic = rb.isKinematic; 79 | } 80 | else { 81 | hadRigidbody = false; 82 | // Add Rigidbody without registering with Undo 83 | rb = obj.AddComponent(); 84 | } 85 | 86 | rb.collisionDetectionMode = CollisionDetectionMode.ContinuousDynamic; 87 | rb.isKinematic = false; 88 | 89 | // Handle PhysicsDropperComponent 90 | var dropperComponent = obj.GetComponent(); 91 | if (!dropperComponent) { 92 | // Add PhysicsDropperComponent without registering with Undo 93 | dropperComponent = obj.AddComponent(); 94 | } 95 | 96 | // Prepare data for PhysicsDropperObject 97 | var physicsDropperObject = new PhysicsDropperObject { 98 | GameObject = obj, 99 | Rigidbody = rb, 100 | HadRigidbody = hadRigidbody, 101 | DropperComponent = dropperComponent, 102 | Timer = 0f, 103 | HasLanded = false, 104 | IsDroppingComplete = false, 105 | OriginalCollisionDetectionMode = originalCollisionDetectionMode, 106 | OriginalIsKinematic = originalIsKinematic, 107 | OriginalPosition = originalPosition, 108 | OriginalRotation = originalRotation, 109 | TotalSimulationTime = 0f, 110 | ColliderDataList = new List(), 111 | }; 112 | 113 | SetupColliders(obj, physicsDropperObject); 114 | 115 | m_droppingObjects.Add(physicsDropperObject); 116 | } 117 | 118 | if (m_droppingObjects.Count <= 0) return; 119 | m_prevSimulationMode = Physics.simulationMode; 120 | Physics.simulationMode = SimulationMode.Script; 121 | 122 | m_isDropping = true; 123 | EditorApplication.update += UpdatePhysics; 124 | 125 | Undo.undoRedoPerformed += OnUndoRedoPerformed; 126 | } 127 | 128 | void CollectNonSelectedRigidbodies(GameObject[] selectedObjects) { 129 | Rigidbody[] allRigidbodies = Object.FindObjectsByType(FindObjectsSortMode.None); 130 | HashSet selectedSet = new(selectedObjects); 131 | 132 | foreach (var rb in allRigidbodies) { 133 | if (!rb || !rb.gameObject) continue; 134 | 135 | if (!selectedSet.Contains(rb.gameObject)) { 136 | m_nonSelectedRigidbodies.Add 137 | ( 138 | new RigidbodyState { 139 | Rigidbody = rb, 140 | OriginalIsKinematic = rb.isKinematic, 141 | } 142 | ); 143 | } 144 | } 145 | } 146 | 147 | void DisableNonSelectedRigidbodies() { 148 | foreach (var rbState in m_nonSelectedRigidbodies) { 149 | rbState.Rigidbody.isKinematic = true; 150 | } 151 | } 152 | 153 | void RestoreNonSelectedRigidbodies() { 154 | foreach (var rbState in m_nonSelectedRigidbodies) { 155 | rbState.Rigidbody.isKinematic = rbState.OriginalIsKinematic; 156 | } 157 | 158 | m_nonSelectedRigidbodies.Clear(); 159 | } 160 | 161 | static void SetupColliders(GameObject obj, PhysicsDropperObject physicsDropperObject) { 162 | if (obj.transform.childCount > 0) { 163 | // Object has children 164 | // Add colliders to all descendants 165 | foreach (var descendant in obj.GetComponentsInChildren(includeInactive: true)) { 166 | if (descendant == obj.transform) continue; // Skip the parent itself 167 | 168 | var collider = descendant.GetComponent(); 169 | bool hadCollider = collider; 170 | var originalIsConvex = true; 171 | var originalIsTrigger = false; // Initialize the variable 172 | 173 | if (!collider) { 174 | // Add MeshCollider without registering with Undo 175 | collider = descendant.gameObject.AddComponent(); 176 | ((MeshCollider)collider).convex = true; 177 | collider.isTrigger = false; // Ensure it's not a trigger 178 | } 179 | else { 180 | originalIsTrigger = collider.isTrigger; // Store original isTrigger 181 | if (originalIsTrigger) { 182 | collider.isTrigger = false; // Set to false for simulation 183 | } 184 | 185 | if (collider is MeshCollider meshCollider) { 186 | originalIsConvex = meshCollider.convex; 187 | if (!meshCollider.convex) { 188 | meshCollider.convex = true; 189 | } 190 | } 191 | } 192 | 193 | // Add collider data to ColliderDataList 194 | physicsDropperObject.ColliderDataList.Add 195 | ( 196 | new ColliderData { 197 | GameObject = descendant.gameObject, 198 | Collider = collider, 199 | HadCollider = hadCollider, 200 | OriginalIsConvex = originalIsConvex, 201 | OriginalIsTrigger = originalIsTrigger, // Store the original isTrigger 202 | } 203 | ); 204 | } 205 | } 206 | else { 207 | // Object has no children 208 | // Handle Collider for obj 209 | 210 | var collider = obj.GetComponent(); 211 | bool hadCollider = collider; 212 | var originalIsConvex = true; 213 | var originalIsTrigger = false; // Initialize the variable 214 | 215 | if (!collider) { 216 | // Add MeshCollider without registering with Undo 217 | collider = obj.AddComponent(); 218 | ((MeshCollider)collider).convex = true; 219 | collider.isTrigger = false; // Ensure it's not a trigger 220 | } 221 | else { 222 | originalIsTrigger = collider.isTrigger; // Store original isTrigger 223 | if (originalIsTrigger) { 224 | collider.isTrigger = false; // Set to false for simulation 225 | } 226 | 227 | if (collider is MeshCollider meshCollider) { 228 | originalIsConvex = meshCollider.convex; 229 | if (!meshCollider.convex) { 230 | meshCollider.convex = true; 231 | } 232 | } 233 | } 234 | 235 | // Set collider data in physicsDropperObject 236 | physicsDropperObject.Collider = collider; 237 | physicsDropperObject.HadCollider = hadCollider; 238 | physicsDropperObject.OriginalIsConvex = originalIsConvex; 239 | physicsDropperObject.OriginalIsTrigger = originalIsTrigger; // Store the original isTrigger 240 | } 241 | } 242 | 243 | void UpdatePhysics() { 244 | if (!m_isDropping) { 245 | EditorApplication.update -= UpdatePhysics; 246 | return; 247 | } 248 | 249 | // Simulate physics step 250 | float simulationStep = Time.fixedDeltaTime; 251 | Physics.Simulate(simulationStep); 252 | 253 | // Refresh the scene view 254 | SceneView.RepaintAll(); 255 | 256 | // Check if all objects have finished dropping 257 | var allDone = true; 258 | foreach (var obj in m_droppingObjects) { 259 | if (obj.IsDroppingComplete) continue; 260 | 261 | // Check if the GameObject or Rigidbody has been destroyed 262 | if (!obj.GameObject || !obj.Rigidbody || !obj.DropperComponent) { 263 | obj.IsDroppingComplete = true; 264 | continue; 265 | } 266 | 267 | allDone = false; // At least one object is still dropping 268 | 269 | obj.TotalSimulationTime += simulationStep; 270 | 271 | if (obj.TotalSimulationTime >= MaxSimulationTime) { 272 | obj.IsDroppingComplete = true; 273 | continue; 274 | } 275 | 276 | switch (StoppingCriteria) { 277 | case StoppingCriteria.TimeAfterImpact when !obj.HasLanded: 278 | if (obj.DropperComponent.m_hasCollided) { 279 | obj.HasLanded = true; 280 | } 281 | 282 | break; 283 | case StoppingCriteria.TimeAfterImpact: 284 | obj.Timer += simulationStep; 285 | if (obj.Timer >= TimeAfterImpact) { 286 | obj.IsDroppingComplete = true; 287 | } 288 | 289 | break; 290 | case StoppingCriteria.VelocityThreshold: 291 | if (obj.Rigidbody.linearVelocity.magnitude <= VelocityThreshold) { 292 | obj.IsDroppingComplete = true; 293 | } 294 | 295 | break; 296 | default: 297 | throw new ArgumentOutOfRangeException(); 298 | } 299 | } 300 | 301 | if (!allDone) return; 302 | StopDropping(); 303 | SendFalseBool?.Invoke(false); 304 | } 305 | 306 | void OnUndoRedoPerformed() { 307 | if (!m_isDropping) return; 308 | StopDropping(); 309 | RestoreTransforms(); 310 | SendFalseBool?.Invoke(false); 311 | } 312 | 313 | void RestoreTransforms() { 314 | foreach (var obj in m_droppingObjects) { 315 | if (!obj.GameObject) continue; 316 | var transform = obj.GameObject.transform; 317 | Undo.RecordObject(transform, "Restore Transform"); 318 | transform.position = obj.OriginalPosition; 319 | transform.rotation = obj.OriginalRotation; 320 | 321 | // Optionally, reset Rigidbody velocities to prevent further movement 322 | if (!obj.Rigidbody) continue; 323 | obj.Rigidbody.linearVelocity = Vector3.zero; 324 | obj.Rigidbody.angularVelocity = Vector3.zero; 325 | } 326 | } 327 | 328 | public void StopDropping() { 329 | Physics.simulationMode = m_prevSimulationMode; 330 | 331 | // Restore non-selected rigidbodies 332 | RestoreNonSelectedRigidbodies(); 333 | 334 | foreach (var obj in m_droppingObjects) { 335 | if (obj.Rigidbody) { 336 | obj.Rigidbody.isKinematic = obj.OriginalIsKinematic; 337 | obj.Rigidbody.collisionDetectionMode = obj.OriginalCollisionDetectionMode; 338 | 339 | if (!obj.HadRigidbody) { 340 | // Remove Rigidbody without registering with Undo 341 | Object.DestroyImmediate(obj.Rigidbody); 342 | } 343 | } 344 | 345 | if (obj.ColliderDataList is { Count: > 0 }) { 346 | foreach (var colliderData in obj.ColliderDataList) { 347 | if (colliderData.Collider is MeshCollider meshCollider) { 348 | meshCollider.convex = colliderData.OriginalIsConvex; 349 | } 350 | 351 | // Restore original isTrigger value 352 | colliderData.Collider.isTrigger = colliderData.OriginalIsTrigger; 353 | 354 | if (!colliderData.HadCollider) { 355 | // Remove Collider without registering with Undo 356 | Object.DestroyImmediate(colliderData.Collider); 357 | } 358 | } 359 | } 360 | 361 | if (obj.Collider) { 362 | if (obj.Collider is MeshCollider meshCollider) { 363 | meshCollider.convex = obj.OriginalIsConvex; 364 | } 365 | 366 | // Restore original isTrigger value 367 | obj.Collider.isTrigger = obj.OriginalIsTrigger; 368 | 369 | if (!obj.HadCollider) { 370 | // Remove Collider without registering with Undo 371 | Object.DestroyImmediate(obj.Collider); 372 | } 373 | } 374 | 375 | if (obj.DropperComponent) { 376 | // Remove PhysicsDropperComponent without registering with Undo 377 | Object.DestroyImmediate(obj.DropperComponent); 378 | } 379 | } 380 | 381 | m_droppingObjects.Clear(); 382 | m_isDropping = false; 383 | EditorApplication.update -= UpdatePhysics; 384 | 385 | // Unsubscribe from Undo event 386 | Undo.undoRedoPerformed -= OnUndoRedoPerformed; 387 | } 388 | 389 | // Helper method to check for MeshRenderer 390 | static bool HasMeshRenderer(GameObject obj) { 391 | if (obj.TryGetComponent(out _)) { 392 | return true; 393 | } 394 | 395 | foreach (var child in obj.GetComponentsInChildren(true)) { 396 | if (child.TryGetComponent(out _)) { 397 | return true; 398 | } 399 | } 400 | 401 | return false; 402 | } 403 | } 404 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropper.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: a75aa953ef4540409df36f787210acac -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropperObject.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEngine; 3 | namespace TCS.PhysicsDropper { 4 | internal class RigidbodyState 5 | { 6 | public Rigidbody Rigidbody; 7 | public bool OriginalIsKinematic; 8 | } 9 | 10 | internal class ColliderData { 11 | public GameObject GameObject; 12 | public Collider Collider; 13 | public bool HadCollider; 14 | public bool OriginalIsConvex; 15 | public bool OriginalIsTrigger; 16 | } 17 | 18 | internal sealed class PhysicsDropperObject { 19 | public GameObject GameObject; 20 | public Rigidbody Rigidbody; 21 | public bool HadRigidbody; 22 | public Collider Collider; 23 | public bool HadCollider; 24 | public PhysicsDropperComponent DropperComponent; 25 | public float Timer; 26 | public bool HasLanded; 27 | public bool IsDroppingComplete; 28 | public CollisionDetectionMode OriginalCollisionDetectionMode; 29 | public bool OriginalIsKinematic; 30 | public bool OriginalIsConvex; 31 | public bool OriginalIsTrigger; 32 | public Vector3 OriginalPosition; 33 | public Quaternion OriginalRotation; 34 | public float TotalSimulationTime; 35 | public List ColliderDataList; 36 | } 37 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropperObject.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: d5216b2548774528b72e38a326da70cc -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropperOverlay.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using UnityEditor; 3 | using UnityEditor.Overlays; 4 | using UnityEngine; 5 | using UnityEngine.UIElements; 6 | namespace TCS.PhysicsDropper { 7 | [Overlay(typeof(SceneView), null)] 8 | internal sealed class PhysicsDropperOverlay : Overlay, ICreateToolbar { 9 | public override VisualElement CreatePanelContent() => new PhysicsDropToolbarButton(); 10 | 11 | static readonly Texture2D PreloadedIcon = EditorGUIUtility.IconContent("ConstantForce Icon").image as Texture2D; 12 | 13 | public override void OnCreated() { 14 | base.OnCreated(); 15 | displayName = "Physics Dropper"; 16 | rootVisualElement.viewDataKey = "PhysicsDropperOverlay"; 17 | var sprite = PreloadedIcon; 18 | if (sprite) { 19 | collapsedIcon = sprite; 20 | } else { 21 | Logger.LogError("Sprite 'ConstantForceRed' not found."); 22 | } 23 | } 24 | 25 | public override void OnWillBeDestroyed() { 26 | base.OnWillBeDestroyed(); 27 | collapsedIcon = null; 28 | } 29 | 30 | public IEnumerable toolbarElements { get { yield return PhysicsDropToolbarButton.ID; } } 31 | } 32 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropperOverlay.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: c07de6f40f3823345b237bc8ecd95069 -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropperWindow.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using UnityEditor; 3 | using UnityEngine; 4 | namespace TCS.PhysicsDropper { 5 | internal sealed class PhysicsDropperWindow : PopupWindowContent { 6 | readonly PhysicsDropper m_physicsDropper; 7 | public PhysicsDropperWindow(PhysicsDropper physicsDropper) => m_physicsDropper = physicsDropper; 8 | public override Vector2 GetWindowSize() { 9 | var height = 18f; // Initial height for the first label 10 | 11 | height += 18f; // Height for the Stopping Criteria dropdown 12 | 13 | height += 18f; // Height for the current showing label 14 | height += 18f; // Height for the current showing field 15 | 16 | height += 18f; // Height for the Maximum Simulation Time label 17 | height += 18f; // Height for the Maximum Simulation Time field 18 | 19 | return new Vector2(200, height + 9f); 20 | } 21 | 22 | public override void OnGUI(Rect rect) { 23 | if (m_physicsDropper == null) 24 | return; 25 | if (Event.current.type == EventType.Layout) 26 | return; 27 | Draw(rect); 28 | if (Event.current.type == EventType.MouseMove) 29 | Event.current.Use(); 30 | if (Event.current.type != EventType.KeyDown || Event.current.keyCode != KeyCode.Escape) 31 | return; 32 | editorWindow.Close(); 33 | GUIUtility.ExitGUI(); 34 | } 35 | 36 | void Draw(Rect rect) { 37 | if (m_physicsDropper == null) return; 38 | 39 | var rect1 = new Rect(1f, 1f, rect.width - 2f, 18f); 40 | 41 | switch (m_physicsDropper.StoppingCriteria) { 42 | case StoppingCriteria.TimeAfterImpact: 43 | EditorGUI.LabelField(rect1, "Time After Impact"); 44 | rect1.y += 18f; 45 | m_physicsDropper.TimeAfterImpact = EditorGUI.Slider(rect1, m_physicsDropper.TimeAfterImpact, 0.001f, 60f); 46 | break; 47 | case StoppingCriteria.VelocityThreshold: 48 | EditorGUI.LabelField(rect1, "Velocity Threshold"); 49 | rect1.y += 18f; 50 | m_physicsDropper.VelocityThreshold = EditorGUI.Slider(rect1, m_physicsDropper.VelocityThreshold, 0.001f, 0.1f); 51 | break; 52 | default: 53 | throw new ArgumentOutOfRangeException(); 54 | } 55 | 56 | rect1.y += 18f; 57 | EditorGUI.LabelField(rect1, "Maximum Simulation Time"); 58 | rect1.y += 18f; 59 | m_physicsDropper.MaxSimulationTime = EditorGUI.Slider(rect1, m_physicsDropper.MaxSimulationTime, 0.1f, 60f); 60 | rect1.y += 18f; 61 | EditorGUI.LabelField(rect1, "Stopping Criteria"); 62 | rect1.y += 18f; 63 | m_physicsDropper.StoppingCriteria = (StoppingCriteria)EditorGUI.EnumPopup(rect1, m_physicsDropper.StoppingCriteria); 64 | rect1.y += 18f; 65 | } 66 | } 67 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/PhysicsDropperWindow.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 47a4466a7bcd4da58db4def40df9e179 -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/TCS.PhysicsDropper.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TCS.PhysicsDropper.Editor", 3 | "rootNamespace": "TCS.PhysicsDropper", 4 | "references": [ 5 | "GUID:10d479a98eb79b54d8d93eac6792cf8d" 6 | ], 7 | "includePlatforms": [ 8 | "Editor" 9 | ], 10 | "excludePlatforms": [], 11 | "allowUnsafeCode": true, 12 | "overrideReferences": false, 13 | "precompiledReferences": [], 14 | "autoReferenced": true, 15 | "defineConstraints": [], 16 | "versionDefines": [], 17 | "noEngineReferences": false 18 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/TCS.PhysicsDropper.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: ee619416f6887924c82282b5beba51e4 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/Utils.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: fce58fa5f43700240890999b2c1b82ec 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/Utils/Logger.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | namespace TCS.PhysicsDropper { 3 | internal static class Logger { 4 | const string CLASS_NAME = "PhysicsDropper"; 5 | const string CLASS_COLOR = "cyan"; 6 | const string CONTEXT_COLOR = "white"; 7 | 8 | const string COLOR_LOG = "green"; 9 | const string TEXT_LOG ="LOG:"; 10 | 11 | const string COLOR_WARNING = "yellow"; 12 | const string TEXT_WARNING = "WARNING:"; 13 | 14 | const string COLOR_ERROR = "red"; 15 | const string TEXT_ERROR = "ERROR:"; 16 | 17 | const string COLOR_ASSERT = "cyan"; 18 | const string TEXT_ASSERT = "ASSERT:"; 19 | 20 | const string COLOR_TODO = "orange"; 21 | const string TEXT_TODO = "TODO:"; 22 | 23 | static string SetLogPrefix(this object newString, LogType logType) { 24 | string color = logType switch { 25 | LogType.Log => COLOR_LOG, 26 | LogType.Warning => COLOR_WARNING, 27 | LogType.Error => COLOR_ERROR, 28 | LogType.Assert => COLOR_ASSERT, 29 | LogType.TODO => COLOR_TODO, 30 | _ => COLOR_LOG, 31 | }; 32 | return $"{newString}"; 33 | } 34 | 35 | static string SetClassPrefix(this object newString) 36 | => $"[{newString}]"; 37 | 38 | static string SetMessagePrefix(this object newString) 39 | => $"{newString}"; 40 | 41 | static string FormatMessage(object message, LogType logType) { 42 | // [Classname/No color] [LogType/Color] [Message/No color] 43 | string type = logType switch { 44 | LogType.Log => TEXT_LOG, 45 | LogType.Warning => TEXT_WARNING, 46 | LogType.Error => TEXT_ERROR, 47 | LogType.Assert => TEXT_ASSERT, 48 | LogType.TODO => TEXT_TODO, 49 | _ => "", 50 | }; 51 | 52 | return $"{CLASS_NAME.SetClassPrefix()}" + 53 | $" {type.SetLogPrefix(logType)} " + 54 | $"{message.SetMessagePrefix()}"; 55 | } 56 | 57 | static void LogInternal(object message, LogType logType, Object context = null) { 58 | 59 | string fixedMessage = FormatMessage(message, logType); 60 | 61 | switch (logType) { 62 | case LogType.Warning: 63 | if (!context) { 64 | Debug.LogWarning(fixedMessage); 65 | break; 66 | } 67 | Debug.LogWarning(fixedMessage, context); 68 | break; 69 | 70 | case LogType.Error: 71 | if (!context) { 72 | Debug.LogError(fixedMessage); 73 | break; 74 | } 75 | Debug.LogError(fixedMessage, context); 76 | break; 77 | 78 | case LogType.Assert: 79 | if (!context) { 80 | Debug.LogAssertion(fixedMessage); 81 | break; 82 | } 83 | Debug.LogAssertion(fixedMessage, context); 84 | break; 85 | 86 | case LogType.Exception: 87 | string exception = message.SetMessagePrefix(); 88 | if (!context) { 89 | Debug.LogException 90 | ( 91 | new System.Exception(exception) 92 | ); 93 | break; 94 | } 95 | Debug.LogException(new System.Exception(exception), context); 96 | break; 97 | 98 | case LogType.TODO: 99 | case LogType.Log: 100 | default: 101 | if (!context) { 102 | Debug.Log(fixedMessage); 103 | break; 104 | } 105 | Debug.Log(fixedMessage, context); 106 | break; 107 | 108 | } 109 | } 110 | 111 | //Without context 112 | public static void Log(object message) => LogInternal(message, LogType.Log); 113 | public static void LogWarning(object message) => LogInternal(message, LogType.Warning); 114 | public static void LogError(object message) => LogInternal(message, LogType.Error); 115 | public static void LogAssert(object message) => LogInternal(message, LogType.Assert); 116 | public static void LogException(object message) => LogInternal(message, LogType.Exception); 117 | public static void LogTODO(object message) => LogInternal(message, LogType.TODO); 118 | 119 | //With context 120 | public static void Log(object message, Object ctx) => LogInternal(message, LogType.Log, ctx); 121 | public static void LogWarning(object message, Object ctx) => LogInternal(message, LogType.Warning, ctx); 122 | public static void LogError(object message, Object ctx) => LogInternal(message, LogType.Error, ctx); 123 | public static void LogAssert(object message, Object ctx) => LogInternal(message, LogType.Assert, ctx); 124 | public static void LogException(object message, Object ctx) => LogInternal(message, LogType.Exception, ctx); 125 | public static void LogTODO(object message, Object ctx) => LogInternal(message, LogType.TODO, ctx); 126 | 127 | enum LogType { 128 | Log, 129 | Warning, 130 | Error, 131 | Assert, 132 | Exception, 133 | TODO, 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Editor/Utils/Logger.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: cd26da91d9e2856468bec549b385692c 3 | -------------------------------------------------------------------------------- /TCS PhysicsDropper/Runtime.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 75fa80e049940a146ba5e02b20b91573 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /TCS PhysicsDropper/Runtime/PhysicsDropperComponent.cs: -------------------------------------------------------------------------------- 1 | using UnityEngine; 2 | namespace TCS.PhysicsDropper { 3 | [ExecuteAlways] 4 | public class PhysicsDropperComponent : MonoBehaviour { 5 | public bool m_hasCollided = false; 6 | 7 | void OnCollisionEnter(Collision collision) { 8 | m_hasCollided = true; 9 | } 10 | } 11 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Runtime/PhysicsDropperComponent.cs.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 42bef1bac7543134a8d36d9f014d384b 3 | timeCreated: 1730839225 4 | -------------------------------------------------------------------------------- /TCS PhysicsDropper/Runtime/TCS.PhysicsDropper.asmdef: -------------------------------------------------------------------------------- 1 | { 2 | "name": "TCS.PhysicsDropper", 3 | "rootNamespace": "", 4 | "references": [], 5 | "includePlatforms": [], 6 | "excludePlatforms": [], 7 | "allowUnsafeCode": true, 8 | "overrideReferences": false, 9 | "precompiledReferences": [], 10 | "autoReferenced": true, 11 | "defineConstraints": [], 12 | "versionDefines": [], 13 | "noEngineReferences": false 14 | } -------------------------------------------------------------------------------- /TCS PhysicsDropper/Runtime/TCS.PhysicsDropper.asmdef.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 10d479a98eb79b54d8d93eac6792cf8d 3 | AssemblyDefinitionImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | -------------------------------------------------------------------------------- /docs~/images.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 0e4fe16262f41454881d4e9ecf71d73e 3 | folderAsset: yes 4 | DefaultImporter: 5 | externalObjects: {} 6 | userData: 7 | assetBundleName: 8 | assetBundleVariant: 9 | -------------------------------------------------------------------------------- /docs~/images/ExampleGif_1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ddemon26/TCS-PhysicsDropper/e5b7a35ae7d0cdd663dc6d97bff249424da33ad7/docs~/images/ExampleGif_1.gif -------------------------------------------------------------------------------- /docs~/images/ExampleGif_1.gif.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: f27b438366c90c548b21a919428b4b10 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 13 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | flipGreenChannel: 0 24 | isReadable: 0 25 | streamingMipmaps: 0 26 | streamingMipmapsPriority: 0 27 | vTOnly: 0 28 | ignoreMipmapLimit: 0 29 | grayScaleToAlpha: 0 30 | generateCubemap: 6 31 | cubemapConvolution: 0 32 | seamlessCubemap: 0 33 | textureFormat: 1 34 | maxTextureSize: 2048 35 | textureSettings: 36 | serializedVersion: 2 37 | filterMode: 1 38 | aniso: 1 39 | mipBias: 0 40 | wrapU: 0 41 | wrapV: 0 42 | wrapW: 0 43 | nPOTScale: 1 44 | lightmap: 0 45 | compressionQuality: 50 46 | spriteMode: 0 47 | spriteExtrude: 1 48 | spriteMeshType: 1 49 | alignment: 0 50 | spritePivot: {x: 0.5, y: 0.5} 51 | spritePixelsToUnits: 100 52 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 53 | spriteGenerateFallbackPhysicsShape: 1 54 | alphaUsage: 1 55 | alphaIsTransparency: 0 56 | spriteTessellationDetail: -1 57 | textureType: 0 58 | textureShape: 1 59 | singleChannelComponent: 0 60 | flipbookRows: 1 61 | flipbookColumns: 1 62 | maxTextureSizeSet: 0 63 | compressionQualitySet: 0 64 | textureFormatSet: 0 65 | ignorePngGamma: 0 66 | applyGammaDecoding: 0 67 | swizzle: 50462976 68 | cookieLightType: 0 69 | platformSettings: 70 | - serializedVersion: 4 71 | buildTarget: DefaultTexturePlatform 72 | maxTextureSize: 2048 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | ignorePlatformSupport: 0 81 | androidETC2FallbackOverride: 0 82 | forceMaximumCompressionQuality_BC6H_BC7: 0 83 | - serializedVersion: 4 84 | buildTarget: Standalone 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | ignorePlatformSupport: 0 94 | androidETC2FallbackOverride: 0 95 | forceMaximumCompressionQuality_BC6H_BC7: 0 96 | - serializedVersion: 4 97 | buildTarget: Android 98 | maxTextureSize: 2048 99 | resizeAlgorithm: 0 100 | textureFormat: -1 101 | textureCompression: 1 102 | compressionQuality: 50 103 | crunchedCompression: 0 104 | allowsAlphaSplitting: 0 105 | overridden: 0 106 | ignorePlatformSupport: 0 107 | androidETC2FallbackOverride: 0 108 | forceMaximumCompressionQuality_BC6H_BC7: 0 109 | - serializedVersion: 4 110 | buildTarget: WebGL 111 | maxTextureSize: 2048 112 | resizeAlgorithm: 0 113 | textureFormat: -1 114 | textureCompression: 1 115 | compressionQuality: 50 116 | crunchedCompression: 0 117 | allowsAlphaSplitting: 0 118 | overridden: 0 119 | ignorePlatformSupport: 0 120 | androidETC2FallbackOverride: 0 121 | forceMaximumCompressionQuality_BC6H_BC7: 0 122 | spriteSheet: 123 | serializedVersion: 2 124 | sprites: [] 125 | outline: [] 126 | customData: 127 | physicsShape: [] 128 | bones: [] 129 | spriteID: 130 | internalID: 0 131 | vertices: [] 132 | indices: 133 | edges: [] 134 | weights: [] 135 | secondaryTextures: [] 136 | spriteCustomMetadata: 137 | entries: [] 138 | nameFileIdTable: {} 139 | mipmapLimitGroupName: 140 | pSDRemoveMatte: 0 141 | userData: 142 | assetBundleName: 143 | assetBundleVariant: 144 | -------------------------------------------------------------------------------- /docs~/images/ExampleGif_2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ddemon26/TCS-PhysicsDropper/e5b7a35ae7d0cdd663dc6d97bff249424da33ad7/docs~/images/ExampleGif_2.gif -------------------------------------------------------------------------------- /docs~/images/ExampleGif_2.gif.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 244e42d719efbd14c958d6eb9358adde 3 | TextureImporter: 4 | internalIDToNameTable: [] 5 | externalObjects: {} 6 | serializedVersion: 13 7 | mipmaps: 8 | mipMapMode: 0 9 | enableMipMap: 1 10 | sRGBTexture: 1 11 | linearTexture: 0 12 | fadeOut: 0 13 | borderMipMap: 0 14 | mipMapsPreserveCoverage: 0 15 | alphaTestReferenceValue: 0.5 16 | mipMapFadeDistanceStart: 1 17 | mipMapFadeDistanceEnd: 3 18 | bumpmap: 19 | convertToNormalMap: 0 20 | externalNormalMap: 0 21 | heightScale: 0.25 22 | normalMapFilter: 0 23 | flipGreenChannel: 0 24 | isReadable: 0 25 | streamingMipmaps: 0 26 | streamingMipmapsPriority: 0 27 | vTOnly: 0 28 | ignoreMipmapLimit: 0 29 | grayScaleToAlpha: 0 30 | generateCubemap: 6 31 | cubemapConvolution: 0 32 | seamlessCubemap: 0 33 | textureFormat: 1 34 | maxTextureSize: 2048 35 | textureSettings: 36 | serializedVersion: 2 37 | filterMode: 1 38 | aniso: 1 39 | mipBias: 0 40 | wrapU: 0 41 | wrapV: 0 42 | wrapW: 0 43 | nPOTScale: 1 44 | lightmap: 0 45 | compressionQuality: 50 46 | spriteMode: 0 47 | spriteExtrude: 1 48 | spriteMeshType: 1 49 | alignment: 0 50 | spritePivot: {x: 0.5, y: 0.5} 51 | spritePixelsToUnits: 100 52 | spriteBorder: {x: 0, y: 0, z: 0, w: 0} 53 | spriteGenerateFallbackPhysicsShape: 1 54 | alphaUsage: 1 55 | alphaIsTransparency: 0 56 | spriteTessellationDetail: -1 57 | textureType: 0 58 | textureShape: 1 59 | singleChannelComponent: 0 60 | flipbookRows: 1 61 | flipbookColumns: 1 62 | maxTextureSizeSet: 0 63 | compressionQualitySet: 0 64 | textureFormatSet: 0 65 | ignorePngGamma: 0 66 | applyGammaDecoding: 0 67 | swizzle: 50462976 68 | cookieLightType: 0 69 | platformSettings: 70 | - serializedVersion: 4 71 | buildTarget: DefaultTexturePlatform 72 | maxTextureSize: 2048 73 | resizeAlgorithm: 0 74 | textureFormat: -1 75 | textureCompression: 1 76 | compressionQuality: 50 77 | crunchedCompression: 0 78 | allowsAlphaSplitting: 0 79 | overridden: 0 80 | ignorePlatformSupport: 0 81 | androidETC2FallbackOverride: 0 82 | forceMaximumCompressionQuality_BC6H_BC7: 0 83 | - serializedVersion: 4 84 | buildTarget: Standalone 85 | maxTextureSize: 2048 86 | resizeAlgorithm: 0 87 | textureFormat: -1 88 | textureCompression: 1 89 | compressionQuality: 50 90 | crunchedCompression: 0 91 | allowsAlphaSplitting: 0 92 | overridden: 0 93 | ignorePlatformSupport: 0 94 | androidETC2FallbackOverride: 0 95 | forceMaximumCompressionQuality_BC6H_BC7: 0 96 | - serializedVersion: 4 97 | buildTarget: Android 98 | maxTextureSize: 2048 99 | resizeAlgorithm: 0 100 | textureFormat: -1 101 | textureCompression: 1 102 | compressionQuality: 50 103 | crunchedCompression: 0 104 | allowsAlphaSplitting: 0 105 | overridden: 0 106 | ignorePlatformSupport: 0 107 | androidETC2FallbackOverride: 0 108 | forceMaximumCompressionQuality_BC6H_BC7: 0 109 | - serializedVersion: 4 110 | buildTarget: WebGL 111 | maxTextureSize: 2048 112 | resizeAlgorithm: 0 113 | textureFormat: -1 114 | textureCompression: 1 115 | compressionQuality: 50 116 | crunchedCompression: 0 117 | allowsAlphaSplitting: 0 118 | overridden: 0 119 | ignorePlatformSupport: 0 120 | androidETC2FallbackOverride: 0 121 | forceMaximumCompressionQuality_BC6H_BC7: 0 122 | spriteSheet: 123 | serializedVersion: 2 124 | sprites: [] 125 | outline: [] 126 | customData: 127 | physicsShape: [] 128 | bones: [] 129 | spriteID: 130 | internalID: 0 131 | vertices: [] 132 | indices: 133 | edges: [] 134 | weights: [] 135 | secondaryTextures: [] 136 | spriteCustomMetadata: 137 | entries: [] 138 | nameFileIdTable: {} 139 | mipmapLimitGroupName: 140 | pSDRemoveMatte: 0 141 | userData: 142 | assetBundleName: 143 | assetBundleVariant: 144 | -------------------------------------------------------------------------------- /docs~/images/ExampleGif_3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ddemon26/TCS-PhysicsDropper/e5b7a35ae7d0cdd663dc6d97bff249424da33ad7/docs~/images/ExampleGif_3.gif -------------------------------------------------------------------------------- /docs~/images/ExampleGif_4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ddemon26/TCS-PhysicsDropper/e5b7a35ae7d0cdd663dc6d97bff249424da33ad7/docs~/images/ExampleGif_4.gif -------------------------------------------------------------------------------- /docs~/images/IconImage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ddemon26/TCS-PhysicsDropper/e5b7a35ae7d0cdd663dc6d97bff249424da33ad7/docs~/images/IconImage.png -------------------------------------------------------------------------------- /docs~/images/InfoPanel.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/Ddemon26/TCS-PhysicsDropper/e5b7a35ae7d0cdd663dc6d97bff249424da33ad7/docs~/images/InfoPanel.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "com.tcs.physicsdropper", 3 | "displayName": "TCS Physics Dropper", 4 | "description": "A simple navigation system for Unity", 5 | "version": "1.0.9", 6 | "keywords": ["TCS", "Physics", "Dropper", "Tool", "Editor"], 7 | "category": "Tent City Studio", 8 | "dependencies": {}, 9 | "author": { 10 | "name": "Damon Fedorick", 11 | "url": "https://github.com/Ddemon26/TCS-PhysicsDropper" 12 | }, 13 | "documentationUrl": "https://github.com/Ddemon26/TCS-PhysicsDropper/blob/main/README.md" 14 | } 15 | -------------------------------------------------------------------------------- /package.json.meta: -------------------------------------------------------------------------------- 1 | fileFormatVersion: 2 2 | guid: 48966168ffa46944d8d93a5d8a662bde 3 | TextScriptImporter: 4 | externalObjects: {} 5 | userData: 6 | assetBundleName: 7 | assetBundleVariant: 8 | --------------------------------------------------------------------------------