Search Unity

Some AI I'm working on

Discussion in 'Works In Progress - Archive' started by Jibidiah, Feb 22, 2012.

  1. Jibidiah

    Jibidiah

    Joined:
    Oct 17, 2011
    Posts:
    76
    It's unfinished AI but it's getting close to being done. I'm making it for an after-school club that is pretty much Unity3D oriented. We have a robotics team in the school and the club thought it would be cool if we would make the robotics tournament this year, into a Unity3D game. The tournament is Rebound Rumble http://www.youtube.com/watch?v=VkoEvWa62w4 Now we aren't going to put in the balancing on the bridges part because our game really is just going to be collecting balls and shooting them in the hoops; I decided to make AI for the sake of making it more interesting... and for a good learning experience.

    The AI graphics aren't made yet as it's just capsules with cubes as faces, but the code part works. I've just got to touch up the code some more to where it'd fit in the game scenario. The court isn't on here, as this is just an AI testing area.

    Play As Another Robot
    In this webplayer, you play as one of the robots. The AI picks up balls on their side, and throws them at you. You can pick up balls yourself by running over them; you can only hold 3 balls at a time. You can shoot the balls by pressing the LEFT SHIFT.
    http://dl.dropbox.com/u/53915463/Player AI test/WebPlayer.html

    Play As a Ball:
    In this webplayer, you play from the perspective of one of the balls that are being collected and shot by the AI. http://dl.dropbox.com/u/53915463/AI Testing Webplayer/WebPlayer.html

    AI CODE:
    Code (csharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class MyBestAI : MonoBehaviour {
    6.     public Vector3 shootSpot;
    7.     public Vector3 hoop;
    8.     public Vector3 shootBallFrom;
    9.  
    10.     public float maxDistance;
    11.     public int rotationSpeed;
    12.     public float moveSpeed;
    13.  
    14.     private GameObject closestBall;
    15.  
    16.     //The different States being used
    17.     public enum State {
    18.         TargetClosestBall,
    19.         CollectClosestBall,
    20.         RotateToOtherCourtSideAndShootBall,
    21.         NoFreeBalls
    22.     }
    23.  
    24.     public State state;
    25.  
    26.     //assign variables in awake and make current state be TargetClosestBall
    27.     public void Awake() {
    28.         shootSpot =  GameObject.Find("shootSpot").transform.position;
    29.         hoop =  GameObject.Find("hoop").transform.position;
    30.         state = State.TargetClosestBall;
    31.     }
    32.  
    33.     /*make it so collisions don't rotate the AI and
    34.     and also start the Finite State Machine*/
    35.     void Start() {
    36.         rigidbody.freezeRotation = true;
    37.         StartCoroutine(FSM());
    38.     }
    39.  
    40.     /*can somebody please tell me what exactly this is called
    41.      and how it works? All I know is that it finds objects with
    42.      the tag "FreeBall" and assigns the closest one as closestBall*/
    43.     GameObject FindClosestEnemy() {
    44.         GameObject[] gos;
    45.         gos = GameObject.FindGameObjectsWithTag("FreeBall");
    46.         float distance = Mathf.Infinity;
    47.         Vector3 position = transform.position;
    48.  
    49.         foreach (GameObject go in gos) {
    50.             Vector3 diff = go.transform.position - position;
    51.             float curDistance = diff.sqrMagnitude;
    52.  
    53.             if (curDistance < distance) {
    54.                 closestBall = go;
    55.                 distance = curDistance;
    56.             }
    57.         }
    58.         return null;
    59.     }
    60.  
    61.     IEnumerator FSM() {
    62.  
    63.     // Execute the current coroutine (state)
    64.         while (true)
    65.         yield return StartCoroutine(state.ToString());
    66.     }
    67.  
    68.     IEnumerator TargetClosestBall() {
    69.     /* This part works as the Enter function
    70.     of the previous post (it's optional) */
    71.         FindClosestEnemy();
    72.         yield return null;
    73.  
    74.     /* Now we enter in the Execute part of a state
    75.     which will be usually inside a while - yield block */
    76.  
    77.         //check if closestBall is assigned to an object
    78.         if(closestBall != null) {
    79.             bool moveToBall = true;
    80.             bool ballIsGrabbable = false;
    81.             bool closeToBall = false;
    82.             Vector3 targettedBall = closestBall.transform.position;
    83.             targettedBall.y = transform.position.y;
    84.            
    85.             while (moveToBall) {   
    86.  
    87.                 while(!closeToBall) {
    88.  
    89.                     /*check if the tag is still "FreeBall" in the case
    90.                      of another AI getting the ball before we do*/
    91.                     if (closestBall.tag == "FreeBall") {
    92.                         targettedBall = closestBall.transform.position;
    93.                         targettedBall.y = transform.position.y;
    94.  
    95.                         //start rotating towards the ball
    96.                         transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(targettedBall - transform.position), rotationSpeed * Time.deltaTime);
    97.                        
    98.                         /*if the angle difference between our current look rotation and the look rotation of looking right at the object,
    99.                          is within 10 degrees; start moving forward. But continue rotating to accommodate for a rolling ball*/
    100.                         if(Quaternion.Angle(Quaternion.LookRotation(targettedBall - transform.position), transform.rotation) <= 10) {
    101.                             transform.position += transform.forward * (moveSpeed * Time.deltaTime);
    102.                             transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(targettedBall - transform.position), rotationSpeed * Time.deltaTime);
    103.  
    104.                             /*check if the distance between us and the ball, is below or equal to maxDistance,
    105.                              and if the ball is bellow our current y transform (if the ball is touching the ground)*/
    106.                             if(Vector3.Distance(targettedBall, transform.position) <= maxDistance  closestBall.transform.position.y <= gameObject.transform.position.y) {
    107.                                 ballIsGrabbable = true;
    108.                                 closeToBall = true;
    109.                                
    110.                                 //do one last check if the tag and name is still "FreeBall" to see if another AI has grabbed the ball already
    111.                                 if(closestBall.tag == "FreeBall"  closestBall.name == "FreeBall") {
    112.                                     closestBall.transform.parent = gameObject.transform;
    113.                                     closestBall.name = "CapturedBall " + gameObject.name;
    114.                                     closestBall.tag = "CapturedBall";
    115.  
    116.                                     closestBall.layer = 10;
    117.                                 }
    118.                                
    119.                                 //if the tag and/or name is other than "FreeBall" (AKA, ball is already grabbed by other AI)
    120.                                 else {
    121.                                     moveToBall = false;
    122.                                     closestBall = null;
    123.                                     closeToBall = true;
    124.                                     state = State.TargetClosestBall;
    125.                                 }
    126.                             }
    127.                         }
    128.                     }
    129.                    
    130.                     //if the ball does not have the tag of "FreeBall" (from the first check)
    131.                     else {
    132.                         moveToBall = false;
    133.                         closestBall = null;
    134.                         closeToBall = true;
    135.                         state = State.TargetClosestBall;
    136.                     }
    137.                 yield return new WaitForFixedUpdate();
    138.                 }
    139.            
    140.                 //after (!closeToBall) while loop
    141.                 if (ballIsGrabbable  closeToBall) {        
    142.                     moveToBall = false;
    143.                     state = State.CollectClosestBall;
    144.                 }                  
    145.             yield return new WaitForFixedUpdate();
    146.             }          
    147.         }
    148.  
    149.         //there are no FreeBalls on the court, make state NoFreeBalls
    150.         else {
    151.             state = State.NoFreeBalls;
    152.         }
    153.  
    154.         /* And finally do something before leaving
    155.         the state (optional too) and starting a new one */
    156.     }
    157.  
    158.     IEnumerator CollectClosestBall() {
    159.         //Enter
    160.         bool grabbingBall = false;
    161.         yield return null;
    162.  
    163.         //Execute
    164.         int grabbingTime = 2;      
    165.  
    166.         closestBall.rigidbody.isKinematic = true;
    167.         closestBall.rigidbody.useGravity = false;
    168.  
    169.         //this check seems unnecessary but I like to have it just incase
    170.         if(closestBall.name == "CapturedBall " + gameObject.name) {
    171.             grabbingBall = true;               
    172.  
    173.             while(grabbingBall){
    174.                 grabbingTime --;
    175.  
    176.                 /*this check seems necessary, in the case of
    177.                 two AI grabbing a ball at the same time*/
    178.                 if (closestBall.name == "CapturedBall " + gameObject.name) {                   
    179.  
    180.                     if(grabbingTime <= 0){
    181.                         grabbingBall = false;
    182.                         closestBall.transform.localPosition = shootBallFrom;
    183.                         state = State.RotateToOtherCourtSideAndShootBall;
    184.                     }  
    185.                 }
    186.  
    187.                 //if another AI has grabbed the ball while we were grabbing it
    188.                 else {
    189.                     grabbingBall = false;
    190.                     state = State.TargetClosestBall;
    191.                 }  
    192.  
    193.                 //if still grabbing the ball, wait for 1 second
    194.                 if(grabbingBall) {
    195.                     yield return new WaitForSeconds(1f);
    196.                 }
    197.                
    198.                 //else just continue on to the next set of code
    199.                 else {
    200.                     yield return null;
    201.                 }
    202.             }
    203.         }                      
    204.  
    205.         //if the ball's name is not "FreeBall"
    206.         else {
    207.             state = State.TargetClosestBall;
    208.         }
    209.     }
    210.  
    211.     /*I would like to split this into two IEnumerators "Move to shooting spot"  "Shoot Ball"
    212.      to easily make some more advanced shooting options without having while loops inside of while loops.
    213.      I just think it's more clean if you keep functions seperate don't combine IEnumerators*/
    214.     IEnumerator RotateToOtherCourtSideAndShootBall() {
    215.         //Enter
    216.         yield return null;
    217.  
    218.         //Execute
    219.         bool canShoot = false;
    220.         bool aiming = false;
    221.         bool rotating = true;  
    222.  
    223.         //while not in the shooting spot (shootSpot)
    224.         while(!canShoot){
    225.             shootSpot.y = transform.position.y;
    226.  
    227.             //first rotate towards shootSpot, then move towards it
    228.             if(rotating) {
    229.                 transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(shootSpot - transform.position), rotationSpeed * Time.deltaTime);
    230.  
    231.                     if(Quaternion.Angle(Quaternion.LookRotation(shootSpot - transform.position), transform.rotation) < 1) {
    232.                         transform.rotation = Quaternion.LookRotation(shootSpot - transform.position);
    233.                         rotating = false;
    234.                     }
    235.             }
    236.  
    237.             //moving towards shootSpot after rotating towards it
    238.             else {
    239.  
    240.                 //while distance from shootSpot is over maxDistance
    241.                 if(Vector3.Distance(shootSpot, transform.position) > maxDistance) {
    242.                     transform.position += transform.forward * (moveSpeed * Time.deltaTime);
    243.                     transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(shootSpot - transform.position), rotationSpeed * Time.deltaTime);
    244.                 }
    245.  
    246.                 //if distance from shootSpot is under/equal to maxDistance
    247.                 else {
    248.                     canShoot = true;
    249.                 }
    250.             }
    251.             yield return new WaitForFixedUpdate();
    252.         }
    253.  
    254.         //if in the shootSpot
    255.         if (canShoot) {
    256.             aiming = true;
    257.  
    258.             //rotate towards the player
    259.             while(aiming){
    260.                 hoop =  GameObject.Find("Player").transform.position;
    261.                 hoop.y = transform.position.y;
    262.                 transform.rotation = Quaternion.Slerp(transform.rotation, Quaternion.LookRotation(hoop - transform.position), rotationSpeed * Time.deltaTime);
    263.  
    264.                 if (Quaternion.Angle(Quaternion.LookRotation(hoop - transform.position), transform.rotation) <= 2){
    265.                     aiming = false;
    266.                 }
    267.                 yield return new WaitForFixedUpdate();
    268.             }
    269.  
    270.             //shoot the ball at the player
    271.             closestBall.transform.parent = null;
    272.             closestBall.rigidbody.useGravity = true;
    273.             closestBall.rigidbody.isKinematic = false;
    274.             closestBall.transform.renderer.material.color = Color.red;
    275.             closestBall.transform.rotation = gameObject.transform.rotation;
    276.             closestBall.rigidbody.AddRelativeForce(0,10,5, ForceMode.Impulse);
    277.             closestBall = null;
    278.             canShoot = false;
    279.         }
    280.        
    281.  
    282.         //returning back to square one
    283.         state = State.TargetClosestBall;
    284.     }
    285.  
    286.     //this just checks if there is a FreeBall, every second
    287.     IEnumerator NoFreeBalls() {
    288.            //Enter
    289.            yield return null;
    290.  
    291.         while(closestBall == null) {
    292.             FindClosestEnemy();
    293.         yield return new WaitForSeconds(1);
    294.         }
    295.  
    296.         //Exit
    297.         state = State.TargetClosestBall;
    298.     }
    299. }
     
    Last edited: Feb 25, 2012
  2. Ebkac

    Ebkac

    Joined:
    Feb 3, 2012
    Posts:
    62
    Reading comprehension 101. Read the full post before clicking on the webplayer. I had NO idea what was going on. I just kept flying from place to place and unable to move.

    Pretty cool. I'd be curious to watch it from a camera that is stationary, closer to what sports games are broadcast in to help get a better idea of what the action looks like.
     
  3. Jibidiah

    Jibidiah

    Joined:
    Oct 17, 2011
    Posts:
    76
    i'll have that happen next webplayer. I thought it'd be a bit more fun this way, being one of the balls. You can still run around if you're not being grabbed.

    And then I'll add in the actual first person controller you play as.
     
  4. welby

    welby

    Joined:
    Mar 22, 2011
    Posts:
    549
    Stoopid capsules,..

    get off me!

    Why they throw me?! What'd I do?

    :p

    nice job.

    I'd be interested in hearing more about what checks and flags you are using for the AI. Like what's in their mind? Closest ball? boundary line,..etc,..
     
  5. Jibidiah

    Jibidiah

    Joined:
    Oct 17, 2011
    Posts:
    76
    The capsules are prejudice and go after every ball they see... they grew up in the bad part of town. Just be sure to have a fellow ball be in between you and the capsule, and you won't get thrown.

    Then I shall add an explanation of the AI soon, but add it to the top post so it's easily viewable to all.
     
  6. goat

    goat

    Joined:
    Aug 24, 2009
    Posts:
    5,182
    Well I'll be, the Unity Webplayer works with a gyrometer on my EP121 slate.

    It might be OK but it moves much too fast. You start the game and it's over before you can survey anything...
     
  7. Jibidiah

    Jibidiah

    Joined:
    Oct 17, 2011
    Posts:
    76
    I will slow it down in the next webplayer. Sorry, I had it fast for quick debugging purposes; forgot to make it slow again for actual viewing.
     
  8. Jibidiah

    Jibidiah

    Joined:
    Oct 17, 2011
    Posts:
    76
    okay I added a second webplayer. In the second one you play as another robot, it's explained in the top post. This one has the court areas defined. And I shall finish the AI explanation.
     
  9. Cod101

    Cod101

    Joined:
    Aug 25, 2011
    Posts:
    13
    everything is moving, rotating, rolling too fast...
     
  10. Jibidiah

    Jibidiah

    Joined:
    Oct 17, 2011
    Posts:
    76
    in the webplayer where you play as the ball, it's supposed to do that. The webplayer where you play as the robot, it's slowed down.
     
  11. Jibidiah

    Jibidiah

    Joined:
    Oct 17, 2011
    Posts:
    76
    Instead of explaining the AI in a bunch of paragraphs, I'll just post the code with comments on it. That'll just help people understand AI better if they want to; it's some simple AI anyways that I'm not too worried about getting snarfed anyways.
     
  12. Jibidiah

    Jibidiah

    Joined:
    Oct 17, 2011
    Posts:
    76
    AI code has been posted. Been sick lately, sorry for the delay.