Creating Mobile Apps with JavaFX – Part 1

GraalVM and Gluon Substrate Let You Build Native Images

Mobile application offerings for both IOS and Android continue increasing each year.

In this three-part series, I’ll show how to use JavaFX for mobile app development: JavaFX looks great and runs on both mobile platforms. You use the same JavaFX code targeting Google Play and Apple App stores. Performance is excellent and startup time is fast with native images. You use Java 11+ and the latest JavaFX.

Our game is TiltMaze Labyrinth. Figure 1 shows TiltMaze running on an Android Nexus 5X. Figure 2 shows TiltMaze running on an iPhone 8 Plus.

Figure 1. TiltMaze on Android
TiltMaze on iPhone
Figure 2. TiltMaze on iPhone

We’ll discuss TiltMaze in three parts. First, we explore the JavaFX code: the basic structure of an animation-type app and the Gluon Attach API that lets you access hardware-specific features in a device-agnostic way. In Part 2, we’ll discuss the technologies we use with JavaFX to build the three target applications: “regular” JVM, native iOS image, and native Android image. We’ll include the tools and development requirements needed for each target. Lastly in Part 3, we’ll discuss how to upload this application to the respective mobile app stores.

TiltMaze Labyrinth

Let’s start with the end result first. TiltMaze Labyrinth is a mobile game you can install from both the Apple App Store and Google Play. Download TiltMaze here on your mobile device or tablet to play.

The game is simple enough: you navigate a rolling ball through a maze within the given time allotment while avoiding strategically placed holes. As you tilt the phone or tablet, the application reads the device’s accelerometer sensor and moves the ball based on the reading.  The Novice-Expert slider controls how fast the ball rolls and the time allotment for completing the maze. As your skill improves, you can challenge your dexterity by making the ball movements more sensitive while simultaneously decreasing the time allotment.

JavaFX

I am a big proponent of using FXML (FX markup language) to describe your JavaFX views.  To those not familiar with JavaFX, FXML is an XML-based markup language that lets you describe a UI scene. A free tool, Scene Builder, enables drag-and-drop UI design that produces FXML. FXML helps keep your UI separate from your business logic and application control. You can download Scene Builder from Gluon here. We used FXML to build the TiltMaze UI.

Part of the appeal of this mobile application is its simplicity. TiltMaze is a single-view game. It does not require any cloud data, user sign-ins, complicated menus, or multiple views. The UI is the application and standard JavaFX creates the animations that power the game. You can access the JavaFX source code for TiltMaze on GitHub here: https://github.com/gailasgteach/TiltMaze. Note that we removed sensitive licensing and credential information from the project!

The Accelerometer

The accelerometer is a sensor that measures velocity changes in three dimensions: horizontally, vertically, and up-down movements (that include the effects of gravity). We ignore the up-down movements (or the Z-axis) and respond only to changes in the X-axis and Y-axis. The coordinate system for the accelerometer matches the JavaFX coordinate system for the X-axis, where values increase from left to right. For the Y-axis, however, the accelerometer coordinate system is opposite. In JavaFX, the origin for the Y-axis is at the top and numbers increase as you move towards the bottom of the screen. 

The accelerometer is very sensitive; in fact, it’s difficult to hold a phone or tablet in your hand, remaining as motionless as possible, and not see readings change. The good news is that you sample readings in an Animation loop and use these values to update an object in the XY-coordinate space. You multiply the Y-axis reading by -1 so that it conforms to the JavaFX coordinate system. Gluon’s offerings include the Attach API that lets you access the various hardware features of typical mobile devices and tablets. Both Apple IOS and Android devices have accelerometers. Here’s how to access the accelerometer in your JavaFX mobile application.

try {
    service = AccelerometerService.create().get();
    System.out.println("Got accelerometer service.");
} catch (Exception e) {
    // No accelerometer, using mouse events.
    System.out.println("No accelerometer service.");
         . . . 
}

Once you have the AccelerometerService initialized, you can start and stop it, depending on whether the game is in progress.

// start the accelerometer service
service.start();
// stop the accelerometer service
service.stop();

The TiltMaze game lets you control a rolling ball by tilting the phone. As you tilt the phone left or right, the game moves the ball along the X-axis by updating the translateX property of the ball. Similarly, as you tilt the phone vertically, the game moves the ball along the Y-axis by updating its translateY property. Since the accelerometer measures changes in velocity, these readings let you simulate a rolling ball by updating the ball’s position. While the game is playing, we read the accelerometer in an Animation loop, as follows.

acceleration = service.getCurrentAcceleration();
xv = acceleration.getX();
yv = acceleration.getY() * -1;

Using these values, we check for possible collisions or falling into holes before updating the ball’s XY position.

ball.setTranslateX(ball.getTranslateX() + xv);
ball.setTranslateY(ball.getTranslateY() + yv);

As the ball rolls, we also mark its path by updating a JavaFX Path object, adding a LineTo segment to the path with each update.

path.getElements().add(
        new LineTo(ball.getTranslateX(), ball.getTranslateY()));

Figure 3 shows a game in progress. The ball’s path is marked in blue and the countdown timer has 6.5 seconds remaining.  Of course, the game must perform collision detection with the maze barriers, holes, and outside boundaries. We leave this code for you to digest at your leisure!

Figure 3. TiltMaze during play

The Novice/Expert slider is disabled during play, but can be adjusted between games. The Novice setting has the longest game time and the slowest ball roll. The Expert setting corresponds to the shortest game time and the fastest ball roll. And you can experiment with values in between that fit your level.

Scaling to the device size

Although mobile devices are generally similar in that they’re portrait-mode rectangles, their sizes can vary quite a bit. We scale the maze so that the aspect ratio is constant and fits within the device’s form factor. We compute a scale factor, using the resulting scale factor to build the maze’s predefined barriers, boundaries, and holes.

We limit orientation for the game for portrait mode only. If you reorient your device, the application stays in portrait mode.

Mouse Events

The edit-compile-install-run cycle is relatively long for native targets. Therefore, we simulate the maze program on a desktop to test the JavaFX UI as much as possible before installing it on a mobile device. We use mouse events instead of the accelerometer to guide the ball through the maze. Although this is really a poor imitation of an accelerometer, it provides a convenient environment for testing the UI: the progress indicator, the Novice/Expert slider, and the Start/Stop game button.

Performance

We installed the TiltMaze application on an iPhone 8 Plus and an Android Nexus 5X. The iPhone model is a newer and faster device, but both targets perform the ball roll smoothly with no issues. The GraalVM-Gluon build creates images that run natively on the target devices.

Next

In Part 2, we show you how to build and install TiltMaze on a locally connected iPhone and Android device.

Topics:

Don’t Forget to Share This Post!

Comments (4)

Your email address will not be published. Required fields are marked *

Highlight your code snippets using [code lang="language name"] shortcode. Just insert your code between opening and closing tag: [code lang="java"] code [/code]. Or specify another language.

  • Almas Baimagambetov

    Awesome stuff! Great use of `AccelerometerService` API to showcase what JavaFX can do on mobile.

  • Hallvard Trætteberg

    Great to show students, who use JavaFX and FXML to make apps of similar complexity in two university courses I run! I have demonstrated this for them with an app of my own (simple todo-list), but the “last mile” i.e. deploying it to an actual device is in general too tricky for them. E.g. installing the Android dev. kit, connecting a device and running it isn’t trivial, and the setup for iOS seems more complex.

    A more specific comment on part 1: I wonder why you use translateX/Y and not layoutX/Y for the ball’s position? My impression is that translateX/Y in general should be used for temporarily rendering a node with an offset e.g. during drag’n drop, not its “stable” location? I guess it doesn’t really matter if the ball isn’t managed by a pane’s layout logic, but still I’d use layoutX/Y for this.

  • Carl Dea

    Gail,
    Nice work!
    I look forward to the second part. For the assets and icons for iOS how did you create all icon the sizes?

    • Gail Anderson

      Hi Carl,
      I used: https://appicon.co/ — generates a set of icons from a single 1024 x 1024 PNG file. I created the icon image using Inkscape. (From Part 2 🙂

Related Articles

Subscribe to foojay updates:

https://foojay.io/feed/
Copied to the clipboard