Runtime Handles

Runtime Handles is a set of scripts, which will help you to implement runtime scene/level editor. Package divided into several parts, could be used together or independently.

Features:
:heart: Positon handle,
:heart: Rotation handle;
:heart: Scale handle;
:heart: Grid;
:heart: Box Selection;
:heart: Selection gizmo;
:heart: Unit & Bounding Box Snapping;
:heart: Snap To Grid;
:heart: Focus & Auto-Focus;
:heart: Global & Local coordinates;
:heart: Runtime Undo & Redo;
:heart: Runtime Save & Load (PlayerPrefs)
:heart: Editor Demo

Documentation


How could I change the gizmos size?

Thank you! This asset is awesome

It will be possible with version 1.11
Battlehub/RTHandles/Scripts/RuntimeHandles.cs
public static class RuntimeHandles
{
public const float HandleScale = 1.0f;
Send your order number to Vadim.Andriyanov@outlook.com and I’ll send you latest version with this option

Hello Mr. Adryanov,

I would like to buy your program Runtime Editor.
For this I have some questions:

1.How can I zoom out and zoom in?
2.How can I save as name and load as name? Where is everything stored?
3.Can I edit and change the buttons, etc. in the editor?
4.I can install my own objects

Best regards
Detlef Delfing

Great asset.

I think the rotation behavior with several objects selected is a bit weird:

Rather, they should rotate around a common origin (preferably center of all selected objects).

I’m not a big fan of the ResourceMap. Having code that tracks the whole project and slows it down isn’t acceptable, especially if you’re not even interested in the undo-redo functionality. There should be an officially supported way to disable this.

The ExposeToEditor workflow is really neat, but I’d like to see options for what tools are supported as well (maybe the user wants some objects to only be rotatable or movable for example).

Other than that, lovely asset. I hope it evolves.

In version 1.3.1

  • problem with rotation fixed (rotation mode could be either: local or pivot)
  • ResourceMap is not slowing down project anymore, and could be removed at all. User could implement IProjectManager or ISceneManager interface and use own save & load functionality.
  • Undo Redo could be disabled: Battlehub.RTCommon.RuntimeUndo.Enabled = false;

When "Anti Aliasing "in the “Quality Settings” is not disabled, SceneGizmo fails to refresh properly.

Deploy to “Web GL” mode.

3095314--233610--SceneGizmo.PNG

1 Like

Hi,

Thank you for reporting about this problem. I think that you don’t have to switch off antialiasing in quality settings. MSAA should be disabled only on camera which is used to render SceneGizmo. All other cameras could have allowMSAA set to true. I’ve tested it with WebGL build in latest Chrome and Firefox on windows 10 platform.

Could you confirm that you have m_camera.allowMSAA = false in Battlehub/RTHandles/Scripts/SceneGizmo.cs, so we could narrow the problem?

   [RequireComponent(typeof(Camera))]
    public class SceneGizmo : MonoBehaviour
    {
    ....
        private void Start()
        {
    ....
            m_camera = GetComponent<Camera>();
            m_camera.clearFlags = CameraClearFlags.Depth;
            m_camera.renderingPath = RenderingPath.Forward;
            m_camera.allowMSAA = false;
            m_camera.allowHDR = false;
    ....
    }

    ....
    }

3096706--233749--upload_2017-6-6_13-16-21.png
Regards,
Vadim

Here is code to clamp angles per object. Attach ClampAngles script to required objects and set Angle to desired value

using Battlehub.RTCommon;
using Battlehub.RTHandles;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

public class ClampAngles : MonoBehaviour
{
    public float Angle = 45;
    private const float DefaultAngle = 15;
    private static RuntimeSelectionComponent m_selectionComponent;
    static ClampAngles()
    {
       
        RuntimeSelection.SelectionChanged += OnRuntimeSelectionChanged;
        RuntimeTools.ToolChanged += OnToolChanged;
    }

    private static void OnToolChanged()
    {
        TryUpdateRotationHandle();
    }

    private static void OnRuntimeSelectionChanged(Object[] unselectedObjects)
    {
        TryUpdateRotationHandle();
    }

    private static void TryUpdateRotationHandle()
    {
        if (RuntimeTools.Current != RuntimeTool.Rotate)
        {
            return;
        }

        if (m_selectionComponent == null)
        {
            m_selectionComponent = FindObjectOfType<RuntimeSelectionComponent>();
            if(m_selectionComponent == null)
            {
                Debug.LogError("Unable to find RuntimeSelectionComponent");
                return;
            }
        }

        RotationHandle rotationHandle = m_selectionComponent.HandlesParent.GetComponentInChildren<RotationHandle>(true);
        IEnumerable<ClampAngles> clampAngles = RuntimeSelection.gameObjects.Where(go => go.GetComponent<ClampAngles>() != null).Select(go => go.GetComponent<ClampAngles>());
        if (clampAngles.Any())
        {
            rotationHandle.GridSize = clampAngles.Max(ca => ca.Angle);
        }
        else
        {
            rotationHandle.GridSize = DefaultAngle;
        }
    }
}

To fix problems with Postion, Rotation, Scale, Grid, SceneView and other components, set SceneCamera field to your camera. Your camera should have GLCamera script attached.

3096726--233751--upload_2017-6-6_14-1-39.png

3096726--233752--upload_2017-6-6_14-2-16.png

3096726--233753--upload_2017-6-6_14-3-6.png

3096726--233754--upload_2017-6-6_14-4-12.png

Thanks Vadim

Hello Vadim, how i can clear the undo/redo data?
solved
RuntimeUndo.Purge();

1 Like

Hi! Great work with this package, it’s awesome
I have a question, how do listbox and treeview work?? i can use them for create a hierarchy with only instantiated elements in the scene (like cubemen and blocks)?

Dear Vadim,
This line in LockAxes.cs Script don´t lock the Screen Rotation

lockObject.RotationScreen = lockAxes.Any(la => la.RotationScreen);

how can fix this?

Hi, sorry for delay,

you could use them as separate control for any hierarchical and non-hierarchical data,

Regards,
Vadim

Hi modifiy OnDrag method of RotationHandle.cs (lines 417-422) like this:

                Vector3 axis = m_targetInverseMatrix.MultiplyVector(SceneCamera.cameraToWorldMatrix.MultiplyVector(-Vector3.forward));

                if(!LockObject.RotationScreen)
                {
                    rotation = Quaternion.AngleAxis(delta.x, axis);
                }

Full code:

 protected override void OnDrag()
        {
            float deltaX = Input.GetAxis("Mouse X");
            float deltaY = Input.GetAxis("Mouse Y");

            deltaX = deltaX * XSpeed;
            deltaY = deltaY * YSpeed;

            m_deltaX += deltaX;
            m_deltaY += deltaY;


            Vector3 delta = StartingRotation * Quaternion.Inverse(Target.rotation) * SceneCamera.cameraToWorldMatrix.MultiplyVector(new Vector3(m_deltaY, -m_deltaX, 0));
            Quaternion rotation = Quaternion.identity;
            if (SelectedAxis == RuntimeHandleAxis.X)
            {
                Vector3 rotationAxis = Quaternion.Inverse(Target.rotation) * m_startingRotationAxis;

                if (EffectiveGridUnitSize != 0.0f)
                {
                    if (Mathf.Abs(delta.x) >= EffectiveGridUnitSize)
                    {
                        delta.x = Mathf.Sign(delta.x) * EffectiveGridUnitSize;
                        m_deltaX = 0.0f;
                        m_deltaY = 0.0f;
                    }
                    else
                    {
                        delta.x = 0.0f;
                    }
                }

                if(LockObject.RotationX)
                {
                    delta.x = 0.0f;
                }

                rotation = Quaternion.AngleAxis(delta.x, rotationAxis);
            }
            else if (SelectedAxis == RuntimeHandleAxis.Y)
            {
                Vector3 rotationAxis = Quaternion.Inverse(Target.rotation) * m_startingRotationAxis;

                if (EffectiveGridUnitSize != 0.0f)
                {
                    if (Mathf.Abs(delta.y) >= EffectiveGridUnitSize)
                    {
                        delta.y = Mathf.Sign(delta.y) * EffectiveGridUnitSize;
                        m_deltaX = 0.0f;
                        m_deltaY = 0.0f;
                    }
                    else
                    {
                        delta.y = 0.0f;
                    }
                }

                if (LockObject.RotationY)
                {
                    delta.y = 0.0f;
                }

                rotation = Quaternion.AngleAxis(delta.y, rotationAxis);

            }
            else if (SelectedAxis == RuntimeHandleAxis.Z)
            {
                Vector3 rotationAxis = Quaternion.Inverse(Target.rotation) * m_startingRotationAxis;

                if (EffectiveGridUnitSize != 0.0f)
                {
                    if (Mathf.Abs(delta.z) >= EffectiveGridUnitSize)
                    {
                        delta.z = Mathf.Sign(delta.z) * EffectiveGridUnitSize;
                        m_deltaX = 0.0f;
                        m_deltaY = 0.0f;
                    }
                    else
                    {
                        delta.z = 0.0f;
                    }
                }

                if (LockObject.RotationZ)
                {
                    delta.z = 0.0f;
                }

                rotation = Quaternion.AngleAxis(delta.z, rotationAxis);

            }
            else if (SelectedAxis == RuntimeHandleAxis.Free)
            {
                delta = StartingRotationInv * delta;

                if (LockObject.RotationX)
                {
                    delta.x = 0.0f;
                }

                if (LockObject.RotationY)
                {
                    delta.y = 0.0f;
                }

                if (LockObject.RotationZ)
                {
                    delta.z = 0.0f;
                }

                rotation = Quaternion.Euler(delta.x, delta.y, delta.z);
                m_deltaX = 0.0f;
                m_deltaY = 0.0f;
            }
            else
            {
                delta = m_targetInverse * new Vector3(m_deltaY, -m_deltaX, 0);
                if (EffectiveGridUnitSize != 0.0f)
                {
                    if (Mathf.Abs(delta.x) >= EffectiveGridUnitSize)
                    {
                        delta.x = Mathf.Sign(delta.x) * EffectiveGridUnitSize;
                        m_deltaX = 0.0f;
                        m_deltaY = 0.0f;
                    }
                    else
                    {
                        delta.x = 0.0f;
                    }
                }


                Vector3 axis = m_targetInverseMatrix.MultiplyVector(SceneCamera.cameraToWorldMatrix.MultiplyVector(-Vector3.forward));

                if(!LockObject.RotationScreen)
                {
                    rotation = Quaternion.AngleAxis(delta.x, axis);
                }
            }

            if (EffectiveGridUnitSize == 0.0f)
            {
                m_deltaX = 0.0f;
                m_deltaY = 0.0f;
            }


            for (int i = 0; i < ActiveTargets.Length; ++i)
            {
                ActiveTargets[i].rotation *= rotation;
            }
        }

Regards,
Vadim

3165004–240927–RT_Handles_1_3_f17_RotationHandle_Screen_Rotation_Is_Not_Locked.unitypackage (3.19 KB)

now it works, Thanks!

Hi, how can i activate the selection of an object, and his handles, from a button and not only from raycast?? What function of what script should i call?

Hi,
to select object programmatically please use RuntimeSelection class

using UnityEngine;
using Battlehub.RTCommon;

public class Test : MonoBehaviour {

    public GameObject Obj;
    // Use this for initialization
    void Start () {
        RuntimeSelection.activeObject = Obj;
    }
}

Thank you very much!

Great Asset. However, looking through the code i can’t figure out how to clamp position and scale of objects. Given i’m I’m not an amazing programmer, however is there a way for me to do it without interfering with Runtime Handles? I’ve a simple clamp script that updates every frame, but if the object is being dragged, it does not clamp until you let go of the handle. And even afterwards, it doesn’t clamp properly. Is this a built in function? I can’t seem to find it.