Website may be up and down over next few months. I'm currently doing a complete overhaul of everything. Going back to simple individual .htm pages, new overall site theme, sanitizing and cleaning up html of all pages and blog posts, attempting to implement a new tooling and publishing system etc etc.

The code snippet below allows you to attach a translation gizmo to a object to allow the user to move that object while the game is running. Works just like the unity translation gizmo.

TranslationGizmo

    using System;        
    using UnityEngine;

    /// <summary>
    /// The translation gizmo.
    /// </summary>
    public class TranslationGizmo : MonoBehaviour
    {
        #region Fields

        /// <summary>
        /// The camera reference used to determin distance to translation gizmo.
        /// </summary>
        public UnityEngine.Camera cameraReference;

        /// <summary>
        /// Used to determine how thick the envelope is around a axis line when attempting to click and drag it with the mouse.
        /// </summary>
        public float axisEnvelope = 0.04f;

        /// <summary>
        /// Determines the length of the cone.
        /// </summary>
        public float coneLength = 0.85f;

        /// <summary>
        /// Specifies how many segments the cone is made up of.
        /// </summary>
        public int coneSegments = 30;

        /// <summary>
        /// Determines the diameter of the cone.
        /// </summary>
        public float coneSize = 0.075f;

        /// <summary>
        /// Determines the length of the axis lines.
        /// </summary>
        public float lineLength = 0.13f;

        /// <summary>
        /// The line material used to render the lines.
        /// </summary>
        public Material lineMaterial;

        /// <summary>
        /// Determines the size of the square panning gizmos.
        /// </summary>
        public float panScale = 0.3f;

        /// <summary>
        /// Determines the transparency level of the axis plane quads.
        /// </summary>
        public float planeTransparency = 0.3f;

        /// <summary>
        /// The color that will be used for the X axis.
        /// </summary>
        public Color xAxisColor = Color.red;

        /// <summary>
        /// The color that will be used for the Y axis.
        /// </summary>
        public Color yAxisColor = Color.green;

        /// <summary>
        /// The color that will be used for the Z axis.
        /// </summary>
        public Color zAxisColor = Color.blue;

        /// <summary>
        /// Holds the button state used to determine if dragging has started.
        /// </summary>
        protected bool inputButtonState;

        /// <summary>
        /// Holds the relative mouse X position.
        /// </summary>
        protected float mouseAxisX;

        /// <summary>
        /// Holds the relative mouse Y position.
        /// </summary>
        protected float mouseAxisY;

        /// <summary>
        /// Holds the pre-calculated distance value from the camera to the game object.
        /// </summary>
        private float cameraDistance;

        /// <summary>
        /// The hit mouse down.
        /// </summary>
        private Vector3 hitMouseDown;

        /// <summary>
        /// The hit mouse move.
        /// </summary>
        private Vector3 hitMouseMove;

        /// <summary>
        /// Holds wheather or not the input axis has changed.
        /// </summary>
        private bool inputAxisChanged;

        /// <summary>
        /// Holds wheather or not the mouse if being dragged.
        /// </summary>
        private bool isDragging;

        /// <summary>
        /// Holds XY plane information.
        /// </summary>
        private Plane planeXY;

        /// <summary>
        /// Holds XZ plane information.
        /// </summary>
        private Plane planeXZ;

        /// <summary>
        /// Holds YZ plane information.
        /// </summary>
        private Plane planeYZ;

        /// <summary>
        /// Holds the previous input button state.
        /// </summary>
        private bool previousInputButtonState;

        /// <summary>
        /// Holds the rotation matrix used to determine at what rotation the gizmo will be drawn at.
        /// </summary>
        private Matrix4x4 rotationMatrix;

        /// <summary>
        /// Holds the value for the <see cref="WorldTranslation"/> property.
        /// </summary>
        [SerializeField]
        private bool worldTranslation;

        /// <summary>
        /// Gets or sets a value indicating whether world translation is enabled.
        /// </summary>
        /// <value>
        ///   <c>true</c> if world translation is active; otherwise, <c>false</c> for local translation.
        /// </value>
        public bool WorldTranslation
        {
            get
            {
                return this.worldTranslation;
            }

            set
            {
                this.worldTranslation = value;
            }
        }

        /// <summary>
        /// Holds the type of axis movement is currently being made.
        /// </summary>
        private TypeOfMove typeMovementBeingMade;

        #endregion

        #region Public Events

        /// <summary>
        /// Occurs when position changed.
        /// </summary>
        public event EventHandler<Vector3EventArgs> PositionChanged;

        #endregion

        #region Enums

        /// <summary>
        /// Enum defining the types of axis movement.
        /// </summary>
        private enum TypeOfMove
        {
            /// <summary>
            /// No axis movement.
            /// </summary>
            None,

            /// <summary>
            /// Movement along the X axis.
            /// </summary>
            XAxis,

            /// <summary>
            /// Movement along the 
            /// </summary>
            X2Axis,

            /// <summary>
            /// Movement along the Y axis.
            /// </summary>
            YAxis,

            /// <summary>
            /// The y 2 axis.
            /// </summary>
            Y2Axis,

            /// <summary>
            /// Movement along the Z axis.
            /// </summary>
            ZAxis,

            /// <summary>
            /// The z 2 axis.
            /// </summary>
            Z2Axis,

            /// <summary>
            /// Movement along the XZ axis.
            /// </summary>
            XZAxis,

            /// <summary>
            /// Movement along the YZ axis.
            /// </summary>
            YZAxis,

            /// <summary>
            /// Movement along the XY axis.
            /// </summary>
            XYAxis,
        };

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// Awake is called when the script instance is being loaded.
        /// </summary>
        public void Awake()
        {
            // if no material assigned setup a default material
            if (this.lineMaterial == null)
            {
#if !UNITY_5
                this.lineMaterial =
                     new Material(
                         "Shader \"Lines/Colored Blended\" {" + "SubShader { Pass { " + "    Blend SrcAlpha OneMinusSrcAlpha "
                         + "    ZWrite Off Cull Off Fog { Mode Off } ZTest Always" + "    BindChannels {"
                         + "      Bind \"vertex\", vertex Bind \"color\", color }" + "} } }");
#else
                // Unity has a built-in shader that is useful for drawing
                // simple colored things.
                var shader = Shader.Find("Hidden/Internal-Colored");
                this.lineMaterial = new Material(shader);
                this.lineMaterial.hideFlags = HideFlags.HideAndDontSave;
                // Turn on alpha blending
                this.lineMaterial.SetInt("_SrcBlend", (int)UnityEngine.Rendering.BlendMode.SrcAlpha);
                this.lineMaterial.SetInt("_DstBlend", (int)UnityEngine.Rendering.BlendMode.OneMinusSrcAlpha);
                // Turn backface culling off
                this.lineMaterial.SetInt("_Cull", (int)UnityEngine.Rendering.CullMode.Off);
                // Turn off depth writes
                this.lineMaterial.SetInt("_ZWrite", 0);
#endif
            }
        }

        /// <summary>
        /// Update is called every frame, if the MonoBehaviour is enabled.
        /// </summary>
        public void Update()
        {
            if (cameraReference == null)
            {
                return;
            }

            // calculate distance once between the camera and the game objects position
            var transformReference = this.transform;
            var position = transformReference.position;
            this.cameraDistance = Vector3.Distance(this.cameraReference.transform.position, position) * this.lineLength;

            this.previousInputButtonState = this.inputButtonState;
            this.GetInputButtonState();

            // if the input button is released stop moving
            if (!this.inputButtonState)
            {
                this.isDragging = false;
                this.typeMovementBeingMade = TypeOfMove.None;
                return;
            }

            // only handle dragging is already dragging or if input button state was pressed
            if (this.isDragging || (!this.previousInputButtonState && this.inputButtonState))
            {
                // get mouse/input values
                this.GetInputValues();
                this.inputAxisChanged = Math.Abs(this.mouseAxisX) > float.Epsilon || Math.Abs(this.mouseAxisY) > float.Epsilon;

                // update planes based on world or local translation
                if (this.worldTranslation)
                {
                    // update planes
                    this.planeXZ.SetNormalAndPosition(Vector3.up, position);
                    this.planeXY.SetNormalAndPosition(Vector3.forward, position);
                    this.planeYZ.SetNormalAndPosition(Vector3.right, position);
                }
                else
                {
                    // update planes
                    this.planeXZ.SetNormalAndPosition(transformReference.up, position);
                    this.planeXY.SetNormalAndPosition(transformReference.forward, position);
                    this.planeYZ.SetNormalAndPosition(transformReference.right, position);
                }

                // cast a ray once
                var ray = this.cameraReference.ScreenPointToRay(Input.mousePosition);

                // handle axis translations
                this.HandleXZ(ray);
                this.HandleXY(ray);
                this.HandleYZ(ray);
            }
        }

        #endregion

        #region Methods

        /// <summary>
        /// Get the state of the input button used to determine if dragging has occurred.
        /// </summary>
        protected virtual void GetInputButtonState()
        {
            this.inputButtonState = Input.GetMouseButton(0);
        }

        /// <summary>
        /// Gets the X/Y input values
        /// </summary>
        protected virtual void GetInputValues()
        {
            this.mouseAxisX = Input.GetAxis("Mouse X");
            this.mouseAxisY = Input.GetAxis("Mouse Y");
        }

        /// <summary>
        /// Raises the <see cref="PositionChanged"/> event.
        /// </summary>
        /// <param name="previousPosition">
        /// The previous Position.
        /// </param>
        /// <param name="position">
        /// The position.
        /// </param>
        protected virtual void OnPositionChanged(Vector3 previousPosition, Vector3 position)
        {
            var handler = this.PositionChanged;
            if (handler != null)
            {
                handler(this, new Vector3EventArgs(previousPosition, position));
            }
        }

        /// <summary>
        /// Uses OpenGL to draw a line for the axis.
        /// </summary>
        /// <param name="color">
        /// The color to use when drawing the cone.
        /// </param>
        /// <param name="axis">
        /// Defines axis that the cone will be drawn against.
        /// </param>
        /// <param name="axisU">
        /// Represents the "X" axis to draw the base of the cone against.
        /// </param>
        /// <param name="axisV">
        /// Represents the "Y" axis to draw the base of the cone against.
        /// </param>
        private void DrawAxis(Color color, Vector3 axis, Vector3 axisU, Vector3 axisV)
        {
            // scale the axis by the camera distance
            axis = axis * this.cameraDistance;

            // start drawing lines
            GL.Begin(GL.LINES);
            GL.Color(color);
            GL.Vertex3(0, 0, 0);
            GL.Vertex3(axis.x, axis.y, axis.z);
            GL.End();

            // draw the cone for the axis
            this.DrawCone(axis, axisU, axisV, this.cameraDistance * this.coneSize, this.coneLength, color);
        }

        /// <summary>
        /// Uses OpenGL to draw a cone for the axis.
        /// </summary>
        /// <param name="axis">
        /// Defines axis that the cone will be drawn against.
        /// </param>
        /// <param name="axisU">
        /// Represents the "X" axis to draw the base of the cone against.
        /// </param>
        /// <param name="axisV">
        /// Represents the "Y" axis to draw the base of the cone against.
        /// </param>
        /// <param name="radius">
        /// Specifies the radius for the base of the cone.
        /// </param>
        /// <param name="length">
        /// Specifies how tall the cone is.
        /// </param>
        /// <param name="color">
        /// The color to use when drawing the cone.
        /// </param>
        private void DrawCone(Vector3 axis, Vector3 axisU, Vector3 axisV, float radius, float length, Color color)
        {
            GL.Begin(GL.TRIANGLES);
            GL.Color(color);

            // pre-calculate the angle step for each cone segment
            var angle = (2 * Mathf.PI) / this.coneSegments;

            for (var i = 0; i <= this.coneSegments; i++)
            {
                var pt = axisU * Mathf.Cos(angle * i) * radius;
                pt += axisV * Mathf.Sin(angle * i) * radius;
                pt += axis * length;
                GL.Vertex(pt);

                pt = axisU * Mathf.Cos(angle * (i + 1)) * radius;
                pt += axisV * Mathf.Sin(angle * (i + 1)) * radius;
                pt += axis * length;
                GL.Vertex(pt);

                GL.Vertex(axis);
            }

            GL.End();
        }

        /// <summary>
        /// Uses OpenGL to draw a square plane for the axis.
        /// </summary>
        /// <param name="size">
        /// Defines size of the plane that will be drawn for the axis.
        /// </param>
        /// <param name="axisU">
        /// Represents the "X" axis to draw the plane against.
        /// </param>
        /// <param name="axisV">
        /// Represents the "Y" axis to draw the plane against.
        /// </param>
        /// <param name="color">
        /// The color to use when drawing the plane.
        /// </param>
        private void DrawQuad(float size, Vector3 axisU, Vector3 axisV, Color color)
        {
            color.a = this.planeTransparency;
            var pts = new Vector3[4];
            pts[0] = Vector3.zero;
            pts[1] = axisU * size;
            pts[2] = (axisU + axisV) * size;
            pts[3] = axisV * size;

            GL.Begin(GL.QUADS);
            GL.Color(color);
            GL.Vertex(pts[0]);
            GL.Vertex(pts[1]);
            GL.Vertex(pts[2]);
            GL.Vertex(pts[3]);
            GL.End();
            color.a = 1f;

            GL.Begin(GL.LINES);
            GL.Color(color);
            GL.Vertex(pts[0]);
            GL.Vertex(pts[1]);
            GL.Vertex(pts[1]);
            GL.Vertex(pts[2]);
            GL.Vertex(pts[2]);
            GL.Vertex(pts[3]);
            GL.Vertex(pts[3]);
            GL.Vertex(pts[0]);
            GL.End();
        }

        /// <summary>
        /// Start is called just before any of the Update methods is called the first time.
        /// </summary>
        public void Start()
        {
            if (this.cameraReference == null)
            {
                this.cameraReference = UnityEngine.Camera.main;
            }
        }

        /// <summary>
        /// Handles dragging along the XU plane.
        /// </summary>
        /// <param name="ray">
        /// The reay used to determine if the XY plane was being interacted with.
        /// </param>
        private void HandleXY(Ray ray)
        {
            float enter;
            this.planeXY.Raycast(ray, out enter);
            var hit = ray.GetPoint(enter);
            hit = this.rotationMatrix.inverse.MultiplyPoint(hit);

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.x > 0f && hit.x <= this.panScale * this.cameraDistance && hit.y > 0
                && hit.y <= this.panScale * this.cameraDistance)
            {
                this.typeMovementBeingMade = TypeOfMove.XYAxis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.XYAxis)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.z = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.x > 0f && hit.x <= this.cameraDistance
                && Mathf.Abs(hit.y) < this.axisEnvelope * this.cameraDistance)
            {
                // case x
                this.typeMovementBeingMade = TypeOfMove.X2Axis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.X2Axis && this.inputAxisChanged)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.y = 0;
                this.hitMouseMove.z = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.y > 0f && hit.y <= this.cameraDistance
                && Mathf.Abs(hit.x) < this.axisEnvelope * this.cameraDistance)
            {
                // case y
                this.typeMovementBeingMade = TypeOfMove.YAxis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.YAxis && this.inputAxisChanged)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.z = 0;
                this.hitMouseMove.x = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }
        }

        /// <summary>
        /// Handles dragging along the XZ plane.
        /// </summary>
        /// <param name="ray">
        /// The reay used to determine if the XZ plane was being interacted with.
        /// </param>
        private void HandleXZ(Ray ray)
        {
            float enter;
            this.planeXZ.Raycast(ray, out enter);
            var hit = ray.GetPoint(enter);
            hit = this.rotationMatrix.inverse.MultiplyPoint(hit);

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.x > 0f && hit.x <= this.panScale * this.cameraDistance && hit.z > 0
                && hit.z <= this.panScale * this.cameraDistance)
            {
                this.typeMovementBeingMade = TypeOfMove.XZAxis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.XZAxis && this.inputAxisChanged)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.y = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.x > 0f && hit.x <= this.cameraDistance
                && Mathf.Abs(hit.z) < this.axisEnvelope * this.cameraDistance)
            {
                // case x
                this.typeMovementBeingMade = TypeOfMove.XAxis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.XAxis && this.inputAxisChanged)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.y = 0;
                this.hitMouseMove.z = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.z > 0f && hit.z <= this.cameraDistance
                && Mathf.Abs(hit.x) < this.axisEnvelope * this.cameraDistance)
            {
                // case  z
                this.typeMovementBeingMade = TypeOfMove.ZAxis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.ZAxis && this.inputAxisChanged)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.y = 0;
                this.hitMouseMove.x = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }
        }

        /// <summary>
        /// Handles dragging along the YZ plane.
        /// </summary>
        /// <param name="ray">
        /// The reay used to determine if the YZ plane was being interacted with.
        /// </param>
        private void HandleYZ(Ray ray)
        {
            float enter;
            this.planeYZ.Raycast(ray, out enter);
            var hit = ray.GetPoint(enter);
            hit = this.rotationMatrix.inverse.MultiplyPoint(hit);

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.z > 0 && hit.z <= this.panScale * this.cameraDistance && hit.y > 0
                && hit.y <= this.panScale * this.cameraDistance)
            {
                this.typeMovementBeingMade = TypeOfMove.YZAxis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.YZAxis)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.x = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.z > 0f && hit.z <= this.cameraDistance
                && Mathf.Abs(hit.y) < this.axisEnvelope * this.cameraDistance)
            {
                // case  z
                this.typeMovementBeingMade = TypeOfMove.Z2Axis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.Z2Axis && this.inputAxisChanged)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.y = 0;
                this.hitMouseMove.x = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }

            if (this.typeMovementBeingMade == TypeOfMove.None && hit.y > 0f && hit.y <= this.cameraDistance
                && Mathf.Abs(hit.z) < this.axisEnvelope * this.cameraDistance)
            {
                // case y
                this.typeMovementBeingMade = TypeOfMove.Y2Axis;
                this.hitMouseDown = hit;
                this.isDragging = true;
            }

            if (this.typeMovementBeingMade == TypeOfMove.Y2Axis && this.inputAxisChanged)
            {
                this.hitMouseMove = hit - this.hitMouseDown;
                this.hitMouseMove.z = 0;
                this.hitMouseMove.x = 0;
                this.UpdatePosition(this.worldTranslation ? this.hitMouseMove : this.transform.localRotation * this.hitMouseMove);
            }
        }

        /// <summary>
        /// Called by unity when after camera has rendered the scene.
        /// </summary>
        private void OnRenderObject()
        {         
            // set the material pass is a material has been specified
            var material = this.lineMaterial;
            if (material != null)
            {
                material.SetPass(0);
            }

            // push a matrix on to the stack
            GL.PushMatrix();
            this.rotationMatrix = this.transform.localToWorldMatrix;

            // setup rotation matrix
            if (this.worldTranslation)
            {
                this.rotationMatrix = Matrix4x4.TRS(this.transform.position, Quaternion.identity, Vector3.one);
            }
            else
            {
                this.rotationMatrix = Matrix4x4.TRS(this.transform.position, this.transform.localRotation, Vector3.one);
            }

            GL.MultMatrix(this.rotationMatrix);

            // draw each axis
            this.DrawAxis(this.xAxisColor, Vector3.right, Vector3.up, Vector3.forward);
            this.DrawAxis(this.yAxisColor, Vector3.up, Vector3.right, Vector3.forward);
            this.DrawAxis(this.zAxisColor, Vector3.forward, Vector3.right, Vector3.up);

            // draw each plane quad
            this.DrawQuad(this.panScale * this.cameraDistance, Vector3.forward, Vector3.up, this.xAxisColor);
            this.DrawQuad(this.panScale * this.cameraDistance, Vector3.right, Vector3.forward, this.yAxisColor);
            this.DrawQuad(this.panScale * this.cameraDistance, Vector3.right, Vector3.up, this.zAxisColor);

            GL.PopMatrix();
        }

        /// <summary>
        /// Updates the transform position and raises the <see cref="PositionChanged"/> event.
        /// </summary>
        /// <param name="value">
        /// The value to add on to the existing transform position.
        /// </param>
        private void UpdatePosition(Vector3 value)
        {
            var position = this.transform.position;
            var previousPosition = position;
            position += value;
            this.transform.position = position;
            this.OnPositionChanged(previousPosition, position);
        }

        #endregion
    }

    /// 
    /// Provides event arguments for the  type.
    /// 
    public class Vector3EventArgs : EventArgs
    {
        #region Constructors and Destructors

        /// 
        /// Initializes a new instance of the  class.
        /// 
        /// 
        /// The previous value.
        /// 
        /// 
        /// The current value.
        /// 
        public Vector3EventArgs(Vector3 previousValue, Vector3 value)
        {
            this.Value = value;
            this.PreviousValue = previousValue;
        }

        /// 
        /// Initializes a new instance of the  class.
        /// 
        public Vector3EventArgs()
        {
        }

        #endregion

        #region Public Properties

        /// 
        /// Gets or sets a previous  value.
        /// 
        public Vector3 PreviousValue { get; set; }

        /// 
        /// Gets or sets a  value.
        /// 
        public Vector3 Value { get; set; }

        #endregion
    }

The code below provides a handy helper method for drawing GUI textures via GUI.DrawTextureWithTexCoords.

/// 
/// Draws a image image.
/// 
/// The destination image.
/// The x position in the destination image.
/// The y position in the destination image.
/// The destination width of the drawn image.
/// The destination height of the drawn image.
/// If set to true the image will be drawn fliped horizontally.
/// If set to true the image will be drawen flipped vertically.
/// If set to true the image will be tiled across the destination area.
/// image    
/// If width, height, sourceWidth or sourceHeight are less then 1.
public static void Draw(Texture2D image, float x, float y, float width, float height, bool flipHorizontally, bool flipVertically, bool tile)
{
    Draw(image, x, y, width, height, 0, 0, image.width, image.height, false, false, false);
}

/// 
/// Draws a image image.
/// 
/// The destination image.
/// The x position in the destination image.
/// The y position in the destination image.
/// The destination width of the drawn image.
/// The destination height of the drawn image.
/// The x position in the source image.
/// The y position in the source image.
/// The source width.
/// The source height.
/// image    
/// If width, height, sourceWidth or sourceHeight are less then 1.
public static void Draw(Texture2D image, float x, float y, float width, float height, float sourceX, float sourceY, float sourceWidth, float sourceHeight)
{
    Draw(image, x, y, width, height, sourceX, sourceY, sourceWidth, sourceHeight, false, false, false);
}

/// 
/// Draws a image image.
/// 
/// The destination image.
/// The x position in the destination image.
/// The y position in the destination image.
/// The destination width of the drawn image.
/// The destination height of the drawn image.
/// The x position in the source image.
/// The y position in the source image.
/// The source width.
/// The source height.
/// If set to true the image will be drawn fliped horizontally.
/// If set to true the image will be drawen flipped vertically.
/// If set to true the image will be tiled across the destination area.
/// image    
/// If width, height, sourceWidth or sourceHeight are less then 1.
/// This method has issues with Clamped textures.
public static void Draw(Texture2D image, float x, float y, float width, float height, float sourceX, float sourceY, float sourceWidth, float sourceHeight,
    bool flipHorizontally, bool flipVertically, bool tile)
{
    // perform input validation
    if (image == null)
    {
        throw new ArgumentNullException("image");
    }

    if (sourceWidth < float.Epsilon)
    {
        throw new ArgumentOutOfRangeException("sourceWidth");
    }

    if (sourceHeight < float.Epsilon)
    {
        throw new ArgumentOutOfRangeException("sourceHeight");
    }

    if (width < float.Epsilon)
    {
        return; 
    }

    if (height < float.Epsilon)
    {
        return; 
    }

    var imgWidth = (float)image.width;
    var imgHeight = (float)image.height;
    var srcWidth = sourceWidth / imgWidth;
    var srcHeight = sourceHeight / imgHeight;
    var position = new Rect(x, y + height, width, -height);
    if (tile)
    {
        srcWidth = width / imgWidth;
        srcHeight = height / imgHeight;
    }

    srcWidth = flipHorizontally ? -srcWidth : srcWidth;
    srcHeight = !flipVertically ? -srcHeight : srcHeight;

    var texCoords = new Rect(sourceX / imgWidth, imgHeight - (sourceY / imgHeight), srcWidth, srcHeight);
    
    GUI.DrawTextureWithTexCoords(position, image, texCoords, true);
}

/// <summary>
/// Determines whether the renderer is visible from the specified camera.
/// </summary>
/// <param name="renderer">The renderer to check for visibility.</param>
/// <param name="camera">The camera to check against.</param>
/// <returns>true if the renderer is visible to the camera; otherwise false.</returns>
public static bool IsVisibleFrom(this Renderer renderer, Camera camera)
{
    var planes = GeometryUtility.CalculateFrustumPlanes(camera);
    return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}

The code below allows you to set and automatically restore the GUI.enabled state when used with a using block similar to GUILayout.HorizontialScope.

/// <summary>
/// Provides  a class for setting and restoring GUI.enabled.
/// </summary>
public class GuiEnabled : IDisposable
{
    /// <summary>
    /// Gets or sets a value indicating the state that is to be restored.
    /// </summary>  
    public bool StateToBeRestored { get; set; }

    /// <summary>
    /// Initializes a new instance of the <see cref="GuiEnabled"/> class.
    /// </summary>
    /// <param name="stateToBeRestored">Value indicating the state that is to be restored.</param>
    public GuiEnabled(bool stateToBeRestored)                                            
    {
        this.StateToBeRestored = stateToBeRestored;
    }

    /// <summary>
    /// Initializes a new instance of the <see cref="GuiEnabled"/> class.
    /// </summary>
    /// <param name="stateToBeRestored">If set to <c>true</c> the GUI.enabled state will be restored to this value.</param>
    /// <param name="setState">Immediatley sets the value of GUI.enabled to this state.</param>
    public GuiEnabled(bool stateToBeRestored, bool setState) : this(stateToBeRestored)
    {
        GUI.enabled = setState;
    }

    /// <summary>
    /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
    /// </summary>
    public void Dispose()
    {
        GUI.enabled = this.StateToBeRestored;
    }
}

Here is an simple use case

GUILayout.Button("Enabled button");
using (var enabled = new GuiEnabled(GUI.enabled, false))
{
    GUILayout.Button("Disabled button");
    //if (someCondition)
    //{   
        // setting to false means after we exit the using block GUI.enabled will be set to false. 
    //    enabled.StateToBeRestored = false; 
    //}
}
GUILayout.Button("Enabled button");

If you need your editor scripts to have the same functionality as “Assets->Show In Explorer” check out the cross platform method EditorUtility.RevealInFinder. This method is currently undocumented in Unity 5.2.1.


When writing editor scripts involving EditorWindow’s it is often important to initialize and cleanup your code when the window is shown and hidden. Specifically it is important to differentiate between the OnDisable and OnDestroy methods if you need to perform some kind of cleanup before the window is closed or disposed of. OnDestroy is called when the user closes the window, where as OnDisable is called after unity recompiles scripts. Think of the OnDestroy method as a close event for the window but the window still resides in memory, where the OnDisable method signals that the window is about to be unloaded from memory such as during a script recompile.

This differentiation is important when you need to save data to disk before the window is destroyed during a recompile. OnDestroy will not get called during recompile only OnDisable does. The OnEnable method is typically intended as a initialization method where you can load data related to the window.

I only wish the Unity team had made these methods more descriptive ala .NET window forms naming scheme. OnDestroy & OnDisable are not the most descriptive for what they do as well as being somewhat similar in spelling. But I digress.


If you are writing custom scripts there may be situations where you don’t want the same component added more then once to a game object. For such situations Unity provides the DisallowMultipleComponent attribute that you can specify in your scripts code.


It’s not something people think about these days. Back in the 90’s when MS-DOS was king, alerting the user to a problem involved both a visual alert as well as a auditory alert in the form of a “beep”. It’s actually something I miss from those days. Luckily the unity editor has an API to alert the user and wouldn't you know it, it’s called “Beep”!


If you are developing unity editor extensions often it is necessary to know weather or not unity is compiling the projects scripts. To determine if unity is currently compiling you can simply check the EditorApplication.isCompiling flag in your code before deciding what to do. See older related tip and code example here.


ProjectAndHierarchyEnhancements

Unity provides hooks into the Project and Hierarchy windows OnGui event. This allows you to add additional flair to these windows. To learn how to enhance these windows see the fallowing documentation pages

  1. HierarchyWindowChanged
  2. HierarchyWindowItemOnGUI
  3. ProjectWindowItemOnGUI
  4. ProjectWindowChanged

If you want an example project to work off of and learn from there is an open source project called “UnityEditorEnhancements” that you can download as a zip file or you can fork the Mercurial repository.


Created by: X

Just another personal website in this crazy online world

Name of author Dean Lunz (aka Created by: X)
Computer programming nerd, and tech geek.
About Me -- Resume