Search Unity

Proper settings for Worm Boss movement

Discussion in 'Scripting' started by Emolk, Dec 6, 2019.

  1. Emolk

    Emolk

    Joined:
    Feb 11, 2014
    Posts:
    241
    Hi. So i have tried to implement the worm boss from Terraria into my 2D platformer. Basically it works by the head moves and the tail parts all follow the previous tail section and thus forming a link/chain.

    Currently it works like a 'homing missile' in that it rotates itself. So the head moves as thus:

    Code (CSharp):
    1. void HeadMovement(){
    2.  
    3.         Vector2 direction = (Vector2)target.transform.position - body.position;
    4.         direction.Normalize ();
    5.         float rotateAmount = Vector3.Cross (direction, transform.up).z;
    6.         body.angularVelocity = -rotateAmount * rotateSpeed;
    7.         body.velocity = transform.up * movementSpeed;
    8.     }
    and the tail parts as thus:

    Code (CSharp):
    1. void Movement(){
    2.         Vector2 direction = (Vector2)nextTail.transform.position - body.position;
    3.         direction.Normalize ();
    4.         float rotateAmount = Vector3.Cross (direction, transform.up).z;
    5.         body.angularVelocity = -rotateAmount * rotateSpeed;
    6.         body.velocity = transform.up * movementSpeed;
    7.     }
    This mostly works, however if i increase the movespeed or rotate speed it bugs out. I want the boss to have a high speed but a low rotate speed, so that it makes 'passes' at Players in that it tries to hit the Player then swings back by rotating slowly. But my code just flat out bugs out at high speeds because the tails keep getting separated.

    I have also tried to just use Vector3.MoveTowards (shown below) for the tail sections movement but the tails also seem to get separated here.

    Code (CSharp):
    1. void BodyMovement(){
    2.  
    3.         int i = 0;
    4.  
    5.         foreach (var body in bodies)
    6.         {
    7.             if (i == 0){
    8.                 body.transform.position = Vector3.MoveTowards(body.transform.position, transform.position, speed);
    9.             }
    10.             else{
    11.                 body.transform.position = Vector3.MoveTowards(body.transform.position, bodies[i-1].transform.position, bodySpeed);
    12.             }
    13.             i++;
    14.         }
    15.     }
    Also help to smooth this out would be much appreciated.
     
  2. Emolk

    Emolk

    Joined:
    Feb 11, 2014
    Posts:
    241
    Bump
     
  3. lordconstant

    lordconstant

    Joined:
    Jul 4, 2013
    Posts:
    389
    Hey,

    So did a quick a test & you want something like this:

    Code (CSharp):
    1.  
    2. //Target is the piece infront (As a Vector3)
    3. //body is the current piece (As a GameObject)
    4.  
    5. //Look at the target (Due to being in 2d, we want to change the up vector not the forward)
    6. body.transform.rotation = Quaternion.LookRotation(Vector3.forward, (target - body.transform.position).normalized);
    7.  
    8. //Our actual target is how close we are allowed to be behind that piece
    9. target = target - (body.transform.up * minBodyDist);
    10. //Get the current distance from our target
    11. float dist = (target - body.transform.position).magnitude;
    12. //Move towards the target, never allowing us to go farther away than the maxBodyDist
    13. body.transform.position = Vector3.MoveTowards(body.transform.position, target, Mathf.Lerp(0.0f, minBodyDist, dist/maxBodyDist));
     
  4. lordconstant

    lordconstant

    Joined:
    Jul 4, 2013
    Posts:
    389
    My full code:

    Code (CSharp):
    1.    public GameObject head;
    2.     public List<GameObject> bodyPieces;
    3.     public float minBodyDist;
    4.     public float maxBodyDist;
    5.     public float rotateSpeed;
    6.     public float moveSpeed;
    7.  
    8.     // Start is called before the first frame update
    9.     void Start()
    10.     {
    11.        
    12.     }
    13.  
    14.     // Update is called once per frame
    15.     void Update()
    16.     {
    17.         Vector3 target = Input.mousePosition;
    18.         target = Camera.main.ScreenToWorldPoint(target);
    19.         Vector3 lastPosition = head.transform.position;
    20.         head.transform.rotation = Quaternion.RotateTowards(head.transform.rotation, Quaternion.LookRotation(Vector3.forward, (target - head.transform.position).normalized), rotateSpeed * Time.deltaTime);
    21.         head.transform.position += head.transform.up * (moveSpeed * Time.deltaTime);
    22.  
    23.         for(int i = 0; i < bodyPieces.Count; i++)
    24.         {
    25.             GameObject body = bodyPieces[i];
    26.             target = lastPosition;
    27.             lastPosition = body.transform.position;
    28.             body.transform.rotation = Quaternion.LookRotation(Vector3.forward, (target - body.transform.position).normalized);
    29.             target = target - (body.transform.up * minBodyDist);
    30.             float dist = (target - body.transform.position).magnitude;
    31.             body.transform.position = Vector3.MoveTowards(body.transform.position, target, Mathf.Lerp(0.0f, minBodyDist, dist/maxBodyDist));
    32.         }
    33.     }
     
    Emolk likes this.
  5. lordconstant

    lordconstant

    Joined:
    Jul 4, 2013
    Posts:
    389
    Sorry made a mistake this line should be:

    Code (CSharp):
    1.  
    2. //Need to lerp to the distance we are away or we won't catch up
    3. body.transform.position = Vector3.MoveTowards(body.transform.position, target, Mathf.Lerp(0.0f, dist, dist/maxBodyDist));
     
  6. Emolk

    Emolk

    Joined:
    Feb 11, 2014
    Posts:
    241
    This is absolutely perfect thanks.