Add copy/paste functionality to all object Transforms in Unity
December 1st, 2012
I’m going to focus my first Unity developer tutorial on something that I personally would’ve loved to know about a year ago when I started using Unity! I’m not sure how big a deal this is for other Unity devs, but the number of times I’d be playing my game in the Unity Editor, seeing how things played out, then playing around with objects in the scene while it was still running, moving everything into its perfect position, then realising that it was all going to snap back to how it was before when I stop playing that instance! Wouldn’t it be great if you could just copy the positions of the game objects in the scene and then paste them back after stopping the game…?
This tutorial will go over how to write a Unity editor extension for the Transform component, which will add “Copy/Paste” buttons to the Inspector for every GameObject in your project.
We’ll start by adding our own reverse engineered version of Unity’s built-in UnityEditor.TransformInspector class into our projects “Editor” folder. This script was based on a script posted on the Unity wiki here, and I’ve added two (currently useless) buttons, “Copy” and “Paste”.
Note: It is important that this script gets added to a folder named “Editor” in your project hierarchy, otherwise it won’t have any effect! If you haven’t got an “Editor” folder, then create one.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | using UnityEngine; using System.Collections; using UnityEditor; [CustomEditor(typeof(Transform))] public class TransformCopy : Editor { public override void OnInspectorGUI () { Transform t = (Transform)target; // Replicate the standard transform inspector gui EditorGUIUtility.LookLikeControls(); EditorGUI.indentLevel = 0; Vector3 position = EditorGUILayout.Vector3Field("Position", t.localPosition); Vector3 eulerAngles = EditorGUILayout.Vector3Field("Rotation", t.localEulerAngles); Vector3 scale = EditorGUILayout.Vector3Field("Scale", t.localScale); EditorGUILayout.BeginHorizontal(); if(GUILayout.Button("Copy Transform")) { Debug.Log("Copy Transform"); } if(GUILayout.Button("Paste Transform")) { Debug.Log("Paste Transform"); } EditorGUILayout.EndHorizontal(); EditorGUIUtility.LookLikeInspector(); if (GUI.changed) { Undo.RegisterUndo(t, "Transform Change"); t.localPosition = TidyVector3(position); t.localEulerAngles = TidyVector3(eulerAngles); t.localScale = TidyVector3(scale); } } } |
You should now notice that all of the Transform components in your project have an additional two buttons added to the bottom. How handy!
Now lets make those buttons do something useful.
Add this static string variable to your TransformCopy class:
1 | public static string TRANSFORM_COPY_PREFIX = "eqguqero124"; |
Add this within your “Copy Transform” button if statement (line 23 in script above):
1 2 3 4 5 6 7 8 9 10 11 12 | PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_pos_x", t.localPosition.x); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_pos_y", t.localPosition.y); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_pos_z", t.localPosition.z); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_rot_x", t.localRotation.x); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_rot_y", t.localRotation.y); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_rot_z", t.localRotation.z); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_rot_w", t.localRotation.w); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_scale_x", t.localScale.x); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_scale_y", t.localScale.y); PlayerPrefs.SetFloat(TRANSFORM_COPY_PREFIX + "_scale_z", t.localScale.z); |
Add this within your “Paste Transform” button if statement (line 28 in the script above):
1 2 3 4 5 6 | Undo.RegisterUndo(t, "Transform Paste"); // General object transform data found t.localPosition = new Vector3(PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_pos_x"), PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_pos_y"), PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_pos_z")); t.localRotation = new Quaternion(PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_rot_x"), PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_rot_y"), PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_rot_z"), PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_rot_w")); t.localScale = new Vector3(PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_scale_x"), PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_scale_y"), PlayerPrefs.GetFloat(TRANSFORM_COPY_PREFIX + "_scale_z")); |
You should now be able to copy and paste any objects Transform data, and paste it onto other objects. This works by saving the state of the Transform into the PlayerPrefs, which is stored locally on your PC.
In order to ensure that the transform data doesn’t get saved over any existing game data with the same key name, we’re prefixing the data keys with the unique random string TRANSFORM_COPY_PREFIX.
New Blog Started!
September 5th, 2012
Hi everyone, I’m Tom Figg, author of this here new blog.
I’m a computer games developer and general application programmer. Check out my previous works under the Portfolio section of this site.
Here I’ll be blogging about various development how-to’s and also my personal projects and independent releases.
I’ll be mainly aiming my content at fellow programmers and games development enthusiasts.
I’m currently quite an avid Unity game engine fan, using it for my day job and in my personal projects, so expect there to be an emphasis on Unity development to start with!