Search Unity

  1. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Question Moving Enemy GameObjects between Positions Randomly

Discussion in '2D' started by DaveIsBrave, Oct 10, 2023.

  1. DaveIsBrave

    DaveIsBrave

    Joined:
    Oct 10, 2023
    Posts:
    7
    Hello Everyone

    I'm Fairly new to unity so I apologize if my question is silly.

    I wanted to create a 2D platformer enemy that moves between Positions A, B, C .. etc. I used a simple method to do so which is completely fine and working but it has one flaw though.. Its Static and each position the enemy will move to is hard coded which is fine for a simple enemy but in the game I'm building I will have many different types of enemies. This is the code I wrote:-

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Test : MonoBehaviour
    6. {
    7.     [SerializeField] private Transform startPos;
    8.     [SerializeField] private Transform pos1, pos2: // Adding more positions as needed.
    9.     [SerializeField] private float speed;
    10.     [SerializeField] private float startWaitTime;
    11.     [SerializeField] private float waitTime;
    12.  
    13.     private bool facingRight = true;
    14.     private Vector3 nextPos;
    15.  
    16.     void Awake()
    17.     {
    18.         nextPos = startPos.position;
    19.  
    20.     }
    21.  
    22.    
    23.     void Update()
    24.     {
    25.         if (transform.position == pos1.position)
    26.         {
    27.             if (waitTime <= 0) { nextPos = pos2.position; waitTime = startWaitTime; Flip(); }
    28.             else { waitTime -= Time.deltaTime; }
    29.  
    30.         }
    31.         else if (transform.position == pos2.position)
    32.         {
    33.             if (waitTime <= 0) { nextPos = pos1.position; waitTime = startWaitTime; Flip(); }
    34.             else { waitTime -= Time.deltaTime; }
    35.         }
    36.  
    37.         transform.position = Vector3.MoveTowards(transform.position, nextPos, speed * Time.deltaTime);
    38.  
    39.  
    40.     }
    41.  
    42.     private void Flip()
    43.     {
    44.         facingRight = !facingRight;
    45.         Vector3 Scaler = transform.localScale;
    46.         Scaler.x *= -1;
    47.         transform.localScale = Scaler;
    48.     }
    49. }
    50.  
    As I mentioned earlier the code is working fine and tested it on multiple positions, However.. I want my enemy to pick a position randomly and move towards it I don't want it to be dull as hell so I attempted this code:-

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Test : MonoBehaviour
    6. {
    7.     [SerializeField] private Transform startPos;
    8.     [SerializeField] private Transform pos1, pos2, pos3, pos4, pos5, pos6;
    9.     [SerializeField] private float speed;
    10.     [SerializeField] private float startWaitTime;
    11.     [SerializeField] private float waitTime;
    12.     [SerializeField] private Transform[] randomPos;
    13.  
    14.     int pickRandomPos;
    15.  
    16.     private bool facingRight = true;
    17.     private Vector3 nextPos;
    18.  
    19.     void Awake()
    20.     {
    21.         nextPos = startPos.position;
    22.         pickRandomPos = Random.Range(0, randomPos.Length);
    23.  
    24.     }
    25.  
    26.    
    27.     void Update()
    28.     {
    29.         if (transform.position == randomPos[pickRandomPos].position)
    30.         {
    31.             if (waitTime <= 0) { nextPos = randomPos[pickRandomPos].position; waitTime = startWaitTime;  Flip(); }
    32.             else { waitTime -= Time.deltaTime; }
    33.  
    34.         }
    35.         else if (transform.position == randomPos[pickRandomPos].position)
    36.         {
    37.             if (waitTime <= 0) { nextPos = randomPos[pickRandomPos].position; waitTime = startWaitTime; Flip(); }
    38.             else { waitTime -= Time.deltaTime; }
    39.         }
    40.  
    41.         transform.position = Vector3.MoveTowards(transform.position, nextPos, speed * Time.deltaTime);
    42.  
    43.  
    44.     }
    45.  
    46.     private void Flip()
    47.     {
    48.         facingRight = !facingRight;
    49.         Vector3 Scaler = transform.localScale;
    50.         Scaler.x *= -1;
    51.         transform.localScale = Scaler;
    52.     }
    53. }
    54.  
    I added an array and implemented the randomness logic but it didn't work for me because I cant figure out why! honestly I understand the concept but I think I'm not implementing it correctly.

    After so many attempts and reads i gave up on that code and decided to watch a tutorial and ended up with the following code:-

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Patrol : MonoBehaviour
    6. {
    7.  
    8.  
    9.     [SerializeField] private float currentSpeed;
    10.     [SerializeField] private float startWaitTime;
    11.     [SerializeField] private float waitTime;
    12.     [SerializeField] private Transform[] moveSpots;
    13.  
    14.     private int randomSpot;
    15.  
    16.     void Start()
    17.     {
    18.         randomSpot = Random.Range(0, moveSpots.Length);
    19.         //transform.LookAt(moveSpots[randomSpot]);
    20.     }
    21.  
    22.  
    23.     void Update()
    24.     {
    25.  
    26.         transform.position = Vector2.MoveTowards(transform.position, moveSpots[randomSpot].position, currentSpeed * Time.deltaTime);
    27.  
    28.         if (Vector2.Distance(transform.position, moveSpots[randomSpot].position) < 0.2)
    29.         {
    30.             if(waitTime <= 0)
    31.             {
    32.                 randomSpot = Random.Range(0, moveSpots.Length);
    33.                 //transform.LookAt(moveSpots[randomSpot]);
    34.                 waitTime = startWaitTime;
    35.             }
    36.             else { waitTime -= Time.deltaTime; }
    37.         }
    38.  
    39.     }
    40.  
    41. }
    42.  
    I added a few Positions to the array and the code worked pretty well but unfortunately I didn't know how to implement the Flip() function into that no matter what I did. The only semi successful attempt was playing around the Sprite Renderer Flip X bool but it only works when the Enemy is literally positioned on the 0 X axis so its really not a good solution.

    My request is for you to help me to make the first code pick a Position randomly or help me make my Character flip its dumb face in the last code.

    PS. I've tried to use LookAt() functionality but it made my character's Sprite disappear for unknown reasons.

    I appreciate your time and effort!
    looking forward to read your suggestions.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,240
    That's awesome! All you have is probably just a little bug, and here's how to track it down.

    ALSO: focus on getting it to MOVE correctly first, don't worry about the flipping / pointing part yet.

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    Visit Google for how to see console output from builds. If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer for iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    If your problem is with OnCollision-type functions, print the name of what is passed in!

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    "When in doubt, print it out!(tm)" - Kurt Dekker (and many others)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.


    -----------

    When you get the moving correct, then switching the facing is probably just:

    - if I'm moving left enough, face left
    - if I'm moving right enough, face right
    - otherwise either:
    ---> face the player or else
    ---> don't change how I already was facing.
     
  3. DaveIsBrave

    DaveIsBrave

    Joined:
    Oct 10, 2023
    Posts:
    7

    Oh wow! that's Hella lot of useful info about debugging that I didn't know about, thank you so much for that. Ill start working on it right away. As I'm reading your comment i think there is one thing never crossed my mind before.. I think my enemy gameObject doesn't know if it reached a position or not and that's why it never actually switch to another one. Ill try to implement something to check that and work accordingly.

    Again, thank you so much for the insight it helps a lot.
     
  4. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,240
    That's actually a SUPER-common problem... BUT...

    I think your code might be immune to that specific problem.

    Here's why:

    - you use MoveTowards

    - that means it won't overshoot

    - you check distance less than 0.2

    - That distance should become zero or at least waaaaay less than 0.2

    So... slap some debugs in there, see what's happening. I think you're close.

    EDIT: okay, I think I'm confused by what you've posted... perhaps you updated it. Hey, if it works, SHIP IT! MOVE ON! :)
     
  5. DaveIsBrave

    DaveIsBrave

    Joined:
    Oct 10, 2023
    Posts:
    7
    Mr. @Kurt-Dekker .. it is Done

    I decided to work on the last code since it was the closest to be fully working and thanks to your guidance and soooooo much debugging i managed to make my enemy patrol between a few positions and flip its face accordingly. Here is my final working code:-

    Code (CSharp):
    1. using System.Collections;
    2. using System.Collections.Generic;
    3. using UnityEngine;
    4.  
    5. public class Patrol : MonoBehaviour
    6. {
    7.  
    8.     [SerializeField] private float speed;
    9.     [SerializeField] private float startWaitTime;
    10.     [SerializeField] private float waitTime;
    11.     [SerializeField] private Transform[] Position;
    12.  
    13.     private int randomPos;
    14.     private bool facingRight = true;
    15.     private bool isMoving = true; //Might use later for chasing player
    16.  
    17.     void Awake()
    18.     {
    19.         randomPos = Random.Range(0, Position.Length);
    20.     }
    21.  
    22.     void Update()
    23.     {
    24.  
    25.         transform.position = Vector2.MoveTowards(transform.position, Position[randomPos].position, speed * Time.deltaTime);
    26.  
    27.         if (Vector2.Distance(transform.position, Position[randomPos].position) < 0.2)
    28.         {
    29.             if (waitTime <= 0)
    30.             {
    31.                 isMoving = true;
    32.                 randomPos = Random.Range(0, Position.Length);
    33.                 waitTime = startWaitTime;
    34.             }
    35.             else { waitTime -= Time.deltaTime; isMoving = false; }
    36.         }
    37.  
    38.         FlipTheDamnFace();
    39.     }
    40.  
    41.     private void FlipTheDamnFace()
    42.     {
    43.         if (transform.position.x > Position[randomPos].position.x && facingRight == true) Flip();
    44.         if (transform.position.x < Position[randomPos].position.x && facingRight == false) Flip();
    45.     }
    46.  
    47.     private void Flip()
    48.     {
    49.         facingRight = !facingRight;
    50.         Vector3 Scaler = transform.localScale;
    51.         Scaler.x *= -1;
    52.         transform.localScale = Scaler;
    53.     }
    54.  
    55. }
    56.  
    Edit: I just basically did it the simplest way like I did my Player and compared the position of the enemy with the position it's heading to.

    I appreciate your help!
    Thank you.
     
    Kurt-Dekker likes this.