Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions templates/Fun-and-Games-LibGDX/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# The bundle and its provenance record are generated by the publish workflow.
# Neither is ever committed — see templates/README.md, "Build provenance".
*.cgt
cgt-build.properties
94 changes: 94 additions & 0 deletions templates/Fun-and-Games-LibGDX/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
# Fun and Games LibGDX

A [Code on the Go](https://github.com/appdevforall/CodeOnTheGo) template bundle that adds
**three small Android games** built with [libGDX](https://libgdx.com/) 1.13.1 to the New Project
screen. Each one creates a complete, playable game project that builds and runs on the device.
They are ports of the jMonkeyEngine games in [`../Fun-and-Games-JME`](../Fun-and-Games-JME).

| Template | Directory | Language | Game |
|---|---|---|---|
| Demo (libGDX) | `demo/` | Java | A 3D Earth you drag to spin, an orbiting rocket with an exhaust trail and bloom glow, a starfield; tap for points |
| Block Game (libGDX) | `blockgame/` | Kotlin | Falling-block puzzle: drag to move, drag down to drop faster, tap to rotate, long-press to hard-drop |
| Bubble Wand (libGDX) | `bubblewand/` | Kotlin | First-person shooter: catch floating balloon animals in bubbles with an on-screen D-pad and **FIRE** button |

## How it works

There is no code. The bundle is a `.cgt` file: a zip of the three directories plus
`templates.json`, which Code on the Go reads directly. Install it under **Preferences →
Extensions Manager → Templates** with the **+** button, and the three templates appear in
**New Project**. Nothing to enable, no permissions.

Files ending in `.peb` are rendered by Pebble at project-creation time and lose the suffix;
everything else is copied byte for byte. Besides `${{APP_NAME}}` and `${{PACKAGE_NAME}}`, these
templates take the toolchain from the IDE: `${{AGP_VERSION}}`, `${{KOTLIN_VERSION}}`,
`${{GRADLE_VERSION}}`, `${{COMPILE_SDK}}`, `${{TARGET_SDK}}`, `${{MIN_SDK}}` and the Java
compatibility tokens.

## How the build works

- **libGDX ships in the bundle.** `templates.json` lists the libGDX files under `libraries`, and
the bundle build downloads them from Maven Central and places them in each game's `app/libs/`:
`gdx-1.13.1.jar`, `gdx-jnigen-loader-2.5.2.jar` (which `gdx` needs),
`gdx-backend-android-1.13.1.aar`, and the `gdx-platform` natives jars for `armeabi-v7a` and
`arm64-v8a`. Each `app/build.gradle` uses those files, so a generated project does not fetch
libGDX.
- **Native libraries:** `libgdx.so` sits inside the per-ABI natives jars. A `copyAndroidNatives`
task in `app/build.gradle` unpacks them into `build/gdx-natives/<abi>/` before AGP merges
native libraries. Builds include `armeabi-v7a` and `arm64-v8a` only. The unpacked files must not
go into `app/libs/`: a Copy task owns its whole destination, so Gradle would count the jars
there as its output and fail the compile for using them without depending on it.
- **AndroidX:** libGDX needs `androidx.core` at runtime. A local `.aar` does not carry its
dependencies, so `app/build.gradle` declares `androidx.core:core` directly. Code on the Go
resolves `androidx.*` only from its offline Maven repository, which lacks some of what newer
`androidx.core` releases pull in, so the templates force versions the repository has:

| Module | Forced version |
|---|---|
| `androidx.core:core` | 1.9.0 |
| `androidx.collection:collection` | 1.4.2 |
| `androidx.annotation:annotation` | 1.8.1 |
| `androidx.lifecycle:lifecycle-runtime`, `lifecycle-common` | 2.5.1 |

These match the versions Code on the Go's own AndroidX templates use.

## Controls

| Game | Controls |
|---|---|
| Demo | Drag to rotate the Earth · flick to spin with inertia · tap for +10 points |
| Block Game | Drag left/right to move · drag down to soft-drop · tap to rotate · long-press to hard-drop |
| Bubble Wand | Left half: drag to walk · right half: drag to look, tap to shoot · or use the D-pad and **FIRE** · **HIDE UI** toggles the buttons |

A hardware keyboard also works (arrow keys, space, WASD).

## Notes for template authors

- **AGP 9 built-in Kotlin:** the Kotlin templates do not apply `org.jetbrains.kotlin.android` in
the app module (AGP 9 rejects it); `jvmTarget` is set through `kotlin { compilerOptions { } }`.
- **Pebble drops the newline right after `}}`.** A token at the end of a line needs a trailing
space (`compileSdk = ${{COMPILE_SDK}} `), or the next line is joined onto it. Do not strip the
trailing whitespace in these files.
- **Don't drop to libGDX 1.12.x.** It avoids AndroidX, but its `libgdx.so` isn't 16 KB-page
aligned, and Google Play Protect blocked the builds as harmful. libGDX 1.13.0 also uses
`androidx.core` at runtime without declaring it, so it crashes on launch without the pins above.
- **Changing the libGDX version** means changing three places together: the file names in each
`app/build.gradle.peb`, the `src` URLs and `sha256` values in `templates.json`, and
`gradle/libs.versions.toml.peb`.

## Building

The `.cgt` is **never committed**. The publish workflow generates it. To build one locally:

```sh
./scripts/build-templates.sh Fun-and-Games-LibGDX
unzip -l dist/fun-and-games-libgdx.cgt
```

See [`../README.md`](../README.md) for authoring guidance and the format reference.

## Credit

Written by **James Turner**. Converted from the standalone
[FunandGames-libGDX](https://github.com/appdevforall/FunandGames-libGDX) repository to a template
bundle in this repository. The game source is unchanged; the build files now take libGDX from
`app/libs`.
22 changes: 22 additions & 0 deletions templates/Fun-and-Games-LibGDX/addon.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
{
"summary": "Adds three playable libGDX games to the New Project screen: a 3D demo, Block Game and Bubble Wand.",
"description": "Installs three small Android game projects built with libGDX, so you can start from a complete, playable game instead of an empty activity. Demo is a 3D Earth you spin by touch with an orbiting rocket, written in Java. Block Game is a falling-block puzzle and Bubble Wand is a first-person bubble shooter, both written in Kotlin. Each project builds and runs on the device. These are libGDX ports of the Fun and Games JME templates.",
"tags": [
"games",
"libgdx",
"templates",
"kotlin",
"java"
],
"origin": "appdevforall",
"license": "AGPL-3.0-or-later",
"author": {
"name": "James Turner",
"url": ""
},
"template": {
"id": "org.appdevforall.funandgameslibgdx",
"version": "1.0.0",
"minAppVersion": "26.40"
}
}
7 changes: 7 additions & 0 deletions templates/Fun-and-Games-LibGDX/blockgame/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
.gradle/
build/
local.properties
*.iml
.idea/
.DS_Store
captures/
101 changes: 101 additions & 0 deletions templates/Fun-and-Games-LibGDX/blockgame/app/build.gradle.peb
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
plugins {
alias(libs.plugins.android.application)
}

configurations {
natives
}

// libGDX 1.13.x needs androidx.core at runtime. Pin its tree to versions that
// Code On The Go's offline Maven repository carries (the same ones its built-in
// AndroidX templates use); the newer androidx.core libGDX asks for pulls in
// modules (profileinstaller, collection 1.0.0, ...) that the repository lacks.
configurations.configureEach {
resolutionStrategy {
force "androidx.core:core:1.9.0"
force "androidx.collection:collection:1.4.2"
force "androidx.annotation:annotation:1.8.1"
force "androidx.lifecycle:lifecycle-runtime:2.5.1"
force "androidx.lifecycle:lifecycle-common:2.5.1"
}
}

android {
namespace = "${{PACKAGE_NAME}}"
compileSdk = ${{COMPILE_SDK}}

defaultConfig {
applicationId = "${{PACKAGE_NAME}}"
minSdk = ${{MIN_SDK}}
targetSdk = ${{TARGET_SDK}}
versionCode = 1
versionName = "1.0"

ndk {
abiFilters "armeabi-v7a", "arm64-v8a"
}
}

sourceSets {
main {
// copyAndroidNatives unpacks libgdx.so here; app/libs holds only the shipped jars
jniLibs.srcDirs = [layout.buildDirectory.dir("gdx-natives").get().asFile]
}
}

buildTypes {
release {
minifyEnabled false
}
}

compileOptions {
sourceCompatibility = ${{JAVA_SOURCE_COMPAT}}
targetCompatibility = ${{JAVA_TARGET_COMPAT}}
}

packaging {
jniLibs {
useLegacyPackaging = true
}
}
}

// AGP 9+ compiles Kotlin itself (built-in Kotlin), so there is no kotlin-android plugin here
kotlin {
compilerOptions {
jvmTarget = org.jetbrains.kotlin.gradle.dsl.JvmTarget.fromTarget("${{JAVA_TARGET}}")
}
}

dependencies {
implementation(files("libs/gdx-1.13.1.jar"))
implementation(files("libs/gdx-jnigen-loader-2.5.2.jar"))
implementation(files("libs/gdx-backend-android-1.13.1.aar"))
// gdx-backend-android needs androidx.core at runtime; a local .aar does not
// carry that dependency, so declare it here (pinned to 1.9.0 above).
implementation("androidx.core:core:1.9.0")
natives(files("libs/gdx-platform-1.13.1-natives-armeabi-v7a.jar"))
natives(files("libs/gdx-platform-1.13.1-natives-arm64-v8a.jar"))
}

// libGDX ships its Android .so files inside per-ABI classifier jars; unpack them
// into build/gdx-natives/<abi>/ so AGP packages them as jniLibs. Written as a plain Copy
// task (no project access at execution time) so it works with the configuration cache.
tasks.register("copyAndroidNatives", Copy) {
def natives = configurations.natives
// Not app/libs: a Copy task owns its whole destination, so the jars there would
// count as its output and every compile task would need to depend on it.
into layout.buildDirectory.dir("gdx-natives")
["armeabi-v7a", "arm64-v8a"].each { abi ->
def jar = natives.filter { it.name.endsWith("natives-" + abi + ".jar") }
from(zipTree { jar.singleFile }) {
include "*.so"
into abi
}
}
}

tasks.matching { it.name.contains("merge") && it.name.contains("JniLibFolders") }.configureEach {
it.dependsOn "copyAndroidNatives"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android">

<uses-feature android:glEsVersion="0x00020000" android:required="true"/>

<application
android:label="@string/app_name"
android:icon="@mipmap/ic_launcher"
android:allowBackup="true">

<activity
android:name=".MainActivity"
android:configChanges="orientation|keyboardHidden|screenSize"
android:screenOrientation="portrait"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>

</application>

</manifest>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Loading