├── .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 | 
3 |
4 | 
5 |
6 | [](https://discord.gg/knwtcq3N2a)
7 | 
8 | 
9 | 
10 | 
11 | 
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 | ##
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 |
--------------------------------------------------------------------------------