Search Unity

Caculating directions os an object relative to camera

Discussion in 'Scripting' started by Dahlvash, May 28, 2015.

  1. Dahlvash

    Dahlvash

    Joined:
    Feb 9, 2014
    Posts:
    54
    Hi.
    I am having trouble working out how to determine the relative positions of a resting object.
    I know there are other threads that do this in general but my situation is a little more specific:

    I have a 'rolling' script that rolls objects along an edge be it cube, pyramid etc.
    The objects have colliders half way along each edge to determine what edges are in contact with the ground and therefore are available for rolling over.
    Example:

    The idea is that I can place these triggers on the edges of an object of any shape and be able to determine through WASD or pathfinding what edge to roll over.
    I am unable to find a way to 'map' each collider currently in contact with the ground to WASD relative to a fixed camera. So the 'furthest or top' collider maps to W for example. This is complicated when trying to map only 3 colliders of a pyramid and is the crux of my problem.

    Any help would be greatly appreciated!
     
  2. StarManta

    StarManta

    Joined:
    Oct 23, 2006
    Posts:
    8,775
    I think what you are looking to do is:
    1. Create a vector from the player's input (e.g. W becomes (0,0,1) ) which represents desired movement relative to the camera
    2. Convert this vector to world space, probably using camera.transform.TransformDirection
    3. Find which of the mid-edge colliders on a particular object are closest to this direction, relative to the centerpoint of the object being rolled. I think Vector3.Angle is what you want here.

    Here's a rough version of what the algorithm might look like. It assumes that you have a class you put on each of your edge colliders that knows when it is touching the ground. (I don't usually write code in responses here, but this algorithm was fun to solve)
    (obviously untested)
    Code (csharp):
    1.  
    2. //returns either the collider best matched for the input pressed, or null if there is no match or no input was pressed
    3. YourColliderClass GetBestColliderForInput(YourRootObject obj) {
    4. //step 1
    5. Vector3 camLocalMovement = new Vector3(Input.GetAxis("Horizontal"), 0f, Input.GetAxis("Vertical") );
    6. if (camLocalMovement == Vector3.zero) return null; //not pressing anything, don't move anything
    7.  
    8. //step 2
    9. Vector3 worldMovement = Camera.main.transform.TransformDirection(camLocalMovement);
    10.  
    11. //step 3
    12. float smallestAngleDiff = 180f;
    13. YourColliderClass bestMatchCollider = null;
    14. foreach (YourColliderClass col in obj.allEdgeColliders) {
    15. if (col.IsTouchingGround() ) {
    16. Vector3 thisOffset = col.transform.position - objectRoot.transform.position;
    17. thisOffset.y = 0f; //unnecessary as long as you're on flat ground, but this should prevent edges at different heights from getting preferential treatment
    18. float thisAngleDiff = Vector3.Angle(thisOffset, worldMovement);
    19.  
    20. if (thisAngleDiff < smallestAngleDiff) {
    21. smallestAngleDiff = thisAngleDiff;
    22. bestMatchCollider = col;
    23. }
    24. }
    25. }
    26. return bestMatchCollider;
    27. }
    28.  
     
  3. Dahlvash

    Dahlvash

    Joined:
    Feb 9, 2014
    Posts:
    54
    Exactly that, put much more eloquently than I :3. Thank you for the help, it works perfectly!
     
    StarManta likes this.