Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

AI Laggy

Discussion in 'Scripting' started by JoeCBS, Jun 11, 2014.

  1. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
    Okay, so right now whenever my spawner spawns my models, there is no framerate drop, but the second they start moving(I came into range and they started to chase me) it lags my game. It cuts it practically in half(with 4 spawned. I go from 80fps to 40, with 8 spawned down to 20-25 fps). I am going to post the script, see anything I can alter to make it not lag so bad?

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3.  
    4. public class EnemyAI : MonoBehaviour {
    5.     public Transform _target;
    6.     public int moveSpeed;
    7.     public int rotationSpeed;
    8.     public int maxDistance;
    9.     private SphereCollider _sphereCollider;
    10.     public float perceptionRadius = 10f;
    11.     private const float ROTATION_DAMP = .3f;
    12.     private const float FORWARD_DAMP = .9f;
    13.     public float baseMeleeRange = 3.5f;
    14.     private Transform _myTransform;
    15.  
    16.     private Transform myTransform;
    17.  
    18.     void Awake() {
    19.         myTransform = transform;
    20.     }
    21.  
    22.     // Use this for initialization
    23.     void Start () {
    24.         //Setup ();
    25.         GameObject go = GameObject.FindGameObjectWithTag("Player");
    26.  
    27.         _target = go.transform;
    28.  
    29.         maxDistance = 2;
    30.    
    31.    
    32.     }
    33.    
    34.     // Update is called once per frame
    35.     void Update () {
    36.         Debug.DrawLine (_target.position, myTransform.position, Color.yellow);
    37.         Move ();
    38.         /*//Look at target
    39.         myTransform.rotation = Quaternion.Slerp (myTransform.rotation, Quaternion.LookRotation(target.position - myTransform.position), rotationSpeed * Time.deltaTime);
    40.  
    41.         if (Vector3.Distance (target.position, myTransform.position) > maxDistance) {
    42.  
    43.         //Move towards target
    44.         myTransform.position += myTransform.forward * moveSpeed * Time.deltaTime;
    45.         }*/
    46.     }
    47.  
    48.     private void Move() {
    49.         Debug.Log ("Moving");
    50.         //stopWatch.Start ();
    51.         if (_target) {
    52.             Vector3 dir = (_target.position - myTransform.position).normalized;
    53.             float direction = Vector3.Dot(dir, transform.forward);
    54.            
    55.             float dist = Vector3.Distance(_target.position, myTransform.position);
    56.            
    57.             Debug.Log("dist");
    58.             if(direction > FORWARD_DAMP && dist > baseMeleeRange) {
    59.                 SendMessage("MoveMeForward", AdvancedMovement.Forward.forward);
    60.             }
    61.             else {
    62.                 SendMessage("MoveMeForward", AdvancedMovement.Forward.none);
    63.             }
    64.            
    65.             dir = (_target.position - myTransform.position).normalized;
    66.             direction = Vector3.Dot(dir, transform.right);
    67.            
    68.             if(direction > ROTATION_DAMP) {
    69.                 SendMessage("RotateMe", AdvancedMovement.Turn.right);
    70.             }
    71.             else if(direction < -ROTATION_DAMP) {
    72.                 SendMessage("RotateMe", AdvancedMovement.Turn.left);
    73.             }
    74.             else {
    75.                 SendMessage("RotateMe", AdvancedMovement.Turn.none);
    76.             }
    77.         }
    78.         else {
    79.             SendMessage("MoveMeForward", AdvancedMovement.Forward.none);
    80.             SendMessage("RotateMe", AdvancedMovement.Turn.none);
    81.         }
    82.     }
    83.  
    84.     private void Setup() {
    85.         _sphereCollider.center = GetComponent<CharacterController> ().center;
    86.         _sphereCollider.radius = perceptionRadius;
    87.         _sphereCollider.isTrigger = true;
    88.     }
    89. }
    90.  
     
  2. Ereous

    Ereous

    Joined:
    Aug 29, 2012
    Posts:
    163
    Using character controller is not a good choice for AI its pretty nasty resource wise. Switching it out for rigidbody and capsule collider I guarantee you can get a bunch more then 8.

    I had this issue a ways back. I could get about 20 before it started dropping fps. Switched it over to rigidbody and capsule and I was able to get 300+. Upwards of 600 with 30fps.
     
  3. _met44

    _met44

    Joined:
    Jun 1, 2013
    Posts:
    633
    Also you use plenty SendMessage which is known for its poor performances. It really isn't much hasle to replace it with proper references to object/method delegates...

    Simply add the script with thoose methods as a private variable and gather it with GetComponent<YourOtherScript>() then call the methods directly and you'll gain a lot of execution speed.

    May I be curious why you have 2 "myTransform" variables ?
    Code (CSharp):
    1. private Transform _myTransform;
    2. private Transform myTransform;
     
  4. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
    Haha, well I am new at programming, so I didn't realize i had that when I did that and now have one gone. Going to post my new code in a sec as I'm stuck on a new problem
     
  5. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
    Okay, I have now fixed the AI with the rigid bodies, but now they just play their walk animation, but just sit there. will post gif along with this so you get an idea along with a picture of the scripts in the editor.

    GIF: http://gyazo.com/ef70fe08b188d88ebdd988eeb066a4ba(not that laggy in game, that's just Gyazo)
    Image of Inspector: http://gyazo.com/15fc150bf449f38c9565ea0d6a45f387

    And the code:
    Code (CSharp):
    1. /// <summary>
    2. /// Advanced movement.cs
    3. /// May 14th, 2014
    4. ///
    5. /// This script is responsible for getting the player movement inputs and adjusting the characters animations accordingly.
    6. ///
    7. /// This script will be automatically attach to your player or mob with the use of the PlayerInput.cs and AI.cs scripts.
    8. ///
    9. /// This script assumes that you have these animations with the following names
    10. /// Player:
    11. /// walk    - a walk animation
    12. /// run        - a run animatino
    13. /// jump    - a jump animation
    14. /// fall    - a falling animation
    15. /// idle    - an idle animation
    16. ///
    17. /// Mob:
    18. /// run        - a run animation
    19. /// jump    - a jump animation
    20. /// fall    - a falling animation
    21. /// idle    - an idle animation
    22. ///
    23. /// </summary>
    24. using UnityEngine;
    25. using System.Collections;
    26.  
    27. [RequireComponent (typeof(Rigidbody))]
    28. public class EnemyAdvancedMovement : MonoBehaviour {
    29.     public enum State {
    30.         Idle,
    31.         Init,
    32.         Setup,
    33.         Run
    34.     }
    35.  
    36.     public enum Turn {
    37.         left = -1,
    38.         none = 0,
    39.         right = 1
    40.     }
    41.     public enum Forward {
    42.         back = -1,
    43.         none = 0,
    44.         forward = 1
    45.     }
    46.  
    47.     public string walkAnimName;
    48.     public string runAnimName;
    49.     public string jumpAnimName;
    50.     public string idleAnimName;
    51.     public string fallAnimName;
    52.     public string attackAnimName1;
    53.     public string attackAnimName2;
    54.  
    55.     public float strafeSpeed = 3.5f;            //the speed our character strafes at
    56.     public float runMultiplier = 4;                //how fast the player runs compared to the walk speed
    57.     public float walkSpeed = 3;                    //the speed our character walks at
    58.     public float rotateSpeed  = 125;            //the speed our character turns at
    59.     public float gravity = 20;                    //the setting for gravity
    60.     public float airTime = 0;                    //how long have we been in the air since the last time we touched the ground
    61.     public float fallTime = .5f;                //the length of time we have to be falling before the system knows its a fall
    62.     public float jumpHeight = 8;                //the height we move when we are jumping
    63.     public bool doRun = true;
    64.     public float jumpTime = 1.5f;
    65.  
    66.     private CollisionFlags _collisionFlags;        //the collisionFlags we have from the last frame
    67.  
    68.     private Vector3 _moveDirection;                //this is the direction our character is moving
    69.     private Transform _myTransform;                //our cached transform
    70.     private Rigidbody _rigidBody;                //our cached RigidBody
    71.  
    72.     private Turn _turn;
    73.     private Forward _forward;
    74.     private Turn _strafe;
    75.     private bool _run;
    76.     private bool _jump;
    77.     private float distToGround;
    78.  
    79.     private State _state;
    80.  
    81.  
    82.     //Called before the script starts
    83.     public void Awake() {
    84.         _myTransform = transform;
    85.         _rigidBody = GetComponent<Rigidbody> ();
    86.         distToGround = collider.bounds.extents.y;
    87.      
    88.         _state = EnemyAdvancedMovement.State.Init;
    89.     }
    90.  
    91.     // Use this for initialization
    92.     IEnumerator Start () {
    93.         while (true) {
    94.             switch(_state) {
    95.             case State.Init:
    96.                 Init ();
    97.                 break;
    98.             case State.Setup:
    99.                 Setup ();
    100.                 break;
    101.             case State.Run:
    102.                 ActionPicker();
    103.                 break;
    104.              
    105.             }
    106.             yield return null;
    107.          
    108.         }
    109.     }
    110.  
    111.     void Update() {
    112.         _rigidBody.AddForce (transform.forward * runMultiplier);
    113.     }
    114.  
    115.     private void Init() {
    116.         if(!GetComponent<Rigidbody>())return;
    117.         if(!GetComponent<Animation>())return;
    118.      
    119.         _state = EnemyAdvancedMovement.State.Setup;
    120.     }
    121.     private void Setup() {
    122.         animation.Stop ();                                        //stop any animations that might be set to play automatically
    123.         animation.wrapMode = WrapMode.Loop;                        //set all animations to loop by default
    124.         //        animation [jumpAnimName].layer = 1;                        //move jump to a higher layer
    125.         animation [jumpAnimName].wrapMode = WrapMode.Once;        //set jump to only play once
    126.         animation.Play(idleAnimName);                            //start the idle animation when the script starts
    127.      
    128.         _moveDirection = Vector3.zero;                            //zero our the vector3 we will use for moving our player
    129.         _turn = EnemyAdvancedMovement.Turn.none;
    130.         _forward = EnemyAdvancedMovement.Forward.none;
    131.         _strafe = Turn.none;
    132.         _run = true;
    133.         _jump = false;
    134.      
    135.         _state = EnemyAdvancedMovement.State.Run;
    136.     }
    137.  
    138.     private void ActionPicker() {
    139.         //allow the player to turn left and right
    140.         _myTransform.Rotate(0, (int)_turn * Time.deltaTime * rotateSpeed, 0);
    141.      
    142.      
    143.      
    144.         //if we are on the ground, let us move
    145.         if (_rigidBody) {
    146.             //reset the air time if we are on the ground
    147.             airTime = 0;
    148.          
    149.          
    150.             //get the user input if we should be moving forward or sideways
    151.             //we will calculate a new vector3 for where the player needs to be
    152.             _moveDirection = new Vector3((int)_strafe,0, (int)_forward);
    153.             _moveDirection = _myTransform.TransformDirection(_moveDirection).normalized;
    154.             _moveDirection *= walkSpeed;
    155.          
    156.             if(Input.GetKeyDown(KeyCode.Slash)) {          
    157.                 doRun = !doRun;                              
    158.             }
    159.             if(_forward != Forward.none) {  
    160.                 if(_run) {              
    161.                     _moveDirection *= runMultiplier;        //move user at run speed
    162.                     Run();                                    //play run animation
    163.                 }
    164.                 else {
    165.                     Walk();                                    //play walk animation
    166.                 }
    167.             }
    168.             else if(_strafe != EnemyAdvancedMovement.Turn.none) {
    169.                 Strafe ();
    170.             }
    171.             else {
    172.                 Idle ();                                    //play idle animation
    173.             }
    174.          
    175.             if(_jump) {                                        //if the user presses the jump key
    176.                 if(airTime < jumpTime) {                    //if we have not already been in the air to long
    177.                     _moveDirection.y += jumpHeight;            //move them upwards
    178.                     Jump ();                                //play jump animation
    179.                     _jump = false;
    180.                 }
    181.             }
    182.          
    183.         }
    184.         else {
    185.             if((_collisionFlags & CollisionFlags.CollidedBelow) == 0) {
    186.                 airTime += Time.deltaTime;
    187.              
    188.                 if(airTime > fallTime) {
    189.                     Fall();
    190.                 }
    191.             }
    192.          
    193.         }
    194.      
    195.         //_moveDirection.y -= gravity * Time.deltaTime;
    196.      
    197.         //_collisionFlags =
    198.         //_rigidBody.AddForce (transform.forward * runMultiplier);
    199.     }
    200.  
    201.     public void MoveMeForward(Forward z) {
    202.         _forward = z;
    203.     }
    204.  
    205.     public void ToggleRun() {
    206.         _run = !_run;
    207.     }
    208.  
    209.     public void RotateMe(Turn y) {
    210.         _turn = y;
    211.     }
    212.  
    213.     public void Strafe(Turn x) {
    214.         _strafe = x;
    215.     }
    216.  
    217.     public void JumpUp() {
    218.         _jump = true;
    219.     }
    220.  
    221.     public void Idle() {
    222.         if(idleAnimName == null)
    223.             return;
    224.         animation.CrossFade(idleAnimName);
    225.     }
    226.  
    227.     public void Walk() {
    228.         if(walkAnimName == null)
    229.             return;
    230.         animation [walkAnimName].speed = 2;
    231.         animation.CrossFade(walkAnimName);
    232.     }
    233.  
    234.     public void Run () {
    235.         if(runAnimName == null)
    236.             return;
    237.      
    238.         animation [runAnimName].speed = 1.5f;
    239.         animation.CrossFade(runAnimName);
    240.     }
    241.  
    242.     public void Jump () {
    243.         if(jumpAnimName == null)
    244.             return;
    245.         animation.CrossFade(jumpAnimName);
    246.     }
    247.  
    248.     public void Strafe () {
    249.         if(runAnimName == null)
    250.             return;
    251.         animation.CrossFade(runAnimName);
    252.     }
    253.  
    254.     public void Fall () {
    255.         if(fallAnimName == null)
    256.             return;
    257.         animation.CrossFade(fallAnimName);
    258.     }
    259.  
    260.     public void AttackOne() {
    261.         if(attackAnimName1 == null)
    262.             return;
    263.         animation.CrossFade(attackAnimName1);
    264.     }
    265.  
    266.     public void AttackTwo() {
    267.         if(attackAnimName2 == null)
    268.             return;
    269.         animation.CrossFade(attackAnimName2);
    270.     }
    271.  
    272.     public bool IsGrounded() {
    273.         return Physics.Raycast(transform.position, - Vector3.up ,distToGround + 0.1f);
    274.     }
    275. }
     
    Last edited: Jun 11, 2014
  6. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
    Hmm okay, so yea, if I take off gravity they just go flying at me, LOL. Can not figure this one out :( Still pretty new to C#
     
  7. Ereous

    Ereous

    Joined:
    Aug 29, 2012
    Posts:
    163
    Not sure where your telling them to move. But if you want to move with the rigidbody you want to use the rigidbody.AddForce.

    Example:
    Code (CSharp):
    1.  _targetVelocity = new Vector3(1, 0, 1);
    2.         _targetVelocity = transform.TransformDirection(_targetVelocity);
    3. Vector3 velocity = rigidbody.velocity;
    4.         Vector3 velocityChange = (_targetVelocity - velocity);
    5. //You can do clamping to limit how much is applied.
    6.         velocityChange.x = Mathf.Clamp(velocityChange.x, -maxVelocityChange, maxVelocityChange);
    7. rigidbody.AddForce(velocityChange, ForceMode.VelocityChange);
     
  8. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
    I use

    private Rigidbody _rigidBody;

    _rigidBody.AddForce (transform.forward)

    That is at the end of ActionPicker
    Right now it just kind of keeps gaing speed, then flies by me, turn around and start again
     
  9. chrisall76

    chrisall76

    Joined:
    May 19, 2012
    Posts:
    667
    Depending on your game, I would recommend using a navmesh for movement instead (it became free in the 4.x cycle).
    it's what I use, works great.
     
  10. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
    Woah, yea that looks awesome. Now to learn how to use it! haha
     
  11. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
    300?! I am now using navmeshagent, but whenever my animation plays, with 4 spawned I get 30FPS, 8 20FPS. Without animations it's 4 60FPS, 8 30FPS. Not a clue how you managed that! Any ideas?
     
  12. Ereous

    Ereous

    Joined:
    Aug 29, 2012
    Posts:
    163
    Did you change the colliders to Capsule Colliders and remove all the CharacterController items? If you just added rigidbody but still used the Character controller its kind of pointless.

    Its hard to know whats wrong with very small pieces of information.
     
  13. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
  14. chrisall76

    chrisall76

    Joined:
    May 19, 2012
    Posts:
    667
    Might want to update your script so we can see what you have now.
    I know it's possible to make this work, as I have with a AI package I built (not released yet though, having problems getting the interface working).
    http://forum.unity3d.com/threads/wip-quick-ai.242949/
     
  15. JoeCBS

    JoeCBS

    Joined:
    Feb 25, 2013
    Posts:
    41
    I have fixed it now, it was all of my Debugs. Thanks to Ereous! Thanks a ton for all the help.