Bring Godot to React Native ๐ฎ. Create immersive 3D experiences or interactive games directly within React Native, allowing for high-performance graphics and responsive interactions.
- ๐๏ธ Native C++ JSI performance
- ๐ฅ GPU-accelerated by Metal and OpenGL/Vulkan
- โ Supports old and new arch
- ๐ Supports Godot Variants in React Native
- ๐งจ Call GDScript methods in React Native
- ๐ฆ Easy import of your Godot projects
iOS support is implemented, full support for Android is almost ready. We'll ship that soon ๐
Platform | Supported |
---|---|
iOS Simulator | โ |
iOS Device | โ |
Android Emulator | ๐ง |
Android Device | ๐ง |
- Godot 4.3 (https://godotengine.org/)
npm install react-native-godot
or
yarn add react-native-godot
Take a look at the example
folder for a full implem ๐.
You can send messages from React Native to Godot and receive messages from Godot in React Native.
- React Native -> Godot: You can send messages from React Native to Godot using the
emitMessage
method. - Godot -> React Native: You can receive messages from Godot in React Native using the
onMessage
prop.
// โ ๏ธ IMPORTANT โ ๏ธ
// GodotProvider is required to initalize Godot properly
// (See in the example folder for more details)
//
// <GodotProvider>
// <Example />
// <GodotProvider/>
//
// It should be at the root of your app.
// The highest level is recommended. e.g. App.tsx
import React, {useRef} from 'react';
import {Godot, GodotView, GodotProvider, useGodot} from 'react-native-godot';
const Example = () => {
const godotRef = useRef<GodotView>(null);
const {Vector3, Vector2} = useGodot();
// Call gdsript method from React Native
useEffect(() => {
if (!godotRef.current || !godotRef.current?.isReady) {
return;
}
// Emit a message to Godot from React Native
godotRef.current?.emitMessage({
message: 'Hello from React Native!',
position: Vector3(1, 2, 3),
});
// Use Godot Vector3 and Vector2 variants
// All methods and properties are available too :)
console.log('Vector3 y:', Vector3(1, 2, 3).y);
console.log('Length', Vector2(3, 1).length());
// Retrieve a node from your scene
const node = godotRef.current?.getRoot()?.getNode('MySuperNode');
if (!node) {
return;
}
// Call method `hello_world` from the gdscript attached to the node in your scene
node.hello_world();
// You can also call your method and return a value with any supported types
const something = node.method_that_returns_something();
console.log('Something:', something);
}, [godotRef.current?.isReady]);
return (
<Godot
ref={godotRef}
style={{flex: 1}}
source={require('./assets/game.pck')}
scene="res://main.tscn"
{/* Receive messages from Godot */}
onMessage={(message) => console.log('Godot message:', message)}
/>
);
};
# This class is a demonstration of GDScript with React Native.
extends Node
func _ready() -> void:
if Engine.has_singleton("ReactNative"): # Always check if the ReactNative singleton exists
Engine.get_singleton("ReactNative").on_message(_on_message)
func _on_message(message: Dictionary) -> void:
print("React Native message:", message)
func _input(event: InputEvent) -> void:
if "position" not in event:
return
var adjusted_position = adjust_for_window(event.position)
if Engine.has_singleton("ReactNative"):
# Emit a message to React Native
Engine.get_singleton("ReactNative").emit_message({
"message": "Input event position",
"pos": adjusted_position,
})
func hello_world() -> void:
print("Hello World!")
func method_that_returns_something() -> int:
return 42
## This function is used to adjust the screen position for the window.
func adjust_for_window(pos: Vector2) -> Vector2:
var window = get_viewport().get_window()
var window_id = window.get_window_id()
if window_id == DisplayServer.MAIN_WINDOW_ID or window_id == DisplayServer.INVALID_WINDOW_ID:
return pos
var window_position = Vector2()
if Engine.has_singleton("ReactNative"):
window_position = Engine.get_singleton("GDReactNative").get_subwindow_position(window_id)
return Vector2(
pos.x + window_position.x,
pos.y + window_position.y
)
Godot variants are available in React Native, here is the list:
AABB | Basis | Color | Plane | Projection | Quaternion | Rect2 | Rect2i | Transform2D | Transform3D | Vector2 | Vector2i | Vector3 | Vector3i | Vector4 | Vector4i
.
For primitives like int
, float
, bool
, dictionary
, array
, etc, you can use normal JS types and it will be automatically converted to Godot variants and vice versa.
All methods and properties are available too, for instance, you can use Vector3(1, 2, 3).length()
.
Complete documentation is available at https://docs.godotengine.org/en/stable/classes/index.html#variant-types.
You can retrieve a node from your scene in React Native and call methods on it.
Current supported methods for a Node are:
- getNode(name: string): Node | null
- getParent(): Node | null
- getChildren(): Node[]
- getChildCount(): number
(+ Any method you've defined in your gdscript ๐)
-
To import your Godot project into React Native, you need to generate a pck file that basically packs up all your game assets, scripts etc. It's a convenient way to pack your game into a single file.
-
First, you need to add a
export_presets.cfg
in the directory of your Godot project. We provide a working example of this file at the root of this repository. -
After that, you're now able to generate a pck file, just run
./gen-pck PROJECT_FOLDER_PATH
. Be sure you have/Applications/Godot.app
set on your machine, if you're using another path or another OS than macOS, just modify this very simple shell at your convenience. -
Then, you just need to move the pck file in your assets folder.
-
One last thing, add a
project.godot
in your assets with the pck, see in the example folder for more details.
- You need to add the following to your
metro.config.js
in order to treat.pck
files as assets and exclude them from being treated as source files.
// Treat `.pck` files as assets
assetExts: [...assetExts, 'pck'],
// Exclude `.pck` from being treated as source files
sourceExts: sourceExts.filter(ext => ext !== 'pck'),
And...
server: {
enhanceMiddleware: (middleware) => {
return (req, res, next) => {
if (/\.pck$/.test(req.url)) {
res.setHeader('Content-Type', 'application/octet-stream');
}
return middleware(req, res, next);
};
},
},
The Godot engine is quite large, so the library size is also quite large too ๐ .
Godot with all features enabled is around 140MB for iOS (arm64). We might be able to reduce this size in the future.
For example by disabling features that are not needed, removing MoltenVK
for iOS in Godot 4.4 (which is around 9MB), not depending on godot-cpp
too much etc.
Also, your pck file must be considered in the size of your app. Which can be quite large too if you have a lot of big assets like 3D models, textures, etc.
- When importing a texture or 3D model, be sure you don't import them as
VRAM Compressed
, for some reason when exporting the pck file, it doesn't import the assets. Might be a mistake from our side.... (TBD) ๐
- PCK Asset Swapping: For now, you can't swap the pck asset at runtime properly, you need to reopen the app to load a new pck asset. It seems to be a limitation of the Godot engine itself, but we're investigating this as it would be super useful to debug on device in almost real-time.
- iOS support
- Android support
- Improve library size
- Add support for all Godot variants
- Investigate PCK asset swapping
- Add support for more Godot features
We're open to any contributions. Feel free to open an issue if you want to help us improve this library.
All the interesting stuff is located in a private repository so if you want to contribute, just send us an email at team@calico.games
.
You should have previous experiences of building the Godot Engine yourself, C++, and building blazing fast React Native libraries is a plus.
Bazel is also used internally to build the library fyk.
Copyright Calico Games 2024. All rights reserved.
This library is released under a Custom License with the following conditions:
- Free for non-commercial use: You may freely use this library for personal, educational, or open-source projects.
- Commercial use by revenue-generating entities: Any company or individual with an annual revenue exceeding $50,000 must obtain a commercial license to use this library.
- No Redistribution Allowed: This library cannot be redistributed, repackaged, or resold.
PS: We are pretty flexible atm and we would like to also support the Godot Foundation by giving them a share of the revenue generated by this library.
For commercial licensing inquiries, please contact us at team@calico.games
.
- Special thanks to all the contributors of the Godot Engine.
- A big shoutout to Migeran that helped us a lot to build this library.