Tutorial: Moving objects along a path

Tutorial: Moving objects along a path

There are many ways to move objects in Corona SDK. If you want to move an object from point A to B, the simplest approach is to use transition.to(). But what if you need to move it along a path with multiple segments, like moving a knight on a chess board in its unique “L” pattern? This tutorial outlines how to achieve sequential movement via a series of queued transitions.

Initial setup

The basis of this process is a table of x and y coordinate pairs to move the object along, in sequence. In its most simple format, the table may look like this:

This just declares a series of movement points, starting at index 1 and progressing across as many points as you wish. By default, these points equate to specific coordinates on the screen, not points relative to the object’s starting position, but we’ll include a setting to let you choose which option is most suitable to your application.

Customizing the path parameters

In addition to the basic x and y coordinate setup, we’ll allow two additional parameters for each “segment” in the path: time and easingMethod. For example, we may expand our table like this:

If a custom time parameter is specified, it will override any other time settings, and the object will move to that point over that exact duration. Similarly, if easingMethod is defined and set to one of Corona’s easing methods, the object will move to that point using that easing method, not the default linear interpolation.

Distance function

For calculating the distance between two points, we’ll need to include a quick function. The purpose of this will be explained later, but let’s add it now:

Create the object(s)

Obviously, we’ll need one or more objects to move along the path we created. Let’s create two basic circles now:

The setPath() function

Now that we’ve done the basic setup, let’s explore the function which will queue up all of the transitions for an object. Let’s call the function setPath() and provide it with three arguments: the object to move, the path to move along, and a table of params which we can use to customize the movement.

In the first several lines of the function, we set some local variables, most of which are used to check if various parameters are passed in via the params table. Each of these parameters will be explained as we step through the tutorial.

Delta

This gives us the option to use delta position via a boolean value — useDelta — passed in via the params table. If set to true, the object’s path will be relative to its starting position. If set to false, or omitted, the path points will equate to explicit screen coordinates instead.

Whether to use params.useDelta = true depends on the scenario. For moving a knight on a chess board, delta would be the logical choice, since the knight may reside on any square of the board and we’d need to move it in its “L” pattern from the current square to another valid square.

If useDelta is passed in the params table, let’s set deltaX and deltaY to the object’s starting position, instead of their default of 0. When the transitions are set up, this will be used to offset each point along the path by the object’s starting position. It will also be used to refactor the constant rate of movement, discussed in a moment.

Constant rate of movement

Another option we’ll add is the ability to set a “constant rate of movement.” For example, we may wish to move the object at a steady, constant rate across the entire path, even if the distance between the starting point and the 2nd point is 100 pixels but the distance between the 2nd and 3rd point is 280 pixels. To accomplish this, we just need to calculate a speed factor based on a “time” value passed in via params.constantTime.

The value that should be passed to params.constantTime is simply an integer “time” value, and speedFactor is calculated by the distance between the starting point and the 2nd point. In other words, if we use a value of 1200, the object will move from the starting point to the 2nd point in 1200 milliseconds, and the speed established along that segment will be applied to all other segments in the path, no matter their distance apart.

Default easing method

If we wish to use a non-linear easing method for all segments in the path, we can tell the module to use any of the easing methods. For example, to use a quadratic-in-out method, we can pass easingMethod = easing.inOutQuad in the params table. This easing method will be applied to all transitions along the path except those with a specific easingMethod setting in the path table.

Transition tagging

One of the features in the transition library is the ability to tag (name) any number of transitions and then cancel, pause, or resume all transitions sharing the same tag. Since we’ll be building paths that consist of multiple related transitions, tagging is essential if you want to pause or resume the path movement as it progresses from point to point. To tag all of the transitions that will collectively make up the path, just pass the tag parameter (string value) in the params table.

Looping through the points

Now, let’s loop through our points and set up the queue of transitions. For simplicity, we’ll declare all of them initially and apply a delay parameter on each, so each transition starts when the previous one is finished.

First, we’ll start our loop and immediately set a default segmentTime of 500 milliseconds. Then, we’ll check if params.constantTime has been supplied and, if so, we’ll overwrite segmentTime with a refactored time — specifically, the distance between the points multiplied by the speedFactor that we calculated above:

As mentioned above, we can optionally set a custom time on any specific segment in the path. If supplied, this value will override both the default of 500 milliseconds and the “constant rate” value, if it’s being used. Let’s check if a custom time has been specified for this segment:

In addition, let’s check if a custom easingMethod parameter has been set on this specific path segment. If declared, this will override the optional default easing method applied to the path as a whole.

And finally, the heart of the entire process — creating each transition for the path:

Notice that the parameters table for each actual transition is populated based on the values we gathered or calculated in the lines above. Also, note line #66 — here, we add to the total delay value for each new transition in sequence, thus making each transition begin when the previous one has completed.

Setting an object in motion

Let’s start our circles in motion across the path! At the most basic level, the setPath() function may be called like this:

However, this doesn’t include any options like useDelta or constantTime, so let’s expand on it:

And that’s it — the circles will both follow the same path, movePath, and the path will be offset by each object’s starting position because we used the delta setting. The rate of movement across each segment will be constant, and an in-out quadratic easing will be applied to all segments.

Pausing, resuming, canceling

Because we tagged every transition in the sequence with the "moveObject" tag, pausing, resuming, or canceling is simple — just pass the tag name to one of the transition control APIs:

In summary

Hopefully this tutorial gets you started on path-based movement in Corona. In closing, note the following:

  • The functional format allows you to create and re-use several unique path “patterns” and apply them to various objects by simply passing the appropriate path table to the setPath() function, along with the object and the optional parameters. In this manner, you could, for example, create several different movement paths for pieces in a board game and re-use those paths as needed depending on the player’s move.
  • This tutorial outlines just linear path-based movement. If you need curved-based path methods, please refer to the working with curved paths tutorial.

Brent Sorrentino
[email protected]

Brent Sorrentino is a full-time Developer Evangelist and technical writer who assists others with game development, code, and in overcoming other challenges to help them bring their app dreams to life.

28 Comments
  • fuhongxue
    Posted at 18:12h, 07 January

    How can I Moving Objects Along a Bezier Path?
    Is there some easy way ?

    • juf jannie
      Posted at 10:10h, 09 January

      Or a curve.
      Adding every coordinate for a curve by hand really is no fun.

      • Brent
        Posted at 11:34h, 09 January

        This tutorial isn’t geared toward curved paths. If there are enough requests, I may work up another tutorial involving bezier paths.

        Brent

        • Peter Rich
          Posted at 21:12h, 09 January

          +1

        • Kawika
          Posted at 05:25h, 12 January

          Ii vote YES to a curved path tutorial. thanks Brent!

        • Fernker
          Posted at 12:36h, 13 March

          I’d love to see one on curved paths.

        • Nathan Harper
          Posted at 21:07h, 13 May

          Curves please!

        • Joe Colling
          Posted at 09:54h, 04 September

          Yes, please! +1 curved paths.

        • Chris
          Posted at 02:00h, 28 January

          Another +1 for bezier path tutorial please.

        • Noah (Chunky Apps)
          Posted at 07:25h, 16 February

          +1 for curved path. Been waiting for that for years!

        • Evandro
          Posted at 16:21h, 04 March

          +1

        • Charley
          Posted at 06:04h, 01 November

          Curved Path yes!

  • Erich Grüttner Díaz
    Posted at 19:35h, 07 January

    Excellent tutorial, as usual!
    Perhaps could be interesting to add a “loop” param (true or false). What do you think?

    Thanks Brent!!!

  • Tony
    Posted at 04:34h, 12 January

    Please make a tut for moving objects along a curved path! Thanks!

  • Sid
    Posted at 08:45h, 13 January

    For Bezier curves check out Level Director (3rd party tools), I’ve been using this in my projects and it allows you to plot paths and beziers and allows you to make objects follow them automatically, pretty cool.

  • Dave Baxter
    Posted at 05:18h, 15 January

    I used this to get objects moving along a Bezier curve –

    http://developer.coronalabs.com/code/bezier-curve-corona-sdk

    Dave

  • Erik
    Posted at 20:29h, 28 April

    This tutorial is amazing! Thank you very much for this guide, it is very useful. Only thing this amazing program is missing is an option to reset it back to first point and forever looping through all points with a true or false param. Would greatly appreciate a param like this 🙂

  • Nick
    Posted at 16:02h, 25 May

    Vote up for curve tutorial

    Thank you!!

  • Olivier Romanetti
    Posted at 07:16h, 30 May

    Vote up for curve tutorial too 🙂

  • Nick
    Posted at 11:34h, 03 June

    curve!

  • keenan
    Posted at 06:49h, 25 June

    awesome stuff are we free to use this in our projects?

  • Joe
    Posted at 15:24h, 04 September

    Great post. One question, though….

    Under “INITIAL SETUP” towards the top of the post, it says just under the first set of code –

    “By default, these points equate to specific coordinates on the screen, not points relative to the object’s starting position, but we’ll include a setting to let you choose which option is most suitable to your application.”

    Now, I read through the post several times and did not find where this setting is shown. Did I miss it, or is it not there??? What is the “setting to let me choose which option is most suitable for my app”?

    Please advise. Many thanks.

    • Brent
      Posted at 21:46h, 04 September

      Hi Joe,
      The setting you’re speaking of is the “delta” setting. Read over that sub-section, try both options, and observe the difference.

      Brent

      • Joe
        Posted at 11:21h, 06 September

        Ah. I see now. *puts on glasses*

        Okay. Well, I do have one more question. under the “SetPath” section, the code starts out like this –

        local function setPath( object, path, params )

        For the “params” part – does it mean I have to put in every parameter I am going to use in my transition statement? It also talks about a params table. Where is it written in the tutorial here? I’m not understanding where Params comes from…..May just be the the word “params” thats confusing me….Anyway, I understand “object” and “path” – however, I dont understand why “params” is there…

        It seems like “params” is being called first, and defined second…..Which cant be right, right? Or am I wrong? Can you kindly explain what “params” in that snippet of code is for and why it is there? I’m just not getting it.

        Thanks in advance, sir.
        -Joe

        • Brent
          Posted at 14:04h, 06 September

          Hi Joe,
          “params” is simply the table that is passed in as the third argument to the “setPath” function. It’s not actually named “params” in the code, so just consider that I’m referring to that table as “params”.

  • Mikel
    Posted at 10:40h, 27 February

    Very good tutorial.
    Takes me 1 hour and now my enemies are following my path.
    Very nice. Thank you.

  • Brian
    Posted at 08:53h, 28 February

    I think there might be a slight issue with the code. You pass in ‘constantTime’ as a parameter, but in your setPath() function you refer to ‘constantRate’. Thus, the variable ‘constant’ in the setPath() function will always be nil.

    • Brent Sorrentino
      Posted at 14:04h, 29 February

      Hi Brian,
      Thanks for pointing that out… the name was indeed incorrect.
      – Brent