Performing complex movements with MotionPaths

Players in games have been obliged to jump on moving platforms since the dawn of gaming. Even with the incredibly advanced games of today, it's not uncommon to encounter this most primitive game mechanic albeit with better graphics. There's also a popular retro genre that calls for the same, not the least for mobile games.

How do we do that in jMonkeyEngine? One way is, of course, to simply use move or setLocalTranslation on geometries. This can quickly get complex if we want to make sequenced paths. A better option is to use MotionPaths and MotionEvents.

A MotionPath object is basically a set of waypoints through which an object will move in an interpolated way meaning the movement will be smooth. The MotionEvent is the control class defining when and how the object should move along the MotionPath object. It can define how an object should be rotated along the path and if and how the path should be cycled through.

In this recipe, we'll check out how to use them for a game, which could be a side-scrolling 2D game, but the same principles can be used to create advanced cinematic cutscenes.

How to do it...

Let's begin by creating a platform object to move, by performing the following steps:

  1. We define a new Geometry called platform and apply the Unshaded material to it, as shown in the following code:
    platform = new Geometry("Platform", new Box(1f, 0.1f, 1f));
    platform.setMaterial(new Material(assetManager, "MatDefs/Misc/Unshaded.j3md"));
  2. Then, we attach the platform object to rootNode.
  3. Next, we define a new MotionPath object called path.
  4. We add 8 waypoints in a circular pattern, using the following code:
    for(inti = 0 ; i< 8; i++){
      path.addWayPoint(new Vector3f(0, FastMath.sin(FastMath.QUARTER_PI * i) * 10f, FastMath.cos(FastMath.QUARTER_PI * i) * 10f));
    }
  5. Then, we call path.setCycle(true) to make it connect the first and last waypoints.
  6. Now, we can define a new MotionEvent called event and supply platform and path in the constructor.
  7. We call event.setInitialDuration(10f) and setSpeed(1f).
  8. Finally, we call event.setLoopMode(LoopMode.Loop).
    How to do it...

    Debug MotionPath with red waypoints

  9. Optionally, we can visualize the path by calling the following method:
    path.enableDebugShape(assetManager, rootNode);
  10. Now, all we need to do is call event.play() to start the event!

How it works...

The for loop creates eight waypoints along a circle at 45 degrees distance from each other. However, to make a complete circle the first and last waypoints need to be connected or the path will stop at the final one. This is why setCycle(true) must be set. This is treated as the ninth waypoint at the same position as the first.

MotionEvent's initialDuration is the time it should take to complete the path. The speed defines the factor at which the initialDuration should be completed. So, setting the speed to 2f will halve the actual time it takes for the object to complete its movement. The loopMode, not surprisingly, defines whether the object should stop once it has completed the path, or continue. There's also an option to make it go back the same path again with LoopMode.Cycle. This is not related to MotionPath's setCycle method.

While this recipe doesn't explore the option, it's possible to have the spatial in MotionPath perform various types of rotation. By default, no rotation will be applied. By calling setDirectionType it is possible to, for example, let the object follow the path's rotation (face the direction of the path) or rotate by a fixed amount or always face a certain point. Some of the direction types require a rotation to be supplied with the setRotation method.

There's more...

Now, the object is moving along its given path and we can add several platforms moving in different patterns. Let's say we want something to happen once a platform reaches the end of its path. Maybe it should start the next one or trigger one of our ScriptObjects from the previous recipes.

In that case, we can use MotionPathListener. This is an interface with a callback method called onWayPointReached, which will be called every time the path passes a waypoint. It will supply both the MotionEvent and the index of the waypoint. If we want to trigger something at the end of the path, it might look like the following code snippet:

path.addListener(new MotionPathListener() {
  public void onWayPointReach(MotionEvent control, intwayPointIndex) {
    if (path.getNbWayPoints() == wayPointIndex + 1) {
      nextMotionEvent.play();
    }
  }
});
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.135.191.86