Search Unity

How to move multiple enemies independently towards different target positions

Discussion in 'Scripting' started by juliushg, Apr 27, 2015.

  1. juliushg

    juliushg

    Joined:
    Mar 27, 2015
    Posts:
    18
    (title edited, formerly said "towards one object")

    I got this code in the script attached to every Enemy gameObject:

    (edited because a mistake)

    Code (CSharp):
    1. public static bool isEnemyMoving = false; // static because other objects have to wait until this finish
    2. public Vector3 targetEPosition;
    3.  
    4.   void Update () {
    5.  
    6.   // enemyTurn is static from another script
    7.  
    8.     if (enemyTurn && !isPlayerMoving) {
    9.  
    10.       enemyDir = ChooseEnemyDir ((int)transform.position.x, (int)transform.position.z, enemyDir, (int)player.transform.position.x, (int)player.transform.position.z);
    11.  
    12.       enemyTurn = false;
    13.  
    14.       if (enemyDir == 1 & !isEnemyMoving) {
    15.  
    16.         targetEPosition = new Vector3 (transform.position.x, transform.position.y, transform.position.z + 1);
    17.   isEnemyMoving = true;
    18.  
    19.       }
    20.  
    21.       if (enemyDir == 2 & !isEnemyMoving) {
    22.  
    23.       targetEPosition = new Vector3 (transform.position.x+1, transform.position.y, transform.position.z);
    24.   isEnemyMoving = true;
    25.  
    26.       }
    27.  
    28.       if (enemyDir == 3 & !isEnemyMoving) {
    29.  
    30.         targetEPosition = new Vector3 (transform.position.x, transform.position.y, transform.position.z - 1);
    31.   isEnemyMoving = true;
    32.  
    33.       }
    34.  
    35.       if (enemyDir == 4 & !isEnemyMoving) {
    36.  
    37.         targetEPosition = new Vector3 (transform.position.x - 1, transform.position.y, transform.position.z);
    38.   isEnemyMoving = true;
    39.  
    40.       }
    41.  
    42.  
    43.       if (isEnemyMoving) {
    44.  
    45.         transform.position = Vector3.MoveTowards (transform.position, targetEPosition,  speed*Time.deltaTime);
    46.  
    47.         if (transform.position == targetEPosition){
    48.           isEnemyMoving = false;
    49.  
    50.         }
    51.  
    52.       } // end if
    53.  
    54.     } // end update
    55.  
    56.     int ChooseEnemyDir (parameters) {
    57.  
    58.       // this function returns the direction chosen by the enemy, no part of the problem
    59.  
    60.     }
    This code works for me when there is only one enemy active. But if I add more objects, others than the first behave towards a position x:0 y:0 z:0, and I'm positive that the problem is the variable targetEPosition, that results affected by every iteration of the code. The first enemy behaves correctly.

    How can I make that variable value independent for every object?
     
    Last edited: Apr 27, 2015
  2. proandrius

    proandrius

    Unity Technologies

    Joined:
    Dec 4, 2012
    Posts:
    544
    Your all if statements from line 14 to line 40 does the same thing.
     
  3. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    The problem is isEnemyMoving, which is static because (according to the comment) everybody else needs to wait until one enemy is done moving. That's what the code says to do, and from your description, that's what they're doing.

    So, if that's not actually what you want, then take out isEnemyMoving. (And as @proandrius points out, you can greatly simplify the code too by noting that all the if blocks do the same thing.)
     
  4. juliushg

    juliushg

    Joined:
    Mar 27, 2015
    Posts:
    18
    Ok, two things, I've edited the code, I just copy the first "if" to simplify and later decided to copy the 3 directions left, so my bad.

    @JoeStrut that's what I want, that everybody else waits until one enemy is done moving, so I can't take isEnemyMoving out.

    Now, the lines are correct, the code does what I want with the first enemy, but the rest of them behaves incorrectly. Because targetEPosition is turning to 0, 0, 0 with the enemies after the first.

    That makes me thing that there's something wrong with that variable, whose value has to be independent for every execution of the code of different game objects. What do you think the error is?
     
  5. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    The problem is that you're setting targetEPosition inside an "if" block that says "only do this if no other enemy is moving."

    So it doesn't seem at all surprising to me that the other enemies don't do this while another enemy is moving.

    Your theory that targetEPosition is somehow not "independent for every execution of the code of different game objects" is simply incorrect. That's not it at all.

    Perhaps you want to set targetEPosition outside the if-block, so that the target always gets set. But put a proper check around the updating of the actual transform.position instead, so that only one enemy actually moves. I'm not sure, because I'm still not entirely clear on what you're trying to accomplish here.
     
  6. juliushg

    juliushg

    Joined:
    Mar 27, 2015
    Posts:
    18
    What I'm trying to accomplish is: a turn based board like game. I move the player, then all other enemies make their move, one cell at a time each. But because of the code, only one enemy makes the movement correctly. Others not.

    Because is a grid like movement, it's not proper to set the movement targeting always the player. Every enemy, in every move, has to target one specific cell, decided by the DecideEnemyDir function, and because it's a maze, the next move is decided logically, not physically. Something like the movement of the Pacman ghosts, only that this is turn based. Please notice that the logic of the function I wrote to decide the next move is correct and works well with only one enemy, so my problem is about the structure of the code that executes the movement.

    I almost understand your idea of taking out the variable. But I think that I still don't understand the correct mechanic of the update with the shared script, do they execute the script simultaneously? Maybe I'm supposing that the execution is one after another,and that's why the targetEPosition doesn't gets established for all gameObjects? Working on that.
     
  7. JoeStrout

    JoeStrout

    Joined:
    Jan 14, 2011
    Posts:
    9,859
    OK, when you have the same (or different) scripts assigned to multiple game objects, the Update() method of each one gets called in turn, in no particular order.

    So, here's how I would tackle this, assuming my script is called EnemyMovement:

    1. Make a static property "static EnemyMovement curMover". This will be a reference to the particular instance of the script that should currently be moving. Any other properties you need should not be static.

    2. In the Update method, structure it like this:

    Code (CSharp):
    1. if (curMover == null) {
    2.     // nobody's moving, so I guess it's my turn!
    3.     curMover = this;
    4. }
    5. if (curMover == this) {
    6.     // I'm the one that's moving!
    7.     MoveTowardsPlayer();
    8.     if (DoneMoving()) curMover = null;   // all done!
    9. }
    ...where MoveTowardsPlayer is a method that calls ChooseDir (if needed) and updates the transform, and DoneMoving is a method that returns true when this enemy is done with its turn.
     
  8. juliushg

    juliushg

    Joined:
    Mar 27, 2015
    Posts:
    18
    Thanks, I will implement this approach and report the result.
     
  9. juliushg

    juliushg

    Joined:
    Mar 27, 2015
    Posts:
    18
    Well, it worked; of course I had to modify the whole script structure as you said and voila! The only issue left is that after the first player movement, all enemies move two cells at once each, after that, they behave correctly, one cell at a time, but I suppose is something I missed. I'll try to fix it tomorrow and if I can't find the bug, I'll ask; so please keep watching this. Thanks Joe Strout!
     
    JoeStrout likes this.