Updating and managing project dependencies
This recipe will show you how to leverage Gradle in order to maintain your project and its dependencies. By the end of the recipe, you will be able to upgrade to a newer version of Libgdx and add third-party extensions and arbitrary Java libraries.
Oftentimes, people tend to be reluctant to learn new technologies, especially build systems such as Gradle. However, they actually tremendously simplify the process, thus helping us make even more awesome games.
Getting ready
Let's start with the environment-test
project we created in the Setting up a cross-platform development environment recipe. At this point, you should have the project up and running within Eclipse or the IDE of your choice.
How to do it…
Your application's dependencies are expressed in the build.gradle
text file, which is pretty much the only file we will manipulate. Be advised against tinkering with the project-specific Gradle files as you stand a really good chance of making all hell break loose.
Throughout this primer, and for space reasons, we will only show small snippets from the build file.
Go ahead and open the build.gradle
file from Eclipse. The first thing you will come across is the buildscript
element, which defines the list of repositories and basic dependencies. Repositories act as a library-serving system. We can reference libraries by name, and Gradle will ask the list of repositories for a library that matches the name:
buildscript { repositories { maven { url 'https://github.com/steffenschaefer/gwt-gradle-plugin/raw/maven-repo/' } ... } dependencies { ... } }
The allprojects
element contains a string with the application version. Additionally, it defines appName
as well as the Libgdx and roboVM versions it should build against. It also provides a list of repositories to fetch from:
allprojects { apply plugin: "eclipse" apply plugin: "idea" version = "1.0" ext { appName = "environment-test" gdxVersion = "1.2.0" roboVMVersion = "0.0.13" } repositories { ... } }
Every project has a project element indicating its name. A skeleton application's core project will only depend on the previously defined Libgdx version:
project(":core") { apply plugin: "java" dependencies { compile "com.badlogicgames.gdx:gdx:$gdxVersion" } }
Platform-specific projects, such as a desktop project, will depend on core as well as their corresponding backend and potentially native libraries:
project(":desktop") { apply plugin: "java" dependencies { compile project(":core") compile "com.badlogicgames.gdx:gdx-backend-lwjgl:$gdxVersion" compile "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-desktop" } }
Do not panic if you do not fully understand everything that goes on inside the build script. However, you should at least have a very basic grasp on how the general structure holds itself together.
Now, let's get on to some useful business.
Dependencies that are pulled from repositories take the following typical Maven format:
compile '<groupId>:<artifactId>:<version>:<classifier>'
Intuitively, whenever you desire to change a dependency version, you just need to go and modify the version component of its declaration. Now, imagine the Libgdx team has released a new version and we are all very excited with the new features; it is time to try them out. Conveniently enough, throughout the script, the Libgdx version points to the gdxVersion
variable. We only need to find the allprojects
element and change the following:
gdxVersion = "1.1.0"
To the following, you are free to choose whichever version you like:
gdxVersion = "1.2.0"
To make Gradle fetch the new dependencies, select all the projects, right-click on Gradle, and then click on Refresh All.
Note
Libgdx has stable and nightly builds. Stable builds are well tested, planned builds that can be identified by their version number, 1.2.0, for instance. Nightly builds, in turn, are generated overnight from whatever the Git repository contains. To use nightly builds in your project, you need to set 1.2-SNAPSHOT
as the version identifier. Nightly builds are good to test and get the latest features as they are introduced; however, they are considerably riskier and prone to breaking. Use the stable builds if peace of mind is what you seek. Luckily enough, you can switch between them just by changing the gdxVersion
variable.
Libgdx comes with several additional libraries that provide a ton of extra features. The reason they are not part of the core is because either not everyone is likely to need them or because they might not work on all backends. These extensions have been mavenized and can be fetched from the repositories.
Note
Linking against libraries you do not need will unnecessarily increase the size of your distributable package. Desktop downloads are not too big of a problem as we have AAA game downloads going up to 50 GB nowadays. However, mobile games need to be careful about this since some 3G connections have bandwidth limits.
Currently, the following are the Libgdx Gradle-ready extensions along with their required dependencies for each of the projects. The core dependency will add the interfaces for you to use within the game code, whilst the platform-specific dependencies will contain the implementation of such interfaces. You will need to add them inside the corresponding dependencies
element.
A bullet is a wrapper for the popular open source 3D physics library. Note that it is not compatible with the HTML5 backend as it needs to run native code.
To use it with desktop, we use the following:
compile "com.badlogicgames.gdx:gdx-bullet-platform:$gdxVersion:natives-desktop"
The FreeTypeFont extension helps you generate bitmaps from TTF fonts on the fly. It is not compatible with the HTML5 backend.
To use it with desktop, we use the following:
compile "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-desktop"
The Controllers extension provides an API to get events from the game controllers. It is not compatible with the iOS backend; although the project still compiles and runs, it will just not detect any controller or event. For more information on controllers, see Chapter 4, Detecting User Input.
To use it with desktop, we use the following:
compile "com.badlogicgames.gdx:gdx-controllers-desktop:$gdxVersion" compile "com.badlogicgames.gdx:gdx-controllers-platform:$gdxVersion:natives-desktop"
The Box2D extension will provide you with a full-blown rigid body physics engine compatible with all backends. Read more about it in Chapter 10, Rigid Body Physics with Box2D.
We run the following code to use it with desktop:
compile "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-desktop"
For Android, we use the following code:
compile "com.badlogicgames.gdx:gdx-box2d:$gdxVersion" natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-armeabi" natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-armeabi-v7a" natives "com.badlogicgames.gdx:gdx-box2d-platform:$gdxVersion:natives-x86"
The Tools extension provides texture packing, font generation, and particle editor functionalities, only compatible with the desktop backend.
It is possible to add extra repositories to Gradle to look for the files you need by adding them to the allprojects
section. Gradle supports Maven- and Ivy-formatted repositories:
allprojects { ... repositories { ivy { url "https://some-ivy-repo.com/repo" } maven { url "https://some-maven-repo.com/repo" } } }
The library you want to use so desperately might not be in any Maven or Ivy repository. Is everything lost? Of course not! You can make projects depend on local files such as arbitrary JAR packages.
For instance, you can place the JAR files you need inside a lib
folder in each project. Then, you will need to add the following entry to the dependencies
section of the projects:
dependencies { compile fileTree(dir: 'libs', include: '*.jar') }
HTML5 projects will require extra attention when adding dependencies. The GWT compiler needs to know about the modules the application will use. This information needs to be specified in both the GdxDefinition.gwt.xml
and GdxDefinitionSuperdev.gwt.xml
files located in the class path. The following snippet shows a typical gwt.xml
file highlighting the addition of the popular Universal Tween Engine dependency:
<module rename-to="html">
<inherits name='com.badlogic.gdx.backends.gdx_backends_gwt' />
<inherits name='com.cookbook.environment.EnvironmentTest' />
<inherits name='aurelienribon.tweenengine'/>
<entry-point class='com.cookbook.environment.client.GwtLauncher' />
<set-configuration-property name="gdx.assetpath" value="../android/assets" />
</module>
The Box2D extension will require you to inherit from the following module:
<inherits name='com.badlogic.gdx.physics.box2d.box2d-gwt' />
The Controllers extension will ask for the following module:
<inherits name='com.badlogic.gdx.controllers.controllers-gwt' />
The AI extension will require the following:
<inherits name='com.badlogic.gdx.ai' />
Managing GWT projects can be a bit fiddly, and we will cover this topic more thoroughly in the Making libraries compatible with GWT recipe of Chapter 11, Third-party Libraries and Extras.
Every time you add or update a dependency, it is advisable to rebuild the Gradle model so that everything is up to date and you can carry on working normally. Select Gradle and Refresh All from the project by right-clicking on the contextual menu.
There's more…
Telling Gradle to refresh a project's dependencies will automatically make the system download those that have changed when the dependency is a snapshot. For example, this is what happens with the Libgdx nightly builds:
gdxVersion = "1.2.0"
However, you might want to force Gradle to redownload a specific dependency or even all of them. This can come in handy when a library changes, but the version number is still the same. Though rare, this can very well happen if someone makes a mistake.
Gradle downloads and puts dependencies in a .gradle
directory inside the user's home
folder. It is possible to delete either the whole folder or specific libraries to make Gradle download them again the next time it tries to build the project.
Digging a bit deeper, you can tell Gradle that a particular dependency is prone to change often. It will then check every 24 hours whether it has changed. If it has, it will redownload the dependency. This is achieved with the changing
property:
dependencies { compile group: "group", name: "project", version: "1.1-SNAPSHOT", changing: true }
Once more, for further information on how to tune Gradle to your taste, refer to the official user guide.
See also
- If you want to know more about libraries and tools that work well with Libgdx and can help you in your game development adventure, do not forget to read Chapter 11, Third-party Libraries and Extras.