Quantcast
Channel: Envato Tuts+ Game Development
Viewing all articles
Browse latest Browse all 728

Introduction to JavaFX for Game Development

$
0
0

JavaFX is a cross platform GUI toolkit for Java, and is the successor to the Java Swing libraries. In this tutorial, we will explore the features of JavaFX that make it easy to use to get started programming games in Java.

This tutorial assumes you already know how to code in Java. If not, check out Learn Java for Android, Introduction to Computer Programming With Java: 101 and 201, Head First Java, Greenfoot, or Learn Java the Hard Way to get started.

Installation

If you already develop applications with Java, you probably don't need to download anything at all: JavaFX has been included with the standard JDK (Java Development Kit) bundle since JDK version 7u6 (August 2012).  If you haven't updated your Java installation in a while, head to the Java download website for the latest version. 

Basic Framework Classes

Creating a JavaFX program begins with the Application class, from which all JavaFX applications are extended.  Your main class should call the launch() method, which will then call the init() method and then the start() method, wait for the application to finish, and then call the stop() method.  Of these methods, only the start() method is abstract and must be overridden.

The Stage class is the top level JavaFX container. When an Application is launched, an initial Stage is created and passed to the Application's start method. Stages control basic window properties such as title, icon, visibility, resizability, fullscreen mode, and decorations; the latter is configured using StageStyle. Additional Stages may be constructed as necessary. After a Stage is configured and the content is added, the show() method is called.

Knowing all this, we can write a minimal example that launches a window in JavaFX:

Structuring Content

Content in JavaFX (such as text, images, and UI controls) is organized using a tree-like data structure known as a scene graph, which groups and arranges the elements of a graphical scene. 

JavaFX Scene Graph
Representation of a JavaFX Scene Graph.

A general element of a scene graph in JavaFX is called a Node. Every Node in a tree has a single "parent" node, with the exception of a special Node designated as the "root".  A Group is a Node which can have many "child" Node elements. Graphical transformations (translation, rotation, and scale) and effects applied to a Group also apply to its children. Nodes can be styled using JavaFX Cascading Style Sheets (CSS), quite similar to the CSS used to format HTML documents.

The Scene class contains all content for a scene graph, and requires a root Node to be set (in practice, this is often a Group). You can set the size of a Scene specifically; otherwise, the size of a Scene will be automatically calculated based on its content. A Scene object must be passed to the Stage (by the setScene() method) in order to be displayed.

Rendering Graphics

Rendering graphics is particularly important to game programmers! In JavaFX, the Canvas object is an image on which we can draw text, shapes, and images, using its associated GraphicsContext object. (For those developers familiar with the Java Swing toolkit, this is similar to the Graphics object passed to the paint() method in the JFrame class.)

The GraphicsContext object contains a wealth of powerful customization abilities. To choose colors for drawing text and shapes, you can set the fill (interior) and stroke (border) colors, which are Paint objects: these can be a single solid Color, a user-defined gradient (either LinearGradient or RadialGradient), or even an ImagePattern. You can also apply one or more Effect style objects, such as LightingShadow, or GaussianBlur, and change fonts from the default by using the Font class. 

The Image class makes it easy to load images from a variety of formats from files and draw them via the GraphicsContext class. It's easy to construct procedurally generated images by using the WritableImage class together with the PixelReader and PixelWriter classes.

Using these classes, we can write a much more worthy "Hello, World"-style example as follows. For brevity, we'll just include the start() method here (we'll skip the import statements and main() method); however, complete working source code can be found in the GitHub repo that accompanies this tutorial.

The Game Loop

Next, we need to make our programs dynamic, meaning that the game state changes over time. We'll implement a game loop: an infinite loop that updates the game objects and renders the scene to the screen, ideally at a rate of 60 times per second. 

The easiest way to accomplish this in JavaFX is using the AnimationTimer class, where a method (named handle()) may be written that will be called at a rate of 60 times per second, or as close to that rate as is possible. (This class does not have to be used solely for animation purposes; it is capable of far more.)

Using the AnimationTimer class is a bit tricky: since it is an abstract class, it cannot be created directly—the class must be extended before an instance can be created. However, for our simple examples, we will extend the class by writing an anonymous inner class. This inner class must define the abstract method handle(), which will be passed a single argument: the current system time in nanoseconds. After defining the inner class, we immediately invoke the start() method, which begins the loop. (The loop can be stopped by calling the stop() method.)

With these classes, we can modify our "Hello, World" example, creating an animation consisting of the Earth orbiting around the Sun against a starry background image.

There are alternative ways to implement a game loop in JavaFX. A slightly longer (but more flexible) approach involves the Timeline class, which is an animation sequence consisting of a set of KeyFrame objects. To create a game loop, the Timeline should be set to repeat indefinitely, and only a single KeyFrame is required, with its Duration set to 0.016 seconds (to attain 60 cycles per second). This implementation can be found in the Example3T.java file in the GitHub repo.

Frame-Based Animation

Another commonly needed game programming component is frame-based animation: displaying a sequence of images in rapid succession to create the illusion of movement. 

Assuming that all animations loop and all frames display for the same number of seconds, a basic implementation could be as simple as follows:

To integrate this class into the previous example, we could create an animated UFO, initializing the object using the code:

...and, within the AnimationTimer, adding the single line of code:

...at the appropriate spot. For a complete working code example, see the file Example3AI.java in the GitHub repo

Handling User Input

Detecting and processing user input in JavaFX is straightforward. User actions that can be detected by the system, such as key presses and mouse clicks, are called events. In JavaFX, these actions automatically cause the generation of objects (such as KeyEvent and MouseEvent) that store the associated data (such as the actual key pressed or the location of the mouse pointer). Any JavaFX class which implements the EventTarget class, such as a Scene, can "listen" for events and handle them; in the examples that follow, we'll show how to set up a Scene to process various events.

Glancing through the documentation for the Scene class, there are many methods that listen for handling different types of input from different sources. For instance, the method setOnKeyPressed() can assign an EventHandler that will activate when a key is pressed, the method setOnMouseClicked() can assign an EventHandler that activates when a mouse button is pressed, and so on. The EventHandler class serves one purpose: to encapsulate a method (called handle()) that is called when the corresponding event occurs. 

When creating an EventHandler, you must specify the type of Event that it handles: you can declare an EventHandler<KeyEvent> or an EventHandler<MouseEvent>, for example. Also, EventHandlers are often created as anonymous inner classes, as they are typically only used once (when they are passed as an argument to one of the methods listed above).

Handling Keyboard Events

User input is often processed within the main game loop, and thus a record must be kept of which keys are currently active. One way to accomplish this is by creating an ArrayList of String objects. When a key is initially pressed, we add the String representation of the KeyEvent's KeyCode to the list; when the key is released, we remove it from the list. 

In the example below, the canvas contains two images of arrow keys; whenever a key is pressed, the corresponding image becomes green. 


The source code is contained in the file Example4K.java in the GitHub repo.

Handling Mouse Events

Now let's look at an example that focuses on the MouseEvent class rather than the KeyEvent class. In this mini-game, the player earns a point every time the target is clicked.


Since the EventHandlers are inner classes, any variables they use must be final or "effectively final", meaning that the variables can not be reinitialized. In the previous example, the data was passed to the EventHandler by means of an ArrayList, whose values can be changed without reinitializing (via the add() and remove() methods). 

However, in the case of basic data types, the values cannot be changed once initialized. If you would like the EventHandler to access basic data types that are changed elsewhere in the program, you can create a wrapper class that contains either public variables or getter/setter methods. (In the example below, IntValue is a class that contains a publicint variable called value.)

The full source code is contained in the GitHub repo; the main class is Example4M.java.

Creating a Basic Sprite Class With JavaFX

In video games, a sprite is the term for a single visual entity. Below is an example of a Sprite class that stores an image and position, as well as velocity information (for mobile entities) and width/height information to use when calculating bounding boxes for the purposes of collision detection. We also have the standard getter/setter methods for most of this data (omitted for brevity), and some standard methods needed in game development:

  • update(): calculates the new position based on the Sprite's velocity.
  • render(): draws the associate Image to the canvas (via the GraphicsContext class) using the position as coordinates.
  • getBoundary(): returns a JavaFX Rectangle2D object, useful in collision detection due to its intersects method.
  • intersects(): determines whether the bounding box of this Sprite intersects with that of another Sprite.

The full source code is included in Sprite.java in the GitHub repo.

Using the Sprite Class

With the assistance of the Sprite class, we can easily create a simple collecting game in JavaFX.  In this game, you assume the role of a sentient briefcase whose goal is to collect the many money bags that have been left lying around by a careless previous owner. The arrow keys move the player around the screen.

This code borrows heavily from previous examples: setting up fonts to display the score, storing keyboard input with an ArrayList, implementing the game loop with an AnimationTimer, and creating wrapper classes for simple values that need to be modified during the game loop.

One code segment of particular interest involves creating a Sprite object for the player (briefcase) and an ArrayList of Sprite objects for the collectibles (money bags):

Another code segment of interest is the creation of the AnimationTimer, which is tasked with:

  • calculating the time elapsed since the last update
  • setting the player velocity depending on the keys currently pressed
  • performing collision detection between the player and collectibles, and updating the score and list of collectibles when this occurs (an Iterator is used rather than the ArrayList directly to avoid a Concurrent Modification Exception when removing objects from the list)
  • rendering the sprites and text to the canvas

As usual, complete code can be found in the attached code file (Example5.java) in the GitHub repo.

Next Steps

Conclusion

In this tutorial, I've introduced you to JavaFX classes that are useful in game programming.  We worked through a series of examples of increasing complexity, culminating in a sprite-based collection-style game.  Now you're ready to either investigate some of the resources listed above, or to dive in and start creating your own game. The best of luck to you in your endeavors!


Viewing all articles
Browse latest Browse all 728

Trending Articles