Search Unity

Creating Your Own Transform?

Discussion in 'Scripting' started by 11clock, Feb 3, 2017.

  1. 11clock

    11clock

    Joined:
    Jun 2, 2015
    Posts:
    24
    Hello, I am making a game that uses the coordinates as if it was a popup book. Basically, the y axis is at a slant of 45 degrees. With an angled camera, this allows for the appearance similar to that of a popup book.

    This is very cumbersome with the default Transform component, so I thought it would be a good idea to create my own Popup Transform component, which allows you to use the slanted y axis but also keep the original y axis if you need it.

    How does one go about creating such a component? I know there are tutorials for extending the inspector for Transform, but since I need to access the slanted y axis easily in code, a custom inspector would not be enough.

    I was thinking making a child of Transform and adding a property for translating the slanted y axis, but if there are other ways that are better, please let me know.
     
  2. KelsoMRK

    KelsoMRK

    Joined:
    Jul 18, 2010
    Posts:
    5,539
    Just make a MonoBehaviour that does whatever calculations based off the Transform. MonoBehaviours are components.
     
  3. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    I've done a similiar way in a 2D game where all objects 'orbit' around a circle shaped planet. Each objects needs to constantly point towards the center, so I wrote a small component called 'Orbit' which provides these restrictions. Then I hid Unity's default scene view handles and added my own which I used to only allow circular movement around the circle. Works well, since I can use handles in the editor and the components methods at runtime for the same behaviour.
     
  4. 11clock

    11clock

    Joined:
    Jun 2, 2015
    Posts:
    24
    Is Orbit a child of Transform? Or is it its own stand-alone MonoBehavior that bases itself on Transform?
     
  5. AndyGainey

    AndyGainey

    Joined:
    Dec 2, 2015
    Posts:
    216
    I did something like this for my team's entry in Ludum Dare 37 by altering the projection matrix of the camera. This allowed me to keep everything orthogonal, while still getting the same effect as if vertical stuff was slanted back by 45 degrees. Super simple because it requires zero work per game object; just a bit of tweaking of the camera itself. Though it does make visualizing things from within the Scene window difficult, because I don't know of a way to alter that window's camera beyond switching between perspective and orthographic mode.

    The following is the result of game jam hackery, so I can't promise it's exactly what you want or need, but it might point you in the right direction. Just slap this script on the camera, and have the camera facing straight forward along the z axis.

    Code (CSharp):
    1. using UnityEngine;
    2.  
    3. [ExecuteInEditMode]
    4. [RequireComponent(typeof(Camera))]
    5. public class CameraSkew : MonoBehaviour
    6. {
    7.     public float skew = 1;
    8.  
    9.     private Camera _camera;
    10.  
    11.     protected void Start()
    12.     {
    13.         _camera = GetComponent<Camera>();
    14.     }
    15.  
    16.     protected void Update()
    17.     {
    18.         var projectionMatrix = Matrix4x4.Ortho(
    19.             -_camera.orthographicSize,
    20.             +_camera.orthographicSize,
    21.             -_camera.orthographicSize - skew * transform.position.z * _camera.aspect,
    22.             +_camera.orthographicSize - skew * transform.position.z * _camera.aspect,
    23.             _camera.nearClipPlane, _camera.farClipPlane);
    24.         projectionMatrix[1, 2] = projectionMatrix[1, 1] * -skew * _camera.aspect;
    25.         projectionMatrix[1, 1] = projectionMatrix[1, 1] * _camera.aspect;
    26.         _camera.projectionMatrix = projectionMatrix;
    27.     }
    28. }
    Update: Apparently there are some possible ways to get the Scene window camera that you could explore, if the above does work for you but also makes the editor harder to work with.
     
  6. Xarbrough

    Xarbrough

    Joined:
    Dec 11, 2014
    Posts:
    1,188
    No, you cannot inherit most of the Unity components. The idea is, that you modify what is given to you via other components. So Orbit would only modify the transform.

    Code (CSharp):
    1. public void LookAtCenter()
    2. {
    3.     Vector3 directionToCenter = Vector3.zero - transform.position;
    4.     float zRotation = Mathf.Atan2(directionToCenter.y, directionToCenter.x) * Mathf.Rad2Deg;
    5.  
    6.     // Offset 90 degrees to make bottom face the center.
    7.     transform.rotation =  Quaternion.Euler(0, 0, zRotation + 90f);
    8. }
    9.  
    10. public void UpdatePosition()
    11. {
    12.     float x = Mathf.Cos(_angle * Mathf.Deg2Rad) * _height;
    13.     float y = Mathf.Sin(_angle * Mathf.Deg2Rad) * _height;
    14.     transform.position = new Vector3(x, y, transform.position.z);
    15. }
    I also would think about if you really need to change your world setup in this way. Changing only the camera projection might make more sense. In my case it was a simple requirement that all rotations are fixes in a way that the objects points towards the center, but in your case, you might only need the visual effect of a distorted perspective.
     
  7. RayRay26

    RayRay26

    Joined:
    Apr 28, 2016
    Posts:
    2
    11clock and I found a better solution. The idea was not to make a different transform, but change where the object was rendered.
    We used the events OnWillRenderObject and OnRenderObject
    Code (CSharp):
    1.     public static float eulerSlant = 45f;
    2.     [HideInInspector]
    3.     public Vector3 nonrigged;
    4.     [HideInInspector]
    5.     public bool transformAltered = false;
    6.  
    7.     void OnWillRenderObject() {
    8.         if(Controller.main.renderModeEnabled && !transformAltered) {
    9.             transformAltered = true;
    10.             nonrigged = transform.position;
    11.             transform.rotation = Quaternion.Euler(new Vector3(eulerSlant, 0, 0));
    12.             transform.position = RigPosition(transform.position);
    13.         }
    14.     }
    15.  
    16.     void OnRenderObject() {
    17.         if(transformAltered) {
    18.             transformAltered = false;
    19.             transform.position = nonrigged;
    20.             transform.rotation = Quaternion.identity;
    21.         }
    22.     }
    This code does wonders in Unity. The Scene viewer may display everything just like the Game view, but the epic part is the gizmos stay in the same place. Colliders, for example, can display the true position of the character.

    Will take a bit of getting used to in the Scene view though, but at least we don't have to process the actual position or make collisions with rhombuses. *shudder*

    A few notes: the nonrigged variable is public just in case we put more rendering code. And what RigPosition does is modify the Y and Z coordinates based on the original Y value.
     
    Last edited: Feb 28, 2017
  8. anamta93

    anamta93

    Joined:
    Mar 21, 2014
    Posts:
    12
    This could help

    GameObject emptyGO = new GameObject();
    Transform newTransform = empt.transform;