Building a Game with React Native and Axmol Engine
Combine React Native product UI with an Axmol-powered native game surface only after validating the native view bridge and lifecycle on both platforms. This revised guide emphasizes supported APIs, production tradeoffs, and an upgrade-friendly path without tying the advice to a calendar year.

Modern implementation baseline
Combine React Native product UI with an Axmol-powered native game surface only after validating the native view bridge and lifecycle on both platforms.
Treat React Native as the product shell and the game engine as a native rendering subsystem with a narrow bridge. Validate engine support, rendering ownership, lifecycle, input, audio, memory, and store packaging before committing to the architecture.
Recommended approach
- Keep engine setup and teardown deterministic.
- Define a small typed command and event protocol.
- Measure release frame pacing and memory before feature expansion.
Production checklist
- Prototype the native view boundary before building gameplay.
- Profile frame pacing, thermal behavior, memory, and resume flows.
- Keep gameplay state independent from React component state.
Authoritative references
Why Use React Native with Axmol Engine?
React Native is excellent for building cross-platform mobile apps with a single codebase, leveraging JavaScript and React for UI development. Axmol Engine, a modern fork of Cocos2d-x, excels in high-performance 2D game development with C++ and supports platforms like iOS, Android, Windows, macOS, and more. By integrating these two, you can create a game with a React Native frontend for UI and Axmol for game logic and rendering, offering a balance of ease and performance.
This guide assumes you have basic knowledge of JavaScript and some familiarity with React Native. No prior C++ experience is required, but we'll touch on basic integration steps. We'll build a simple 2D game where a player moves a sprite to avoid obstacles, using modern tools and packages.
Note: This guide focuses on Android integration for simplicity. iOS integration with Axmol requires Objective-C++ (.mm) bridging and Metal support. For iOS-specific steps, refer to Axmol’s official iOS integration guide.
Prerequisites
Before we start, ensure you have the following installed:
- Node.js (v20.x or later, LTS recommended): Download from nodejs.org.
- npm (v10.x or later, comes with Node.js).
- React Native CLI: For setting up the project.
- CMake (v3.28.1+): Required for Axmol builds.
- Android Studio: Use the current stable release with compatible Android SDK and NDK tooling.
- Xcode (15+): For iOS development (macOS only).
- Python (3.9+): For Axmol setup scripts.
- Git: For cloning repositories.
- A code editor like VS Code.
Step-by-Step Guide to Building the Game
Step 1: Set Up the React Native Project
-
Install React Native CLI: Run the following command to install the React Native CLI globally:
npm install -g @react-native-community/cli -
Create a New React Native Project: Initialize a new project called
MyAxmolGame:npx @react-native-community/cli@latest init MyAxmolGame --version 0.75.4Use an active stable React Native release that is compatible with the native engine integration. The New Architecture is the standard baseline, but compatibility still needs to be proven with a release-build prototype.
-
Navigate to the Project Directory:
cd MyAxmolGame -
Test the Project: Run the app to ensure the setup works:
npx react-native run-androidor, for iOS (on macOS):
npx react-native run-iosThis should launch a basic React Native app on your emulator or device.
Step 2: Install and Configure Axmol Engine
-
Clone the Axmol Engine Repository: Axmol is a C++-based engine, so we need to set it up for native integration. Clone the latest version (v2.3.0+):
git clone https://github.com/axmolengine/axmol.gitThis clones the Axmol repository, which is actively maintained with updates as recent.
-
Set Up Axmol Environment: Navigate to the Axmol directory and run the setup script:
cd axmol
python setup.pyAfter completion, restart your terminal to apply environment variables.
-
Install CMake and NDK for Android:
- CMake: Ensure CMake 3.28.1+ is installed. On macOS, use:
sudo "/Applications/CMake.app/Contents/bin/cmake-gui" --install - NDK: Axmol v2.3.0 requires NDK r25+. Install it manually since Android Studio’s SDK Manager may not list it:
Alternatively, set the NDK version in the
cd axmol
./tools/external/install-ndk-r25.sh.axprojfile (created later).
- CMake: Ensure CMake 3.28.1+ is installed. On macOS, use:
-
Verify Axmol Installation: Create a test Axmol project to ensure the engine is set up correctly:
axmol new TestAxmol -p com.example.testaxmol -l cpp
cd TestAxmol
axmol build -p androidThis generates and builds an Android project. If successful, Axmol is ready.
Step 3: Integrate Axmol with React Native
To combine Axmol’s rendering with React Native’s UI, we’ll use a native module to bridge the C++ game logic with the JavaScript frontend. React Native and Axmol render in separate layers: Axmol renders via OpenGL in its own surface (GLSurfaceView), while React Native renders native views. You can place buttons, scores, and overlays using standard React Native components above or below the Axmol surface.
-
Create a Native Module: In your React Native project, create a native module to interface with Axmol. Create the following files in
MyAxmolGame/android/app/src/main/java/com/myaxmolgame/:AxmolModule.javaAxmolPackage.java
// AxmolModule.java
package com.myaxmolgame;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
public class AxmolModule extends ReactContextBaseJavaModule {
AxmolModule(ReactApplicationContext context) {
super(context);
}
@Override
public String getName() {
return "AxmolModule";
}
@ReactMethod
public void startGame() {
// Placeholder for starting Axmol game loop
// Will be linked to C++ code
}
}// AxmolPackage.java
package com.myaxmolgame;
import com.facebook.react.ReactPackage;
import com.facebook.react.bridge.NativeModule;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.uimanager.ViewManager;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class AxmolPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AxmolModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
return Collections.emptyList();
}
} -
Register the Native Module: Update
MainActivity.javato include the package:// android/app/src/main/java/com/myaxmolgame/MainActivity.java
import com.myaxmolgame.AxmolPackage;
@Override
protected List<ReactPackage> getPackages() {
@SuppressWarnings("UnnecessaryLocalVariable")
List<ReactPackage> packages = new PackageList(this).getPackages();
packages.add(new AxmolPackage());
return packages;
} -
Link Axmol to the Native Module:
- Copy the
axmolfolder toMyAxmolGame/android/app/src/main/jniLibs/. - Create a
CMakeLists.txtinMyAxmolGame/android/app/src/main/cpp/:cmake_minimum_required(VERSION 3.28.1)
project(MyAxmolGame)
include_directories(${CMAKE_SOURCE_DIR}/../../../../axmol/core)
add_library(axmol SHARED IMPORTED)
set_target_properties(axmol PROPERTIES IMPORTED_LOCATION ${CMAKE_SOURCE_DIR}/../jniLibs/libaxmol.so)
add_library(native-lib SHARED native-lib.cpp)
target_link_libraries(native-lib axmol) - Create
native-lib.cppin the same directory:#include <axmol.h>
USING_NS_AX;
extern "C" JNIEXPORT void JNICALL Java_com_myaxmolgame_AxmolModule_startGame(JNIEnv* env, jobject thiz) {
auto director = Director::getInstance();
auto scene = Scene::create();
auto sprite = Sprite::create("player.png");
sprite->setPosition(Vec2(100, 100));
scene->addChild(sprite);
director->runWithScene(scene);
}
- Copy the
-
Update Android Build Configuration:
- In
android/app/build.gradle, add:android {
// Existing config
externalNativeBuild {
cmake {
path "src/main/cpp/CMakeLists.txt"
}
}
} - Create a
.axprojfile in the project root with:This aligns with Axmol requirements for Android 16 KB page alignment and NDK r25+.packageName=com.myaxmolgame
minSdk=21
targetSdk=35
ndkVer=25.2.9519653
cmakeVer=3.28.1
cmakeOptions=[]
- In
Step 4: Create the Game Logic
-
Set Up Game Assets:
- Place a
player.pngsprite inMyAxmolGame/assets/. This will be the player’s character. - Ensure Axmol can load it by updating the resource path in
native-lib.cpp:FileUtils::getInstance()->addSearchPath("assets");
- Place a
-
Implement Basic Game Logic: Update
native-lib.cppto add movement and collision detection:#include <axmol.h>
USING_NS_AX;
class GameScene : public Scene {
public:
static Scene* createScene() {
return GameScene::create();
}
bool init() override {
if (!Scene::init()) return false;
auto visibleSize = Director::getInstance()->getVisibleSize();
auto origin = Director::getInstance()->getVisibleOrigin();
// Add player sprite
player = Sprite::create("player.png");
player->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
this->addChild(player);
// Add obstacle
obstacle = Sprite::create("obstacle.png");
obstacle->setPosition(Vec2(visibleSize.width - 100, visibleSize.height / 2));
this->addChild(obstacle);
// Schedule updates
scheduleUpdate();
return true;
}
void update(float dt) override {
auto pos = player->getPosition();
pos.x += 100 * dt; // Move right
if (pos.x > Director::getInstance()->getVisibleSize().width) {
pos.x = 0; // Reset position
}
player->setPosition(pos);
// Basic collision detection
if (player->getBoundingBox().intersectsRect(obstacle->getBoundingBox())) {
log("Collision detected!");
}
}
private:
Sprite* player;
Sprite* obstacle;
};
extern "C" JNIEXPORT void JNICALL Java_com_myaxmolgame_AxmolModule_startGame(JNIEnv* env, jobject thiz) {
auto director = Director::getInstance();
auto scene = GameScene::createScene();
director->runWithScene(scene);
} -
Add Obstacle Asset: Place an
obstacle.pnginMyAxmolGame/assets/. This represents an obstacle the player must avoid.
Step 5: Build the React Native UI
-
Create a Game UI: Update
App.jsto include a button to start the game, display the score, and render the Axmol view:import React, { useState, useEffect } from 'react';
import { View, Text, Button, StyleSheet } from 'react-native';
import { NativeModules, requireNativeComponent } from 'react-native';
const { AxmolModule } = NativeModules;
const AxmolView = requireNativeComponent('AxmolView');
export default function App() {
const [score, setScore] = useState(0);
const startGame = () => {
AxmolModule.startGame();
// Simulate score update (in a real game, this would come from Axmol)
setScore(score + 1);
};
useEffect(() => {
return () => {
// Clean up Axmol engine on unmount
AxmolModule.stopGame && AxmolModule.stopGame();
};
}, []);
return (
<View style={styles.container}>
<Text style={styles.title}>My Axmol Game</Text>
<AxmolView style={styles.gameView} />
<Text>Score: {score}</Text>
<Button title="Start Game" onPress={startGame} />
</View>
);
}
const styles = StyleSheet.create({
container: { flex: 1, justifyContent: 'center', alignItems: 'center' },
title: { fontSize: 24, marginBottom: 20 },
gameView: { width: 300, height: 300, marginBottom: 20 },
});Note: The score is simulated here. In production, use the native bridge (e.g., a callback from Axmol C++ to JS using
RCTDeviceEventEmitter) to send game state to the UI. -
Add a Game View: To render Axmol’s OpenGL context, create a custom view. In
MyAxmolGame/android/app/src/main/java/com/myaxmolgame/, add:// AxmolView.java
package com.myaxmolgame;
import android.content.Context;
import android.opengl.GLSurfaceView;
public class AxmolView extends GLSurfaceView {
public AxmolView(Context context) {
super(context);
setEGLContextClientVersion(2); // OpenGL ES 2.0 for Axmol
setRenderer(new AxmolRenderer());
}
}// AxmolRenderer.java
package com.myaxmolgame;
import android.opengl.GLSurfaceView;
import javax.microedition.khronos.egl.EGLConfig;
import javax.microedition.khronos.opengles.GL10;
public class AxmolRenderer implements GLSurfaceView.Renderer {
@Override
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
// Initialize Axmol
}
@Override
public void onSurfaceChanged(GL10 gl, int width, int height) {
// Update viewport
}
@Override
public void onDrawFrame(GL10 gl) {
// Render Axmol frame
}
}To expose
AxmolViewto React Native, createAxmolViewManager.java:// AxmolViewManager.java
package com.myaxmolgame;
import com.facebook.react.uimanager.SimpleViewManager;
import com.facebook.react.uimanager.ThemedReactContext;
public class AxmolViewManager extends SimpleViewManager<AxmolView> {
@Override
public String getName() {
return "AxmolView";
}
@Override
protected AxmolView createViewInstance(ThemedReactContext reactContext) {
return new AxmolView(reactContext);
}
}Update
AxmolPackage.javato include the view manager:// AxmolPackage.java
public class AxmolPackage implements ReactPackage {
@Override
public List<NativeModule> createNativeModules(ReactApplicationContext reactContext) {
List<NativeModule> modules = new ArrayList<>();
modules.add(new AxmolModule(reactContext));
return modules;
}
@Override
public List<ViewManager> createViewManagers(ReactApplicationContext reactContext) {
List<ViewManager> managers = new ArrayList<>();
managers.add(new AxmolViewManager());
return managers;
}
}Note: To avoid memory leaks, ensure to stop the Axmol engine properly when the component is unmounted or the app exits. Add a
stopGamemethod toAxmolModule.javaand call it in theuseEffectcleanup function inApp.js.
Step 6: Build and Test the Game
-
Build for Android:
cd MyAxmolGame
npx react-native run-androidEnsure your Android emulator or device is running with API level 21+.
-
Build for iOS (macOS only):
npx react-native run-iosUse Xcode to configure the
.xcodeprojgenerated by Axmol if needed, following Axmol’s iOS guide. -
Test the Game:
- Launch the app, press “Start Game,” and verify the player sprite moves and detects collisions with the obstacle in the
AxmolView. - The score updates in the React Native UI (simulated for now).
- Launch the app, press “Start Game,” and verify the player sprite moves and detects collisions with the obstacle in the
Step 7: Enhance the Game
- Add Input Handling: Use React Native’s
PanResponderto capture touch events and pass them to Axmol via the native module to control the player sprite. - Improve Collision Detection: Use Axmol’s built-in physics engine (e.g., Chipmunk) for more accurate collisions.
- Add Animations: Use Axmol’s
Animationclass to animate sprites. - Polish the UI: Use Tailwind CSS (via
react-native-tailwindcss) for styling the React Native UI.
Troubleshooting Tips
- Build Errors: Ensure CMake, NDK, and Xcode versions match the requirements. Check the
.axprojfile for correct configurations. - Axmol Setup Issues: If you encounter path errors, wrap paths with spaces in single quotes or move to a directory without spaces.
- Performance: Optimize sprite rendering by using Axmol’s sprite batching and ensure React Native’s New Architecture is enabled.
Conclusion
By combining React Native for the UI and Axmol Engine for game logic, you’ve built a simple cross-platform 2D game that’s performant and extensible. This setup leverages React Native’s ease of use and Axmol’s high-performance rendering, making it ideal for indie developers. Explore Axmol’s documentation for advanced features like physics and particle effects, and enhance your React Native UI with modern libraries like Tailwind CSS.
For further help, join the Axmol community on GitHub or Discord, and check React Native’s official docs at reactnative.dev.
Additional Resources
- dopebase.com - Mobile app development resources and templates
- instamobile.io - Explore our production-ready React Native templates
- instaflutter.com - Check out our Flutter templates for cross-platform development
- iosapptemplates.com - Premium iOS app templates for quick development