Using Switch for Simple Unity3D Patrol Movement

1k views Asked by At

I'm using a switch statement to create two movement types on an enemy: Forward, and Backwards. The enemy has three patrol points. When he begins, I want him moving from the first patrol point and adding 1 to the current point when he hits his second patrol point (empty 3D gameobject), and so on. Then I'll have him reverse direction when he hits the final point.

switch (moveType)
        {
        case MoveType.Forward:
            if (transform.position == patrolPoints[currentPoint].position)
            {
                currentPoint ++;
            }
            break;
        case MoveType.Backwards:
            if (transform.position == patrolPoints[patrolPointsLength].position)
            {
                currentPoint --;
            }
            break;
        }

The problem is, I can't figure out a way to "trigger" the two MoveTypes. How do I code this so that when the enemy hits his final patrol point, he switches to MoveType.Backwards? I'm sure I'm making this way harder than it needs to be. Thanks for the help!

3

There are 3 answers

2
Jayson Ash On BEST ANSWER

This is how I would do it if I really wanted to use the switch statement:

    float someSmallValue = 0.5f; // Adjust this as per your needs

    if (Vector3.Distance(transform.position, patrolPoints[currentPoint].position) < someSmallValue)
    {
        switch (moveType)
        {
            case MoveType.Forward:
                currentPoint++;
                if (currentPoint > patrolPoints.Length - 1)
                {
                    currentPoint -= 1;
                    moveType = MoveType.Backwards;
                }
            break;

            case MoveType.Backwards:
                currentPoint--;
                if (currentPoint < 0)
                {
                    currentPoint = 1;
                    moveType = MoveType.Forward;
                }
            break;
        }

    }

I think renaming currentPoint to targetPoint would make the variable name more clear for this chunk of code.

EDIT: I forgot to decrement currentPoint inside the Backwards case block. Updated my answer.

1
Reasurria On

The solution I have here adds some things like a pause time. It also ensures that fast moving entities won't overshoot the destination and not turn around or something.

// Movement speed normalized. So 1 is instantaneous travel and zero is no movement.
public float movementSpeed = 0.025;
// Let's add a 'pause' time where the unit waits a while at the turning point.
public float waitTime = 1;
// Lets say the list has 5 points.
public List<Vector3> patrolPoints ... 
// We keep track of our starting and ending points. Here we start at zero and move to position 1.
public Vector2 currentLeg = new Vector2(0,1);

// We use a coroutine
IEnumerator Patrol()
{
    // This keeps track of where we are. 0 is at the starting point and 1 is at the destination.
    float progress = 0;

    while(true)
    {
            Vector3 startingPoint = patrolPoints[currentLeg.x];
            Vector3 destination = patrolPoints[currentLeg.y];

            // Please note this won't compile. It's for brevity. You must lerp x,y,z indiviualy in C#.
            transform.position = Mathf.Lerp(startingPoint, destination, progress);
            progress+= movementSpeed;

            // If we are at our destination
            if(progress >=1 )
            {
                // Reset our progress so wa can start over.
                progress = 0;

                // Our current point is now what our destination was before.
                currentLeg.x = currentLeg.y;

                switch(moveType)
                {
                    case MoveType.Forward: 
                    {
                        // If this condition is true then it means we are at the final point (4 in this case). So we invert the movement direction and set the current point to 3.
                        if(currentLeg.y == patrolPoints.Count()-1)
                        {
                            currentLeg.y -= 1;
                            moveType = MoveType.Backwards;

                           // We wait 1 seconds and then do everything again.
                           yield return new WaitForSeconds(waitTime);
                        }
                        else
                            currentLeg.y++;
                    }
                    break;
                    case MoveType.Backward:
                    {
                        // If this condition is true then it means we are at the starting point (0). So we invert the movement direction and set the current point to 1.
                        if(currentLeg.y == 0)
                        {
                            currentLeg.y += 1;
                            moveType = MoveType.Forward;

                            // We wait 1 seconds and then do everything again.
                            yield return new WaitForSeconds(waitTime);
                        }
                        else
                            currentLeg.y--;
                    }
                    break;
                }

            }
    }
}

For a quick fix Jayson's answer will be better. But it might fail if the unit moves fast or the unit will stop too early if it moves too slow.

EDIT: The wait time was in the wrong place.

0
maraaaaaaaa On

So you want to use a switch to patrol because only 1 enum can be selected at a time?

Why not use a public Transform target; variable and have your AI always follow whats in that variable? Then just make an empty game object and stick it into that variable and he will follow it wherever it goes. He wont be limited to "Forward" and "Backward", and you wont have to recode or be confused, when you want to recycle the code for an AI moving "Left" to "Right"

This will speed up execution, clean up your code, get rid of tons of lines of code as well, and you can still use your switch statement too, because this actually will open your code up to more dynamic abilities such as:

public enum ActionType
{
    Patrol,
    Veer,
    Stop
}

Lets say hes patrolling and halfway to the target he spots an enemy, ActionType curAction; Can be set to ActionType.Veer , now he is veering off the patrol line to attack the enemy, and after you can set it back to ActionType.Patrol and he continues to the target.

So for patrolling you can set up a public List<Vector3> wayPoints; and just add a bunch of Vector3's in there. When he reaches the target, he can stop for a sec or two, then have the empty game object target jump to the next vector3 in the list.