Search Unity

Need Simple PointAt Code Example

Discussion in 'Scripting' started by marty, Jun 10, 2005.

  1. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Let say I just cast a ray down from object A onto object B. I then position object A at the point where the ray hit object B, using this code:

    transform.position = hit.point

    Now, I want to have object A point it's Y-axis at a point directly above hit.point, parallel to hit.normal. The result being that object A is "standing" upright at the location where the ray hit object B - sort of like a "pointAt" method might do.

    I'm guessing this is one of those Quaternion things. :wink:

    Anyone know how to do this?
     
  2. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    I'll try to write a few HOWTOs on how to set up all this (then we can ship the howto's in searchable format with Unity)

    I'll post something soooon....
     
  3. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
  4. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    It's actually quite cool to drag an object around in the editor in playmode with this script attached. Should do sth like that in the editor at some point :-]
     
  5. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    You've been tinkering with my code - I'm flattered! :wink:

    Every time I come to a new 3D API, I write a surface tracking routine because it's a great way to learn how transforms work there. Unity has been a lot tougher than most - I'm glad to hear you plan to smooth out the transform methods.

    BTW, the WIKI looks great! When does it go online and where can we sign up to use it?
     
  6. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    Do you have a link for the BEST 3D transform API? Would love to see what they do different.... This is something that you use all the time while doing 3D games, so any input is very much appreciated.

    So far, the WIKI is used for internal manual writing (all builtin docs are generated from this)...

    Not sure how public to make it - so far it is the authorative version, and I don't want to risk shipping manuals that are incorrect. on the other hand, doc writing is sth where any community help would be great. What do you think?

    (Occasionally, I will probably pop in and ask users for feedback).

    Also, if you have good ideas for howtos, please let me know...
     
  7. marty

    marty

    Joined:
    Apr 27, 2005
    Posts:
    1,170
    Hard to say which API is best, especially when you're as lame at 3D math as me.

    I do know that the Java3D transform commands seemed straightforward. Macromedia Director Shockwave3D uses virtually the same approach, with a few nice refinements. One of my favorite features of the latter is the "translate" and "rotate" commands which are executed on (their version of a Unity Vector3), with the option to specify in the parameters whether the transform change is world-relative, self-relative, or relative to another point/node/object in 3D worldspace. That was handy.

    As for the WIKI, it might be nice if you opened it up and allowed users to post candidate entries/examples in it. That could take a huge burden off of your shoulders so you can get Unity to 2.0!
     
  8. nmceri

    nmceri

    Joined:
    Aug 4, 2005
    Posts:
    56
    I'm having some difficulty understanding the rest of the LookAt functionality. I've got an object pointing at another object just fine, but I'd like to point the y axis of the object straight up right after the look.

    Code (csharp):
    1. void LookAt (Vector3 worldPosition, Vector3 worldUp = Vector3.up)
    2.  
    if this is right it seems I can point a vector3 direction at something after the "Vector3 worldPositon" but sofar i've just not been able to get it to work.

    Code (csharp):
    1. var target : Transform;
    2. function Update (){
    3.    if(Input.GetMouseButtonDown(0)){
    4.       ray = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);
    5.       var hit : RaycastHit;
    6.       if (Physics.Raycast (ray, hit)){
    7.          target.transform.position = hit.point;
    8.          transform.LookAt(target.position, need help here);
    9.       }
    10.    }
    11. }
    12.  
    Can anyone suggest how I could do this with the code I have posted? If it's not possible with LookAt would it be possible with something like..
    Code (csharp):
    1. transform.localRotation.x -= transform.localRotation.x;
     
  9. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    localRotation is a quaternion. You will want to use the eulerAngles variable instead.

    This works in Unity 1.1b1. There was a bug in the euler angle calculation code which might affect this.
    If this script doesn't work on 1.0.4, please upgrade to 1.1 beta 1.

    Code (csharp):
    1.  
    2. var target : Transform;
    3. function Update (){
    4.    if(Input.GetMouseButtonDown(0)){
    5.       ray = Camera.mainCamera.ScreenPointToRay(Input.mousePosition);
    6.       var hit : RaycastHit;
    7.       if (Physics.Raycast (ray, hit)){
    8.          target.transform.position = hit.point;
    9.          transform.LookAt(target.position);
    10.      transform.eulerAngles.x = 0;
    11.       }
    12.    }
    13. }
    14.  
     
  10. nmceri

    nmceri

    Joined:
    Aug 4, 2005
    Posts:
    56
    It's so simple!
    I was really pulling my hair out on that one. Thank you.
     
  11. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Hi there,

    I'm afraid all this RayCast stuff is giving me a headache! Can anyone show me how I would simply cast a ray between two known objects. The objects won't be pointing at one another. I just need to cast the ray and then check if object A actually has a clear line of sight to object B.

    In pseudo-code I need something like:

    Code (csharp):
    1.  
    2. RayCast from this.transform.position to target.transform.position;
    3. if RayCast hit is actually the target {
    4.  do things;
    5.  }
    6.  
    If anyone can help it will save a bit of cursing.
     
  12. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    Try:
    Code (csharp):
    1.  
    2. var otherObject : Transform;
    3. function Update () {
    4.   var hit : RaycastHit;
    5.   if (Physics.Raycast (transform.position, otherObject.position - transform.Position, out hit)) {
    6.     if (hit.collider.transform == otherObject) {
    7.       print ("Saw me!");
    8.     }
    9.   }
    10.  
    Something like that anyways.
     
  13. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Thanks for that. Just what I needed.

    How would I use the CompareTag() function to see if the returned hit object is what I'm looking for? E.g. something like:

    Code (csharp):
    1.  
    2. if (Physics.Raycast (transform.position, otherObject.position - transform.Position, out hit)) {
    3.     if (hit.collider.transform.CompareTag("theEnemy")) {
    4.       print ("I see the enemy!");
    5.     }
    6.  
    I tried this and it only works if the two objects are actually touching. Very puzzling. I'll try some different approaches but if someone can show me what I'm doing wrong I'd appreciate it.

    Cheers.
     
  14. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    I'm getting there thanks to the handy Debug.DrawLine() function.
    I've added the following code so I can see a line drawn between my two target objects:

    Code (csharp):
    1.  
    2. Debug.DrawLine(this.transform.position, other.transform.position, Color.red);
    3.  
    This works perfectly because the DrawLine function uses the start and end positions to draw the line. Unfortunately the Raycast function doesn't work like this. It takes the start position as above, but then wants to know the ANGLE (as a Vector3) from this position to cast the ray. Is there any way I can replicate the Debug.DrawLine behaviour and simply cast a ray from one position to another. (The code Nicholas provided doesn't seem to work unfortunately. The end position is always off target.)

    Alternatively it's easy to work out the angle between the two object positions using Vector3.AngleBetween. Unfortunately this gives an angle in radians. If I could convert this to a Vector3 I could plug it into the Raycast function. Anyone know how to do this?

    Gah, this is complicated stuff. I'm probably making obvious mistakes but am too tired to see them. The Vector3 class methods probably contain what I need but without examples I don't understand what they all do.
     
  15. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    Code (csharp):
    1.  
    2. dir = target.position - transform.position;
    3. var hit : RaycastHit;
    4. if (Physics.Raycast (transform.position, dir, hit, dir.magnitude))
    5. {
    6.    if (hit.collider.transform.CompareTag("theEnemy")) {
    7.       print ("Saw me");
    8.      Debug.DrawLine(transform.position, hit.point, Color.red);
    9.  
    10.    }
    11. }
    12.  
    Now you need to watch out that the player itself doesnt have a collider.
    And if it has a collider you need to ignore the player collider when casting the ray.
    The easiest way to do this is to change the player's layer to "Ignore Raycast" in the inspector.

    I also added a Linecast function to the next beta version as this seems to be simpler to understand.
     
  16. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Thank you very much! This is definitely appreciated. I'll try it out tomorrow and let you know how it goes. At this rate I may be able to get something into the widget contest. I'm away all next week so I only have a couple of days to finish my code and work on the models and textures.
     
  17. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    I'm finding the lookAt function very useful but by its nature it makes for very abrupt transitions as an object suddenly snaps into a new rotation. Is there a way to make my player smoothly rotate until it's looking at the target object?
     
  18. NicholasFrancis

    NicholasFrancis

    Joined:
    Apr 8, 2005
    Posts:
    1,587
    There might be a 'better' way, but this should actually work

    Code (csharp):
    1.  
    2. var target : Transform;
    3. var smoothness : float;
    4.  
    5. function Update () {
    6.     var oldRotation = transform.rotation;
    7.     transform.LookAt(target);
    8.     transform.rotation = Quaternion.Slerp (oldRotation, transform.rotation, Time.deltaTime * smoothness);
    9. }
    10.  
    Basically we grab a copy of the rotation, turn towards the target then interpolate (with Lerp) back towards the old target.
     
  19. pdrummond

    pdrummond

    Joined:
    Jun 23, 2005
    Posts:
    185
    Marvellous! And I even understand how some of it works!