From 2e6dae7e6e9be053774ffaf1fd4fb05660ef68bb Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 13:43:34 +0100 Subject: [PATCH 01/15] Add Android raylib example Signed-off-by: Uilian Ries --- .../android/raylib/app/build.gradle | 62 +++++++ .../raylib/app/src/main/AndroidManifest.xml | 19 +++ .../raylib/app/src/main/cpp/CMakeLists.txt | 24 +++ .../main/cpp/conan_android_toolchain.cmake | 15 ++ .../raylib/app/src/main/cpp/native-lib.cpp | 153 ++++++++++++++++++ .../cross_build/android/raylib/build.gradle | 16 ++ .../android/raylib/settings.gradle | 18 +++ 7 files changed, 307 insertions(+) create mode 100644 examples/cross_build/android/raylib/app/build.gradle create mode 100644 examples/cross_build/android/raylib/app/src/main/AndroidManifest.xml create mode 100644 examples/cross_build/android/raylib/app/src/main/cpp/CMakeLists.txt create mode 100644 examples/cross_build/android/raylib/app/src/main/cpp/conan_android_toolchain.cmake create mode 100644 examples/cross_build/android/raylib/app/src/main/cpp/native-lib.cpp create mode 100644 examples/cross_build/android/raylib/build.gradle create mode 100644 examples/cross_build/android/raylib/settings.gradle diff --git a/examples/cross_build/android/raylib/app/build.gradle b/examples/cross_build/android/raylib/app/build.gradle new file mode 100644 index 00000000..7b7736cc --- /dev/null +++ b/examples/cross_build/android/raylib/app/build.gradle @@ -0,0 +1,62 @@ +plugins { + id 'com.android.application' +} + +task conanInstall { + def conanExecutable = "conan" // define the path to your conan installation + def buildDir = new File("app/build") + buildDir.mkdirs() + ["Debug", "Release"].each { String build_type -> + ["armv8"].each { String arch -> + def cmd = conanExecutable + " install " + + "../src/main/cpp --profile android -s build_type="+ build_type +" -s arch=" + arch + + " --build missing -c tools.cmake.cmake_layout:build_folder_vars=['settings.arch']" + print(">> ${cmd} \n") + + def sout = new StringBuilder(), serr = new StringBuilder() + def proc = cmd.execute(null, buildDir) + proc.consumeProcessOutput(sout, serr) + proc.waitFor() + println "$sout $serr" + if (proc.exitValue() != 0) { + throw new Exception("out> $sout err> $serr" + "\nCommand: ${cmd}") + } + } + } +} + +android { + namespace 'com.example.raylibexample' + compileSdk 34 + + defaultConfig { + applicationId "com.example.raylibexample" + minSdk 27 + targetSdk 34 + versionCode 1 + versionName "1.0" + + externalNativeBuild { + cmake { + arguments "-DANDROID_STL=c++_shared" + } + } + + ndk { + abiFilters 'arm64-v8a' + } + } + + externalNativeBuild { + cmake { + path file('src/main/cpp/CMakeLists.txt') + version '3.22.1' + } + } + + buildTypes { + release { + minifyEnabled false + } + } +} \ No newline at end of file diff --git a/examples/cross_build/android/raylib/app/src/main/AndroidManifest.xml b/examples/cross_build/android/raylib/app/src/main/AndroidManifest.xml new file mode 100644 index 00000000..8f58e318 --- /dev/null +++ b/examples/cross_build/android/raylib/app/src/main/AndroidManifest.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/examples/cross_build/android/raylib/app/src/main/cpp/CMakeLists.txt b/examples/cross_build/android/raylib/app/src/main/cpp/CMakeLists.txt new file mode 100644 index 00000000..515b501a --- /dev/null +++ b/examples/cross_build/android/raylib/app/src/main/cpp/CMakeLists.txt @@ -0,0 +1,24 @@ +cmake_minimum_required(VERSION 3.22.1) +project("raylibexample" LANGUAGES C CXX) + +set(NATIVE_APP_GLUE_DIR ${ANDROID_NDK}/sources/android/native_app_glue) + +find_package(raylib CONFIG REQUIRED) + +add_library(${CMAKE_PROJECT_NAME} SHARED) + +target_sources(${CMAKE_PROJECT_NAME} PRIVATE + ${NATIVE_APP_GLUE_DIR}/android_native_app_glue.c + native-lib.cpp) + +target_include_directories(${CMAKE_PROJECT_NAME} PRIVATE + ${NATIVE_APP_GLUE_DIR}) + +target_link_libraries(${CMAKE_PROJECT_NAME} PRIVATE + android + log + EGL + GLESv2 + OpenSLES + m + raylib) \ No newline at end of file diff --git a/examples/cross_build/android/raylib/app/src/main/cpp/conan_android_toolchain.cmake b/examples/cross_build/android/raylib/app/src/main/cpp/conan_android_toolchain.cmake new file mode 100644 index 00000000..8ea03e74 --- /dev/null +++ b/examples/cross_build/android/raylib/app/src/main/cpp/conan_android_toolchain.cmake @@ -0,0 +1,15 @@ +if ( NOT ANDROID_ABI OR NOT CMAKE_BUILD_TYPE ) + return() +endif() + +if(${ANDROID_ABI} STREQUAL "x86_64") + include("${CMAKE_CURRENT_LIST_DIR}/build/x86_64/${CMAKE_BUILD_TYPE}/generators/conan_toolchain.cmake") +elseif(${ANDROID_ABI} STREQUAL "x86") + include("${CMAKE_CURRENT_LIST_DIR}/build/x86/${CMAKE_BUILD_TYPE}/generators/conan_toolchain.cmake") +elseif(${ANDROID_ABI} STREQUAL "arm64-v8a") + include("${CMAKE_CURRENT_LIST_DIR}/build/armv8/${CMAKE_BUILD_TYPE}/generators/conan_toolchain.cmake") +elseif(${ANDROID_ABI} STREQUAL "armeabi-v7a") + include("${CMAKE_CURRENT_LIST_DIR}/build/armv7/${CMAKE_BUILD_TYPE}/generators/conan_toolchain.cmake") +else() + message(FATAL_ERROR "Not supported configuration: ${ANDROID_ABI}") +endif() \ No newline at end of file diff --git a/examples/cross_build/android/raylib/app/src/main/cpp/native-lib.cpp b/examples/cross_build/android/raylib/app/src/main/cpp/native-lib.cpp new file mode 100644 index 00000000..46bf1595 --- /dev/null +++ b/examples/cross_build/android/raylib/app/src/main/cpp/native-lib.cpp @@ -0,0 +1,153 @@ +#include + +#include +#include +#include + +#include "raylib.h" + + +extern "C" { + +int main() { + // --- Initialization --- + const int screenW = 800; + const int screenH = 450; + InitWindow(screenW, screenH, "Jump to Survive!"); + SetExitKey(0); // Disable back button from closing app automatically + + // --- Player Setup --- + Rectangle player = { 100, screenH - 80, 40, 60 }; + float vy = 0; + const float gravity = 1000.0f; + const float jumpImpulse = -450.0f; + + // --- Ground Definition --- + const int groundY = screenH - 20; + + // --- Obstacle Management --- + std::vector obstacles; + float spawnTimer = 0.0f; + float spawnInterval = 1.2f; + const float obstacleSpeed = 300.0f; + + const float minSpawnInterval = 0.8f; + const float maxSpawnInterval = 1.6f; + const int minObsWidth = 40; + const int maxObsWidth = 120; + + // --- Game State Variables --- + int score = 0; + bool gameOver = false; + + // --- Back button double press logic --- + float backPressTime = 0.0f; + bool backPressedOnce = false; + const float doublePressInterval = 0.5f; // 0.5 seconds + + SetTargetFPS(60); + + while (!WindowShouldClose()) { + float dt = GetFrameTime(); + + // --- Back button exit logic --- + if (backPressedOnce) { + backPressTime += dt; + if (backPressTime > doublePressInterval) { + backPressedOnce = false; + } + } + + if (IsKeyPressed(KEY_BACK)) { + if (backPressedOnce) { + break; // Exit game + } else { + backPressedOnce = true; + backPressTime = 0.0f; + } + } + + if (!gameOver) { + // Jump logic - using touch instead of keyboard + if (GetTouchPointCount() > 0 && player.y + player.height >= groundY) { + vy = jumpImpulse; + } + + // Apply gravity + vy += gravity * dt; + player.y += vy * dt; + + // Ground collision + if (player.y + player.height > groundY) { + player.y = groundY - player.height; + vy = 0; + } + + // Spawn obstacles with random width & interval + spawnTimer += dt; + if (spawnTimer >= spawnInterval) { + spawnTimer = 0.0f; + spawnInterval = GetRandomValue(int(minSpawnInterval*100), + int(maxSpawnInterval*100)) / 100.0f; + int w = GetRandomValue(minObsWidth, maxObsWidth); + obstacles.push_back({ float(screenW), float(groundY - 40), + float(w), 40.0f }); + } + + // Move & collide obstacles + for (int i = 0; i < (int)obstacles.size(); i++) { + obstacles[i].x -= obstacleSpeed * dt; + if (CheckCollisionRecs(player, obstacles[i])) { + gameOver = true; + } + } + + // Remove off-screen obstacles & increment score + if (!obstacles.empty() && + obstacles.front().x + obstacles.front().width < 0) { + obstacles.erase(obstacles.begin()); + score++; + } + } + else { + // Accepting restart + if (GetTouchPointCount() > 0) { + // Reset everything + player.y = screenH - 80; + vy = 0; + obstacles.clear(); + spawnTimer = 0.0f; + spawnInterval = 1.2f; + score = 0; + gameOver = false; + } + } + + // --- Drawing --- + BeginDrawing(); + ClearBackground(RAYWHITE); + + DrawRectangle(0, groundY, screenW, 20, DARKGRAY); + DrawRectangleRec(player, BLUE); + for (auto &obs : obstacles) DrawRectangleRec(obs, RED); + + DrawText(TextFormat("Score: %d", score), 10, 10, 20, BLACK); + + if (gameOver) { + DrawText("GAME OVER! Tap to restart", 200, screenH/2 - 20, 20, MAROON); + } + + if (backPressedOnce) { + const char *msg = "Press back again to exit"; + int textWidth = MeasureText(msg, 20); + DrawText(msg, (screenW - textWidth) / 2, screenH - 420, 20, BLACK); + } + + EndDrawing(); + } + + CloseWindow(); + return 0; +} + +} // extern "C" \ No newline at end of file diff --git a/examples/cross_build/android/raylib/build.gradle b/examples/cross_build/android/raylib/build.gradle new file mode 100644 index 00000000..dc45c703 --- /dev/null +++ b/examples/cross_build/android/raylib/build.gradle @@ -0,0 +1,16 @@ +buildscript { + repositories { + google() + mavenCentral() + } + dependencies { + classpath 'com.android.tools.build:gradle:8.2.0' + } +} + +allprojects { + repositories { + google() + mavenCentral() + } +} \ No newline at end of file diff --git a/examples/cross_build/android/raylib/settings.gradle b/examples/cross_build/android/raylib/settings.gradle new file mode 100644 index 00000000..28ab1b0e --- /dev/null +++ b/examples/cross_build/android/raylib/settings.gradle @@ -0,0 +1,18 @@ +pluginManagement { + repositories { + google() + mavenCentral() + gradlePluginPortal() + } +} + +dependencyResolutionManagement { + repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS) + repositories { + google() + mavenCentral() + } +} + +rootProject.name = 'RaylibExample' +include ':app' \ No newline at end of file From 736d6ba954b05ece32b14a81bef3ebf6bfc36cb1 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 13:49:08 +0100 Subject: [PATCH 02/15] Add conanfile.txt Signed-off-by: Uilian Ries --- .../android/raylib/app/src/main/cpp/conanfile.txt | 9 +++++++++ 1 file changed, 9 insertions(+) create mode 100644 examples/cross_build/android/raylib/app/src/main/cpp/conanfile.txt diff --git a/examples/cross_build/android/raylib/app/src/main/cpp/conanfile.txt b/examples/cross_build/android/raylib/app/src/main/cpp/conanfile.txt new file mode 100644 index 00000000..3e8763ea --- /dev/null +++ b/examples/cross_build/android/raylib/app/src/main/cpp/conanfile.txt @@ -0,0 +1,9 @@ +[requires] +raylib/5.0 + +[generators] +CMakeToolchain +CMakeDeps + +[layout] +cmake_layout From 0727e971880383df3166e1a397eb617560c9e8ea Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 13:59:08 +0100 Subject: [PATCH 03/15] Remove extra projects Signed-off-by: Uilian Ries --- .../android/raylib/app/build.gradle | 6 ---- .../cross_build/android/raylib/build.gradle | 7 ---- .../android/raylib/ci_test_example.py | 32 +++++++++++++++++++ 3 files changed, 32 insertions(+), 13 deletions(-) create mode 100644 examples/cross_build/android/raylib/ci_test_example.py diff --git a/examples/cross_build/android/raylib/app/build.gradle b/examples/cross_build/android/raylib/app/build.gradle index 7b7736cc..7cd4d7fb 100644 --- a/examples/cross_build/android/raylib/app/build.gradle +++ b/examples/cross_build/android/raylib/app/build.gradle @@ -36,12 +36,6 @@ android { versionCode 1 versionName "1.0" - externalNativeBuild { - cmake { - arguments "-DANDROID_STL=c++_shared" - } - } - ndk { abiFilters 'arm64-v8a' } diff --git a/examples/cross_build/android/raylib/build.gradle b/examples/cross_build/android/raylib/build.gradle index dc45c703..36941ff5 100644 --- a/examples/cross_build/android/raylib/build.gradle +++ b/examples/cross_build/android/raylib/build.gradle @@ -7,10 +7,3 @@ buildscript { classpath 'com.android.tools.build:gradle:8.2.0' } } - -allprojects { - repositories { - google() - mavenCentral() - } -} \ No newline at end of file diff --git a/examples/cross_build/android/raylib/ci_test_example.py b/examples/cross_build/android/raylib/ci_test_example.py new file mode 100644 index 00000000..bde6b58b --- /dev/null +++ b/examples/cross_build/android/raylib/ci_test_example.py @@ -0,0 +1,32 @@ +import os + +from test.examples_tools import run + +# ############# Example ################ +print("- Use the Android NDK to cross-build a package -") + + +profile = """ + +[settings] +os=Android +os.api_level=27 +arch=armv8 +compiler=clang +compiler.version=18 +compiler.libcxx=c++_static +compiler.cppstd=17 +build_type=Debug + +[conf] +tools.android:ndk_path={} +""" + +ndk_path = os.environ.get("ANDROID_NDK") or os.environ.get("ANDROID_NDK_HOME") + +if ndk_path: + profile = profile.format(ndk_path) + with open("android", "w") as _f: + _f.write(profile) + + run("gradlew assembleDebug") \ No newline at end of file From 7cfc004c406c604fa5d6794b8b48a49bb856f072 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 15:07:08 +0100 Subject: [PATCH 04/15] Find gradlew Signed-off-by: Uilian Ries --- .github/workflows/ci.yml | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index bc7db299..3b0c49ca 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,6 +36,13 @@ jobs: with: python-version: "3.11" + - name: Setup Gradle + uses: gradle/actions/setup-gradle@v5 + + - name: Find gradlew executable + id: find-gradlew + run: find / -type f -name gradlew + - name: Install CMake uses: jwlawson/actions-setup-cmake@v1.14 with: From f5da0d6d7ad040b10142a36f3b17528e53f80594 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 15:23:04 +0100 Subject: [PATCH 05/15] Use gradle Signed-off-by: Uilian Ries --- .github/workflows/ci.yml | 7 ------- examples/cross_build/android/raylib/ci_test_example.py | 2 +- 2 files changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3b0c49ca..bc7db299 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -36,13 +36,6 @@ jobs: with: python-version: "3.11" - - name: Setup Gradle - uses: gradle/actions/setup-gradle@v5 - - - name: Find gradlew executable - id: find-gradlew - run: find / -type f -name gradlew - - name: Install CMake uses: jwlawson/actions-setup-cmake@v1.14 with: diff --git a/examples/cross_build/android/raylib/ci_test_example.py b/examples/cross_build/android/raylib/ci_test_example.py index bde6b58b..2d5bb90f 100644 --- a/examples/cross_build/android/raylib/ci_test_example.py +++ b/examples/cross_build/android/raylib/ci_test_example.py @@ -29,4 +29,4 @@ with open("android", "w") as _f: _f.write(profile) - run("gradlew assembleDebug") \ No newline at end of file + run("gradle assembleDebug") \ No newline at end of file From bef2a8a117163cd47c8ba73f6ed62c55d9583bff Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 15:31:18 +0100 Subject: [PATCH 06/15] Fix android profile path Signed-off-by: Uilian Ries --- examples/cross_build/android/raylib/ci_test_example.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/examples/cross_build/android/raylib/ci_test_example.py b/examples/cross_build/android/raylib/ci_test_example.py index 2d5bb90f..3edb4bd4 100644 --- a/examples/cross_build/android/raylib/ci_test_example.py +++ b/examples/cross_build/android/raylib/ci_test_example.py @@ -23,10 +23,9 @@ """ ndk_path = os.environ.get("ANDROID_NDK") or os.environ.get("ANDROID_NDK_HOME") - if ndk_path: profile = profile.format(ndk_path) - with open("android", "w") as _f: - _f.write(profile) + with open(os.path.join("app", "src", "main", "cpp", "android"), "w") as fd: + fd.write(profile) run("gradle assembleDebug") \ No newline at end of file From eeebb7d937fef9304b93a0c69bc770ca8c37eb23 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 15:43:09 +0100 Subject: [PATCH 07/15] Fix android profile path 2 Signed-off-by: Uilian Ries --- examples/cross_build/android/raylib/ci_test_example.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cross_build/android/raylib/ci_test_example.py b/examples/cross_build/android/raylib/ci_test_example.py index 3edb4bd4..4b361fbe 100644 --- a/examples/cross_build/android/raylib/ci_test_example.py +++ b/examples/cross_build/android/raylib/ci_test_example.py @@ -25,7 +25,7 @@ ndk_path = os.environ.get("ANDROID_NDK") or os.environ.get("ANDROID_NDK_HOME") if ndk_path: profile = profile.format(ndk_path) - with open(os.path.join("app", "src", "main", "cpp", "android"), "w") as fd: + with open(os.path.join("app", "build", "android"), "w") as fd: fd.write(profile) run("gradle assembleDebug") \ No newline at end of file From 07a6d321119d84047803fe2fc33596bf23864b6a Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 15:45:04 +0100 Subject: [PATCH 08/15] Create build folder Signed-off-by: Uilian Ries --- examples/cross_build/android/raylib/ci_test_example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/cross_build/android/raylib/ci_test_example.py b/examples/cross_build/android/raylib/ci_test_example.py index 4b361fbe..fa1ff3e7 100644 --- a/examples/cross_build/android/raylib/ci_test_example.py +++ b/examples/cross_build/android/raylib/ci_test_example.py @@ -25,6 +25,7 @@ ndk_path = os.environ.get("ANDROID_NDK") or os.environ.get("ANDROID_NDK_HOME") if ndk_path: profile = profile.format(ndk_path) + os.makedirs(os.path.join("app", "build"), exist_ok=True) with open(os.path.join("app", "build", "android"), "w") as fd: fd.write(profile) From 56548f2b0b2d873aa0820ea0e0c3a90882f5a3dc Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 15:53:46 +0100 Subject: [PATCH 09/15] Update Raylib version Signed-off-by: Uilian Ries --- .../cross_build/android/raylib/app/src/main/cpp/conanfile.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/cross_build/android/raylib/app/src/main/cpp/conanfile.txt b/examples/cross_build/android/raylib/app/src/main/cpp/conanfile.txt index 3e8763ea..b556b149 100644 --- a/examples/cross_build/android/raylib/app/src/main/cpp/conanfile.txt +++ b/examples/cross_build/android/raylib/app/src/main/cpp/conanfile.txt @@ -1,5 +1,5 @@ [requires] -raylib/5.0 +raylib/5.5 [generators] CMakeToolchain From acab2564d76f7deeaaa1e761bb82b6afd6b030a7 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 16:03:49 +0100 Subject: [PATCH 10/15] toolchain Signed-off-by: Uilian Ries --- examples/cross_build/android/raylib/app/build.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/examples/cross_build/android/raylib/app/build.gradle b/examples/cross_build/android/raylib/app/build.gradle index 7cd4d7fb..759d6cd8 100644 --- a/examples/cross_build/android/raylib/app/build.gradle +++ b/examples/cross_build/android/raylib/app/build.gradle @@ -44,6 +44,8 @@ android { externalNativeBuild { cmake { path file('src/main/cpp/CMakeLists.txt') + cppFlags '-v' + arguments("-DCMAKE_TOOLCHAIN_FILE=conan_android_toolchain.cmake") version '3.22.1' } } From a656a299dfb8cbf1a686020302d06f6bebaf10cd Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 16:11:16 +0100 Subject: [PATCH 11/15] toolchain Signed-off-by: Uilian Ries --- .../cross_build/android/raylib/app/build.gradle | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/examples/cross_build/android/raylib/app/build.gradle b/examples/cross_build/android/raylib/app/build.gradle index 759d6cd8..9ec0d236 100644 --- a/examples/cross_build/android/raylib/app/build.gradle +++ b/examples/cross_build/android/raylib/app/build.gradle @@ -39,17 +39,17 @@ android { ndk { abiFilters 'arm64-v8a' } - } - externalNativeBuild { - cmake { - path file('src/main/cpp/CMakeLists.txt') - cppFlags '-v' - arguments("-DCMAKE_TOOLCHAIN_FILE=conan_android_toolchain.cmake") - version '3.22.1' + externalNativeBuild { + cmake { + cppFlags '-v' + arguments("-DCMAKE_TOOLCHAIN_FILE=conan_android_toolchain.cmake", "-DANDROID_STL=c++_shared") + } } } + + buildTypes { release { minifyEnabled false From 7e0b30d367514c046ad9191f104619db7223f276 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 16:22:52 +0100 Subject: [PATCH 12/15] Validate generated .apk Signed-off-by: Uilian Ries --- .../android/raylib/app/build.gradle | 2 - .../raylib/app/src/main/cpp/native-lib.cpp | 61 +++++++++---------- .../android/raylib/ci_test_example.py | 3 +- 3 files changed, 32 insertions(+), 34 deletions(-) diff --git a/examples/cross_build/android/raylib/app/build.gradle b/examples/cross_build/android/raylib/app/build.gradle index 9ec0d236..618ad0ec 100644 --- a/examples/cross_build/android/raylib/app/build.gradle +++ b/examples/cross_build/android/raylib/app/build.gradle @@ -48,8 +48,6 @@ android { } } - - buildTypes { release { minifyEnabled false diff --git a/examples/cross_build/android/raylib/app/src/main/cpp/native-lib.cpp b/examples/cross_build/android/raylib/app/src/main/cpp/native-lib.cpp index 46bf1595..76f53fa5 100644 --- a/examples/cross_build/android/raylib/app/src/main/cpp/native-lib.cpp +++ b/examples/cross_build/android/raylib/app/src/main/cpp/native-lib.cpp @@ -1,15 +1,15 @@ -#include - #include #include #include - #include "raylib.h" +#include +#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "RaylibApp", __VA_ARGS__)) extern "C" { int main() { + LOGI("Starting Raylib"); // --- Initialization --- const int screenW = 800; const int screenH = 450; @@ -19,26 +19,28 @@ int main() { // --- Player Setup --- Rectangle player = { 100, screenH - 80, 40, 60 }; float vy = 0; - const float gravity = 1000.0f; - const float jumpImpulse = -450.0f; + const float gravity = 1000.0f; + const float jumpImpulse = -450.0f; // --- Ground Definition --- const int groundY = screenH - 20; // --- Obstacle Management --- std::vector obstacles; - float spawnTimer = 0.0f; - float spawnInterval = 1.2f; - const float obstacleSpeed = 300.0f; + float spawnTimer = 0.0f; + float spawnInterval = 1.2f; + const float obstacleSpeed = 300.0f; const float minSpawnInterval = 0.8f; const float maxSpawnInterval = 1.6f; - const int minObsWidth = 40; - const int maxObsWidth = 120; + + const int minObsWidth = 40; + const int maxObsWidth = 120; // --- Game State Variables --- - int score = 0; + int score = 0; bool gameOver = false; + float gameOverTimer = 0.0f; // --- Back button double press logic --- float backPressTime = 0.0f; @@ -67,17 +69,14 @@ int main() { } } + if (!gameOver) { - // Jump logic - using touch instead of keyboard + // Jump logic if (GetTouchPointCount() > 0 && player.y + player.height >= groundY) { vy = jumpImpulse; } - - // Apply gravity vy += gravity * dt; player.y += vy * dt; - - // Ground collision if (player.y + player.height > groundY) { player.y = groundY - player.height; vy = 0; @@ -87,11 +86,11 @@ int main() { spawnTimer += dt; if (spawnTimer >= spawnInterval) { spawnTimer = 0.0f; - spawnInterval = GetRandomValue(int(minSpawnInterval*100), - int(maxSpawnInterval*100)) / 100.0f; + // recalc next interval + spawnInterval = GetRandomValue(int(minSpawnInterval*100), int(maxSpawnInterval*100)) / 100.0f; + // random width int w = GetRandomValue(minObsWidth, maxObsWidth); - obstacles.push_back({ float(screenW), float(groundY - 40), - float(w), 40.0f }); + obstacles.push_back({ float(screenW), float(groundY - 40), float(w), 40.0f }); } // Move & collide obstacles @@ -99,27 +98,27 @@ int main() { obstacles[i].x -= obstacleSpeed * dt; if (CheckCollisionRecs(player, obstacles[i])) { gameOver = true; + gameOverTimer = 0.0f; // Reset timer on game over } } - - // Remove off-screen obstacles & increment score - if (!obstacles.empty() && - obstacles.front().x + obstacles.front().width < 0) { + // Remove off-screen & score + if (!obstacles.empty() && obstacles.front().x + obstacles.front().width < 0) { obstacles.erase(obstacles.begin()); score++; } } else { - // Accepting restart - if (GetTouchPointCount() > 0) { - // Reset everything + gameOverTimer += dt; + // Want to wait 2 seconds before accepting the restart + if (GetTouchPointCount() > 0 && gameOverTimer > 1.0f) { + // reset everything player.y = screenH - 80; vy = 0; obstacles.clear(); - spawnTimer = 0.0f; + spawnTimer = 0.0f; spawnInterval = 1.2f; - score = 0; - gameOver = false; + score = 0; + gameOver = false; } } @@ -150,4 +149,4 @@ int main() { return 0; } -} // extern "C" \ No newline at end of file +} // extern "C" diff --git a/examples/cross_build/android/raylib/ci_test_example.py b/examples/cross_build/android/raylib/ci_test_example.py index fa1ff3e7..d794f6af 100644 --- a/examples/cross_build/android/raylib/ci_test_example.py +++ b/examples/cross_build/android/raylib/ci_test_example.py @@ -29,4 +29,5 @@ with open(os.path.join("app", "build", "android"), "w") as fd: fd.write(profile) - run("gradle assembleDebug") \ No newline at end of file + run("gradle assembleDebug") + assert os.path.exists(os.path.join("app", "build", "outputs", "apk", "debug", "app-debug.apk")) From 0a427a6d0a2993d69f2ed1d31f5dc050661cc341 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 16:29:05 +0100 Subject: [PATCH 13/15] Add link to blog post Signed-off-by: Uilian Ries --- examples/cross_build/README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/examples/cross_build/README.md b/examples/cross_build/README.md index d0dd7f55..a2874315 100644 --- a/examples/cross_build/README.md +++ b/examples/cross_build/README.md @@ -8,3 +8,8 @@ ### [Use Android NDK to cross-build](android/ndk_basic) - Learn how to cross-build packages for Android. [Docs](https://docs.conan.io/2/examples/cross_build/android.html) + + +### [GameDev Raylib: Running on Android](android/raylib) + +- Learn how to port your Raylib C++ game to Android using Android Studio, the NDK, and Conan for dependency management. [Blog](https://blog.conan.io/cpp/gamedev/android/conan/raylib/2025/11/24/GameDev-Raylib-Android.html) From 8e2c1034dc96fc366b859b3d7c3805e78c5daeb1 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 16:45:04 +0100 Subject: [PATCH 14/15] Stop gradle daemon after building Signed-off-by: Uilian Ries --- examples/cross_build/android/raylib/ci_test_example.py | 1 + 1 file changed, 1 insertion(+) diff --git a/examples/cross_build/android/raylib/ci_test_example.py b/examples/cross_build/android/raylib/ci_test_example.py index d794f6af..409c27f2 100644 --- a/examples/cross_build/android/raylib/ci_test_example.py +++ b/examples/cross_build/android/raylib/ci_test_example.py @@ -30,4 +30,5 @@ fd.write(profile) run("gradle assembleDebug") + run("gradle --stop") assert os.path.exists(os.path.join("app", "build", "outputs", "apk", "debug", "app-debug.apk")) From d4c1cd0490ce0177937ce4c7c4abc7d9efaa6a29 Mon Sep 17 00:00:00 2001 From: Uilian Ries Date: Wed, 26 Nov 2025 16:55:54 +0100 Subject: [PATCH 15/15] No daemon Signed-off-by: Uilian Ries --- examples/cross_build/android/raylib/ci_test_example.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/examples/cross_build/android/raylib/ci_test_example.py b/examples/cross_build/android/raylib/ci_test_example.py index 409c27f2..a3525dfd 100644 --- a/examples/cross_build/android/raylib/ci_test_example.py +++ b/examples/cross_build/android/raylib/ci_test_example.py @@ -29,6 +29,5 @@ with open(os.path.join("app", "build", "android"), "w") as fd: fd.write(profile) - run("gradle assembleDebug") - run("gradle --stop") + run("gradle --no-daemon assembleDebug") assert os.path.exists(os.path.join("app", "build", "outputs", "apk", "debug", "app-debug.apk"))