Search Unity

Fps Tutorial Mysteries

Discussion in 'Editor & General Support' started by AaronC, Dec 14, 2006.

  1. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    Are there any obvious reasons why the fps tut robots would ignore a target tagged player? Im using a car as target, but even using the fps prefab, 90 percent of efforts end up with the bots ignoring the target... I had it working once, and took for granted I had it sussed, now I f@#%d with the settings and its gone.
    After a couple of long days, I still cant get them to recognise the entity that I tag player.
    The one time I had it working, I didnt have anything in the target slot of the AI script...

    So much time spent on stuff that should just work...Makes me feel real thick.
    I kinda wish I hadnt set my sights on entering the 3du comp as its turning my interest in game designing a into frustrating chore where I fell like, and am, wasting heaps of time...

    Any tips on the Ai? more detailed comments on the AI script?
    Yo
    AC
     
  2. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    The AI script will only attack the target if there is a clear line of sight.


    See the CanSeeTarget function. Also the enemy needs to be within attackRange distance, which is a property exposed in the inspector.

    Possibly there are some colliders occluding the line of sight. The best way to verify that is to simply return true in the CanSeeTarget function in the beginning. This way you know the raycasts get occluded by some geometry.

    Use this script to visualize the line that is being drawn:
    Code (csharp):
    1.  
    2. function CanSeeTarget () : boolean
    3. {
    4.     if (Vector3.Distance(transform.position, target.position) > attackRange)
    5.         return false;
    6.        
    7.     var hit : RaycastHit;
    8.     if (Physics.Linecast (transform.position, target.position, hit))
    9.     {
    10.         Debug.DrawLine(transform.position, hit.point, Color.white);
    11.         return hit.transform == target;
    12.     }
    13.     return false;
    14. }
    15.  
     
  3. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    When I get home, Ill try putting this script on robots-thats what Im supposed to do , right?
    Thanks Joe
    AC
     
  4. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    No. Open the AI script and find the CanSeeTarget function. Then modify the AI script like i described above.
     
  5. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    Thanks Joe,
    I could see that that wasnt the problem. My scene is quite open. Interesting tool...
    Sometimes I can get the Ai to work. When I do, I run in to problems :

    I have a car, it takes damage, is destroyed and fps player instantiates.

    At that point the robots have nothing to shoot at (even though player and car are both tagged"Player")

    Is there any way at all to get the robots to find the other tagged GO?
    Once they destroy the car, all script behavior stops.

    I can see how to change the tag the ai is seeking to something other than "Player", but not halfway through a scene...?Nor can I patch the Ai script to seek 2 objects..
    Thanks
    AC
     
  6. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    At the moment the ai script was coded to find the player at start of the game. You can see the code for it in the start function, You could simply move this finding a player target again code into the patrol function. Then it will pick another target when the first one is dead.
     
  7. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    I came up with this
    getting close?
    Code (csharp):
    1.  
    2. var speed = 3.0;
    3. var rotationSpeed = 5.0;
    4. var shootRange = 15.0;
    5. var attackRange = 30.0;
    6. var shootAngle = 4.0;
    7. var dontComeCloserRange = 5.0;
    8. var delayShootTime = 0.35;
    9. var pickNextWaypointDistance = 2.0;
    10. var target : Transform;
    11.  
    12. private var lastShot = -10.0;
    13.  
    14. // Make sure there is always a character controller
    15. @script RequireComponent (CharacterController)
    16.  
    17. function Start () {
    18.     // Auto setup player as target through tags
    19.     if (target == null  GameObject.FindWithTag("Player"))
    20.         target = GameObject.FindWithTag("Player").transform;
    21.  
    22.     Patrol();
    23. }
    24.  
    25. function Patrol ()
    26. {   if (target == null  GameObject.FindWithTag("Player"))
    27.         target = GameObject.FindWithTag("Player").transform;
    28.     var curWayPoint = AutoWayPoint.FindClosest(transform.position);
    29.     while (true)   
    30.     {
    31.         var waypointPosition = curWayPoint.transform.position;
    32.         // Are we close to a waypoint? -> pick the next one!
    33.         if (Vector3.Distance(waypointPosition, transform.position) < pickNextWaypointDistance)
    34.             curWayPoint = PickNextWaypoint (curWayPoint);
    35.  
    36.         // Attack the player and wait until
    37.         // - player is killed
    38.         // - player is out of sight    
    39.         if (CanSeeTarget ())
    40.             yield StartCoroutine("AttackPlayer");
    41.        
    42.         // Move towards our target
    43.         MoveTowards(waypointPosition);
    44.        
    45.         yield;
    46.     }
    47. }
    48.  
    49.  
    50. function CanSeeTarget () : boolean
    51. {   if (target == null  GameObject.FindWithTag("Player"))
    52.         target = GameObject.FindWithTag("Player").transform;
    53.     if (Vector3.Distance(transform.position, target.position) > attackRange)
    54.         return false;
    55.        
    56.     var hit : RaycastHit;
    57.     if (Physics.Linecast (transform.position, target.position, hit))
    58.         return hit.transform == target;
    59.  
    60.     return false;
    61. }
    62.  
    63. function Shoot ()
    64. {   if (target == null  GameObject.FindWithTag("Player"))
    65.         target = GameObject.FindWithTag("Player").transform;
    66.     // Start shoot animation
    67.     animation.CrossFade("shoot", 0.3);
    68.  
    69.     // Wait until half the animation has played
    70.     yield WaitForSeconds(delayShootTime);
    71.    
    72.     // Fire gun
    73.     BroadcastMessage("Fire");
    74.    
    75.     // Wait for the rest of the animation to finish
    76.     yield WaitForSeconds(animation["shoot"].length - delayShootTime);
    77. }
    78.  
    79. function AttackPlayer ()
    80. {   if (target == null  GameObject.FindWithTag("Player"))
    81.         target = GameObject.FindWithTag("Player").transform;
    82.     var lastVisiblePlayerPosition = target.position;
    83.     while (true)
    84.     {
    85.         if (CanSeeTarget ())
    86.         {
    87.             // Target is dead - stop hunting
    88.             if (target == null)
    89.                 return;
    90.  
    91.             // Target is too far away - give up
    92.             var distance = Vector3.Distance(transform.position, target.position);
    93.             if (distance > shootRange * 3)
    94.                 return;
    95.            
    96.             lastVisiblePlayerPosition = target.position;
    97.             if (distance > dontComeCloserRange)
    98.                 MoveTowards (lastVisiblePlayerPosition);
    99.             else
    100.                 RotateTowards(lastVisiblePlayerPosition);
    101.  
    102.             var forward = transform.TransformDirection(Vector3.forward);
    103.             var targetDirection = lastVisiblePlayerPosition - transform.position;
    104.             targetDirection.y = 0;
    105.  
    106.             var angle = Vector3.Angle(targetDirection, forward);
    107.  
    108.             // Start shooting if close and play is in sight
    109.             if (distance < shootRange  angle < shootAngle)
    110.                 yield StartCoroutine("Shoot");
    111.         }
    112.         else
    113.         {
    114.             yield StartCoroutine("SearchPlayer", lastVisiblePlayerPosition);
    115.             // Player not visible anymore - stop attacking
    116.             if (!CanSeeTarget ())
    117.                 return;
    118.         }
    119.  
    120.         yield;
    121.     }
    122. }
    123.  
    124. function SearchPlayer (position : Vector3)
    125. {   if (target == null  GameObject.FindWithTag("Player"))
    126.         target = GameObject.FindWithTag("Player").transform;
    127.     // Run towards the player but after 3 seconds timeout and go back to Patroling
    128.     var timeout = 3.0;
    129.     while (timeout > 0.0)
    130.     {
    131.         MoveTowards(position);
    132.  
    133.         // We found the player
    134.         if (CanSeeTarget ())
    135.             return;
    136.  
    137.         timeout -= Time.deltaTime;
    138.         yield;
    139.     }
    140. }
    141.  
    142. function RotateTowards (position : Vector3)
    143. {   if (target == null  GameObject.FindWithTag("Player"))
    144.         target = GameObject.FindWithTag("Player").transform;
    145.     SendMessage("SetSpeed", 0.0);
    146.    
    147.     var direction = position - transform.position;
    148.     direction.y = 0;
    149.     if (direction.magnitude < 0.1)
    150.         return;
    151.    
    152.     // Rotate towards the target
    153.     transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
    154.     transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
    155. }
    156.  
    157. function MoveTowards (position : Vector3)
    158. {   if (target == null  GameObject.FindWithTag("Player"))
    159.         target = GameObject.FindWithTag("Player").transform;
    160.     var direction = position - transform.position;
    161.     direction.y = 0;
    162.     if (direction.magnitude < 0.5)
    163.     {
    164.         SendMessage("SetSpeed", 0.0);
    165.         return;
    166.     }
    167.    
    168.     // Rotate towards the target
    169.     transform.rotation = Quaternion.Slerp (transform.rotation, Quaternion.LookRotation(direction), rotationSpeed * Time.deltaTime);
    170.     transform.eulerAngles = Vector3(0, transform.eulerAngles.y, 0);
    171.  
    172.     // Modify speed so we slow down when we are not facing the target
    173.     var forward = transform.TransformDirection(Vector3.forward);
    174.     var speedModifier = Vector3.Dot(forward, direction.normalized);
    175.     speedModifier = Mathf.Clamp01(speedModifier);
    176.  
    177.     // Move the character
    178.     direction = forward * speed * speedModifier;
    179.     GetComponent (CharacterController).SimpleMove(direction);
    180.    
    181.     SendMessage("SetSpeed", speed * speedModifier, SendMessageOptions.DontRequireReceiver);
    182. }
    183.  
    184. function PickNextWaypoint (currentWaypoint : AutoWayPoint)
    185. {   if (target == null  GameObject.FindWithTag("Player"))
    186.         target = GameObject.FindWithTag("Player").transform;
    187.     // We want to find the waypoint where the character has to turn the least
    188.  
    189.     // The direction in which we are walking
    190.     var forward = transform.TransformDirection(Vector3.forward);
    191.  
    192.     // The closer two vectors, the larger the dot product will be.
    193.     var best = currentWaypoint;
    194.     var bestDot = -10.0;
    195.     for (var cur : AutoWayPoint in currentWaypoint.connected)
    196.     {
    197.         var direction = Vector3.Normalize(cur.transform.position - transform.position);
    198.         var dot = Vector3.Dot(direction, forward);
    199.         if (dot > bestDot  cur != currentWaypoint)
    200.         {
    201.             bestDot = dot;
    202.             best = cur;
    203.         }
    204.     }
    205.    
    206.     return best;
    207. }
    Cheers
    AC
     
  8. HiggyB

    HiggyB

    Unity Product Evangelist

    Joined:
    Dec 8, 2006
    Posts:
    6,183
    That seems about right based on Joachim's suggestion, assuming you're still looking for the GO named "Player", as opposed to having the AI look for one GO on start-up (PlayerCar), then another later while on patrol. Did you give it a test yet?

    edited for typos...
     
  9. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    yeah no response from the Ai. once they blow up the first assigned target, they dont bother shooting at the player...
    Weird
    Welcome Aboard Tom
    AC
     
  10. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    Can anybody tell me which bit of this to change? I can change start to update and
    yadda yadda, but nothing makes this work...i really cant see why?
    Cheers
    AC

    Edit
    this should probably be in the wishlist, but I reckon OTEE should consider representing the 3rd fps tutorial. If you look at the first two, they go into the scripting side in good detail, wheras the third doesnt touch it...I kinda feel it was rushed? and the most important(Good Ai is right up there with good art) scripts arent discussed at all?
    I guess it comes down to how much time you guys have. when the first and second fps tutorials came out, there was so much to learn. personally I soaked it in over a long time so when the third and even better tut came out, there was nothing in it ...?literally...
    Some script breakdown would be nice/essential. take this photo. the script is not called Ai because I've been trying to rewrite and understand it for a few weeks, with no luck.

    1. What does Shoot range attack range and dont come closer range actually mean? Theres no where near enough comments anywhere.

    2.Pick next waypoint distance. if this was set to "1" does this mean the closest waypoint? the first made in the scene? 1 metre away? that the robot will only go to one waypoint and stop? what if it were set to 99. or 9999?




    All that happens in reality is they run where they want, when they want, which is kinda cute but usless. especially when they ignore Tagged FPS prefabs that are instantiated after hitting play. Theres not enough info. Yes Im a beginner but the third fps tut was for kids and I was suprised how lite it was. There was nothing in it, and it was sad to read that was the end of the series...

    Personally I cant get the health pickup thing to work outside of the demo scene either, and Fade and Load level crashes my machine, so wheres the instructions?

    Tired and over it? perhaps. I wish it were a damn site easier.
    AC


    3.And what if the prefabs tagged "player" and the camera is tagged "MainCamera"? Does that screw over the engine so things are negative null?

    -if a thing is destroyed, its not null then is it? or is it?, or is it negative null?
    Its not null if it ..
    -oh whatever
     

    Attached Files:

  11. nafonso

    nafonso

    Joined:
    Aug 10, 2006
    Posts:
    377
    I think that Tom's suggestion may be the solution. Try and see if all the objects have the same tag that you are searching for.

    And if all fails, do the poor man's debug (prints all around to see the flow of your program after the first one is dead.
     
  12. hsparra

    hsparra

    Joined:
    Jul 12, 2005
    Posts:
    750
    I can't follow where the thread is at. Am I correct in that the AI is still not switching targets after the first target is destroyed? If so, I don't know if the target variable gets set to null (I don't know enough about .Net). I would assume that when target is assigned, it gets a pointer reference to the object. When the target is destroyed I would think that the target variable is not also set to null since it was the object pointed to by the target variable that got destroyed/nulled, not the target variable itself. So, I would think your target variable still has a value, just that it does not point to anything that still exists.

    If the above is the case, then one way you could do the change is to have a message sent when the target is destroyed that the AI script could "listen" for (i.e. have a function). When the message is recieved then a new target would be set.

    Did any of the above make any sense?
     
  13. Joachim_Ante

    Joachim_Ante

    Unity Technologies

    Joined:
    Mar 16, 2005
    Posts:
    5,203
    References to UnityEngine.Object based classes are weak-references. That means, if you destroy the object you are referencing and then check the reference against null, it will return true. So you don't need some kind of listener function call. Unity will handle that for you.
     
  14. hsparra

    hsparra

    Joined:
    Jul 12, 2005
    Posts:
    750
    Good to know :)
     
  15. AaronC

    AaronC

    Joined:
    Mar 6, 2006
    Posts:
    3,552
    Thanks Guys
    Id love to see an example
    My 3du work is posted now, Players have to feel ok about shooting passive robots.

    Unless that last minute change fixed it

    Will post in showcase
    AC