Compiling the AndEngine Racer Game Demo

The creator of AndEngine, Nicolas Gramlich, has released a number of sample projects to illustrate how to create games with the engine. The Racer sample is a simple top-down game where you drive a race car around a track and avoid obstacles. Here it is running in the emulator:

Creating the Eclipse Project

Getting this sample up and running is pretty straightforward once you know how. Start by creating a new Android project as normal. We want to add the AndEngine JAR file to this project so it's available to our code. Right-click the new project in Eclipse Navigator, and choose Properties. Click Java Build Path in the left-hand pane of the project properties dialog, and then select the Libraries tab.

Click the Add External JARs... browse to your AndEngine Box 2D extension JAR file and select it. Be sure to add the Box 2D extension not AndEngine core - the extension JAR also contains the core engine and the duplicate AndEngine classes will throw 'Already Added' Exceptions that prevent the project from being built.

Now open up your project's Activity source file, and replace the default code with Nicolas's Racer code from the samples project (but keep your package name). You'll also need to rename the file to RacerGameActivity.java to match the class name.

The following image files are needed by our project:

Download these and place them in a folder called assets/gfx off your project's root.

There's one last step before we can run our project in the emulator - download the compiled .so file for the Box 2D extension to a directory called libs/armeabi off our project root. Once it's there, the project should compile and run in the emulator just fine.

Analysis of the AndEngine Racer Code

I now want to have a detailed look at Nicolas' code, to break it down in order to understand what's going on where. There seems to be such a small amount of code to create this game and all its features that I'm very eager to know how it was accomplished. I want to look at features such as the acceleration of the car, cornering, collision detection both with the edges of the track and also the objects (crates) on the track, and physics behaviours such as how the boxes move when they are struck.

Pointing Eclipse to the JAR Source

To help us in our quest to understand what's going on under the bonnet, we can link the AndEngine JAR file to its source project, assuming that you compiled the JAR yourself. To do it, right-click the project in the Navigator, and choose Properties. On the project properties dialog, select Java Build Path in the left-hand pane, and open the Libraries tab. Expand the entry for the andenginebox2d.jar (or however yours is named), and select Source attachment. Now click the Edit.. button, then Workspace and select the Eclipse project which houses the Box 2D extension.

Now that Eclipse knows where to find the source, we can easily jump to the code for a particular class by pressing F3 when the cursor is at the class name, and also JavaDoc comments from the source will be used for the pop-up information the IDE produces when hovering over class or method names. This latter won't be too useful unfortunately, as Nicolas has used very few JavaDoc blocks in his code. Hopefully we'll also be able to step through the AndEngine code with the Eclipse debugger. All good juicy stuff!

RacerGameActivity Type Hierarchy

We can examine the entire class inheritance tree by pressing F4 with the RacerGameActivity.java file open in the editor. This shows us that the RacerGameActivity class extends BaseGameActivity, an AndEngine UI class which itself extends BaseActivity, another AndEngine UI class. BaseActivity extends the Android platform Activity class. BaseGameActivity also implements IGameInterface, another AndEngine UI component. BaseGameActivity does not however implement any of this interface's methods, so that must be done by RacerGameActivity.

The onLoadEngine() Method

Sure enough, when the app runs, the first method to execute is onLoadEngine(), one of the IGameInterface methods that must be implemented. It is invoked by the BaseGameActivity's onCreate() method. Inside onLoadEngine(), RacerGameActivity first instantiates an AndEngine Camera object and stores it in the mCamera class variable. The Camera constructor parameters are the camera's left edge X position, its top Y position, and the camera's width and height respectively. The camera represents a viewport onto the gameworld. The gameworld could be larger than the viewport, in which case the camera will only show a section of it. As AndEngine is a 2D engine, there's no Z coordinate to worry about.

The next line of onLoadEngine() instantiates an AndEngine Engine object. passing in a few options as an EngineOptions instance, as well as the camera created in the previous line. The engine is then returned by onLoadEngine() to the calling code in BaseGameActivity's onCreate() method, which stores the engine as the mEngine class variable.

The onLoadResources() Method

The next RacerGameActivity method to fire is onLoadResources(), also from IGameInterface via BaseGameActivity. As its name suggests, this method sets up resources for the game by loading various textures into class variables.

The onLoadScene() Method

This is the next RacerGameActivity method to execute, and originates in the IGameInterface interface we inherited from BaseGameActivity. It begins by instantiating an AndEngine Scene object, which represents the visible on-screen playing area, and also seems to handle touchscreen inputs. Next a background colour is set for the scene.

Then a Box 2D Physics world is created using the constructor with the signature below:

FixedStepPhysicsWorld(final int pStepsPerSecond, final Vector2 pGravity, final boolean pAllowSleep, final int pVelocityIterations, final int pPositionIterations)

Referring to this signature, we can see the Physics world is created having 30 steps every second, zero gravity, sleep is prevented, and 8 velocity iterations and 1 position iteration - whatever that means.

The remaining initialisation tasks have been split into private methods of RacerGameActivity, and these are then called in turn. Finally, the Physics world is linked to the Scene as an update handler presumably so that the scene will get its updates from the Physics world, which makes sense.

The initRaceTrack() method

As its name suggests, this private method sets up the race track around which the player drives the car. The race track is built in much the same way as a Scalextric track, but using textures rather than physical track sections. This way the track can be built from just two types of pieces - straight type and corner type. For the simple oval track in this game, there are two horizontal straight sections which are built as a TextureRegion instance that is textured with the straight texture and set at a width of three times that of the straight texture.

The top and bottom straight sections are attached to the Scene by calling the attachChild() method of the mScene private variable. passing in a Sprite created from the horizontal texture and positioned at the appropriate location.

The left and right vertical straight sections are added in much the same way, although before being added to the Scene, the Sprite created for each is rotated by 90 degrees.

The initRaceTrackBorders() method

This method creates the red border on each edge of the straight sections. The borders are created as Shape objects of 2 pixels width. Each shape is added to the Physics world by passing it into the PhysicsFactory.createBoxBody() static method along with the mPhysicsWorld private PhysicsWorld instance and a couple of other parameters that define how the body should act in the physics world.

All the shapes are then added to the scene and this method is done. So far we seem to have added the straight sections of the track and created the wall on each of their edges. It's not yet clear how or where the corners are dealt with!

The initCar() method

No surprises here - this method adds the player car to the physics world and to the scene. The car is a Sprite instance - or rather it is an instance of the TiledSprite subclass of Sprite. This subclass is used because the car texture is supplied in a tiled format i.e. multiple different textures in a single image file. The specific texture tile we want for our car is set by the setCurrentTileIndex() method of the TiledSprite.

As with the track edges, physics properties are given to our car by passing it into PhysicsFactory.createBoxBody(). As this is a dynamic object however, we need to link the box body returned by this method to the car sprite by creating a PhysicsConnector instance from the sprite and the box body, and passing that into the registerPhysicsConnector() method of the private mPhysicsWorld variable.

Lastly we attach the Sprite to the Scene.

The initObstacles() method

This method adds the obstacles - four wooden crates - to the track. They are added in similar fashion to the car, as they are also dynamic items and therefore need a PhysicsConnector. Note that they are created with a density of 0.1 while the car's density was 1. This is what makes the boxes go flying when struck by the car while the car just slows down.

The initOnScreenControls() method

This is the last method for setting up the game world, and it creates an on-screen analogue controller for the game, which is added as a child scene of the mScene private variable.

Hi, I have and error when I compile, Please help me:
[2011-12-18 23:58:39 - Racer] ERROR: Unknown option '--no-crunch'
[2011-12-18 23:58:39 - Racer] Android Asset Packaging Tool
[2011-12-18 23:58:39 - Racer]
[2011-12-18 23:58:39 - Racer] Usage:
[2011-12-18 23:58:39 - Racer] aapt l[ist] [-v] [-a] file.{zip,jar,apk}
[2011-12-18 23:58:39 - Racer] List contents of Zip-compatible archive.
[2011-12-18 23:58:39 - Racer]
[2011-12-18 23:58:39 - Racer] aapt d[ump] [--values] WHAT file.{apk} [asset [asset ...]]
[2011-12-18 23:58:39 - Racer] badging Print the label and icon for the app declared in APK.
[2011-12-18 23:58:39 - Racer] permissions Print the permissions from the APK.
[2011-12-18 23:58:39 - Racer] resources Print the resource table from the APK.
[2011-12-18 23:58:39 - Racer] configurations Print the configurations in the APK.
[2011-12-18 23:58:39 - Racer] xmltree Print the compiled xmls in the given assets.
[2011-12-18 23:58:39 - Racer] xmlstrings Print the strings of the given compiled xml assets.
[2011-12-18 23:58:39 - Racer]
[2011-12-18 23:58:39 - Racer] aapt p[ackage] [-d][-f][-m][-u][-v][-x][-z][-M AndroidManifest.xml] \
[2011-12-18 23:58:39 - Racer] [-0 extension [-0 extension ...]] [-g tolerance] [-j jarfile] \
[2011-12-18 23:58:39 - Racer] [--debug-mode] [--min-sdk-version VAL] [--target-sdk-version VAL] \
[2011-12-18 23:58:39 - Racer] [--app-version VAL] [--app-version-name TEXT] [--custom-package VAL] \
[2011-12-18 23:58:39 - Racer] [--rename-manifest-package PACKAGE] \
[2011-12-18 23:58:39 - Racer] [--rename-instrumentation-target-package PACKAGE] \
[2011-12-18 23:58:39 - Racer] [--utf16] [--auto-add-overlay] \
[2011-12-18 23:58:39 - Racer] [--max-res-version VAL] \
[2011-12-18 23:58:39 - Racer] [-I base-package [-I base-package ...]] \
[2011-12-18 23:58:39 - Racer] [-A asset-source-dir] [-G class-list-file] [-P public-definitions-file] \
[2011-12-18 23:58:39 - Racer] [-S resource-sources [-S resource-sources ...]] [-F apk-file] [-J R-file-dir] \
[2011-12-18 23:58:39 - Racer] [--product product1,product2,...] \
[2011-12-18 23:58:39 - Racer] [raw-files-dir [raw-files-dir] ...]
[2011-12-18 23:58:39 - Racer]
[2011-12-18 23:58:39 - Racer] Package the android resources. It will read assets and resources that are
[2011-12-18 23:58:39 - Racer] supplied with the -M -A -S or raw-files-dir arguments. The -J -P -F and -R
[2011-12-18 23:58:39 - Racer] options control which files are output.
[2011-12-18 23:58:39 - Racer]
[2011-12-18 23:58:39 - Racer] aapt r[emove] [-v] file.{zip,jar,apk} file1 [file2 ...]
[2011-12-18 23:58:39 - Racer] Delete specified files from Zip-compatible archive.
[2011-12-18 23:58:39 - Racer]
[2011-12-18 23:58:39 - Racer] aapt a[dd] [-v] file.{zip,jar,apk} file1 [file2 ...]
[2011-12-18 23:58:39 - Racer] Add specified files to Zip-compatible archive.
[2011-12-18 23:58:39 - Racer]
[2011-12-18 23:58:39 - Racer] aapt v[ersion]
[2011-12-18 23:58:39 - Racer] Print program version.
[2011-12-18 23:58:39 - Racer]
[2011-12-18 23:58:39 - Racer] Modifiers:
[2011-12-18 23:58:39 - Racer] -a print Android-specific data (resources, manifest) when listing
[2011-12-18 23:58:39 - Racer] -c specify which configurations to include. The default is all
[2011-12-18 23:58:39 - Racer] configurations. The value of the parameter should be a comma
[2011-12-18 23:58:39 - Racer] separated list of configuration values. Locales should be specified
[2011-12-18 23:58:39 - Racer] as either a language or language-region pair. Some examples:
[2011-12-18 23:58:39 - Racer] en
[2011-12-18 23:58:39 - Racer] port,en
[2011-12-18 23:58:39 - Racer] port,land,en_US
[2011-12-18 23:58:39 - Racer] If you put the special locale, zz_ZZ on the list, it will perform
[2011-12-18 23:58:39 - Racer] pseudolocalization on the default locale, modifying all of the
[2011-12-18 23:58:39 - Racer] strings so you can look for strings that missed the
[2011-12-18 23:58:39 - Racer] internationalization process. For example:
[2011-12-18 23:58:39 - Racer] port,land,zz_ZZ
[2011-12-18 23:58:39 - Racer] -d one or more device assets to include, separated by commas
[2011-12-18 23:58:39 - Racer] -f force overwrite of existing files
[2011-12-18 23:58:39 - Racer] -g specify a pixel tolerance to force images to grayscale, default 0
[2011-12-18 23:58:39 - Racer] -j specify a jar or zip file containing classes to include
[2011-12-18 23:58:39 - Racer] -k junk path of file(s) added
[2011-12-18 23:58:39 - Racer] -m make package directories under location specified by -J
[2011-12-18 23:58:39 - Racer] -u update existing packages (add new, replace older, remove deleted files)
[2011-12-18 23:58:39 - Racer] -v verbose output
[2011-12-18 23:58:39 - Racer] -x create extending (non-application) resource IDs
[2011-12-18 23:58:39 - Racer] -z require localization of resource attributes marked with
[2011-12-18 23:58:39 - Racer] localization="suggested"
[2011-12-18 23:58:39 - Racer] -A additional directory in which to find raw asset files
[2011-12-18 23:58:39 - Racer] -G A file to output proguard options into.
[2011-12-18 23:58:39 - Racer] -F specify the apk file to output
[2011-12-18 23:58:39 - Racer] -I add an existing package to base include set
[2011-12-18 23:58:39 - Racer] -J specify where to output R.java resource constant definitions
[2011-12-18 23:58:39 - Racer] -M specify full path to AndroidManifest.xml to include in zip
[2011-12-18 23:58:39 - Racer] -P specify where to output public resource definitions
[2011-12-18 23:58:39 - Racer] -S directory in which to find resources. Multiple directories will be scanned
[2011-12-18 23:58:39 - Racer] and the first match found (left to right) will take precedence.
[2011-12-18 23:58:39 - Racer] -0 specifies an additional extension for which such files will not
[2011-12-18 23:58:39 - Racer] be stored compressed in the .apk. An empty string means to not
[2011-12-18 23:58:39 - Racer] compress any files at all.
[2011-12-18 23:58:39 - Racer] --debug-mode
[2011-12-18 23:58:39 - Racer] inserts android:debuggable="true" in to the application node of the
[2011-12-18 23:58:39 - Racer] manifest, making the application debuggable even on production devices.
[2011-12-18 23:58:39 - Racer] --min-sdk-version
[2011-12-18 23:58:39 - Racer] inserts android:minSdkVersion in to manifest. If the version is 7 or
[2011-12-18 23:58:39 - Racer] higher, the default encoding for resources will be in UTF-8.
[2011-12-18 23:58:39 - Racer] --target-sdk-version
[2011-12-18 23:58:39 - Racer] inserts android:targetSdkVersion in to manifest.
[2011-12-18 23:58:39 - Racer] --max-res-version
[2011-12-18 23:58:39 - Racer] ignores versioned resource directories above the given value.
[2011-12-18 23:58:39 - Racer] --values
[2011-12-18 23:58:39 - Racer] when used with "dump resources" also includes resource values.
[2011-12-18 23:58:39 - Racer] --version-code
[2011-12-18 23:58:39 - Racer] inserts android:versionCode in to manifest.
[2011-12-18 23:58:39 - Racer] --version-name
[2011-12-18 23:58:39 - Racer] inserts android:versionName in to manifest.
[2011-12-18 23:58:39 - Racer] --custom-package
[2011-12-18 23:58:39 - Racer] generates R.java into a different package.
[2011-12-18 23:58:39 - Racer] --auto-add-overlay
[2011-12-18 23:58:39 - Racer] Automatically add resources that are only in overlays.
[2011-12-18 23:58:39 - Racer] --rename-manifest-package
[2011-12-18 23:58:39 - Racer] Rewrite the manifest so that its package name is the package name
[2011-12-18 23:58:39 - Racer] given here. Relative class names (for example .Foo) will be
[2011-12-18 23:58:39 - Racer] changed to absolute names with the old package so that the code
[2011-12-18 23:58:39 - Racer] does not need to change.
[2011-12-18 23:58:39 - Racer] --rename-instrumentation-target-package
[2011-12-18 23:58:39 - Racer] Rewrite the manifest so that all of its instrumentation
[2011-12-18 23:58:39 - Racer] components target the given package. Useful when used in
[2011-12-18 23:58:39 - Racer] conjunction with --rename-manifest-package to fix tests against
[2011-12-18 23:58:39 - Racer] a package that has been renamed.
[2011-12-18 23:58:39 - Racer] --product
[2011-12-18 23:58:39 - Racer] Specifies which variant to choose for strings that have
[2011-12-18 23:58:39 - Racer] product variants
[2011-12-18 23:58:39 - Racer] --utf16
[2011-12-18 23:58:39 - Racer] changes default encoding for resources to UTF-16. Only useful when API
[2011-12-18 23:58:39 - Racer] level is set to 7 or higher where the default encoding is UTF-8.
[2011-12-18 23:58:39 - Racer] --non-constant-id
[2011-12-18 23:58:39 - Racer] Make the resources ID non constant. This is required to make an R java class
[2011-12-18 23:58:39 - Racer] that does not contain the final value but is used to make reusable compiled
[2011-12-18 23:58:39 - Racer] libraries that need to access resources.

The error you have (it is really just one error) is produced by the Android Asset Packaging Tool (aapt) during the compilation process. It seems like it doesn't recognise an option that it is being started with, and so it's spitting out its full usage help text.

I believe this is a version issue, you need to update "Android SDK Platform-Tool" and "Android Asset Packaging Tool" to Revision 8 from the Android SDK manager in Eclipse.

Once you've done this, clean the project and try again.

Post new comment

The content of this field is kept private and will not be shown publicly.
  • Web page addresses and e-mail addresses turn into links automatically.
  • Lines and paragraphs break automatically.

More information about formatting options


Theme port sponsored by Duplika Hosting reloaded by Deeson Design
Home Back To Top