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

How to make 2D AI?

Discussion in 'Scripting' started by b4gieta, Mar 17, 2019.

  1. b4gieta

    b4gieta

    Joined:
    Jul 17, 2018
    Posts:
    97
    Hi
    I'm trying to do enemy in 2D game. I've tried many tutorials. Literally, everything doesn't work. I just want my enemy to move between two waypoints and detect if it's walking left or right.
     
  2. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    If this was literally true, then you would have stumbled across an answer. :) It may be worth giving an example of what, exactly, you have tried and what the problem is. Including things like complete error messages showing line numbers can be very helpful. It is useful for you to learn and for others to help you.

    However, here is a simple script to patrol across a range from a left hand point. You will have to find a way to adapt it to your needs but I hope it helps.
    Code (CSharp):
    1. public class Test : MonoBehaviour
    2. {
    3.     void Start()
    4.     {
    5.         // Ensure that xRight is to the right of xLeft.
    6.         xRight = xLeft + Mathf.Abs(xRange);
    7.     }
    8.  
    9.     void Update()
    10.     {
    11.         bool changeDirection = false;
    12.  
    13.         if(walkSpeed > 0f)
    14.         {   // Have we walked too far right?
    15.             changeDirection = transform.position.x >= xRight;
    16.         }
    17.         else
    18.         {   // Have we walked too far left?
    19.             changeDirection = transform.position.x <= xLeft;
    20.         }
    21.  
    22.         if(changeDirection)
    23.             walkSpeed = -walkSpeed;
    24.  
    25.         transform.Translate(walkSpeed, 0f, 0f);
    26.     }
    27.  
    28.     [SerializeField] [Range(0.5f, 2f)] float walkSpeed = 0.5f;
    29.     [SerializeField] float xLeft = 0f;
    30.     [SerializeField] [Range(0.5f, 100f)] float xRange = 5f;
    31.     float xRight;
    32. }
     
  3. b4gieta

    b4gieta

    Joined:
    Jul 17, 2018
    Posts:
    97
    Yeah, it works, thanks. But I have one more question. How can I make enemy's sprite scaled to left? I tried
    Code (CSharp):
    1. if (walkSpeed < 0)
    2.         {
    3.             transform.right = Vector2.left;
    4.         }
    But, logically, it scales whole character, so he walks right, but scaled? Any idea?
     
  4. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Do you mean that the sprite is being rotated but you instead want it flipped? If so, then you could either try this method, or, if you want to flip only the graphics, then you can adjust the flip flag in the renderer.

    Incidentally, I've just realised that I did not multiply the walk speed in the
    Translate
    above by
    Time.deltaTime
    . You may want to add that in to smooth out the animation effect.
     
  5. b4gieta

    b4gieta

    Joined:
    Jul 17, 2018
    Posts:
    97
    Second method can rotate only one object, and whole object is about 20 object (etc. arm -> forearm -> hand) so it's useless for me. First method works but after facing left (when character is flipped) and keeps flipping as long as it don't touch minimum value of range. The code is:

    Code (CSharp):
    1. void Flip()
    2.     {
    3.         // Multiply the player's x local scale by -1
    4.         Vector3 theScale = transform.localScale;
    5.         theScale.x *= -1;
    6.         transform.localScale = theScale;
    7.     }
    8.  
    9. //some other code
    10.  
    11.         if (walkSpeed < 0)
    12.         {
    13.             facingRight = true;
    14.             Flip();
    15.         }
    16.  
    17.         else if (walkSpeed > 0)
    18.         {
    19.             facingRight = false;
    20.         }
    I've tried also
    Code (CSharp):
    1.  
    2.         if (!facingRight)
    3.         {
    4.             Flip();
    5.             facingRight = false;
    6.         }
    7.  
    8.         else if (facingRight)
    9.         {
    10.             Flip();
    11.             facingRight = true;
    12.         }
    but then the enemy is flipping all the time
     
    Last edited: Mar 17, 2019
  6. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    First of all, your
    Flip
    method looks fine. Just to be sure, are you clear on how it is working? Do you understand the significance of the
    *= -1
    ?

    If you do follow it, then the issue is when exactly should Flip be called? To answer that, I would suggest you consider these 2 questions:
    1. What is (are) the key moment (moments) during the object's patrol at which it would be appropriate to call Flip?
    2. Given the code that I pasted above, can you see a point where a call to Flip would naturally go?
     
  7. b4gieta

    b4gieta

    Joined:
    Jul 17, 2018
    Posts:
    97
    Finally, everything is working. I decided to make flip at certain points, not at speed levels. I added maxRight which is public float set to value 10 bigger than xRange. It must be done in Unity Inspector, because in script (Visual Studio) you can't add 10 to non-static value. Final code is
    Code (CSharp):
    1. if (transform.position.x == maxRight)
    2.         {
    3.             Flip();
    4.             facingRight = false;
    5.         }
    6.  
    7.         else if (transform.position.x == xLeft)
    8.         {
    9.             Flip();
    10.             facingRight = true;
    11.         }
    Thanks to these two questions I found where bug is. Thanks!
     
    Doug_B likes this.
  8. Doug_B

    Doug_B

    Joined:
    Jun 4, 2017
    Posts:
    1,596
    Good stuff, I'm glad you figured it out. However, if I could make a couple of observations.

    First, you could have simply added a call to Flip inside the
    if
    (at line 22 in my post above). Of course, you would still need to run the current line 23 there as well which would require the use of curly braces to run both lines.

    Second- and more generally- when comparing floating point values, don't use equality (==). It is really not uncommon for this to not work as you expect. Instead use a comparison function; see here for more details.