Search Unity

Help with enemyAI for a 2D classic beat em up

Discussion in 'Scripting' started by gdossantos87, Mar 31, 2016.

  1. gdossantos87

    gdossantos87

    Joined:
    Mar 18, 2014
    Posts:
    43
    heló fellow unity developers, this is my first big project beside making classic arcade remakes in unity like space invaders, pac man and some mini game made for educational purpose, this time i'm trying to make a 2D beat em up style game like street of rage and final fight, i have a basic enemyAI that looks for the player, attacks the player plays animations hits the player and dies, i will like to add a condition that ask how many enemies are attacking the player, of there is more than 2 enemies attacking the other players should wait, do you guys have any idea how to accomplish this?? thanks for your time.

    Code (csharp):
    1.  
    2. using UnityEngine;
    3. using System.Collections;
    4.  
    5. public class Enemy : MonoBehaviour
    6. {
    7.  
    8.     public Transform playerTransform;
    9.  
    10.     //public GameObject player;
    11.     public float currentSpeed;
    12.  
    13.     //float enemyDistanceFromPlayer = 2f;
    14.     bool isFacingThePlayer = false;
    15.     bool isOnRange = false;
    16.  
    17.     Animator enemyAnim;
    18.     SpriteRenderer enemySprite;
    19.  
    20.     // Use this for initialization
    21.     void Awake()
    22.     {
    23.  
    24.         playerTransform = GameObject.FindGameObjectWithTag("Player").transform;
    25.         enemySprite = GetComponentInChildren<SpriteRenderer>();
    26.         enemyAnim = GetComponent<Animator>();
    27.     }
    28.  
    29.     // Update is called once per frame
    30.     void Update()
    31.     {
    32.  
    33.         //increase or decrease sorting layer depending on enemy position
    34.         enemySprite.sortingOrder = (int)(transform.position.y * -1);
    35.  
    36.  
    37.         if (isOnRange )
    38.         {
    39.             //if isOnRange is true the enemy stops moving so he can attack in its current position
    40.             transform.position = new Vector2(transform.position.x, transform.position.y);
    41.         }
    42.         else
    43.         {
    44.             //else look for the player
    45.             transform.position = Vector2.MoveTowards(transform.position, playerTransform.position, currentSpeed * Time.deltaTime);
    46.          
    47.  
    48.         }
    49.  
    50.         //this variable detects player position so the sprite always faces the enemy
    51.         float localOffset = transform.localPosition.x - playerTransform.transform.localPosition.x;
    52.         //si el jugador esta del lado derecho y no esta mirando al player
    53.  
    54.  
    55.         if (localOffset < 0 && !isFacingThePlayer)
    56.         {
    57.             Flip();
    58.         }
    59.         else if (localOffset > 0 && isFacingThePlayer)
    60.         {
    61.             Flip();
    62.         }
    63.  
    64.     }
    65.  
    66.  
    67.     //Flip method
    68.     void Flip()
    69.     {
    70.         isFacingThePlayer = !isFacingThePlayer;
    71.         Vector3 theScale = enemySprite.transform.localScale;
    72.         theScale.x *= -1;
    73.         enemySprite.transform.localScale = theScale;
    74.     }
    75.  
    76.     //if player is detected by the collider
    77.     void OnTriggerEnter2D(Collider2D col)
    78.     {
    79.         if (col.gameObject.tag == "Player")
    80.         {
    81.  
    82.             enemyAnim.SetBool("isAttacking", true);
    83.             isOnRange = true;
    84.         }
    85.     }
    86.  
    87.     //if player is not detected by the collider
    88.     void OnTriggerExit2D(Collider2D col)
    89.     {
    90.         if (col.gameObject.tag == "Player")
    91.         {
    92.             enemyAnim.SetBool("isAttacking", false);
    93.             isOnRange = false;
    94.         }
    95.     }
    96.  
    97.     public void SetSpeed(float speed)
    98.     {
    99.         currentSpeed = speed;
    100.     }
    101.  
    102.     public void StrikeCurrentTarget(float damage)
    103.     {
    104.         if (playerTransform)
    105.         {
    106.             Health health = playerTransform.GetComponent<Health>();
    107.             if (health)
    108.             {
    109.                 health.DealDamage(damage);
    110.                 //if (health.isDead)
    111.                 //{
    112.                 //    playerTransform = null;
    113.                 //}
    114.             }
    115.         }
    116.     }
    117. }
    118.  
    119.  
     
  2. Zaladur

    Zaladur

    Joined:
    Oct 20, 2012
    Posts:
    392
    There are a few approaches. You could set up another class that tracks all enemies who are in range to attack the player. When a player enters attack range, add them to the List of enemies contained in this class. When an enemy dies or leaves attack range, remove them from the List.

    Whenever you add or subtract an enemy from the list, just run a method that sets up to the first two enemies to attacking. Make sure to disable the attacking of an enemy when you remove them from the list for whatever reason.

    This changes if you want enemies to alter attacks with no more than 2 attacking at a time. In that case, you could use a queuing system.
     
  3. ericbegue

    ericbegue

    Joined:
    May 31, 2013
    Posts:
    1,353
    In AI, you can use a blackboard to coordinate the action of your entities. A blackboard is basically a writable/readable space that is shared between different entities. Each entity can add or removed information to the blackboard in order for the other entities to consider this information to make their decision. So the number of enemies currently attacking the player could be an information retrieve from the blackboard.

    What @Zaladur proposed, could be seen as a blackboard. Each enemy would register itself while attacking the player and unregister itself when its attack is done. The blackboard would have a method to return the number of enemies currently attacking the player. This method would be used by the other enemies to decide whether to attack the player or not.

    This is not directly related to your problem, but I see that you are coding you AI in plain C#. Coding this way will make your code harder to read, therefore to debug, as your AI grows in complexity. If you want to learn more about AI techniques, I would suggest to have a look at Behaviour Tree. As a programmer, it's a great technique to add at your tool belt (next to Finite State Machine).

    I made a script-based Behaviour Tree engine: Panda BT. It's available here:

    http://www.pandabehaviour.com

    Let me know if you have any question about using this tool.