├── .gitignore
├── Editor.meta
├── Editor
├── DevSlem.MoveTool.Editor.asmdef
├── DevSlem.MoveTool.Editor.asmdef.meta
├── MoveToolDrawer.cs
├── MoveToolDrawer.cs.meta
├── MoveToolEditor.cs
└── MoveToolEditor.cs.meta
├── Images.meta
├── Images
├── move-tool-collection.webp
├── move-tool-collection.webp.meta
├── move-tool-custom-type-collection.webp
├── move-tool-custom-type-collection.webp.meta
├── move-tool-float.webp
├── move-tool-float.webp.meta
├── move-tool-vector2.webp
├── move-tool-vector2.webp.meta
├── move-tool-vector3.webp
└── move-tool-vector3.webp.meta
├── LICENSE
├── LICENSE.meta
├── README.md
├── README.md.meta
├── Runtime.meta
├── Runtime
├── DevSlem.MoveTool.asmdef
├── DevSlem.MoveTool.asmdef.meta
├── MoveToolAttributes.cs
├── MoveToolAttributes.cs.meta
├── StringExtension.cs
└── StringExtension.cs.meta
├── Samples~
├── SamplesMoveTool.meta
└── SamplesMoveTool
│ ├── MoveTool Sample.prefab
│ ├── MoveTool Sample.prefab.meta
│ ├── MoveToolSample.cs
│ ├── MoveToolSample.cs.meta
│ ├── MoveToolSampleScene.unity
│ └── MoveToolSampleScene.unity.meta
├── package.json
└── package.json.meta
/.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/*
--------------------------------------------------------------------------------
/Editor.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 30ce4f09ef0b16d4493dc4c5350555db
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Editor/DevSlem.MoveTool.Editor.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "DevSlem.MoveTool.Editor",
3 | "rootNamespace": "",
4 | "references": [
5 | "GUID:a31c1babfbfb4654fb3f28ab7a1ed780"
6 | ],
7 | "includePlatforms": [],
8 | "excludePlatforms": [],
9 | "allowUnsafeCode": false,
10 | "overrideReferences": false,
11 | "precompiledReferences": [],
12 | "autoReferenced": true,
13 | "defineConstraints": [],
14 | "versionDefines": [],
15 | "noEngineReferences": false
16 | }
--------------------------------------------------------------------------------
/Editor/DevSlem.MoveTool.Editor.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c240c42246d5ecb42a73b23d9c9fdab2
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Editor/MoveToolDrawer.cs:
--------------------------------------------------------------------------------
1 | //#define MOVETOOLDRAWER_DEPRECATED
2 | using System.Collections;
3 | using System.Linq;
4 | using UnityEditor;
5 | using UnityEngine;
6 | using System.Collections.Generic;
7 | using DevSlem.Extensions;
8 |
9 | namespace DevSlem.UnityEditor
10 | {
11 | #if UNITY_EDITOR
12 | ///
13 | /// Display the position mode of MoveToolAttribute on editor inspector.
14 | ///
15 | [CustomPropertyDrawer(typeof(MoveToolAttribute), true)]
16 | public sealed class MoveToolDrawer : PropertyDrawer
17 | {
18 | // For setting MoveToolEditors
19 | private static readonly MoveToolEditorManager manager = new MoveToolEditorManager();
20 | private bool isArray;
21 |
22 | #if MOVETOOLDRAWER_DEPRECATED
23 | private static GameObject targetGameObject;
24 | private static List moveToolEditors = new List();
25 | private static bool isAdded;
26 |
27 | public MoveToolDrawer()
28 | {
29 | if (!isAdded)
30 | {
31 | SceneView.duringSceneGui += SetMoveTool;
32 | isAdded = true;
33 | }
34 | }
35 | #endif
36 |
37 | private class MoveToolEditorManager
38 | {
39 | private Dictionary container;
40 | private GameObject targetGameObject;
41 |
42 | public MoveToolEditorManager()
43 | {
44 | container = new Dictionary();
45 | SceneView.duringSceneGui += SetMoveTool;
46 | }
47 |
48 | private void SetMoveTool(SceneView obj)
49 | {
50 | // If there's no target game-object, destory every old editors and terminate.
51 | if (Selection.activeGameObject == null)
52 | {
53 | foreach (var moveTool in container.Values)
54 | Object.DestroyImmediate(moveTool.editor);
55 |
56 | container.Clear();
57 | targetGameObject = null;
58 | return;
59 | }
60 |
61 | // for prefab game-object
62 | if (Selection.activeGameObject.scene.name == null)
63 | {
64 | foreach (var moveTool in container.Values)
65 | Object.DestroyImmediate(moveTool.editor);
66 |
67 | container.Clear();
68 | return;
69 | }
70 |
71 | var monoBehaviours = Selection.activeGameObject.GetComponents();
72 | // If active target game-object is changed.
73 | if (Selection.activeGameObject != targetGameObject)
74 | {
75 | // Destory every old editors.
76 | foreach (var moveTool in container.Values)
77 | Object.DestroyImmediate(moveTool.editor);
78 | container.Clear();
79 |
80 | // Create editors of new object.
81 | targetGameObject = Selection.activeGameObject;
82 | for (int i = 0; i < monoBehaviours.Length; i++)
83 | container[monoBehaviours[i]] = (Editor.CreateEditor(monoBehaviours[i], typeof(MoveToolEditor)) as MoveToolEditor, true);
84 | }
85 |
86 | // If a new component is added to the target game-object.
87 | if (monoBehaviours.Length > container.Count)
88 | {
89 | var targets = container.Values.Select(m => m.editor.target);
90 | for (int i = 0; i < monoBehaviours.Length; i++)
91 | {
92 | if (!targets.Contains(monoBehaviours[i]))
93 | {
94 | container[monoBehaviours[i]] = (Editor.CreateEditor(monoBehaviours[i], typeof(MoveToolEditor)) as MoveToolEditor, true);
95 | }
96 | }
97 | }
98 | // If a component is removed or switched from the target game-object.
99 | else
100 | {
101 | var keys = container.Keys.ToArray();
102 | foreach (var key in keys)
103 | {
104 | var editor = container[key].editor;
105 | if (editor.target == null)
106 | {
107 | Object.DestroyImmediate(editor);
108 | container.Remove(key);
109 | }
110 | }
111 | }
112 |
113 | // Set move-tool.
114 | try
115 | {
116 | foreach (var pair in container)
117 | {
118 | if (pair.Value.isNeeded && !pair.Value.editor.SetMoveTool())
119 | {
120 | container[pair.Key] = (pair.Value.editor, false);
121 | Object.DestroyImmediate(pair.Value.editor);
122 | }
123 | }
124 | }
125 | catch (System.Exception e)
126 | {
127 | Debug.LogException(e);
128 | }
129 | }
130 | }
131 |
132 | public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
133 | {
134 | // Check to change move-tool editor
135 | //CheckToChangeMoveToolEditor(property);
136 |
137 | var attr = attribute as MoveToolAttribute;
138 |
139 | // if LabelMode doesn't contain inspector-view, just display default property field in the inpsector.
140 | if (!attr.LabelMode.HasFlag(MoveToolLabel.InspectorView))
141 | {
142 | EditorGUI.PropertyField(position, property, label, true);
143 | return;
144 | }
145 |
146 |
147 | string[] splitPath = property.propertyPath.Split('.');
148 |
149 | // If property is just single field.
150 | if (splitPath.LastOrDefault(p => p == "Array") == null)
151 | {
152 | label.text = string.IsNullOrEmpty(attr.Label) ? property.name.InspectorLabel() : attr.Label;
153 | EditorGUI.PropertyField(position, property, label, true); // Default form
154 |
155 | var modePos = position;
156 | modePos.y += EditorGUI.GetPropertyHeight(property, true);
157 | modePos.height = EditorGUIUtility.singleLineHeight;
158 | DisplayModeInfo(modePos);
159 | }
160 | // If property is the element of a collection.
161 | else
162 | {
163 | this.isArray = true;
164 | ICollection field = fieldInfo.GetValue(property.serializedObject.targetObject) as ICollection;
165 | int idx = GetCollectionPropertyIndex(splitPath[splitPath.Length - 1]);
166 | bool isLast = idx + 1 == (field?.Count ?? -1);
167 |
168 | label.text = (string.IsNullOrEmpty(attr.Label) ? fieldInfo.Name.InspectorLabel() : attr.Label) + $" [{idx}]";
169 |
170 | EditorGUI.PropertyField(position, property, label, true); // Default form
171 |
172 | // If this property is the last of the collection
173 | if (isLast)
174 | {
175 | var modePos = position;
176 | modePos.height = EditorGUIUtility.singleLineHeight;
177 | modePos.y += modePos.height + EditorGUI.GetPropertyHeight(property) - 2f * EditorGUIUtility.standardVerticalSpacing;
178 | DisplayModeInfo(modePos);
179 | }
180 | }
181 | }
182 |
183 | private int GetCollectionPropertyIndex(string str)
184 | {
185 | if (str != null)
186 | {
187 | (int start, int end) = (str.LastIndexOf('['), str.LastIndexOf(']'));
188 | if (start >= 0 && end > start + 1 && int.TryParse(str.Substring(start + 1, end - start - 1), out int result))
189 | return result;
190 | }
191 | return -1;
192 | }
193 |
194 | public override float GetPropertyHeight(SerializedProperty property, GUIContent label)
195 | {
196 | return EditorGUI.GetPropertyHeight(property, true) + (this.isArray ? 0f : EditorGUIUtility.singleLineHeight);
197 | }
198 |
199 | // Display current position mode.
200 | private void DisplayModeInfo(Rect position)
201 | {
202 | var indent = EditorGUI.indentLevel;
203 | EditorGUI.indentLevel = 1;
204 |
205 | string modeLabel = (attribute as MoveToolAttribute).PositionMode.ToString();
206 | EditorGUI.Foldout(position, false, $"Position Mode - {modeLabel}"); // Display information.
207 |
208 | // Set indent back to what it was
209 | EditorGUI.indentLevel = indent;
210 |
211 | //Debug.Log(EditorGUIUtility.singleLineHeight);
212 | //EditorGUI.Space(this.modeInfoHeight);
213 | }
214 |
215 | #if MOVETOOLDRAWER_DEPRECATED
216 | [System.Obsolete]
217 | private void CheckToChangeMoveToolEditor(SerializedProperty property)
218 | {
219 | if (moveToolEditors.Count > 0)
220 | return;
221 |
222 | var target = property.serializedObject.targetObject;
223 | var targetGameObject = fieldInfo.ReflectedType.GetProperty("gameObject").GetValue(target) as GameObject;
224 | var monoBehaviours = targetGameObject.GetComponents();
225 | for (int i = 0; i < monoBehaviours.Length; i++)
226 | {
227 | moveToolEditors.Add(Editor.CreateEditor(monoBehaviours[i], typeof(MoveToolEditor)) as MoveToolEditor);
228 | MoveToolDrawer.targetGameObject = targetGameObject;
229 | }
230 | }
231 |
232 | [System.Obsolete]
233 | private static void SetMoveTool(SceneView obj)
234 | {
235 | // If there's no target game-object, destory every old editors and terminate.
236 | if (Selection.activeGameObject == null)
237 | {
238 | for (int i = 0; i < moveToolEditors.Count; i++)
239 | Object.DestroyImmediate(moveToolEditors[i]);
240 |
241 | moveToolEditors.Clear();
242 | targetGameObject = null;
243 | return;
244 | }
245 |
246 | var monoBehaviours = Selection.activeGameObject.GetComponents();
247 | // If active target game-object is changed.
248 | if (Selection.activeGameObject != targetGameObject)
249 | {
250 | // Destory every old editors.
251 | for (int i = 0; i < moveToolEditors.Count; i++)
252 | Object.DestroyImmediate(moveToolEditors[i]);
253 | moveToolEditors.Clear();
254 |
255 | // Create editors of new object.
256 | targetGameObject = targetGameObject = Selection.activeGameObject;
257 | for (int i = 0; i < monoBehaviours.Length; i++)
258 | {
259 | //Debug.Log($"{monoBehaviours[i].GetType().Name} : {monoBehaviours[i].GetInstanceID()}");
260 | moveToolEditors.Add(Editor.CreateEditor(monoBehaviours[i], typeof(MoveToolEditor)) as MoveToolEditor);
261 |
262 | }
263 | }
264 |
265 | // If a new component is added to the target game-object.
266 | if (monoBehaviours.Length > moveToolEditors.Count)
267 | {
268 | var targets = moveToolEditors.Select(e => e.target);
269 | for (int i = 0; i < monoBehaviours.Length; i++)
270 | {
271 | if (!targets.Contains(monoBehaviours[i]))
272 | {
273 | moveToolEditors.Add(Editor.CreateEditor(monoBehaviours[i], typeof(MoveToolEditor)) as MoveToolEditor);
274 | //Debug.Log($"{monoBehaviours[i].GetType().Name} : {monoBehaviours[i].GetInstanceID()}");
275 | }
276 | }
277 | }
278 | // If a component is removed from the target game-object.
279 | else
280 | {
281 | for (int i = 0; i < moveToolEditors.Count; i++)
282 | {
283 | if (moveToolEditors[i].target == null)
284 | {
285 | Object.DestroyImmediate(moveToolEditors[i]);
286 | moveToolEditors.RemoveAt(i--);
287 | }
288 | }
289 | }
290 |
291 | // Set move-tool.
292 | try
293 | {
294 | for (int i = 0; i < moveToolEditors.Count; i++)
295 | moveToolEditors[i].SetMoveTool();
296 | }
297 | catch (System.Exception e)
298 | {
299 | Debug.LogException(e);
300 | }
301 |
302 | }
303 | #endif
304 |
305 | }
306 | #endif
307 | }
308 |
--------------------------------------------------------------------------------
/Editor/MoveToolDrawer.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: add52d0d500eb5b4f953b2706f7a2baa
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Editor/MoveToolEditor.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Reflection;
5 | using UnityEditor;
6 | using UnityEngine;
7 | using DevSlem.Extensions;
8 |
9 | namespace DevSlem.UnityEditor
10 | {
11 | #if UNITY_EDITOR
12 | ///
13 | /// It sets position handles for the fields that define MoveToolAttribute. Note that it's an editor for MonoBehaviour.
14 | ///
15 | [CustomEditor(typeof(MonoBehaviour), false)]
16 | public class MoveToolEditor : Editor
17 | {
18 | private static readonly GUIStyle style = new GUIStyle();
19 |
20 | private readonly static Vector3[] axisVector = new Vector3[3]
21 | {
22 | Vector3.right,
23 | Vector3.up,
24 | Vector3.forward
25 | };
26 |
27 | public void OnEnable()
28 | {
29 | style.fontStyle = FontStyle.Bold;
30 | style.normal.textColor = Color.white;
31 | }
32 |
33 | public void OnSceneGUI()
34 | {
35 | SetOnlyHasMoveToolAttribute();
36 | }
37 |
38 | ///
39 | /// Run MoveToolEditor. You can use move-tools of fields which define MoveToolAttribute in your monobehavior class.
40 | ///
41 | public bool SetMoveTool()
42 | {
43 | style.fontStyle = FontStyle.Bold;
44 | style.normal.textColor = Color.white;
45 |
46 | return SetOnlyHasMoveToolAttribute();
47 | }
48 |
49 | private bool SetOnlyHasMoveToolAttribute()
50 | {
51 | var targetType = target.GetType();
52 | var fields = GetSerializedFields(targetType);
53 | bool isExisting = false;
54 | foreach (var field in fields)
55 | {
56 | // Check if MoveToolAttribute is defined.
57 | var attr = field.GetCustomAttribute(false);
58 | if (attr == null)
59 | continue;
60 | isExisting = true;
61 | SetMoveToolAvailableField((field, -1), (this.target, field, -1), attr);
62 | }
63 |
64 | return isExisting;
65 | }
66 |
67 | ///
68 | /// Set Position Handles in the unity editor scene view.
69 | ///
70 | /// top level field declared in the MonoBehaviour component
71 | /// current field checked now, current.obj is the instance where current.field is declared
72 | /// defined for the top level field
73 | /// Don't set any value. It's the count of recursive calls.
74 | private void SetMoveToolAvailableField((FieldInfo field, int index) top, (object obj, FieldInfo field, int index) current, MoveToolAttribute attr, int n = 0)
75 | {
76 | // If it's vector, call immediately SetPositionHandle() method and then terminate.
77 | object fieldValue = current.field.GetValue(current.obj);
78 |
79 | if (IsVector(fieldValue))
80 | {
81 | string label = string.Empty;
82 | if (attr.LabelMode.HasFlag(MoveToolLabel.SceneView))
83 | {
84 | label = string.IsNullOrEmpty(attr.Label) ? AddIndexLabel(top.field.Name.InspectorLabel(), top.index) : AddIndexLabel(attr.Label, top.index);
85 | if (top.field != current.field)
86 | label += $" - {(n > 1 ? AddIndexLabel(current.field.Name.InspectorLabel(), current.index, true) : current.field.Name.InspectorLabel())}";
87 | }
88 |
89 | SetVectorField(current.obj, current.field, label, attr.PositionMode);
90 | return;
91 | }
92 |
93 | var fieldType = current.field.FieldType; //current field type
94 |
95 | // Array field, List field, Custom type field which inherit from IList
96 | if (fieldType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(IList<>)) is var listType && listType != null)
97 | {
98 | var elementType = listType.GetGenericArguments()[0];
99 | if (!HasAvailableAttribute(elementType))
100 | return;
101 |
102 | var serializedFields = GetSerializedFields(elementType);
103 |
104 | var collectionType = listType.GetInterfaces().FirstOrDefault(i => i.IsGenericType && i.GetGenericTypeDefinition() == typeof(ICollection<>));
105 | var accessor = listType.GetProperty("Item");
106 | int count = (int)collectionType.GetProperty("Count").GetValue(fieldValue, null);
107 | object[] index = { 0 };
108 |
109 | for (int i = 0; i < count; i++)
110 | {
111 | if (top.field == current.field)
112 | top.index = i;
113 |
114 | index[0] = i;
115 | object element = accessor.GetValue(fieldValue, index);
116 |
117 | // Recursive call for each field declared in the current field type
118 | foreach (var nextField in serializedFields)
119 | SetMoveToolAvailableField(top, (element, nextField, i), attr, n + 1);
120 |
121 | // If the current element is a value type, you must paste boxed element to this element.
122 | if (elementType.IsValueType)
123 | accessor.SetValue(fieldValue, element, index);
124 | }
125 | }
126 | // Single custom type field which isn't collection
127 | else
128 | {
129 | if (!HasAvailableAttribute(fieldType))
130 | return;
131 |
132 | var serializedFields = GetSerializedFields(fieldType);
133 | // Recursive call for each field declared in the current field type
134 | object obj = current.field.GetValue(current.obj);
135 | foreach (var nextField in serializedFields)
136 | SetMoveToolAvailableField(top, (obj, nextField, -1), attr, n + 1);
137 |
138 | // If the current field is a value type, you must paste boxed obj to this field. It's because obj isn't the field instance itself, but new boxed instance.
139 | if (fieldType.IsValueType)
140 | current.field.SetValue(current.obj, obj);
141 | }
142 |
143 | #region === Deprecated ===
144 | //// Array
145 | //if (fieldType.IsArray)
146 | //{
147 | // fieldType = fieldType.GetElementType();
148 | // if (!HasAvailableAttribute(fieldType))
149 | // return;
150 |
151 | // var serializedFields = GetSerializedFields(fieldType);
152 | // var array = current.field.GetValue(current.obj) as Array;
153 | // for (int i = 0; i < array.Length; i++)
154 | // {
155 | // if (top.field == current.field)
156 | // top.index = i;
157 |
158 | // // Recursive call for each field declared in the element type of current array
159 | // object obj = array.GetValue(i);
160 | // foreach (var nextField in serializedFields)
161 | // SetMoveToolAvailableField(top, (obj, nextField, i), attr, n + 1);
162 | // if (fieldType.IsValueType)
163 | // array.SetValue(obj, i);
164 | // }
165 | //}
166 | //// List
167 | //else if (fieldType.IsGenericType && typeof(IList).IsAssignableFrom(fieldType))
168 | //{
169 | // fieldType = fieldType.GetGenericArguments()[0];
170 | // if (!HasAvailableAttribute(fieldType))
171 | // return;
172 |
173 | // var serializedFields = GetSerializedFields(fieldType);
174 | // var list = current.field.GetValue(current.obj) as IList;
175 | // for (int i = 0; i < list.Count; i++)
176 | // {
177 | // if (top.field == current.field)
178 | // top.index = i;
179 |
180 | // // Recursive call for each field declared in the element type of current list
181 | // object obj = list[i];
182 | // foreach (var nextField in serializedFields)
183 | // SetMoveToolAvailableField(top, (obj, nextField, i), attr, n + 1);
184 | // if (fieldType.IsValueType)
185 | // list[i] = obj;
186 | // }
187 | //}
188 | //// Just single field
189 | //else
190 | //{
191 | // if (!HasAvailableAttribute(fieldType))
192 | // return;
193 |
194 | // var serializedFields = GetSerializedFields(fieldType);
195 |
196 | // // Recursive call for each field declared in the current field type
197 | // object obj = current.field.GetValue(current.obj);
198 | // foreach (var nextField in serializedFields)
199 | // SetMoveToolAvailableField(top, (obj, nextField, -1), attr, n + 1);
200 |
201 | // // If current field is a value type, you must copy boxed obj to this field. It's because obj isn't the field instance itself, but new boxed instance.
202 | // if (fieldType.IsValueType)
203 | // current.field.SetValue(current.obj, obj);
204 | //}
205 | #endregion
206 | }
207 |
208 | ///
209 | /// Classify wheter the field is a vector field or a vector collection field and then place position handles of it in unity-editor scene view.
210 | ///
211 | private void SetVectorField(object obj, FieldInfo field, string label, MoveToolPosition mode)
212 | {
213 | // the position origin.
214 | Vector3 origin = Vector3.zero;
215 |
216 | switch (mode)
217 | {
218 | case MoveToolPosition.Local:
219 | // If it's local mode, the origin point is set to target(MonoBehaviour) position.
220 | origin = (this.target as MonoBehaviour).transform.position;
221 | break;
222 | }
223 |
224 | //var fieldType = field.FieldType;
225 | bool shiftClicked = Event.current.shift; // check if you've clicked a shift button.
226 | object fieldValue = field.GetValue(obj);
227 |
228 | // Pattern matching to test the fieldValue to see if it matches a vector type.
229 | switch (fieldValue)
230 | {
231 | case float oldFloat:
232 | field.SetValue(obj, SetPositionHandle(label, origin.x, oldFloat, obj, field, target));
233 | break;
234 | case Vector3 oldVector3:
235 | field.SetValue(obj, SetPositionHandle(label, origin, oldVector3, obj, field, target));
236 | break;
237 | case Vector2 oldVector2:
238 | field.SetValue(obj, SetPositionHandle(label, (Vector2)origin, oldVector2, obj, field, target));
239 | break;
240 | case IList floatList:
241 | for (int i = 0; i < floatList.Count; i++)
242 | {
243 | string temp = label;
244 | if (!string.IsNullOrEmpty(label))
245 | temp += $" [{i}]";
246 |
247 | float oldValue = floatList[i];
248 | float newValue = SetPositionHandle(temp, origin.x, oldValue, obj, field, target);
249 | //SetHandleVector3(temp, origin, oldValue, obj, field, v => list[i] = v);
250 | if (shiftClicked && newValue != oldValue)
251 | {
252 | float delta = newValue - oldValue;
253 | for (int j = 0; j < floatList.Count; j++)
254 | floatList[j] += delta;
255 | break;
256 | }
257 | floatList[i] = newValue;
258 | }
259 | break;
260 | case IList vector3List:
261 | for (int i = 0; i < vector3List.Count; i++)
262 | {
263 | string temp = label;
264 | if (!string.IsNullOrEmpty(label))
265 | temp += $" [{i}]";
266 |
267 | Vector3 oldValue = vector3List[i];
268 | Vector3 newValue = SetPositionHandle(temp, origin, oldValue, obj, field, target);
269 | //SetHandleVector3(temp, origin, oldValue, obj, field, v => list[i] = v);
270 | if (shiftClicked && newValue != oldValue)
271 | {
272 | Vector3 delta = newValue - oldValue;
273 | for (int j = 0; j < vector3List.Count; j++)
274 | vector3List[j] += delta;
275 | break;
276 | }
277 | vector3List[i] = newValue;
278 | }
279 | break;
280 | case IList vector2List:
281 | for (int i = 0; i < vector2List.Count; i++)
282 | {
283 | string temp = label;
284 | if (!string.IsNullOrEmpty(label))
285 | temp += $" [{i}]";
286 |
287 | Vector2 oldValue = vector2List[i];
288 | Vector2 newValue = SetPositionHandle(temp, (Vector2)origin, oldValue, obj, field, target);
289 | //SetHandleVector2(temp, origin, oldValue, obj, field, v => list[i] = v);
290 | if (shiftClicked && newValue != oldValue)
291 | {
292 | Vector2 delta = newValue - oldValue;
293 | for (int j = 0; j < vector2List.Count; j++)
294 | vector2List[j] += delta;
295 | break;
296 | }
297 | vector2List[i] = newValue;
298 | }
299 | break;
300 | // If you want to use position handles of other serializable collection, then add here.
301 | default:
302 | break;
303 | }
304 |
305 | #region === Deprecated ===
306 | //if (fieldValue is Vector3 oldVector3)
307 | //{
308 | // //Vector3 oldValue = (Vector3)field.GetValue(obj);
309 | // field.SetValue(obj, SetPositionHandle(label, origin, oldVector3, obj, field));
310 | // //SetHandleVector3(label, origin, oldValue, obj, field, v => field.SetValue(obj, v));
311 | //}
312 | //else if (fieldValue is Vector2 oldVector2)
313 | //{
314 | // //Vector2 oldValue = (Vector2)field.GetValue(obj);
315 | // field.SetValue(obj, SetPositionHandle(label, (Vector2)origin, oldVector2, obj, field));
316 | // //SetHandleVector2(label, origin, oldValue, obj, field, v => field.SetValue(obj, v));
317 | //}
318 | //// Collection which interits from IList interface. Both Array and List belong to it.
319 | //else if (fieldValue is IList vector3List)
320 | //{
321 | // for (int i = 0; i < vector3List.Count; i++)
322 | // {
323 | // string temp = label;
324 | // if (!string.IsNullOrEmpty(label))
325 | // temp += $" [{i}]";
326 |
327 | // Vector3 oldValue = vector3List[i];
328 | // Vector3 newValue = SetPositionHandle(temp, origin, oldValue, obj, field);
329 | // //SetHandleVector3(temp, origin, oldValue, obj, field, v => list[i] = v);
330 | // if (shiftClicked && newValue != oldValue)
331 | // {
332 | // Vector3 delta = newValue - oldValue;
333 | // for (int j = 0; j < vector3List.Count; j++)
334 | // vector3List[j] += delta;
335 | // break;
336 | // }
337 | // vector3List[i] = newValue;
338 | // }
339 | //}
340 | //else if (fieldValue is IList vector2List)
341 | //{
342 | // for (int i = 0; i < vector2List.Count; i++)
343 | // {
344 | // string temp = label;
345 | // if (!string.IsNullOrEmpty(label))
346 | // temp += $" [{i}]";
347 |
348 | // Vector2 oldValue = vector2List[i];
349 | // Vector2 newValue = SetPositionHandle(temp, (Vector2)origin, oldValue, obj, field);
350 | // //SetHandleVector2(temp, origin, oldValue, obj, field, v => list[i] = v);
351 | // if (shiftClicked && newValue != oldValue)
352 | // {
353 | // Vector2 delta = newValue - oldValue;
354 | // for (int j = 0; j < vector2List.Count; j++)
355 | // vector2List[j] += delta;
356 | // break;
357 | // }
358 | // vector2List[i] = newValue;
359 | // }
360 | //}
361 | //// Array
362 | //else if (fieldType.GetElementType() == typeof(Vector3))
363 | //{
364 | // var array = field.GetValue(obj) as Array;
365 | // for (int i = 0; i < array.Length; i++)
366 | // {
367 | // string temp = label;
368 | // if (!string.IsNullOrEmpty(label))
369 | // temp += $" [{i}]";
370 |
371 | // Vector3 oldValue = (Vector3)array.GetValue(i);
372 | // Vector3 newValue = SetPositionHandle(temp, origin, oldValue, obj, field);
373 | // //SetHandleVector3(temp, origin, oldValue, obj, field, v => newValue = v);
374 | // if (shiftClicked && newValue != oldValue)
375 | // {
376 | // Vector3 delta = newValue - oldValue;
377 | // for (int j = 0; j < array.Length; j++)
378 | // array.SetValue((Vector3)array.GetValue(j) + delta, j);
379 | // break;
380 | // }
381 | // array.SetValue(newValue, i);
382 | // }
383 | //}
384 | //else if (fieldType.GetElementType() == typeof(Vector2))
385 | //{
386 | // var array = field.GetValue(obj) as Array;
387 | // for (int i = 0; i < array.Length; i++)
388 | // {
389 | // string temp = label;
390 | // if (!string.IsNullOrEmpty(label))
391 | // temp += $" [{i}]";
392 |
393 | // Vector2 oldValue = (Vector2)array.GetValue(i);
394 | // Vector2 newValue = SetPositionHandle(temp, (Vector2)origin, oldValue, obj, field);
395 | // //SetHandleVector2(temp, origin, oldValue, obj, field, v => array.SetValue(v, i));
396 | // if (shiftClicked && newValue != oldValue)
397 | // {
398 | // Vector2 delta = newValue - oldValue;
399 | // for (int j = 0; j < array.Length; j++)
400 | // array.SetValue((Vector2)array.GetValue(j) + delta, j);
401 | // break;
402 | // }
403 | // array.SetValue(newValue, i);
404 | // }
405 | //}
406 | // List
407 | //else if (fieldType == typeof(List))
408 | //{
409 | // var list = field.GetValue(obj) as List;
410 | // for (int i = 0; i < list.Count; i++)
411 | // {
412 | // string temp = label;
413 | // if (!string.IsNullOrEmpty(label))
414 | // temp += $" [{i}]";
415 |
416 | // Vector3 oldValue = list[i];
417 | // Vector3 newValue = SetPositionHandle(temp, origin, oldValue, obj, field);
418 | // //SetHandleVector3(temp, origin, oldValue, obj, field, v => list[i] = v);
419 | // if (shiftClicked && newValue != oldValue)
420 | // {
421 | // Vector3 delta = newValue - oldValue;
422 | // for (int j = 0; j < list.Count; j++)
423 | // list[j] += delta;
424 | // break;
425 | // }
426 | // list[i] = newValue;
427 | // }
428 | //}
429 | //else if (fieldType == typeof(List))
430 | //{
431 | // var list = field.GetValue(obj) as List;
432 | // for (int i = 0; i < list.Count; i++)
433 | // {
434 | // string temp = label;
435 | // if (!string.IsNullOrEmpty(label))
436 | // temp += $" [{i}]";
437 |
438 | // Vector2 oldValue = list[i];
439 | // Vector2 newValue = SetPositionHandle(temp, (Vector2)origin, oldValue, obj, field);
440 | // //SetHandleVector2(temp, origin, oldValue, obj, field, v => list[i] = v);
441 | // if (shiftClicked && newValue != oldValue)
442 | // {
443 | // Vector2 delta = newValue - oldValue;
444 | // for (int j = 0; j < list.Count; j++)
445 | // list[j] += delta;
446 | // break;
447 | // }
448 | // list[i] = newValue;
449 | // }
450 | //}
451 | #endregion
452 | }
453 |
454 |
455 | ///
456 | /// Create a position handle for the vector3 oldValue. If it's changed, record the taget.
457 | ///
458 | /// changed vector3
459 | public static Vector3 SetPositionHandle(string label, Vector3 origin, Vector3 oldValue, object obj, FieldInfo field, UnityEngine.Object target = null)
460 | {
461 | Handles.Label(origin + oldValue, label, style);
462 | EditorGUI.BeginChangeCheck();
463 | Vector3 newValue = Handles.PositionHandle(origin + oldValue, Quaternion.identity) - origin;
464 | if (EditorGUI.EndChangeCheck() && target != null)
465 | {
466 | // enable ctrl + z & set dirty
467 | Undo.RecordObject(target, $"{target.name}_{target.GetInstanceID()}_{obj.GetHashCode()}_{field.Name}");
468 |
469 | // In the unity document, if the object may be part of a Prefab instance, we have to call this method.
470 | // But, even if i don't call this method, it works well. I don't know the reason.
471 | PrefabUtility.RecordPrefabInstancePropertyModifications(target);
472 | }
473 | return newValue;
474 | }
475 |
476 | ///
477 | /// Create Position Handle for Vector2. If it's changed, record the target.
478 | ///
479 | /// changed vector2
480 | public static Vector2 SetPositionHandle(string label, Vector2 origin, Vector2 oldValue, object obj, FieldInfo field, UnityEngine.Object target = null)
481 | {
482 | //Handles.Label(origin + oldValue, label, style);
483 | //EditorGUI.BeginChangeCheck();
484 | //Vector2 newValue = (Vector2)Handles.PositionHandle(origin + oldValue, Quaternion.identity) - origin;
485 | //if (EditorGUI.EndChangeCheck())
486 | //{
487 | // // enable ctrl + z & set dirty
488 | // Undo.RecordObject(target, $"{target.name}_{target.GetInstanceID()}_{obj.GetHashCode()}_{field.Name}");
489 |
490 | // // In the unity document, if the object may be part of a Prefab instance, we have to call this method.
491 | // // But, even if i don't call this method, it works well. I don't know the reason.
492 | // PrefabUtility.RecordPrefabInstancePropertyModifications(target);
493 | //}
494 | //return newValue;
495 |
496 | Color[] axisColor = new Color[]
497 | {
498 | Handles.xAxisColor,
499 | Handles.yAxisColor,
500 | Handles.zAxisColor
501 | };
502 |
503 | Vector3 position = origin + oldValue;
504 | Handles.Label(position, label, style);
505 | EditorGUI.BeginChangeCheck();
506 |
507 | Handles.color = Handles.zAxisColor;
508 | var size = HandleUtility.GetHandleSize(position) * 0.125f;
509 | var temp = Handles.Slider2D(position + new Vector3(1f, 1f) * size, Vector3.forward, axisVector[0], axisVector[1], size, Handles.RectangleHandleCap, new Vector2(EditorSnapSettings.move[0], EditorSnapSettings.move[1]))
510 | - new Vector3(1f, 1f) * size;
511 | position = (position - temp).sqrMagnitude > 0.001f ? temp : position;
512 |
513 | for (int axis = 0; axis < 2; axis++)
514 | {
515 | Handles.color = axisColor[axis];
516 | Vector3 dir = axisVector[axis];
517 | position = Handles.Slider(position, dir, HandleUtility.GetHandleSize(position), Handles.ArrowHandleCap, EditorSnapSettings.move[axis])
518 | - (Vector3)origin;
519 | }
520 |
521 | if (EditorGUI.EndChangeCheck() && target != null)
522 | {
523 | // enable ctrl + z & set dirty
524 | Undo.RecordObject(target, $"{target.name}_{target.GetInstanceID()}_{obj.GetHashCode()}_{field.Name}");
525 |
526 | // In the unity document, if the object may be part of a Prefab instance, we have to call this method.
527 | // But, even if i don't call this method, it works well. I don't know the reason.
528 | PrefabUtility.RecordPrefabInstancePropertyModifications(target);
529 | }
530 | return position;
531 | }
532 |
533 | public static float SetPositionHandle(string label, float origin, float oldValue, object obj, FieldInfo field, UnityEngine.Object target = null)
534 | {
535 | var position = new Vector3(origin + oldValue, 0f, 0f);
536 | Handles.Label(position, label, style);
537 | EditorGUI.BeginChangeCheck();
538 | Handles.color = Handles.xAxisColor;
539 | Vector3 newValue = Handles.Slider(position, Vector3.right, HandleUtility.GetHandleSize(position), Handles.ArrowHandleCap, EditorSnapSettings.move.x)
540 | - new Vector3(origin, 0f, 0f);
541 | if (EditorGUI.EndChangeCheck() && target != null)
542 | {
543 | // enable ctrl + z & set dirty
544 | Undo.RecordObject(target, $"{target.name}_{target.GetInstanceID()}_{obj.GetHashCode()}_{field.Name}");
545 |
546 | // In the unity document, if the object may be part of a Prefab instance, we have to call this method.
547 | // But, even if i don't call this method, it works well. I don't know the reason.
548 | PrefabUtility.RecordPrefabInstancePropertyModifications(target);
549 | }
550 | return newValue.x;
551 | }
552 |
553 | ///
554 | /// Check the type for which both MoveToolAvailableAttribute and SerializableAttribute are defined.
555 | ///
556 | private bool HasAvailableAttribute(Type type)
557 | {
558 | var available = type.GetCustomAttribute(false);
559 | var seralizable = type.GetCustomAttribute(false);
560 | return available != null && seralizable != null;
561 | }
562 |
563 | ///
564 | /// Return the serialized fields for the type.
565 | ///
566 | private IEnumerable GetSerializedFields(Type type)
567 | {
568 | var fields = type.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
569 |
570 | // If it's the public field and doesn't have NonSerializedAttribute, then add it.
571 | // If it's the non-public field and has UnityEngine.SerializeField, then add it.
572 | var serializedFields =
573 | from f in fields
574 | where (f.IsPublic && f.GetCustomAttribute(false) == null) || (!f.IsPublic && f.GetCustomAttribute(false) != null)
575 | select f;
576 |
577 | return serializedFields;
578 | }
579 |
580 | ///
581 | /// Check wheter obj is vector type instance or vector type collection.
582 | ///
583 | private bool IsVector(object obj) => obj is Vector3 || obj is Vector2 || obj is float || obj is IList || obj is IList || obj is IList;
584 |
585 |
586 | ///
587 | /// Add index label to this label parameter.
588 | /// e.g. Label [index]
589 | ///
590 | private string AddIndexLabel(string label, int index, bool isFront = false)
591 | {
592 | if (index >= 0)
593 | {
594 | if (isFront)
595 | {
596 | label = $"[{index}] {label}";
597 | }
598 | else
599 | {
600 | label += $" [{index}]";
601 | }
602 | }
603 |
604 | return label;
605 | }
606 |
607 | #region === Deprecated ===
608 | // Create Position Handle for Vector3. If it's changed, set and record new value.
609 | // You need to implement a mechanism to set the new Vector3 value in setValue delegate.
610 | [Obsolete]
611 | private void SetHandleVector3(string label, Vector3 origin, Vector3 oldValue, object obj, FieldInfo field, Action setValue)
612 | {
613 | Handles.Label(origin + oldValue, label, style);
614 | EditorGUI.BeginChangeCheck();
615 | Vector3 newValue = Handles.PositionHandle(origin + oldValue, Quaternion.identity) - origin;
616 | if (EditorGUI.EndChangeCheck())
617 | {
618 | // enable ctrl + z & set dirty
619 | Undo.RecordObject(target, $"{target.name}_{target.GetInstanceID()}_{obj.GetHashCode()}_{field.Name}");
620 |
621 | setValue(newValue);
622 |
623 | // In the unity document, if the object may be part of a Prefab instance, we have to call this method.
624 | // But, even if i don't call this method, it works well. I don't know the reason.
625 | PrefabUtility.RecordPrefabInstancePropertyModifications(target);
626 | }
627 | }
628 |
629 | // Create Position Handle for Vector2. If it's changed, set and record new value.
630 | // You need to implement a mechanism to set the new Vector2 value in setValue delegate.
631 | [Obsolete]
632 | private void SetHandleVector2(string label, Vector2 origin, Vector2 oldValue, object obj, FieldInfo field, Action setValue)
633 | {
634 | Handles.Label(origin + oldValue, label, style);
635 | EditorGUI.BeginChangeCheck();
636 | Vector2 newValue = (Vector2)Handles.PositionHandle(origin + oldValue, Quaternion.identity) - origin;
637 | if (EditorGUI.EndChangeCheck())
638 | {
639 | // enable ctrl + z & set dirty
640 | Undo.RecordObject(target, $"{target.name}_{target.GetInstanceID()}_{obj.GetHashCode()}_{field.Name}");
641 |
642 | setValue(newValue);
643 |
644 | // In the unity document, if the object may be part of a Prefab instance, we have to call this method.
645 | // But, even if i don't call this method, it works well. I don't know the reason.
646 | PrefabUtility.RecordPrefabInstancePropertyModifications(target);
647 | }
648 | }
649 |
650 | // Check if it's vector type or vector collection type.
651 | [Obsolete]
652 | private bool IsVector(Type type) => type == typeof(Vector2) || type == typeof(Vector3) ||
653 | typeof(IEnumerable).IsAssignableFrom(type) || typeof(IEnumerable).IsAssignableFrom(type);
654 | #endregion
655 | }
656 | #endif
657 | }
658 |
--------------------------------------------------------------------------------
/Editor/MoveToolEditor.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 131bfc6da0e3e5e4786d05a7be3cc201
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Images.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 63dd707dbde2cce46bc7dd735350a757
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Images/move-tool-collection.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevSlem/unity-move-tool/5b12d13ef8c5d00e53d8b60c40ec7376a624ddf5/Images/move-tool-collection.webp
--------------------------------------------------------------------------------
/Images/move-tool-collection.webp.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: e2c8050ad13b61a42aab53da21bfcfd9
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Images/move-tool-custom-type-collection.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevSlem/unity-move-tool/5b12d13ef8c5d00e53d8b60c40ec7376a624ddf5/Images/move-tool-custom-type-collection.webp
--------------------------------------------------------------------------------
/Images/move-tool-custom-type-collection.webp.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 35050653890877b40b9db98b93b9c583
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Images/move-tool-float.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevSlem/unity-move-tool/5b12d13ef8c5d00e53d8b60c40ec7376a624ddf5/Images/move-tool-float.webp
--------------------------------------------------------------------------------
/Images/move-tool-float.webp.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: c29e1960ed0264f4bbc32b6cbe39f955
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Images/move-tool-vector2.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevSlem/unity-move-tool/5b12d13ef8c5d00e53d8b60c40ec7376a624ddf5/Images/move-tool-vector2.webp
--------------------------------------------------------------------------------
/Images/move-tool-vector2.webp.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: d16543998c0b75c42a9ad877a88789db
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Images/move-tool-vector3.webp:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/DevSlem/unity-move-tool/5b12d13ef8c5d00e53d8b60c40ec7376a624ddf5/Images/move-tool-vector3.webp
--------------------------------------------------------------------------------
/Images/move-tool-vector3.webp.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: ce45d4fe38420e94fbfa751a487888a5
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2022 kgmslem
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: 426441d2742ce7c4680cddded53f7ada
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Move-Tool for Unity
2 |
3 | **Move-Tool** is a tool that makes you use position handles for vector in unity editor scene view.
4 | You can use move-tool so easily by just defining ***some attributes***.
5 |
6 | > Note that it require **C# 7** or higher.
7 | > If you want to use it in a lower version, you need to modify **pattern matching**(only can use in C# 7 or higher) part in `MoveToolEditor` class to `if` statement and simple type checking, but it'll make you tired.
8 |
9 | * [Basic usage](#basic-usage)
10 | * [MoveToolAttribute Properties](#movetoolattribute-properties)
11 | * [Move-Tool available custom type](#move-tool-available-custom-type)
12 | * [Editor](#editor)
13 |
14 | ## Releases
15 |
16 | It is recommended to use a latest, stable version.
17 | [main](https://github.com/DevSlem/unity-move-tool/tree/main) version is unstable because it's under active development.
18 |
19 | | Version | Release Date | Source | C# | .Net Compatibility |
20 | | :------------------------------------------------------------------------------------: | :----------: | :----------------------------------------------------------------------------: | :-----------: | :-------------------------: |
21 | | main(unstable) | -- | [main](https://github.com/DevSlem/unity-move-tool/tree/main) | 7.0 or higher | .Net Standard 2.0 or higher |
22 | | [Release 3.1.0](https://github.com/DevSlem/unity-move-tool/releases/tag/release-3.1.0) | 2022-09-16 | [release-3.1.0](https://github.com/DevSlem/unity-move-tool/tree/release-3.1.0) | 7.0 or higher | .Net standard 2.0 or higher |
23 |
24 | ## Latest Update
25 |
26 | * You can use **Move-Tool** for the `float` field.
27 | * Arrow of z direction of **Move-Tool** for the `Vector2` field has been removed. To be more intuitive!
28 |
29 | ## Installation
30 |
31 | You can select 2 installation methods.
32 |
33 | * Clone the repository and add `package.json` file to your project through Unity Package Manager.
34 | * You can add directly the package from git URL to your project through Unity Package Manager. See the [Installing from a Git URL](https://docs.unity3d.com/Manual/upm-ui-giturl.html).
35 |
36 | ## Basic usage
37 |
38 | You just define `MoveTool` attribute for a field for which you want to use position handle.
39 | The field is okay whether it's vector or vector collection.
40 | It works only if the type of the field is one of the `Vector3`, `Vector2`, `float` type.
41 |
42 | If you want to use ***attributes*** about move-tool, you must declare the following `using` directive.
43 |
44 | ```c#
45 | using DevSlem;
46 | ```
47 |
48 | > Note that the any type that you want to use Move-Tool, it must be serializable.
49 |
50 | ### Vector3
51 |
52 | ```c#
53 | public class MoveToolSample : MonoBehaviour
54 | {
55 | [MoveTool] public Vector3 vector;
56 | }
57 | ```
58 |
59 | 
60 |
61 | ### Vector2
62 |
63 | ```c#
64 | [MoveTool] public Vector2 vector2;
65 | ```
66 |
67 | > Note that `Vector2` type field only moves along the x and y axes.
68 |
69 | 
70 |
71 | ### Float
72 |
73 | ```c#
74 | [MoveTool] public float floatField;
75 | ```
76 |
77 | > Note that `float` type field only moves along the x axis.
78 |
79 | 
80 |
81 | ### Collection
82 |
83 | You can use move-tool to `Array` or `List` collection where each element is vector value.
84 | While you click the **shift** key, you can control all elements of the list at once.
85 |
86 | ```c#
87 | [MoveTool] public List vectorCollection = new List(); // Vector3[] array is also okay.
88 | ```
89 |
90 | 
91 |
92 | ### Non-Public field
93 |
94 | You can only use move-tool for a serializable vector.
95 | So, if you want to use move-tool for a ***non-public*** field like `private` or `protected`, you have to define `UnityEngine.SerializeField` attribute for the field.
96 | See the following code.
97 |
98 | ```c#
99 | [SerializeField, MoveTool] private Vector3 privateVector;
100 | [SerializeField, MoveTool] private List privateCollection = new List();
101 | ```
102 |
103 | ## MoveToolAttribute Properties
104 |
105 | `MoveToolAttribute` has the following properties.
106 |
107 | * `PositionMode` sets the coordinate space of the vector. If you set it to `MoveToolPosition.Local` enum value, the vector works in local coordinate. Default is world coordinate.
108 | * `LabelMode` is a enum flag property. You can display the move-tool label on unity editor through it. By default, the label is displayed on both scene and inspector view.
109 | * `Label` is a custom label that you want to display your own label instead of the default label. Default label is the field name for display.
110 |
111 | ### Sample Code
112 |
113 | ```c#
114 | [MoveTool(PositionMode = MoveToolPosition.Local, LabelMode = MoveToolLabel.SceneView, Label = "My Custom Label")]
115 | public Vector3 customPropertyVector;
116 | ```
117 |
118 | ## Move-Tool available custom type
119 |
120 | If you want to use move-tool for a custom type field which declare vector fields, you must define `System.Serializable` and `MoveToolAvailable` attributes for the type.
121 | The custom type is okay whether class or struct.
122 |
123 | ```c#
124 | public class MoveToolSample : MonoBehaviour
125 | {
126 | [MoveTool] public List customClasses = new List();
127 | }
128 |
129 | [Serializable, MoveToolAvailable]
130 | public class CustomClass
131 | {
132 | public List vectors = new List();
133 | }
134 | ```
135 |
136 | 
137 |
138 | ### Serialize
139 |
140 | A custom type for which you define `MoveToolAvailable` attribute must be serializable. So, if you don't want to use move-tools for the fields which is declared in the custom type, you should set the fields to be non-serializable.
141 |
142 | > Note that you can only use move-tool for a serialized field.
143 |
144 | See the following example.
145 |
146 | ```c#
147 | [Serializable, MoveToolAvailable]
148 | public class CustomClass
149 | {
150 | public Vector3 publicVector; // Can use move-tool.
151 | [SerializeField] private Vector3 serializedPrivateVector; // Can use move-tool.
152 | [NonSerialized] public Vector3 nonSerializedPublicVector; // Can't use move-tool.
153 | private Vector3 privateVector; // Can't use move-tool.
154 | }
155 | ```
156 |
157 | Public vector is always serialized. If you don't want to use move-tool for a public field, you need to define `System.NonSerialized` attribute for it.
158 | Non-public vector isn't always serialized. If you want to use move-tool for a non-public field, you need to define `UnityEngine.SerializeField` attribute for it.
159 |
160 | ## Editor
161 |
162 | Now, you don't have to worry about editor conflict problem. It is solved.
163 | You don't need to create `MoveToolEditor` instance for using concurrently `AnotherEditor` with it.
164 | You just use normally `MoveTool` attribute.
165 |
--------------------------------------------------------------------------------
/README.md.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 86be942ab938a6740a4a4fb361dd8910
3 | TextScriptImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: bdb7a32dbe2d2694c9544a078d41456d
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Runtime/DevSlem.MoveTool.asmdef:
--------------------------------------------------------------------------------
1 | {
2 | "name": "DevSlem.MoveTool",
3 | "rootNamespace": "",
4 | "references": [],
5 | "includePlatforms": [],
6 | "excludePlatforms": [],
7 | "allowUnsafeCode": false,
8 | "overrideReferences": false,
9 | "precompiledReferences": [],
10 | "autoReferenced": true,
11 | "defineConstraints": [],
12 | "versionDefines": [],
13 | "noEngineReferences": false
14 | }
--------------------------------------------------------------------------------
/Runtime/DevSlem.MoveTool.asmdef.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: a31c1babfbfb4654fb3f28ab7a1ed780
3 | AssemblyDefinitionImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Runtime/MoveToolAttributes.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using UnityEngine;
3 |
4 | namespace DevSlem
5 | {
6 | ///
7 | /// You can use move-tool for the vector in unity editor scene view.
8 | ///
9 | [AttributeUsage(AttributeTargets.Field, AllowMultiple = false, Inherited = true)]
10 | public class MoveToolAttribute : PropertyAttribute
11 | {
12 | ///
13 | /// You can control the position mode of move-tool. Default is world position mode.
14 | ///
15 | public MoveToolPosition PositionMode { get; set; } = MoveToolPosition.World;
16 |
17 | ///
18 | /// You can display the move-tool label on unity editor through this enum flags.
19 | ///
20 | public MoveToolLabel LabelMode { get; set; } = MoveToolLabel.SceneView | MoveToolLabel.InspectorView;
21 |
22 | ///
23 | /// Custom Label. Default is field label for display.
24 | ///
25 | public string Label { get; set; } = string.Empty;
26 |
27 | }
28 |
29 | ///
30 | /// If it's defined for a custom type, you can use MoveToolAttribute to the type field.
31 | ///
32 | [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct, AllowMultiple = false, Inherited = true)]
33 | public class MoveToolAvailableAttribute : PropertyAttribute { }
34 |
35 | public enum MoveToolPosition
36 | {
37 | World,
38 | Local
39 | }
40 |
41 | [Flags]
42 | public enum MoveToolLabel
43 | {
44 | None = 0,
45 | SceneView = 1,
46 | InspectorView = 2
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/Runtime/MoveToolAttributes.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: f1146a6e9251184458089671fb4e5704
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Runtime/StringExtension.cs:
--------------------------------------------------------------------------------
1 | namespace DevSlem.Extensions
2 | {
3 | public static class StringExtension
4 | {
5 | ///
6 | /// Change the variable name to the display name for inspector.
7 | ///
8 | /// display name for inspector
9 | public static string InspectorLabel(this string variableName)
10 | {
11 | if (variableName == null)
12 | throw new System.NullReferenceException();
13 |
14 | if (variableName.Length == 0)
15 | return string.Empty;
16 |
17 | string temp = variableName.Trim();
18 | temp = char.ToUpper(temp[0]) + temp.Substring(1); // capitalize the first letter
19 |
20 | // If it changes small letter to capital letter, insert a space.
21 | for (int i = 0; i < temp.Length - 1; i++)
22 | {
23 | if (!char.IsLetterOrDigit(temp[i]) || !char.IsLetterOrDigit(temp[i + 1]))
24 | continue;
25 |
26 | if ((char.IsLower(temp[i]) && !char.IsLower(temp[i + 1])) || (!char.IsUpper(temp[i]) && char.IsUpper(temp[i + 1])))
27 | {
28 | temp = temp.Insert(i + 1, " ");
29 | }
30 | }
31 |
32 | return temp;
33 | }
34 | }
35 | }
--------------------------------------------------------------------------------
/Runtime/StringExtension.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 5e4aea9a5c041d24b84408155b886a75
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Samples~/SamplesMoveTool.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 3bcdc680c1f8c064faa7c36432a9e773
3 | folderAsset: yes
4 | DefaultImporter:
5 | externalObjects: {}
6 | userData:
7 | assetBundleName:
8 | assetBundleVariant:
9 |
--------------------------------------------------------------------------------
/Samples~/SamplesMoveTool/MoveTool Sample.prefab:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!1 &8872950196097312925
4 | GameObject:
5 | m_ObjectHideFlags: 0
6 | m_CorrespondingSourceObject: {fileID: 0}
7 | m_PrefabInstance: {fileID: 0}
8 | m_PrefabAsset: {fileID: 0}
9 | serializedVersion: 6
10 | m_Component:
11 | - component: {fileID: 8872950196097312926}
12 | - component: {fileID: 8872950196097312927}
13 | m_Layer: 0
14 | m_Name: MoveTool Sample
15 | m_TagString: Untagged
16 | m_Icon: {fileID: 0}
17 | m_NavMeshLayer: 0
18 | m_StaticEditorFlags: 0
19 | m_IsActive: 1
20 | --- !u!4 &8872950196097312926
21 | Transform:
22 | m_ObjectHideFlags: 0
23 | m_CorrespondingSourceObject: {fileID: 0}
24 | m_PrefabInstance: {fileID: 0}
25 | m_PrefabAsset: {fileID: 0}
26 | m_GameObject: {fileID: 8872950196097312925}
27 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
28 | m_LocalPosition: {x: 0, y: 0, z: 0}
29 | m_LocalScale: {x: 1, y: 1, z: 1}
30 | m_ConstrainProportionsScale: 0
31 | m_Children: []
32 | m_Father: {fileID: 0}
33 | m_RootOrder: 0
34 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
35 | --- !u!114 &8872950196097312927
36 | MonoBehaviour:
37 | m_ObjectHideFlags: 0
38 | m_CorrespondingSourceObject: {fileID: 0}
39 | m_PrefabInstance: {fileID: 0}
40 | m_PrefabAsset: {fileID: 0}
41 | m_GameObject: {fileID: 8872950196097312925}
42 | m_Enabled: 1
43 | m_EditorHideFlags: 0
44 | m_Script: {fileID: 11500000, guid: b71346e81de833240992d50ebdf6e848, type: 3}
45 | m_Name:
46 | m_EditorClassIdentifier:
47 | vector: {x: 3, y: 0, z: 0}
48 | vector2: {x: 6, y: 0}
49 | floatField: 9
50 | vectorCollection:
51 | - {x: 12, y: 0, z: 0}
52 | - {x: 15, y: 0, z: 0}
53 | privateVector: {x: 18, y: 0, z: 0}
54 | privateCollection:
55 | - {x: 21, y: 0, z: 0}
56 | - {x: 24, y: 0, z: 0}
57 | customPropertyVector: {x: 27, y: 0, z: 0}
58 | customClasses:
59 | - publicVector: {x: 30, y: 0, z: 0}
60 | serializedPrivateVector: {x: 33, y: 0, z: 0}
61 | - publicVector: {x: 36, y: 0, z: 0}
62 | serializedPrivateVector: {x: 39, y: 0, z: 0}
63 |
--------------------------------------------------------------------------------
/Samples~/SamplesMoveTool/MoveTool Sample.prefab.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 15615e270044b4b4bae1016dc8ac08f0
3 | PrefabImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/Samples~/SamplesMoveTool/MoveToolSample.cs:
--------------------------------------------------------------------------------
1 | using DevSlem;
2 | using System;
3 | using System.Collections.Generic;
4 | using UnityEngine;
5 |
6 | public class MoveToolSample : MonoBehaviour
7 | {
8 | [MoveTool] public Vector3 vector;
9 | [MoveTool] public Vector2 vector2;
10 | [MoveTool] public float floatField;
11 | [MoveTool] public List vectorCollection = new List(); // Vector3[] array is also okay.
12 | [SerializeField, MoveTool] private Vector3 privateVector;
13 | [SerializeField, MoveTool] private List privateCollection = new List();
14 | [MoveTool(PositionMode = MoveToolPosition.Local, LabelMode = MoveToolLabel.SceneView, Label = "My Custom Label")]
15 | public Vector3 customPropertyVector;
16 | [MoveTool] public List customClasses = new List();
17 | }
18 |
19 | [Serializable, MoveToolAvailable]
20 | public class CustomClass
21 | {
22 | public Vector3 publicVector; // Can use move-tool.
23 | [SerializeField] private Vector3 serializedPrivateVector; // Can use move-tool.
24 | [NonSerialized] public Vector3 nonSerializedPublicVector; // Can't use move-tool.
25 | private Vector3 privateVector; // Can't use move-tool.
26 | }
--------------------------------------------------------------------------------
/Samples~/SamplesMoveTool/MoveToolSample.cs.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: b71346e81de833240992d50ebdf6e848
3 | MonoImporter:
4 | externalObjects: {}
5 | serializedVersion: 2
6 | defaultReferences: []
7 | executionOrder: 0
8 | icon: {instanceID: 0}
9 | userData:
10 | assetBundleName:
11 | assetBundleVariant:
12 |
--------------------------------------------------------------------------------
/Samples~/SamplesMoveTool/MoveToolSampleScene.unity:
--------------------------------------------------------------------------------
1 | %YAML 1.1
2 | %TAG !u! tag:unity3d.com,2011:
3 | --- !u!29 &1
4 | OcclusionCullingSettings:
5 | m_ObjectHideFlags: 0
6 | serializedVersion: 2
7 | m_OcclusionBakeSettings:
8 | smallestOccluder: 5
9 | smallestHole: 0.25
10 | backfaceThreshold: 100
11 | m_SceneGUID: 00000000000000000000000000000000
12 | m_OcclusionCullingData: {fileID: 0}
13 | --- !u!104 &2
14 | RenderSettings:
15 | m_ObjectHideFlags: 0
16 | serializedVersion: 9
17 | m_Fog: 0
18 | m_FogColor: {r: 0.5, g: 0.5, b: 0.5, a: 1}
19 | m_FogMode: 3
20 | m_FogDensity: 0.01
21 | m_LinearFogStart: 0
22 | m_LinearFogEnd: 300
23 | m_AmbientSkyColor: {r: 0.212, g: 0.227, b: 0.259, a: 1}
24 | m_AmbientEquatorColor: {r: 0.114, g: 0.125, b: 0.133, a: 1}
25 | m_AmbientGroundColor: {r: 0.047, g: 0.043, b: 0.035, a: 1}
26 | m_AmbientIntensity: 1
27 | m_AmbientMode: 0
28 | m_SubtractiveShadowColor: {r: 0.42, g: 0.478, b: 0.627, a: 1}
29 | m_SkyboxMaterial: {fileID: 10304, guid: 0000000000000000f000000000000000, type: 0}
30 | m_HaloStrength: 0.5
31 | m_FlareStrength: 1
32 | m_FlareFadeSpeed: 3
33 | m_HaloTexture: {fileID: 0}
34 | m_SpotCookie: {fileID: 10001, guid: 0000000000000000e000000000000000, type: 0}
35 | m_DefaultReflectionMode: 0
36 | m_DefaultReflectionResolution: 128
37 | m_ReflectionBounces: 1
38 | m_ReflectionIntensity: 1
39 | m_CustomReflection: {fileID: 0}
40 | m_Sun: {fileID: 705507994}
41 | m_IndirectSpecularColor: {r: 0.18028378, g: 0.22571412, b: 0.30692285, a: 1}
42 | m_UseRadianceAmbientProbe: 0
43 | --- !u!157 &3
44 | LightmapSettings:
45 | m_ObjectHideFlags: 0
46 | serializedVersion: 12
47 | m_GIWorkflowMode: 1
48 | m_GISettings:
49 | serializedVersion: 2
50 | m_BounceScale: 1
51 | m_IndirectOutputScale: 1
52 | m_AlbedoBoost: 1
53 | m_EnvironmentLightingMode: 0
54 | m_EnableBakedLightmaps: 1
55 | m_EnableRealtimeLightmaps: 0
56 | m_LightmapEditorSettings:
57 | serializedVersion: 12
58 | m_Resolution: 2
59 | m_BakeResolution: 40
60 | m_AtlasSize: 1024
61 | m_AO: 0
62 | m_AOMaxDistance: 1
63 | m_CompAOExponent: 1
64 | m_CompAOExponentDirect: 0
65 | m_ExtractAmbientOcclusion: 0
66 | m_Padding: 2
67 | m_LightmapParameters: {fileID: 0}
68 | m_LightmapsBakeMode: 1
69 | m_TextureCompression: 1
70 | m_FinalGather: 0
71 | m_FinalGatherFiltering: 1
72 | m_FinalGatherRayCount: 256
73 | m_ReflectionCompression: 2
74 | m_MixedBakeMode: 2
75 | m_BakeBackend: 1
76 | m_PVRSampling: 1
77 | m_PVRDirectSampleCount: 32
78 | m_PVRSampleCount: 500
79 | m_PVRBounces: 2
80 | m_PVREnvironmentSampleCount: 500
81 | m_PVREnvironmentReferencePointCount: 2048
82 | m_PVRFilteringMode: 2
83 | m_PVRDenoiserTypeDirect: 0
84 | m_PVRDenoiserTypeIndirect: 0
85 | m_PVRDenoiserTypeAO: 0
86 | m_PVRFilterTypeDirect: 0
87 | m_PVRFilterTypeIndirect: 0
88 | m_PVRFilterTypeAO: 0
89 | m_PVREnvironmentMIS: 0
90 | m_PVRCulling: 1
91 | m_PVRFilteringGaussRadiusDirect: 1
92 | m_PVRFilteringGaussRadiusIndirect: 5
93 | m_PVRFilteringGaussRadiusAO: 2
94 | m_PVRFilteringAtrousPositionSigmaDirect: 0.5
95 | m_PVRFilteringAtrousPositionSigmaIndirect: 2
96 | m_PVRFilteringAtrousPositionSigmaAO: 1
97 | m_ExportTrainingData: 0
98 | m_TrainingDataDestination: TrainingData
99 | m_LightProbeSampleCountMultiplier: 4
100 | m_LightingDataAsset: {fileID: 0}
101 | m_LightingSettings: {fileID: 0}
102 | --- !u!196 &4
103 | NavMeshSettings:
104 | serializedVersion: 2
105 | m_ObjectHideFlags: 0
106 | m_BuildSettings:
107 | serializedVersion: 2
108 | agentTypeID: 0
109 | agentRadius: 0.5
110 | agentHeight: 2
111 | agentSlope: 45
112 | agentClimb: 0.4
113 | ledgeDropHeight: 0
114 | maxJumpAcrossDistance: 0
115 | minRegionArea: 2
116 | manualCellSize: 0
117 | cellSize: 0.16666667
118 | manualTileSize: 0
119 | tileSize: 256
120 | accuratePlacement: 0
121 | maxJobWorkers: 0
122 | preserveTilesOutsideBounds: 0
123 | debug:
124 | m_Flags: 0
125 | m_NavMeshData: {fileID: 0}
126 | --- !u!1 &705507993
127 | GameObject:
128 | m_ObjectHideFlags: 0
129 | m_CorrespondingSourceObject: {fileID: 0}
130 | m_PrefabInstance: {fileID: 0}
131 | m_PrefabAsset: {fileID: 0}
132 | serializedVersion: 6
133 | m_Component:
134 | - component: {fileID: 705507995}
135 | - component: {fileID: 705507994}
136 | - component: {fileID: 705507996}
137 | m_Layer: 0
138 | m_Name: Directional Light
139 | m_TagString: Untagged
140 | m_Icon: {fileID: 0}
141 | m_NavMeshLayer: 0
142 | m_StaticEditorFlags: 0
143 | m_IsActive: 1
144 | --- !u!108 &705507994
145 | Light:
146 | m_ObjectHideFlags: 0
147 | m_CorrespondingSourceObject: {fileID: 0}
148 | m_PrefabInstance: {fileID: 0}
149 | m_PrefabAsset: {fileID: 0}
150 | m_GameObject: {fileID: 705507993}
151 | m_Enabled: 1
152 | serializedVersion: 10
153 | m_Type: 1
154 | m_Shape: 0
155 | m_Color: {r: 1, g: 0.95686275, b: 0.8392157, a: 1}
156 | m_Intensity: 1
157 | m_Range: 10
158 | m_SpotAngle: 30
159 | m_InnerSpotAngle: 21.80208
160 | m_CookieSize: 10
161 | m_Shadows:
162 | m_Type: 2
163 | m_Resolution: -1
164 | m_CustomResolution: -1
165 | m_Strength: 1
166 | m_Bias: 0.05
167 | m_NormalBias: 0.4
168 | m_NearPlane: 0.2
169 | m_CullingMatrixOverride:
170 | e00: 1
171 | e01: 0
172 | e02: 0
173 | e03: 0
174 | e10: 0
175 | e11: 1
176 | e12: 0
177 | e13: 0
178 | e20: 0
179 | e21: 0
180 | e22: 1
181 | e23: 0
182 | e30: 0
183 | e31: 0
184 | e32: 0
185 | e33: 1
186 | m_UseCullingMatrixOverride: 0
187 | m_Cookie: {fileID: 0}
188 | m_DrawHalo: 0
189 | m_Flare: {fileID: 0}
190 | m_RenderMode: 0
191 | m_CullingMask:
192 | serializedVersion: 2
193 | m_Bits: 4294967295
194 | m_RenderingLayerMask: 1
195 | m_Lightmapping: 1
196 | m_LightShadowCasterMode: 0
197 | m_AreaSize: {x: 1, y: 1}
198 | m_BounceIntensity: 1
199 | m_ColorTemperature: 6570
200 | m_UseColorTemperature: 0
201 | m_BoundingSphereOverride: {x: 0, y: 0, z: 0, w: 0}
202 | m_UseBoundingSphereOverride: 0
203 | m_UseViewFrustumForShadowCasterCull: 1
204 | m_ShadowRadius: 0
205 | m_ShadowAngle: 0
206 | --- !u!4 &705507995
207 | Transform:
208 | m_ObjectHideFlags: 0
209 | m_CorrespondingSourceObject: {fileID: 0}
210 | m_PrefabInstance: {fileID: 0}
211 | m_PrefabAsset: {fileID: 0}
212 | m_GameObject: {fileID: 705507993}
213 | m_LocalRotation: {x: 0.40821788, y: -0.23456968, z: 0.10938163, w: 0.8754261}
214 | m_LocalPosition: {x: 0, y: 3, z: 0}
215 | m_LocalScale: {x: 1, y: 1, z: 1}
216 | m_ConstrainProportionsScale: 0
217 | m_Children: []
218 | m_Father: {fileID: 0}
219 | m_RootOrder: 1
220 | m_LocalEulerAnglesHint: {x: 50, y: -30, z: 0}
221 | --- !u!114 &705507996
222 | MonoBehaviour:
223 | m_ObjectHideFlags: 0
224 | m_CorrespondingSourceObject: {fileID: 0}
225 | m_PrefabInstance: {fileID: 0}
226 | m_PrefabAsset: {fileID: 0}
227 | m_GameObject: {fileID: 705507993}
228 | m_Enabled: 1
229 | m_EditorHideFlags: 0
230 | m_Script: {fileID: 11500000, guid: 474bcb49853aa07438625e644c072ee6, type: 3}
231 | m_Name:
232 | m_EditorClassIdentifier:
233 | m_Version: 1
234 | m_UsePipelineSettings: 1
235 | m_AdditionalLightsShadowResolutionTier: 2
236 | m_LightLayerMask: 1
237 | m_CustomShadowLayers: 0
238 | m_ShadowLayerMask: 1
239 | m_LightCookieSize: {x: 1, y: 1}
240 | m_LightCookieOffset: {x: 0, y: 0}
241 | --- !u!1 &963194225
242 | GameObject:
243 | m_ObjectHideFlags: 0
244 | m_CorrespondingSourceObject: {fileID: 0}
245 | m_PrefabInstance: {fileID: 0}
246 | m_PrefabAsset: {fileID: 0}
247 | serializedVersion: 6
248 | m_Component:
249 | - component: {fileID: 963194228}
250 | - component: {fileID: 963194227}
251 | - component: {fileID: 963194226}
252 | m_Layer: 0
253 | m_Name: Main Camera
254 | m_TagString: MainCamera
255 | m_Icon: {fileID: 0}
256 | m_NavMeshLayer: 0
257 | m_StaticEditorFlags: 0
258 | m_IsActive: 1
259 | --- !u!81 &963194226
260 | AudioListener:
261 | m_ObjectHideFlags: 0
262 | m_CorrespondingSourceObject: {fileID: 0}
263 | m_PrefabInstance: {fileID: 0}
264 | m_PrefabAsset: {fileID: 0}
265 | m_GameObject: {fileID: 963194225}
266 | m_Enabled: 1
267 | --- !u!20 &963194227
268 | Camera:
269 | m_ObjectHideFlags: 0
270 | m_CorrespondingSourceObject: {fileID: 0}
271 | m_PrefabInstance: {fileID: 0}
272 | m_PrefabAsset: {fileID: 0}
273 | m_GameObject: {fileID: 963194225}
274 | m_Enabled: 1
275 | serializedVersion: 2
276 | m_ClearFlags: 1
277 | m_BackGroundColor: {r: 0.19215687, g: 0.3019608, b: 0.4745098, a: 0}
278 | m_projectionMatrixMode: 1
279 | m_GateFitMode: 2
280 | m_FOVAxisMode: 0
281 | m_SensorSize: {x: 36, y: 24}
282 | m_LensShift: {x: 0, y: 0}
283 | m_FocalLength: 50
284 | m_NormalizedViewPortRect:
285 | serializedVersion: 2
286 | x: 0
287 | y: 0
288 | width: 1
289 | height: 1
290 | near clip plane: 0.3
291 | far clip plane: 1000
292 | field of view: 60
293 | orthographic: 0
294 | orthographic size: 5
295 | m_Depth: -1
296 | m_CullingMask:
297 | serializedVersion: 2
298 | m_Bits: 4294967295
299 | m_RenderingPath: -1
300 | m_TargetTexture: {fileID: 0}
301 | m_TargetDisplay: 0
302 | m_TargetEye: 3
303 | m_HDR: 1
304 | m_AllowMSAA: 1
305 | m_AllowDynamicResolution: 0
306 | m_ForceIntoRT: 0
307 | m_OcclusionCulling: 1
308 | m_StereoConvergence: 10
309 | m_StereoSeparation: 0.022
310 | --- !u!4 &963194228
311 | Transform:
312 | m_ObjectHideFlags: 0
313 | m_CorrespondingSourceObject: {fileID: 0}
314 | m_PrefabInstance: {fileID: 0}
315 | m_PrefabAsset: {fileID: 0}
316 | m_GameObject: {fileID: 963194225}
317 | m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
318 | m_LocalPosition: {x: 0, y: 1, z: -10}
319 | m_LocalScale: {x: 1, y: 1, z: 1}
320 | m_ConstrainProportionsScale: 0
321 | m_Children: []
322 | m_Father: {fileID: 0}
323 | m_RootOrder: 0
324 | m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
325 | --- !u!1001 &8872950196796448384
326 | PrefabInstance:
327 | m_ObjectHideFlags: 0
328 | serializedVersion: 2
329 | m_Modification:
330 | m_TransformParent: {fileID: 0}
331 | m_Modifications:
332 | - target: {fileID: 8872950196097312925, guid: 15615e270044b4b4bae1016dc8ac08f0,
333 | type: 3}
334 | propertyPath: m_Name
335 | value: MoveTool Sample
336 | objectReference: {fileID: 0}
337 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
338 | type: 3}
339 | propertyPath: m_RootOrder
340 | value: 2
341 | objectReference: {fileID: 0}
342 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
343 | type: 3}
344 | propertyPath: m_LocalPosition.x
345 | value: 0
346 | objectReference: {fileID: 0}
347 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
348 | type: 3}
349 | propertyPath: m_LocalPosition.y
350 | value: 0
351 | objectReference: {fileID: 0}
352 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
353 | type: 3}
354 | propertyPath: m_LocalPosition.z
355 | value: 0
356 | objectReference: {fileID: 0}
357 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
358 | type: 3}
359 | propertyPath: m_LocalRotation.w
360 | value: 1
361 | objectReference: {fileID: 0}
362 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
363 | type: 3}
364 | propertyPath: m_LocalRotation.x
365 | value: 0
366 | objectReference: {fileID: 0}
367 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
368 | type: 3}
369 | propertyPath: m_LocalRotation.y
370 | value: 0
371 | objectReference: {fileID: 0}
372 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
373 | type: 3}
374 | propertyPath: m_LocalRotation.z
375 | value: 0
376 | objectReference: {fileID: 0}
377 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
378 | type: 3}
379 | propertyPath: m_LocalEulerAnglesHint.x
380 | value: 0
381 | objectReference: {fileID: 0}
382 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
383 | type: 3}
384 | propertyPath: m_LocalEulerAnglesHint.y
385 | value: 0
386 | objectReference: {fileID: 0}
387 | - target: {fileID: 8872950196097312926, guid: 15615e270044b4b4bae1016dc8ac08f0,
388 | type: 3}
389 | propertyPath: m_LocalEulerAnglesHint.z
390 | value: 0
391 | objectReference: {fileID: 0}
392 | m_RemovedComponents: []
393 | m_SourcePrefab: {fileID: 100100000, guid: 15615e270044b4b4bae1016dc8ac08f0, type: 3}
394 |
--------------------------------------------------------------------------------
/Samples~/SamplesMoveTool/MoveToolSampleScene.unity.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 9fc0d4010bbf28b4594072e72b8655ab
3 | DefaultImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "com.devslem.movetool",
3 | "version": "3.1.0",
4 | "displayName": "Move Tool",
5 | "description": "You can use position handles of fields for which you define MoveToolAttribute in the unity editor scene view.",
6 | "unity": "2020.3",
7 | "documentationUrl": "https://github.com/DevSlem/unity-move-tool/blob/release-3.0.0/README.md",
8 | "changelogUrl": "https://github.com/DevSlem/unity-move-tool/releases",
9 | "licensesUrl": "https://github.com/DevSlem/unity-move-tool/blob/main/LICENSE",
10 | "keywords": [
11 | "Move Tool",
12 | "Position Handle",
13 | "Unity Editor"
14 | ],
15 | "author": {
16 | "name": "DevSlem",
17 | "email": "devslem12@gmail.com",
18 | "url": "https://github.com/DevSlem"
19 | },
20 | "hideInEditor": false,
21 | "samples": [
22 | {
23 | "displayName": "MoveTool Sample",
24 | "description": "You can see a MoveTool sample code and usages.",
25 | "path": "Samples~/SamplesMoveTool"
26 | }
27 | ]
28 | }
--------------------------------------------------------------------------------
/package.json.meta:
--------------------------------------------------------------------------------
1 | fileFormatVersion: 2
2 | guid: 6b13454772efb5049a020f4faa760ede
3 | PackageManifestImporter:
4 | externalObjects: {}
5 | userData:
6 | assetBundleName:
7 | assetBundleVariant:
8 |
--------------------------------------------------------------------------------