C Scripting

Write native scripts in plain C using the Modu_* C API bridge for access to the engine runtime.

Note

C scripts use the ScriptRuntimeCAPI.h header and compile to native binaries just like C++ scripts. The compiler automatically generates a C++ wrapper to interface with the engine. Most int return values are boolean (1 = success, 0 = fail).

Overview

You can write native scripts in plain C (.c files). The Modularity compiler generates a C++ bridge automatically and links it with your C object file, producing a shared library.

C scripts cover core object state and transforms, rigidbody helpers, animation, input, settings, sprite clip control, and lightweight inspector widgets. If you need the newer ModuCPP inspector DSL, helper facades, or the full high-level movement and dialogue examples, use ModuCPP or native C++ instead.

Quickstart

  1. Create Assets/Scripts/Runtime/MyScript.c.
  2. In Inspector, add a Script component and set Language to C and assign the file.
  3. Compile: right-click file in File Browser -> Compile Script, or script component menu -> Compile.
  4. Implement a hook like Modu_TickUpdate and test in play mode.

Minimal C Example

MyScript.c
C
1#include "ScriptRuntimeCAPI.h"
2
3void Modu_TickUpdate(ModuScriptContext* ctx, float dt) {
4 ModuVec3 pos = Modu_GetPosition(ctx);
5 pos.x += dt;
6 Modu_SetPosition(ctx, pos);
7}

Supported Hooks

All hooks are optional. Accepted signatures per hook: void Hook(ModuScriptContext* ctx, float dt), void Hook(ModuScriptContext* ctx), void Hook(float dt), or void Hook().

HookDescription
Modu_BeginRuns once per object instance
Modu_TickUpdateRuns every frame (preferred)
Modu_UpdateRuns only if Modu_TickUpdate is missing
Modu_SpecRuns while Spec mode is active
Modu_TestEditorRuns while TestEditor is active
Modu_OnInspectorCalled in Inspector panel when object is selected
Modu_RenderEditorWindowCalled every frame while scripted editor tab is open
Modu_ExitRenderEditorWindowCalled once when scripted editor tab closes

C API Reference

Include ScriptRuntimeCAPI.h in your .c script. All functions are prefixed with Modu_.

Object & Transform

C
1Modu_GetObjectId(ctx)
2Modu_IsObjectEnabled(ctx)
3Modu_SetObjectEnabled(ctx, int enabled)
4Modu_GetPosition(ctx) // returns ModuVec3
5Modu_SetPosition(ctx, ModuVec3)
6Modu_GetRotation(ctx)
7Modu_SetRotation(ctx, ModuVec3)
8Modu_GetScale(ctx)
9Modu_SetScale(ctx, ModuVec3)

Rigidbody & Collision

C
1Modu_SetRigidbodyVelocity(ctx, ModuVec3 velocity)
2Modu_GetRigidbodyVelocity(ctx, ModuVec3* outVelocity)
3Modu_AddRigidbodyForce(ctx, ModuVec3 force)
4Modu_SetRigidbodyRotation(ctx, ModuVec3 rotation)
5Modu_SetRigidbodyYaw(ctx, float yawDegrees)
6Modu_EnsureCapsuleCollider(ctx, float height, float radius)
7Modu_EnsureRigidbody(ctx, int useGravity, int kinematic)
8Modu_RaycastClosestDetailed(ctx, ModuVec3 origin, ModuVec3 dir, float distance,
9 ModuVec3* hitPos, ModuVec3* hitNormal, float* hitDistance,
10 int* hitObjectId, ModuVec3* hitObjectVelocity,
11 float* hitStaticFriction, float* hitDynamicFriction)

Animation

C
1Modu_HasAnimation(ctx)
2Modu_PlayAnimation(ctx, int restart)
3Modu_StopAnimation(ctx, int resetTime)
4Modu_PauseAnimation(ctx, int pause)
5Modu_ReverseAnimation(ctx, int restartIfStopped)
6Modu_SetAnimationTime(ctx, float timeSeconds)
7Modu_GetAnimationTime(ctx) // returns float
8Modu_IsAnimationPlaying(ctx)
9Modu_SetAnimationLoop(ctx, int loop)
10Modu_SetAnimationPlaySpeed(ctx, float speed)
11Modu_SetAnimationPlayOnAwake(ctx, int playOnAwake)

Input & Movement

C
1Modu_IsSprintDown(ctx)
2Modu_IsJumpDown(ctx)
3Modu_GetMoveInputWASD(ctx, float pitchDeg, float yawDeg) // returns ModuVec3
4Modu_ApplyMouseLook(ctx, float* pitchDeg, float* yawDeg,
5 float sensitivity, float maxDelta, float deltaTime, int requireMouseButton)

Script Settings

C
1Modu_GetSettingFloat(ctx, const char* key, float fallback)
2Modu_SetSettingFloat(ctx, const char* key, float value)
3Modu_GetSettingBool(ctx, const char* key, int fallback)
4Modu_SetSettingBool(ctx, const char* key, int value)
5Modu_GetSettingString(ctx, const char* key, const char* fallback,
6 char* outBuffer, int outBufferSize)
7Modu_SetSettingString(ctx, const char* key, const char* value)

Console Logging

C
1Modu_AddConsoleMessage(ctx, const char* message, int type)
ConstantUsage
MODU_CONSOLE_INFOGeneral information
MODU_CONSOLE_WARNINGWarnings
MODU_CONSOLE_ERRORErrors
MODU_CONSOLE_SUCCESSSuccess messages

Sprite Clips

C
1Modu_GetSpriteClipCount(ctx)
2Modu_GetSpriteClipIndex(ctx)
3Modu_SetSpriteClipIndex(ctx, int index)
4Modu_SetSpriteClipName(ctx, const char* name)
5Modu_GetSpriteClipName(ctx, char* outBuffer, int outBufferSize)
6Modu_GetSpriteClipNameAt(ctx, int index, char* outBuffer, int outBufferSize)

Inspector UI Helpers

C
1Modu_InspectorText(ctx, const char* text)
2Modu_InspectorSeparator(ctx)
3Modu_InspectorDragFloat(ctx, label, float* value, speed, min, max, format)
4Modu_InspectorDragFloat2(ctx, label, float* value, speed, min, max, format)
5Modu_InspectorDragFloat3(ctx, label, float* value, speed, min, max, format)
6Modu_InspectorCheckbox(ctx, const char* label, int* value)
7Modu_InspectorObject(ctx, const char* label, int* objectId)

Examples

Inspector + Persisted Settings

Rotate.c
C
1#include "ScriptRuntimeCAPI.h"
2
3static float speed = 45.0f;
4static int enabled = 1;
5
6void Modu_Begin(ModuScriptContext* ctx) {
7 speed = Modu_GetSettingFloat(ctx, "speed", speed);
8 enabled = Modu_GetSettingBool(ctx, "enabled", enabled);
9}
10
11void Modu_TickUpdate(ModuScriptContext* ctx, float dt) {
12 if (!enabled) return;
13 ModuVec3 rot = Modu_GetRotation(ctx);
14 rot.y += speed * dt;
15 Modu_SetRotation(ctx, rot);
16}
17
18void Modu_OnInspector(ModuScriptContext* ctx) {
19 Modu_InspectorText(ctx, "Rotate (C API)");
20 if (Modu_InspectorCheckbox(ctx, "Enabled", &enabled)) {
21 Modu_SetSettingBool(ctx, "enabled", enabled);
22 }
23 if (Modu_InspectorDragFloat(ctx, "Speed", &speed, 0.1f, 0.0f, 720.0f, "%.2f")) {
24 Modu_SetSettingFloat(ctx, "speed", speed);
25 }
26}

Basic Movement

Movement.c
C
1#include "ScriptRuntimeCAPI.h"
2
3void Modu_TickUpdate(ModuScriptContext* ctx, float dt) {
4 ModuVec3 wasd = Modu_GetMoveInputWASD(ctx, 0.0f, 0.0f);
5 ModuVec3 vel = { wasd.x * 5.0f, 0.0f, wasd.z * 5.0f };
6 Modu_SetRigidbodyVelocity(ctx, vel);
7}

Detailed Raycast

Raycast.c
C
1#include "ScriptRuntimeCAPI.h"
2#include <stdio.h>
3
4void Modu_TickUpdate(ModuScriptContext* ctx, float dt) {
5 (void)dt;
6 ModuVec3 pos = Modu_GetPosition(ctx);
7 ModuVec3 forward = { 0.0f, 0.0f, 1.0f };
8 ModuVec3 hitPos, hitNormal, hitVel;
9 float hitDist, sF, dF;
10 int hitId;
11
12 int hit = Modu_RaycastClosestDetailed(ctx, pos, forward, 100.0f,
13 &hitPos, &hitNormal, &hitDist, &hitId, &hitVel, &sF, &dF);
14 if (hit) {
15 char msg[128];
16 snprintf(msg, sizeof(msg), "Hit object %d at %.2fm", hitId, hitDist);
17 Modu_AddConsoleMessage(ctx, msg, MODU_CONSOLE_INFO);
18 }
19}