I am moving an object around from one node to another. I need to tell the object to stop moving when it has reached its destination node.

I am currently using this algorithm for movement and node checking

if (!isFinished)
            {
                // If the level has arrived at the current destination node and not at the final node
                // Destination node is based on the interpolated points on the spline
                if (AtNode(catmullRomSpline.InterpolatedPoints[nodeIndex], node))
                {
                    // If we have not reached the final node/interpolated point on spline
                    if (nodeIndex + 1 < catmullRomSpline.InterpolatedPoints.Count)
                    {
                        // Increase the node index
                        nodeIndex++;
                    }
                    else
                    {
                        isFinished = true;
                    }
                }

                // Now move object unless finished is true

The problem I have is that I don't want to do any of the above if the isFinished boolean is true but if it is flagged as true in the method then the object will still be moved for that frame. This is because the isFinished is only checked at the start of the method.

How can I change the method to avoid this or exit correctly once isFinished is flagged as true?

Lusiphur commented: Well formed question :) +1

Recommended Answers

All 21 Replies

break ;

If I understand this correctly you're intending this process to check for isFinished == true and proceed only if it's true.

Your concern is, if the condition changes WHILE it's processing the steps within your if block, correct?

First, I'm not sure you should be using IF for the initial part of your code block but perhaps WHILE. IF will start the block and run through it once from start to finish as long as the condition existed to begin with. WHILE on the other hand will start the block and conrinue to run the block until the condition that started it changes.

Just judging by what you have within the block it looked more like you wanted a WHILE loop instead of an IF check was all... but if I'm wrong, no harm no foul, someone else will likely get your answer for you :)

break ;

break won't work in this situation, if isn't a loop.

If I understand this correctly you're intending this process to check for isFinished == true and proceed only if it's true.

Each time the method is called isFinished is check and the object moves if the boolean evaluation is false.

First, I'm not sure you should be using IF for the initial part of your code block but perhaps WHILE.

If I used while then the movement update would be stuck until the object had reached its goal. In my case I would like the object to update its position once per frame but only if isFinished is false. The problem is that the object could be finished in the current frame yet the object will still move.

I wonder if a combination of the while loop and break might come in handy :)

Basically a loop that is deliberately broken after the desired effect...

The concept being that it maintains it's "while" check and self terminates if the value evaluates false but also force-terminates when it completes it's initial required step.

Not sure if that makes any sense or not :-/

I wonder if a combination of the while loop and break might come in handy

This would mean that the loop would be broken each frame and then not executed once the boolean value is true. The loop would only ever need one iteration every time before it is broken.

Is there no other way?

This would mean that the loop would be broken each frame and then not executed once the boolean value is true. The loop would only ever need one iteration every time before it is broken.

Is there no other way?

Heck, I was just tossing theories at that point, I'm not super knowledgeable on node navigation :twisted:

if (!isFinished)

{

    // If the level has arrived at the current destination node and not at the final node

    // Destination node is based on the interpolated points on the spline

    if (AtNode(catmullRomSpline.InterpolatedPoints[nodeIndex], node))

    {

        // If we have not reached the final node/interpolated point on spline

        if (nodeIndex + 1 < catmullRomSpline.InterpolatedPoints.Count)

        {

            // Increase the node index

            nodeIndex++;
            if (nodeIndex + 1 == catmullRomSpline.InterpolatedPoints.Count)
            {
                isFinished = true;
            }

        }

        //else

        //{

            //isFinished = true;

        //}

    }

 }

I hope this should work, in order to make the isFinished bool variable as true and once nodeIndex + 1 is equal to catmullRomSpline.InterpolatedPoints.Count, the current destination is achieved.

Thanks,
if its working fine, do not forget to mark it as solved.

if (!isPathFinished)
                {
                    if (AtNode(catmullRomSpline.InterpolatedPoints[nodeIndex], node))
                    {

                        // If we have not reached the final node/interpolated point on spline

                        if (nodeIndex + 1 < catmullRomSpline.InterpolatedPoints.Count)
                        {
                            // Increase the node index
                            nodeIndex++;

                            if (nodeIndex + 1 >= catmullRomSpline.InterpolatedPoints.Count)
                            {
                                isPathFinished = true;          // <=============== (!isPathFinsished)
                            }
                        }
                    }
                }

Doesn't work as it is afflicted with the same problem as the original method, unless I'm mistaken. It doesn't work for me.

It might be a bit extreme, but where you set isFinished, could you just return; and exit the method?

Otherwise, you will need a second boolean check.

if (!isFinished)
            {
                // If the level has arrived at the current destination node and not at the final node
                // Destination node is based on the interpolated points on the spline
                if (AtNode(catmullRomSpline.InterpolatedPoints[nodeIndex], node))
                {
                    // If we have not reached the final node/interpolated point on spline
                    if (nodeIndex + 1 < catmullRomSpline.InterpolatedPoints.Count)
                    {
                        // Increase the node index
                        nodeIndex++;
                    }
                    else
                    {
                        return;
                    }
                }

                // Now move object unless finished is true

or;

if (!isFinished)
            {
                // If the level has arrived at the current destination node and not at the final node
                // Destination node is based on the interpolated points on the spline
                if (AtNode(catmullRomSpline.InterpolatedPoints[nodeIndex], node))
                {
                    // If we have not reached the final node/interpolated point on spline
                    if (nodeIndex + 1 < catmullRomSpline.InterpolatedPoints.Count)
                    {
                        // Increase the node index
                        nodeIndex++;
                    }
                    else
                    {
                        isFinished = true;
                    }
                }

                // Now move object unless finished is true
                if(!isFinished)
                {
                   // Do Stuff
                }
            }

You have a check for "isFinished" up at the top also, is this necessary? I don't know how you're handling things outside this local block so I can't say for certain, but if you thought it may exit immediately once isFinished becomes true inside the block, that is incorrect.

commented: covers both the solutions i would have offered..good post :) +1

I suppose you are using a for loop before checking !isfinished, provide that loop as well. may be we can sort it out..

I suppose you are using a for loop before checking !isfinished, provide that loop as well. may be we can sort it out..

There is no for loop. I've currently got my method looking like this.

public void UpdatePathfinding(float dt)
        {
            Vector3 destinationNode = Vector3.Zero;
            bool isPathFinished = false;

            if (AtNode(destinationNode, catmullRomSpline.InterpolatedPoints[nodeIndex]))
            {
                if (nodeIndex < catmullRomSpline.InterpolatedPoints.Count - 1)
                {
                    nodeIndex++;
                    isPathFinished = false;
                }
                else
                {
                    isPathFinished = true;
                }
            }

            if (!isPathFinished)
            {

As it stands now, the object checks every frame to see if it has arrived at its destination node. The object still checks when it has reached the final node. In a way I think this is good because the check is inexpensive and the node can be updated and the object will move normally.

The node check is just

private bool AtNode(Vector3 nodePosition, Vector3 objectPosition)
        {         
            Vector3 v = nodePosition - objectPosition;
            return Math.Abs(v.LengthSquared()) < 0.04f;
        }

Does this look better?

Ideally I would like the object to stop checking once it has arrived at the final node, and start checking once a new destination node is given. I can't figure out how that would work though.

I have a doubt now, How do u define the destination node..?
My view : Once you u know u have reached the destination node, make the isFinished boolean variable as true.
so, the next time it wouldn't come into the loop...
I hope you understood what I am trying to mean here.

The destination node is defined as a point

catmullRomSpline.InterpolatedPoints[nodeIndex]

where the nodeIndex is index of the points.

The final node is where: nodeIndex = InterpolatedPoints.Count - 1.

The object is at the node if it is within a certain radius of the point. This is to counter floating point errors.

bool isFinished = false;
      // If the level has arrived at the current destination node and not at the final node

      // Destination node is based on the interpolated points on the spline

      if (AtNode(catmullRomSpline.InterpolatedPoints[nodeIndex], node))
      {

      // If we have not reached the final node/interpolated point on spline

      if (nodeIndex == (catmullRomSpline.InterpolatedPoints.Count - 1))
      {
	if (!isFinished)
      	{

	      // Increase the node index

	      nodeIndex++;
         }

         else

         {
   	   isFinished = true;
         }
      }
       
      // Now move object unless finished is true

try this,
let me know.

bool isFinished = false;
      // If the level has arrived at the current destination node and not at the final node

      // Destination node is based on the interpolated points on the spline

      if (AtNode(catmullRomSpline.InterpolatedPoints[nodeIndex], node))
      {

      // If we have not reached the final node/interpolated point on spline

      if (nodeIndex == (catmullRomSpline.InterpolatedPoints.Count - 1))
      {
	if (!isFinished)
      	{

	      // Increase the node index

	      nodeIndex++;
         }

         else

         {
   	   isFinished = true;
         }
      }
       
      // Now move object unless finished is true

This still checks the node even when the object is finished. It doesn't do anything different from my code as far as I can tell.

Dave, can you please describe the entire method and how it's called.

You're implying there is a loop, yet, the code you posted and what you say, means there isn't one. So it's a bit confusing.

Thanks.

Absolutely, sorry for the confusion.

The path finding code is called from the Update() method.

public void Update(float dt)
        {
            HandleInput(dt);
            UpdatePathfinding(dt);
        }

This is a method that is called 60 times per second.

The UpdatePathfinding method itself is not a loop.

Vector3 destinationNode = Vector3.Zero;
            bool isPathFinished = false;

            if (AtNode(destinationNode, catmullRomSpline.InterpolatedPoints[nodeIndex]))
            {
                if (nodeIndex < catmullRomSpline.InterpolatedPoints.Count - 1)
                {
                    nodeIndex++;
                    isPathFinished = false;
                }
                else
                {
                    isPathFinished = true;
                }
            }

            if (!isPathFinished)
            {

I do not wish to execute this method if isPathFinished is true. Setting isPathfinished during the method to true still executes the remainder of the method though and that is where my problem lies.

Then I suggest you take my other approach that I mentioned on the first page. At the point where you set isPathFinished to true, rather than doing that, simply put a return statement.

This will exit the method at that point.

You will always need to find a way of checking whether you are at the end of your path. I think if you want to do this any differently you will have to redesign what this method does.

Unfortunately that would probably require knowledge of code outside of the specific block you want help with.

Also, if if (AtNode(destinationNode, catmullRomSpline.InterpolatedPoints[nodeIndex])) fails, you can use the "else" statement to abort the method.

if (AtNode(destinationNode, catmullRomSpline.InterpolatedPoints[nodeIndex]))
            {
                if (nodeIndex < catmullRomSpline.InterpolatedPoints.Count - 1)
                {
                    nodeIndex++;
                    isPathFinished = false;
                }
                else
                {
                    isPathFinished = true;
                }
            }
            else
            {
                return;
            }

Even though your method is a returning "void" you can still use the return statement to break execution. You won't find it very often because many people take it as bad design (which in most cases is true) But I think you can get away with it in this case.

I second what ketsuekiame said. If there is no code to run after the if(!isFinished) block then use return to exit the method.
If there is code that has to run after the if block regardless of isFinished then add a second condition check. That way you will only move the object if isFinished is false at the start AND remains false after the first section of code.


The UpdatePathfinding method itself is not a loop.

Vector3 destinationNode = Vector3.Zero;
            bool isPathFinished = false;

            if (AtNode(destinationNode, catmullRomSpline.InterpolatedPoints[nodeIndex]))
            {

Just to clarify, you have the destinationNode and isPathFinished delcared inside the UpdatePathfinding method...is that correct or did you just add the declarations at the top there to show hwo they are delcared elsewhere?

Very old discussion but what the heck. Here is a console app proxy that orders the checks and then by ref hands the index to a recursive call until you get to the last node. It returns true when you match nodes or itterate beyond the last nodeIndex without a match. You can add failure cases that return false; wherever needed. I was not familiar with your specific failure points based on your example.

class Program
    {
        static void Main(string[] args)
        {
            int dN = 5;
            int nI = 0;

            Console.WriteLine(FinishPath(dN, ref nI));
            Console.WriteLine(nI);

            int nI2 = 6;

            Console.WriteLine(FinishPath(dN, ref nI2));
            Console.WriteLine(nI2);
            Console.ReadLine();

        }
        static public bool FinishPath(int destinationNode, ref int nodeIndex)
        {
            int nIC = 10; //proxy for catmullRomSpline.InterpolatedPoints.Count

            if (destinationNode == nodeIndex) return true; //Proxy for AtNode(destinationNode, .InterpolatedPoints[nodeIndex])

            if (nodeIndex + 1 > nIC) return true; //We exceeded the index return true

            nodeIndex++; //not there yet increment the index

            return FinishPath(destinationNode, ref nodeIndex); //send us to the next iteration and set of tests
        }
    }

OutPut:
True
5
True
10

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.