Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. We have updated the language to the Editor Terms based on feedback from our employees and community. Learn more.
    Dismiss Notice

Make a boss dash past the player's position, then move the other way dropping projectiles...

Discussion in 'Scripting' started by SilverFang180882, Jun 6, 2020.

  1. SilverFang180882

    SilverFang180882

    Joined:
    Mar 30, 2020
    Posts:
    35
    Hello,

    So, I've created a giant boss who moves in the background, patrolling left and right. I'm trying to create a special attack where:

    1) The boss will quickly dash to the end of her perimeter in the direction of the player in relation to herself.
    2) Once the boss reaches this boundary, she'll start moving toward the opposite boundary at a lesser pace, dropping projectiles along the way.

    Now, while my player is to the boss's extreme left or right, outside her movement perimeter, the attack will perform exactly as wanted. My problem is, if the player is within her movement perimeter the boss often gets jammed on the player's last position.

    I've adjusted the code many times, and no matter what I try, it still seems to keep happening one way or another.

    This controls her patrol movement (stored in the update function):

    Code (CSharp):
    1. if (!dash || !bladeDrop || !chosenDirection)
    2.         {
    3.             if (transform.position.x < leftBoundary.transform.position.x)       //If boss reaches the left boundary
    4.                 moveRight = true;       //Move right
    5.             else if (transform.position.x > rightBoundary.transform.position.x)     //If boss reaches the right boundary
    6.                 moveRight = false;      //Move left
    7.  
    8.             if (moveRight)      //If boss is moving right
    9.             {
    10.                 GetComponent<Rigidbody2D>().velocity = new Vector2(moveSpeed, GetComponent<Rigidbody2D>().velocity.y);      //Move boss right
    11.             }
    12.             else               //If boss is moving left
    13.             {
    14.                 GetComponent<Rigidbody2D>().velocity = new Vector2(-moveSpeed, GetComponent<Rigidbody2D>().velocity.y);     //Move boss left
    15.             }
    16.         }
    The code which triggers the dash is as follows:

    Code (CSharp):
    1. if (!chosenDirection)
    2.                 {
    3.                     playerPosition = thePlayer.transform.position.x;
    4.                     dash = true;
    5.                     chosenDirection = true;
    6.                 }
    and

    Code (CSharp):
    1. if(dash)
    2. Dash();
    Within the dash function:

    Code (CSharp):
    1.  
    2.         if (playerPosition <= transform.position.x)      //If the player is on the left
    3.             {
    4.            
    5.             StartCoroutine("BladeDropEastwardCo");
    6.         }
    7.         else if (playerPosition >= transform.position.x)     //If the player is on the right
    8.         {
    9.                 StartCoroutine("BladeDropWestwardCo");
    10.         }
    One of the blade drop coroutines (the other is exactly the same, but for the opposite direction):

    Code (CSharp):
    1. public IEnumerator BladeDropEastwardCo()
    2.     {
    3.         StopCoroutine("PatrolCo");      //Stops the patrol timer while this coroutine is running
    4.         bladeDrop = true;
    5.  
    6.         if (dash)
    7.         {
    8.             transform.position = Vector3.MoveTowards(transform.position, leftBoundary.transform.position, 3 * moveSpeed * Time.deltaTime);     //Dash to the left boundary
    9.  
    10.             if (transform.position.x <= leftBoundary.transform.position.x)
    11.             {
    12.                 dash = false;
    13.             }
    14.         }
    15.  
    16.         if (!dash && bladeDrop)
    17.         {
    18.  
    19.             transform.position = Vector3.MoveTowards(transform.position, rightBoundary.transform.position, moveSpeed * Time.deltaTime);     //Move to the right boundary
    20.  
    21.             GameObject droppingBlade1 = Instantiate(shootingBlade, new Vector3(transform.position.x + 0.5f, transform.position.y + 4, transform.position.z), transform.rotation) as GameObject;      //Create first spinning blade
    22.             yield return new WaitForSeconds(bladeShootRate);        //Set the timer before the next blade shoots
    23.             bladeShootRate = bladeShootRateStore;       //Resets the blade shoot rate timer
    24.  
    25.             GameObject droppingBlade2 = Instantiate(shootingBlade, new Vector3(transform.position.x + 0.5f, transform.position.y + 4, transform.position.z), transform.rotation) as GameObject;      //Create first spinning blade
    26.             yield return new WaitForSeconds(bladeShootRate);        //Set the timer before the next blade shoots
    27.             bladeShootRate = bladeShootRateStore;       //Resets the blade shoot rate timer
    28.  
    29.             GameObject droppingBlade3 = Instantiate(shootingBlade, new Vector3(transform.position.x + 0.5f, transform.position.y + 4, transform.position.z), transform.rotation) as GameObject;      //Create first spinning blade
    30.             yield return new WaitForSeconds(bladeShootRate);        //Set the timer before the next blade shoots
    31.             bladeShootRate = bladeShootRateStore;       //Resets the blade shoot rate timer
    32.  
    33.             patrolTime = patrolPeriod;      //Resets patrol time
    34.             bladeDrop = false;
    35.             chosenDirection = false;
    36.         }
    37.     }
    I do apologise if my code is a bit messy and certain boolean adjustments are out of order or in wrong places; I've been changing them around so many times, but with very little difference in the results. I'm at my wit's end trying to figure this out, and even get lost within the script now (not an issue I had when scripting this same boss's three other attacks).

    It puzzles me even more because I created another enemy with similar behaviour. If this other boss gets shot by the player's projectile while patrolling, he'll retreat to the end of his perimeter away from the player, then charge towards the player until he reaches the opposite side. I got this boss to work as I wanted, and based the above code on this, but I'm getting much messier results.

    Thanks in advance.
     
  2. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    36,971
    It's gonna be hard for any third party to reason about this, as it will obviously be highly dependent on your own expectations.

    To get additional insight I suggest you put some Debug.Log() statements in here and there in the code. This will let you see what parts of the code are actually running when the problem condition arises. It is most likely just a condition that is testing for true that you either a) didn't realize, or b) didn't expect to be true anymore. Putting in Debug.Log() statements may help you find where it is going wrong.
     
  3. SilverFang180882

    SilverFang180882

    Joined:
    Mar 30, 2020
    Posts:
    35
    The above code are the only ones which affect the boss's movement. I had initially thought it was the statement which determines whether the boss should do the left dash or the right, but I've even tried disabling one of them and staying on the opposite side. The boss WILL dash past the player, but won't do the projectile attack (but it will if the player was outside her perimeter). But worse, when moving back past that position, she'll get stuck again. I'm truly at my wit's end trying to find out what's causing this to happen. Disabling things just changes when it happens.

    Instead of adding Debugs, I set my conditions to public, and they are switching on and off when they're supposed to, just that the boss continues getting stuck no matter how much I change things around.
     
  4. Cannist

    Cannist

    Joined:
    Mar 31, 2020
    Posts:
    64
    Code (CSharp):
    1. if (!dash || !bladeDrop || !chosenDirection)
    Should those
    ||
    be
    &&
    ?
     
  5. SilverFang180882

    SilverFang180882

    Joined:
    Mar 30, 2020
    Posts:
    35
    No, I want them to be "Or". As it is (might need tidying once I get it to work properly), those three conditions switch on and off during different stages of the special attack. I want the patrolling to be disabled throughout the duration of the process.
     
  6. Cannist

    Cannist

    Joined:
    Mar 31, 2020
    Posts:
    64
    Indeed, which is why I suggest the "And". All your booleans are negated in the disjunction. So as soon as one of the booleans is false, the whole expression becomes true and the code gets executed.

    Note that if you want to negate an expression like (a OR b) you cannot simply negate a and b and leave the rest untouched. Instead you use DeMorgan's laws, which state that

    NOT (a OR b) = (NOT a) AND (NOT b)
    and
    NOT (a AND b) = (NOT a) OR (NOT b)

    In your case I assume you want
    !(dash || bladeDrop || chosenDirection)

    which is equivalent to
    !dash && !bladeDrop && !chosenDirection


    If this still does not convince you (after all, I might misunderstand your intention) I suggest you put some
    Debug.Log
    in the body of that if-statement and observe if it actually is only executed when you intend it to.
     
  7. SilverFang180882

    SilverFang180882

    Joined:
    Mar 30, 2020
    Posts:
    35
    Ok, I started everything again. I don't think the problem's with the patrol code, or even the coroutines. It's primary the whole statement involving the player's position.

    Here's what I've changed:

    Code (CSharp):
    1.  
    2. public void Dash()
    3. {
    4.         if (playerPosition <= transform.position.x)
    5.         {
    6.             DashLeft();
    7.         }
    8.         else if (playerPosition >= transform.position.x)
    9.         {
    10.             DashRight();
    11.         }
    12.     }
    Code (CSharp):
    1. public void DashLeft()
    2.     {
    3.         Debug.Log("Going Left");
    4.         transform.position = Vector3.MoveTowards(transform.position, leftBoundary.transform.position, 3 * moveSpeed * Time.deltaTime);     //Dash to the left boundary
    5.     }
    (Again, "GoingRight" is exactly the same, but in the opposite direction)

    With the rest of the special attack removed, I'm literally just trying to get the boss to dash past the player if he's within her perimeter. With the above code, the boss reaches the "playerPosition", then suddenly returns to her patrolling speed (instead of dashing all the way to the left boundary), and keeps moving left past the boundary (this is because I haven't set dash off yet).

    It seems the statement for dashing left and right is running continuously, even when I have the detection for player position switched off using this:

    Code (CSharp):
    1. if (!chosenDirection)
    2.                 {
    3.                     playerPosition = thePlayer.transform.position.x;
    4.                     dash = true;
    5.                     chosenDirection = true;
    6.                 }
    Seeing as chosenDirection is never switched back to false anywhere in my code anymore, I don't know why it's running the function over and over. I only want it to check the player's position once, store that (playerPosition float), then move the boss towards whichever boundary is in the player's direction.

    EDIT: A quick updated. I just tried adding "Dash()" into the coroutine which switches the dash condition to true. Granted, the debug for "Going Left" will only activate once now, but the boss won't even perform the fast movement anymore; she'll just continue at her normal patrol speed, and continue past the boundary off into the distance. It's strange because, as can be seen above, the "Going Left" debug is in the same function as the fast movement, so I don't understand how it's performing one but not the other.
     
    Last edited: Jun 7, 2020