Help with 2D flying Enemy

hi everyone i’ve been having troubles with a flying enemy that i just can’t get his movement right. the enemy must fly (obviously) and then attack the player from point 1 to point 2 wait for a second and then attack him again and do the same thing until he gets killed or the player walks away from it. So this is my code:

using UnityEngine;
using System.Collections;

public class flyingMutantAI : MonoBehaviour {

    private fos_controller_script player;

    public float moveSpeed;

    public float attackingSpeed;


    public float playerRange;

    public LayerMask playerLayer;

    public bool playerInRange;

    public float distance;

    public float distanceToAttack;

    public float attackRange;

    public bool hurtingPlayer = false;

    public bool attacking = false;

    public Transform target;

    // Use this for initialization

    void Start () {
   
        player = FindObjectOfType<fos_controller_script> ();

    }

    // Update is called once per frame
    void Update () {

        playerInRange = Physics2D.OverlapCircle (transform.position, playerRange, playerLayer);

        distance = Vector3.Distance (transform.position, target.transform.position);

        distanceToAttack = Vector3.Distance (transform.position, target.transform.position);


        if (playerInRange){   ///<---- this checks if the player is inside the gizmo 


            transform.position = Vector3.MoveTowards (transform.position, player.transform.position, moveSpeed * Time.deltaTime); ///<--- then when he is InRange the enemy moves with moveSpeed Velocity


            if (distanceToAttack < attackRange ) { ////<--- and when the player is closer then enters to the attackRange

                StartCoroutine ("waitForNextAttack");


            }
        }

    }

    void OnDrawGizmosSelected(){

        Gizmos.DrawSphere (transform.position, playerRange);


    }


    IEnumerator waitForNextAttack(){


        attacking = true;

        transform.position = Vector3.MoveTowards (transform.position, player.transform.position, attackingSpeed * Time.deltaTime);  ////<---- and when he is in attackRange the speed changes to attackingSpeed which is faster

        yield return new WaitForSeconds (1f);

        attacking = false;


    }

}

}

Currently it goes right to the player but it keeps on it all the time and that’s not what i want, i left a draw explaining this if i’m not clear enough (sorry for the quality

).

Thanks to all!!!

Forgive me if I’m missing something, but it doesn’t really look like you’re scripting the enemy to do anything after reaching the player.

One solution is to reserve a variable name for a position at the same height as the enemy starts, but on the opposite side of the player:

public Vector3 followThroughPosition

...

followThroughPosition = Vector3( 2 * player.transform.position.x - transform.position.x, transform.position.y, transform.position.z);

Use that statement once when the enemy spots the player. When the enemy reaches the player during the first motion, then make it go to followThroughPosition.

In case you’re wondering,

2*player.transform.position.x - transform.position.x

is a simplification of

transform.position.x + 2(player.transform.position.x - transform.position.x)

which was derived visually, based on that picture.

A couple other things:

-I don’t see the need for checking OverlapCircle() AND checking the distance to the player, but maybe you put that there for a specific reason
-You might want to try a Physics2D.Raycast() instead of an OverlapCircle() for this, otherwise they will try to attack your player through walls and other objects.
-That picture was very helpful, good thinking. Being detailed like this is a good idea when asking for help, I wish more people did.

1 Like

hi thanks for your answer and you were right my enemy was doing nothing when reaches the player i just erase that code because did not work as i expected and the OverlapCircle and the distance and stuff i need them for other aspects of the enemy itself, and for the purpose of this enemy there’s no problem attacking through walls. And thanks for what you said about the picture sometimes it’s hard to understand what we’re doing, and thanks to you for your help.

in other news i tried the code but i think i’m missing something because Unity is trowing me this error when i tried the code:

error CS0119: Expression denotes a type', where a variable’, value' or method group’ was expected

i just put it after eat enemy reaches the player:

 IEnumerator waitForNextAttack(){
        attacking = true;
        transform.position = Vector3.MoveTowards (transform.position, player.transform.position, attackingSpeed * Time.deltaTime);  ////<---- and when he is in attackRange the speed changes to attackingSpeed which is faster
        yield return new WaitForSeconds (1f);

       followThroughPosition = Vector3 ( 2 * player.transform.position.x - transform.position.x, transform.position.y, transform.position.z);
        attacking = false;
    }
}

sorry if i’m missing something and thanks for your help!!!

Just to make sure: did you declare followThroughPosition somewhere? If not, specifying ‘new Vector3()’ should fix it.

Also, that script doesn’t actually move the enemy after it reaches the player, it just sets the end location in followThroughPosition. You still need to tell your object to move toward that position in your logic!

I want to point out that a coroutine doesn’t seem necessary for the way you have written this. Essentially, using a coroutine but calling one every frame is redundant.

I think it would make more sense to just call the coroutine once and put your waitForNextAttack() code in a for loop, or maybe just call a plain function every frame.

hi again, the way i wrote this may be wrong or not correct but actually i don’t have a clear idea of how to achieve this because i want the player to be able of jumping when the enemy is attacking so the enemy keeps a specific trajectory until reaches the other point whether it hits the player or not but i just achieve enemy’s movement and not the way i want… any ideas??

thank you very much!!!

Sure, just declare another variable to store the position at the time of player detection. You could call it attackPosition or something like that, and set it equal to player.transform.position once when the player is detected.

Then all you need to do is tell your enemy to move toward attackPosition, and once it gets there, move toward followThroughPosition. After it reaches that point, start looking for the player again.

I’ll try and i undestand what you are saying but i’m having troubles writting the code for this…

Give it a try and show us what you came up with. When you have time, build some foundation by studying these tutorials.

More topics available here.

hi again i’ve been writing code and i totally understand how to achieve what i want but i don’t know how to store the position of the player because if i use target.transform.position the update code keeps telling the enemy where the player is even if he jumps or moves out of the enemy’s range it keeps following him, i don’t really know how to to save that value… any help? thanks!!!

You just need to make sure you only store the position value one time. Since you already have an ‘attacking’ state variable, you can perhaps use

if (!attacking)
{
     attackPosition = player.transform.position;
}

This way the attack position is set to wherever the player is just one time: when the enemy detects the player. Then the player will be able to jump over the enemy as it dives, or something like that. Don’t forget to replace ‘attackPosition’ with whatever you named this variable.

hi again, i did what you told me and i think i got it, now the enemy search for the player and when he’s spotted the enemy attacks him but if the player is enough fast or jumps he can dodge it, thanks!!! now the rest…

here’s the code:

void Update () {

        distance = Vector3.Distance (transform.position, target.transform.position);


        if (!attack) {
       
            if (distance < rangeToFollow) {

                isFollowingThePlayer = true;

                transform.position = Vector3.MoveTowards (transform.position, target.transform.position, moveSpeed * Time.deltaTime);

                targetStoredPosition = target.transform.position;
           
                Debug.Log ("player's previous position is:"+ targetStoredPosition);

                if (distance < attackRange) {

                    attack = true;

                }

            }

        }

            if(attack){

                isFollowingThePlayer = false;

                transform.position = Vector3.MoveTowards (transform.position, targetStoredPosition, attackingSpeed * Time.deltaTime);

               

                if(transform.position == targetStoredPosition){

                    attack = false;


                }

            }



    }