To customize raylib behavior in the Naylib wrapper, you can use Nim's --define
option to enable or disable specific features. These settings are configured in the project's config.nims
file.
To enable a feature, such as NaylibSupportAutomationEvents
, add the following line to your config.nims
:
switch("define", "NaylibSupportAutomationEvents")
Alternatively, you can pass it directly via the command line when invoking nim
:
nim c --define:NaylibSupportAutomationEvents my_program.nim
To disable a feature, you can use:
switch("define", "NaylibSupportAutomationEvents=false")
A full list of configurable options can be found in the rconfig.nim
file. Refer to it for the supported feature flags and their descriptions: rconfig.nim.
To compile your project for web browsers using WebAssembly:
-
Install the Emscripten SDK. Follow the official Emscripten installation guide.
-
Create a configuration file for your project. You can use this example as a starting point.
-
Add the
-d:emscripten
flag when compiling, e.g.,nim c -d:emscripten your_project.nim
.This will generate the necessary files for web deployment in the
public
directory. -
To run a local web server, you can use nimhttpd (
nimble install nimhttpd
). Navigate to the directory containing your compiled files and runnimhttpd
.For multithreading support (
--threads:on
), you need to pass the following extra arguments to nimhttpd:nimhttpd -H:"Cross-Origin-Opener-Policy: same-origin" -H:"Cross-Origin-Embedder-Policy: require-corp"
-
Open your web browser and navigate to the address printed by nimhttpd (usually
localhost:1337
).You should now be able to see your game running in the browser window!
When building for web, the following defines are available to customize your build:
-d:GraphicsApiOpenGlEs3
: Use WebGL 2.0 instead of WebGL 1.0 (default: WebGL 1.0)-d:NaylibWebAsyncify
: Enable Asyncify support for blocking operations-d:NaylibWebResources
: Enable filesystem and resource preloading-d:NaylibWebResourcesPath="resources"
: Set the path to preload resources from (default: "resources")
--threads:on
: Enable multithreading support-d:NaylibWebPthreadPoolSize=N
: Set the size of the pthread pool (default: 2)
-d:NaylibWebHeapSize=N
: Set the WebAssembly heap size in bytes (default: 134217728 / 128MiB)
Building for Android is streamlined using the naylib-game-template repository. Follow these steps:
-
Fork the naylib-game-template repository.
-
Clone your forked repository and navigate to its directory.
-
Make sure to install Java JDK and wget then, run the following Nimble tasks in order:
nimble setupBuildEnv # Set up Android SDK and NDK for development nimble setupAndroid # Prepare raylib project for Android development nimble buildAndroid # Compile and package raylib project for Android
-
Install and run the APK on your Android device.
Enable USB Debugging on your Android device, plug it into your computer, select File Transfer, accept the RSA key and install the package with the following command:
nimble deploy # Install and monitor raylib project on Android device/emulator
Now you should be able to run your raylib game on your Android device!
The build_android.nims file in the naylib-game-template repository offers extensive customization options for your Android build:
- Define target Android architectures (armeabi-v7a, arm64-v8a, x86, x86-64)
- Set GLES and Android API versions
- Specify locations of OpenJDK, Android SDK, and NDK on your system
- Configure application properties such as name and icon
- Adjust other build settings to match your project requirements
Review and modify this file to tailor the build process to your specific needs.
By default, Naylib uses OpenGL 3.3 on desktop platforms. To choose a different version, use one of the following flags when compiling:
-d:GraphicsApiOpenGl43
(OpenGL 4.3)-d:GraphicsApiOpenGl33
(OpenGL 3.3 - default)-d:GraphicsApiOpenGl21
(OpenGL 2.1)-d:GraphicsApiOpenGl11
(OpenGL 1.1)-d:GraphicsApiOpenGlEs2
(OpenGL ES 2.0)-d:GraphicsApiOpenGlEs3
(OpenGL ES 3.0)
Note: For Wayland on Linux, add the -d:wayland
flag.
Since Naylib wraps most types with Nim's destructors, closeWindow
needs special attention. It should be called at the very end of your program to avoid conflicts with variables destroyed after the last statement. Here are three recommended methods:
- Using
defer
ortry-finally
:
initWindow(800, 450, "example")
defer: closeWindow()
let texture = loadTexture("resources/example.png")
# Game logic goes here
- Wrapping everything inside a game object:
type
Game = object
proc `=destroy`(x: Game) =
assert isWindowReady(), "Window is already closed"
closeWindow()
# Prevent copying, moving, etc.
proc `=sink`(x: var Game; y: Game) {.error.}
proc `=dup`(y: Game): Game {.error.}
proc `=copy`(x: var Game; y: Game) {.error.}
proc `=wasMoved`(x: var Game) {.error.}
proc initGame(width, height, fps: int32, flags: Flags[ConfigFlags], title: string): Game =
assert not isWindowReady(), "Window is already opened"
setConfigFlags(flags)
initWindow(width, height, title)
setTargetFPS(fps)
let game = initGame(800, 450, 60, flags(Msaa4xHint, WindowHighdpi), "example")
let texture = loadTexture("resources/example.png")
# Game logic goes here
- Opening a new scope:
initWindow(800, 450, "example")
block:
let texture = loadTexture("resources/example.png")
# Game logic goes here
closeWindow()
- Using templates:
const
screenWidth = 800
screenHeight = 450
windowName = "example"
targetFramerate = 60
flags = flags(Msaa4xHint)
template game(gameCode: untyped) =
proc main =
setConfigFlags(flags)
initWindow(screenWidth, screenHeight, windowName)
try:
gameCode
finally:
closeWindow()
main()
template gameLoop(loopCode: untyped) =
setTargetFPS(targetFramerate)
while not windowShouldClose():
loopCode
game:
# Setup code goes here.
let texture = loadTexture("resources/example.png")
gameLoop:
drawing:
clearBackground(RayWhite)
Some types in naylib, like Texture
, don't have =copy
hooks. This prevents direct copying:
let texture = loadTexture("resources/example.png")
let copy = texture # Error: '=copy' is not available for type <Texture>
To work around this, use references:
var texture: ref Texture
new(texture)
texture[] = loadTexture("resources/example.png")
let copy = texture # This works, copying the reference
Remember that texture
and copy
will point to the same object.
- Custom Pixel Formats: To make your external type compatible with the
Pixel
concept, define apixelKind
template that returns the corresponding pixel format.
type RGBAPixel* = distinct byte
template pixelKind*(x: typedesc[RGBAPixel]): PixelFormat = UncompressedR8g8b8a8
- Swapping Raymath: Raylib is designed to be independent of
raymath
. You can use alternative vector math libraries likevmath
,geometrymath
, orglm
. Remember to implement converters forVector2
,Vector3
,Vector4
, andMatrix
if you switch libraries.
converter toVector2*(v: geometrymath.Vector2[float32]): raylib.Vector2 {.inline.} =
raylib.Vector2(x: v.x, y: v.y)
converter fromVector2*(v: raylib.Vector2): geometrymath.Vector2[float32] {.inline.} =
geometrymath.Vector2[float32](x: v.x, y: v.y)