Search Unity

Object follow player

Discussion in 'Scripting' started by ddulshan, Sep 19, 2014.

  1. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    Hi, I'm stuck in a little problem. I have a code that make a object follow the Player. Now I need this object to ignore any collisions and follow player. And the object will get to the original position it was in after some time.

    Here's my code, please help.
    Code (JavaScript):
    1. #pragma strict
    2.  
    3. var target : Transform; //the enemy's target
    4. var moveSpeed = 3; //move speed
    5. var rotationSpeed = 3; //speed of turning
    6. var distance = 3; //max distance from object to player
    7. var myTransform : Transform; //current transform data of this enemy
    8. var startPoint : Vector3;
    9. function Start()
    10. {
    11.      target = GameObject.FindWithTag("Player").transform; //target the player
    12.      startPoint = myTransform.position; //get the start point of the object
    13. }
    14. function Update ()
    15. {  
    16.     var dist = Vector3.Distance(target.position, myTransform.position); //get the distance from the player to object
    17.     myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
    18.     Quaternion.LookRotation(target.position - myTransform.position), rotationSpeed*Time.deltaTime); //rotate to look at the player
    19.    
    20.     var fwd = transform.TransformDirection(Vector3.forward);
    21.     if(Physics.Raycast(transform.position, fwd, 2))
    22.     {
    23.          print("There is something infront of the object, means, the script works!");
    24.     }
    25.     if(dist > distance)
    26.     {
    27.          myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime; //move towards the player
    28.     }
    29. }
     
  2. BmxGrilled

    BmxGrilled

    Joined:
    Jan 27, 2014
    Posts:
    239
    How do you mean ignore collisions? Obstacle avoidance (moving around objects)? or Phantom (moving through objects)?
     
  3. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    Thanks for replying. I meant moving around the object.
     
  4. BmxGrilled

    BmxGrilled

    Joined:
    Jan 27, 2014
    Posts:
    239
    if you cast a ray in front of your character a short distance, and if it is hitting something, check if it's the player and ignore the hit, but if it's not the player, choose a direction, if you use two rays, off to the sides of the character object, you can use that to determine left or right turn. It's important that if a ray is hitting something that's not the player, it overrides any other movement, and the character always walks forward while going where it's going, with respect to slowing and stopping when necessary of course.
    If you need an example of what I mean don't hesitate to ask. Hope this helps! :)
     
  5. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    yeah please. I need a example code. I'm not very good in scripting.
     
  6. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
  7. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
    So I'm rather novice at this myself, but I'll attempt to provide an answer. Ray casting has a "layer mask" that can ignore layers; this is based upon a principle called "bit shifting". If your layer mask is 0, nothing will be counted as an obstruction. If you want to hit only the default layer, your mask (represented by an int in code) should be 1; if you want to ignore a custom defined layer (let's say the 8th layer), then you should change the bits by saying

    Code (CSharp):
    1. int mask = 1;
    2.  
    3. mask = mask << 8;
    4.  
    5. if (Physics.Raycast(ray, out hit, rayCastDistance, mask)) ... etc
    This amounts to "ignore layer 1 and layer 8".

    I hope that this helps. Also, that I'm mostly correct =p
     
  8. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
    To elaborate, you can select an item in the browser and find the "layer" button on the inspector in the upper right. There you can select and create layers. If you put a collider, or a mesh, or whatever into that layer (it can be in more than one) then you can reference that layer to be ignored by your raycast.
     
  9. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    Code (CSharp):
    1. if (Physics.Raycast(ray, out hit, rayCastDistance, mask)) ... etc
    [/QUOTE]

    What should be the values replaced to "ray, out hit and mask"?
     
  10. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
    Well, in your case I think you should just add the last parameter to your existing code, e.g.

    Code (CSharp):
    1. if(Physics.Raycast(transform.position, fwd, 2, mask))
    You'll still need to configure your layers as described in my last post. That's probably going to involve a bit of trial and error.
     
  11. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    What should be the value of "mask"? Is it the name of the Layer or just Mask?
     
  12. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
    The value of mask should start at "1". Any int in Mono is a 32-bit integer, meaning that you can represent 32 different layers. Masks are viewed by the engine as a set of bits. Each bit says whether to count the corresponding layer as an obstacle, where the bits represent 0 for false or 1 for true. As you can see in the layer inspector, the number of the first layer (default layer) is 0. Here is the bit content of an int with value 1:

    Code (CSharp):
    1.  
    2. 000000000000000000000000000000001
    3.  
    The "1" is at the 0th index. A mask of "1" represents only the default layer, the one corresponding to the 0th bit position. In coding, we start at 0 rather than 1, because we are monkeys. Binary is more complex than I seem to be capable of explaining right now, but it's worth reading up on.

    So, for your case, the simple explanation is that your mask should probably be 1, meaning that your follower would be blocked by the default layer -- which includes terrain -- or 0, meaning that your follower ignores absolutely everything.

    Edit: Edited for derp. Beer...
     
    Last edited: Sep 21, 2014
  13. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
  14. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    Nope it's still moving moving through objects. Here's what I have done so far, dont laugh at it I'm just a begginner. :)

    Code (JavaScript):
    1. #pragma strict
    2.  
    3. var target : Transform; //the enemy's target
    4. var moveSpeed = 3; //move speed
    5. var rotationSpeed = 3; //speed of turning
    6. var distance = 3; //max distance from object to player
    7. var myTransform : Transform; //current transform data of this enemy
    8. var startPoint : Vector3; //get start position
    9. var mask : int = 1;
    10. function Start()
    11. {
    12.      target = GameObject.FindWithTag("Player").transform; //target the player
    13.      startPoint = myTransform.position; //get the start point of the object
    14. }
    15. function Update ()
    16. {  
    17.     var dist = Vector3.Distance(target.position, myTransform.position); //get the distance from the player to object
    18.     myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
    19.     Quaternion.LookRotation(target.position - myTransform.position), rotationSpeed*Time.deltaTime); //rotate to look at the player
    20.    
    21.     var fwd = transform.TransformDirection(Vector3.forward);
    22.     if(Physics.Raycast(transform.position, fwd, 2))
    23.     {
    24.          print("There is something infront of the object, means, the script works!");
    25.     }
    26.     if(dist > distance)
    27.     {
    28.          myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime; //move towards the player
    29.     }
    30.     if(Physics.Raycast(transform.position, fwd, 2, mask));
    31. }
     
  15. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
    Oh, I see. Sorry I wasn't explicit in my explanation =)

    I meant to say that you should modify line 20 in your code. Your code snippet should look like this:

    Code (CSharp):
    1. var target : Transform; //the enemy's target
    2. var moveSpeed = 3; //move speed
    3. var rotationSpeed = 3; //speed of turning
    4. var distance = 3; //max distance from object to player
    5. var myTransform : Transform; //current transform data of this enemy
    6. var startPoint : Vector3; //get start position
    7. var mask : int = 1;
    8. function Start()
    9. {
    10.      target = GameObject.FindWithTag("Player").transform; //target the player
    11.      startPoint = myTransform.position; //get the start point of the object
    12. }
    13. function Update ()
    14. {
    15.     var dist = Vector3.Distance(target.position, myTransform.position); //get the distance from the player to object
    16.     myTransform.rotation = Quaternion.Slerp(myTransform.rotation,
    17.     Quaternion.LookRotation(target.position - myTransform.position), rotationSpeed*Time.deltaTime); //rotate to look at the player
    18.  
    19.     var fwd = transform.TransformDirection(Vector3.forward);
    20.     if(Physics.Raycast(transform.position, fwd, 2, mask))
    21.     {
    22.          print("There is something infront of the object, means, the script works!");
    23.     }
    24.     if(dist > distance)
    25.     {
    26.          myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime; //move towards the player
    27.     }
    28. }
    See the mask in the first IF statement? That's where we use the mask to decide which layers we test. Since almost everything starts in the default layer, this should mean that your follower will not follow through objects unless you've added custom layers or purposely changed the layers of objects in your map.

    I'm new too, so this is kind of like the whole "deaf leading the blind" thing =) Still, I think this is what your code needs.
     
  16. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    I used the code above ^. But it's still the same, moving through obstacles. :(
     
  17. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
    Have you added colliders to your obstacles (and your follower)? All the above code should do is keep your follower from "seeing" your character through obstacles. Colliders prevent objects from moving through other objects (that have colliders).
     
  18. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
    Also, just to be sure, you might try using Physics.LineCast(position_player, position_follower, out hit, mask) instead of Physics.RayCast. It is a more explicit way of attempting to draw a line between two absolute coordinates.
     
  19. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    Yeah, obstacles and the follower has colliders they are basically just cubes. xD. And what does "out hit" does? And I wanted the object (follower) to follow player avoiding obstacles. The follower is a AI.
     
  20. McHazard

    McHazard

    Joined:
    May 8, 2013
    Posts:
    13
    Right, so what we've done so far should work. Another thing to check is whether your scripts are fully compiling. If you open MonoDevelop and hit F8 it will attempt to build. If you get a red x in the top bar it means you have errors and that would prevent your scripts from updating. Sorry, I'm not familiar enough with Unity yet to zero in on a problem =)
     
  21. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    Well, I'm not getting any errors when debugged. And thanks for helping. :)
     
  22. BmxGrilled

    BmxGrilled

    Joined:
    Jan 27, 2014
    Posts:
    239
    Sorry for the late reply, different time zones! Anyhow, I can only provide examples in C#, but the principle is basically the same in JS, since the functions are the same, there's just a few syntax differences. Anyhow, here's the example:

    Code (CSharp):
    1. //ObstacleAvoidanceAI.cs
    2. //C#
    3. using UnityEngine;
    4. using System.Collections;
    5.  
    6. public class ObstacleAvoidanceAI : MonoBehaviour
    7. {
    8.     public float moveSpeed;            //speed we walk/run at
    9.     public float turnSpeed;            //speed we turn at
    10.    
    11.     private float move;                //use to keep track of move velocity
    12.     private float turn;                //used to keep track of turn velocity
    13.    
    14.     public float rayAngle;            //angle between the two rays
    15.    
    16.     private float halfAngle;        //for precomputing half of the angle set for the rays
    17.    
    18.     public float rayRange;            //how far to cast our rays from the character
    19.    
    20.     private Rigidbody myTransform;    //cache for our transform component
    21.     private Rigidbody myRigidbody;    //cache for our rigidbody component
    22.    
    23.     public Transform target;        //the target to track towards
    24.    
    25.     public void Awake()
    26.     {
    27.         myTransform = transform;
    28.         myRigidbody = rigidbody;
    29.         halfAngle = rayAngle / 2.0f;
    30.     }
    31.    
    32.     public void FixedUpdate()
    33.     {
    34.         if (target == null) { return; }        //early out if we have no target
    35.        
    36.         turn = 0.0f;        //default no turning
    37.         move = moveSpeed;    //default moving forward
    38.        
    39.         Ray[] rays = new Ray[] {
    40.             //rays[0] = left ray
    41.             new Ray(myRigidbody.position, myRigidbody.rotation * (Quaternion.Euler(0, -halfAngle, 0) * Vector3.forward)),
    42.             //rays[1] = right ray
    43.             new Ray(myRigidbody.position, myRigidbody.rotation * (Quaternion.Euler(0, halfAngle, 0) * Vector3.forward))
    44.         };
    45.        
    46.         RaycastHit[] hitTargets = new RaycastHit[2];
    47.        
    48.         bool[] hits = new bool[] {
    49.             //cast and store left ray
    50.             Physics.Raycast(rays[0], out hitTargets[0], rayRange),
    51.             //cast and store right ray
    52.             Physics.Raycast(rays[1], out hitTargets[1], rayRange)
    53.         }
    54.        
    55.         bool cantGoForward = hits[0] && hits[1];
    56.         bool cantGo = hits[0] || hits[1];
    57.         if (cantGoForward) { turn += turnSpeed }    //both rays are hitting, turn any direction (e.g. right)
    58.         else if (hits[0]) { turn += turnSpeed; }        //left is hitting, so turn right
    59.         else if (hits[1]) { turn -= turnSpeed; }        //right is hitting, so turn left
    60.        
    61.         if (cantGoForward) { move = 0.0f; }    //if both rays are hitting, assume we can't move without turning
    62.         else if (cantGo) { move *= 0.5f; }    //if either ray is hitting, assume we can't move without turning enough
    63.         else
    64.         {//we're good to go
    65.             //direction to target
    66.             Vector3 direction = target.position - myRigidbody.position;
    67.             //distance to target
    68.             float distance = direction.magnitude;
    69.             //normalize direction to unit length so we can use dot product
    70.             direction = direction.normalized;
    71.             //calculate dot products for controlling turn factor
    72.             float dotForward = Vector3.Dot(direction, myTransform.forward);
    73.             float dotRight = Vector3.Dot(direction, myTransform.right);
    74.            
    75.             if (dotForward < 0.1f)
    76.             {//target is behind us
    77.                 turn += turnSpeed;        //keep turning until they're in front
    78.             }
    79.             else
    80.             {//target is in front of us
    81.                 turn += turnSpeed * dotRight;    //right = +1, left = -1;
    82.             }
    83.         }
    84.        
    85.         //we have our turn and move factors, now do it
    86.        
    87.         Vector3 newPosition = myTransform.forward * move;
    88.         Vector3 newPosition = myRigidbody.position + (newPosition * Time.fixedDeltaTime);
    89.        
    90.         Quaternion newRotation = Quaternion.Euler(0, turn * Time.fixedDeltaTime, 0);
    91.         newRotation = myRigidbody.rotation * (myRigidbody.rotation * newRotation);
    92.        
    93.         myRigidbody.MovePosition(newPosition);
    94.         myRigidbody.MoveRotation(newRotation);
    95.     }
    96. }
    97.  
    I hope this helps! :)
     
  23. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    Wow thanks. So when this script is attached the object follows the player while avoiding obstacles? I tried using Nev mesh, though the object avoid obstacles it has difficulties keeping up with player, its trying to come through obstacles which is avoided by nev mesh! xD

    Anyway, I'll try this when I get back on PC, thanks. And I'll try converting it to JS. ;) Thanks again.
     
  24. BmxGrilled

    BmxGrilled

    Joined:
    Jan 27, 2014
    Posts:
    239
    Casting more than two rays will of course produce a more accurate result, two rays should be nice to get the idea behind what is happening though. :)
     
  25. ddulshan

    ddulshan

    Joined:
    Mar 16, 2014
    Posts:
    190
    I'm getting some errors, since I don't know about C# I don't know what to do. Here's the errors,

    1. Follow.cs(53,20): error CS1525: Unexpected symbol `bool'
    2. Follow.cs(55,56): error CS1525: Unexpected symbol `}', expecting `;'
    3. Follow.cs(86,25): error CS0128: A local variable named `newPosition' is already defined in this scope

    Here's the code.

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class Follow : MonoBehaviour
    5. {
    6.     public float moveSpeed;            //speed we walk/run at
    7.     public float turnSpeed;            //speed we turn at
    8.    
    9.     private float move;                //use to keep track of move velocity
    10.     private float turn;                //used to keep track of turn velocity
    11.    
    12.     public float rayAngle;            //angle between the two rays
    13.    
    14.     private float halfAngle;        //for precomputing half of the angle set for the rays
    15.    
    16.     public float rayRange;            //how far to cast our rays from the character
    17.    
    18.     private Rigidbody myTransform;    //cache for our transform component
    19.     private Rigidbody myRigidbody;    //cache for our rigidbody component
    20.    
    21.     public Transform target;        //the target to track towards
    22.    
    23.     public void Awake()
    24.     {
    25.         myTransform = transform;
    26.         myRigidbody = rigidbody;
    27.         halfAngle = rayAngle / 2.0f;
    28.     }
    29.    
    30.     public void FixedUpdate()
    31.     {
    32.         if (target == null) { return; }        //early out if we have no target
    33.        
    34.         turn = 0.0f;        //default no turning
    35.         move = moveSpeed;    //default moving forward
    36.        
    37.         Ray[] rays = new Ray[] {
    38.             //rays[0] = left ray
    39.             new Ray(myRigidbody.position, myRigidbody.rotation * (Quaternion.Euler(0, -halfAngle, 0) * Vector3.forward)),
    40.             //rays[1] = right ray
    41.             new Ray(myRigidbody.position, myRigidbody.rotation * (Quaternion.Euler(0, halfAngle, 0) * Vector3.forward))
    42.         };
    43.        
    44.         RaycastHit[] hitTargets = new RaycastHit[2];
    45.        
    46.         bool[] hits = new bool[] {
    47.             //cast and store left ray
    48.             Physics.Raycast(rays[0], out hitTargets[0], rayRange),
    49.             //cast and store right ray
    50.             Physics.Raycast(rays[1], out hitTargets[1], rayRange)
    51.         }
    52.        
    53.         bool cantGoForward = hits[0] && hits[1];
    54.         bool cantGo = hits[0] || hits[1];
    55.         if (cantGoForward) { turn += turnSpeed }    //both rays are hitting, turn any direction (e.g. right)
    56.         else if (hits[0]) { turn += turnSpeed; }        //left is hitting, so turn right
    57.         else if (hits[1]) { turn -= turnSpeed; }        //right is hitting, so turn left
    58.        
    59.         if (cantGoForward) { move = 0.0f; }    //if both rays are hitting, assume we can't move without turning
    60.         else if (cantGo) { move *= 0.5f; }    //if either ray is hitting, assume we can't move without turning enough
    61.         else
    62.         {//we're good to go
    63.             //direction to target
    64.             Vector3 direction = target.position - myRigidbody.position;
    65.             //distance to target
    66.             float distance = direction.magnitude;
    67.             //normalize direction to unit length so we can use dot product
    68.             direction = direction.normalized;
    69.             //calculate dot products for controlling turn factor
    70.             float dotForward = Vector3.Dot(direction, myTransform.forward);
    71.             float dotRight = Vector3.Dot(direction, myTransform.right);
    72.            
    73.             if (dotForward < 0.1f)
    74.             {//target is behind us
    75.                 turn += turnSpeed;        //keep turning until they're in front
    76.             }
    77.             else
    78.             {//target is in front of us
    79.                 turn += turnSpeed * dotRight;    //right = +1, left = -1;
    80.             }
    81.         }
    82.        
    83.         //we have our turn and move factors, now do it
    84.        
    85.         Vector3 newPosition = myTransform.forward * move;
    86.         Vector3 newPosition = myRigidbody.position + (newPosition * Time.fixedDeltaTime);
    87.        
    88.         Quaternion newRotation = Quaternion.Euler(0, turn * Time.fixedDeltaTime, 0);
    89.         newRotation = myRigidbody.rotation * (myRigidbody.rotation * newRotation);
    90.        
    91.         myRigidbody.MovePosition(newPosition);
    92.         myRigidbody.MoveRotation(newRotation);
    93.     }
    94. }