118 lines
4.9 KiB
Markdown
118 lines
4.9 KiB
Markdown
# Modularity C++ Scripting Quickstart
|
|
|
|
## Project setup
|
|
- Scripts live under `Scripts/` (configurable via `Scripts.modu`).
|
|
- The engine generates a wrapper per script when compiling. It exports fixed entry points with `extern "C"` linkage:
|
|
- `Script_OnInspector(ScriptContext&)`
|
|
- `Script_Begin(ScriptContext&, float deltaTime)`
|
|
- `Script_Spec(ScriptContext&, float deltaTime)`
|
|
- `Script_TestEditor(ScriptContext&, float deltaTime)`
|
|
- `Script_Update(ScriptContext&, float deltaTime)` (fallback if TickUpdate is absent)
|
|
- `Script_TickUpdate(ScriptContext&, float deltaTime)`
|
|
- Build config file: `Scripts.modu` (auto-created per project). Keys:
|
|
- `scriptsDir`, `outDir`, `includeDir=...`, `define=...`, `linux.linkLib`, `win.linkLib`, `cppStandard`.
|
|
|
|
## Lifecycle hooks
|
|
- **Inspector**: `Script_OnInspector(ScriptContext&)` is called when the script is inspected in the UI.
|
|
- **Begin**: `Script_Begin` runs once per object instance before ticking.
|
|
- **Spec/Test**: `Script_Spec` and `Script_TestEditor` run every frame when the global “Spec Mode” / “Test Mode” toggles are enabled (Scripts menu).
|
|
- **Tick**: `Script_TickUpdate` runs every frame for each script; `Script_Update` is a fallback if TickUpdate is missing.
|
|
- All tick-style hooks receive `deltaTime` (seconds) and the `ScriptContext`.
|
|
|
|
## ScriptContext helpers
|
|
Available methods:
|
|
- `FindObjectByName`, `FindObjectById`
|
|
- `SetPosition`, `SetRotation`, `SetScale`
|
|
- `HasRigidbody`
|
|
- `SetRigidbodyVelocity`, `GetRigidbodyVelocity`
|
|
- `SetRigidbodyAngularVelocity`, `GetRigidbodyAngularVelocity`
|
|
- `AddRigidbodyForce`, `AddRigidbodyImpulse`
|
|
- `AddRigidbodyTorque`, `AddRigidbodyAngularImpulse`
|
|
- `SetRigidbodyRotation`, `TeleportRigidbody`
|
|
- `MarkDirty` (flags the project as having unsaved changes)
|
|
Fields:
|
|
- `engine`: pointer to the Engine
|
|
- `object`: pointer to the owning `SceneObject`
|
|
- `script`: pointer to the owning `ScriptComponent` (gives access to per-script `settings`)
|
|
|
|
## Persisting per-script settings
|
|
- Each `ScriptComponent` has `settings` (key/value strings) serialized with the scene.
|
|
- You can read/write them via `ctx.script->settings` or helper functions in your script.
|
|
- After mutating settings or object transforms, call `ctx.MarkDirty()` so Ctrl+S captures changes.
|
|
|
|
## Example pattern (simplified)
|
|
```cpp
|
|
static bool autoRotate = false;
|
|
static glm::vec3 speed = {0, 45, 0};
|
|
|
|
void Script_OnInspector(ScriptContext& ctx) {
|
|
ImGui::Checkbox("Auto Rotate", &autoRotate);
|
|
ImGui::DragFloat3("Speed", &speed.x, 1.f, -360.f, 360.f);
|
|
ctx.MarkDirty();
|
|
}
|
|
|
|
void Script_Begin(ScriptContext& ctx, float) {
|
|
ctx.MarkDirty(); // ensure initial state is saved
|
|
}
|
|
|
|
void Script_TickUpdate(ScriptContext& ctx, float dt) {
|
|
if (autoRotate && ctx.object) {
|
|
ctx.SetRotation(ctx.object->rotation + speed * dt);
|
|
}
|
|
}
|
|
```
|
|
|
|
## Runtime behavior
|
|
- Scripts tick for all objects every frame, even if not selected.
|
|
- Spec/Test toggles are global (main menu → Scripts).
|
|
- Compile scripts via the UI “Compile Script” button or run the build command; wrapper generation is automatic.
|
|
|
|
## Rigidbody helper usage
|
|
- `SetRigidbodyAngularVelocity(vec3)` sets angular velocity in radians/sec for dynamic, non-kinematic bodies.
|
|
```cpp
|
|
ctx.SetRigidbodyAngularVelocity({0.0f, 3.0f, 0.0f});
|
|
```
|
|
- `GetRigidbodyAngularVelocity(out vec3)` reads current angular velocity into `out`. Returns false if unavailable.
|
|
```cpp
|
|
glm::vec3 angVel;
|
|
if (ctx.GetRigidbodyAngularVelocity(angVel)) {
|
|
ctx.AddConsoleMessage("AngVel Y: " + std::to_string(angVel.y));
|
|
}
|
|
```
|
|
- `AddRigidbodyForce(vec3)` applies continuous force (mass-aware).
|
|
```cpp
|
|
ctx.AddRigidbodyForce({0.0f, 0.0f, 25.0f});
|
|
```
|
|
- `AddRigidbodyImpulse(vec3)` applies an instant impulse (mass-aware).
|
|
```cpp
|
|
ctx.AddRigidbodyImpulse({0.0f, 6.5f, 0.0f});
|
|
```
|
|
- `AddRigidbodyTorque(vec3)` applies continuous torque.
|
|
```cpp
|
|
ctx.AddRigidbodyTorque({0.0f, 15.0f, 0.0f});
|
|
```
|
|
- `AddRigidbodyAngularImpulse(vec3)` applies an instant angular impulse.
|
|
```cpp
|
|
ctx.AddRigidbodyAngularImpulse({0.0f, 4.0f, 0.0f});
|
|
```
|
|
- `SetRigidbodyRotation(vec3 degrees)` teleports the rigidbody rotation.
|
|
```cpp
|
|
ctx.SetRigidbodyRotation({0.0f, 90.0f, 0.0f});
|
|
```
|
|
Notes:
|
|
- These return false if the object has no enabled rigidbody or is kinematic.
|
|
- Use force/torque for continuous input and impulses for bursty actions.
|
|
- `SetRigidbodyRotation` is authoritative; use it sparingly during gameplay.
|
|
|
|
## Manual compile (CLI)
|
|
Linux example:
|
|
```bash
|
|
g++ -std=c++20 -fPIC -O0 -g -I../src -I../include -c SampleInspector.cpp -o ../Cache/ScriptBin/SampleInspector.o
|
|
g++ -shared ../Cache/ScriptBin/SampleInspector.o -o ../Cache/ScriptBin/SampleInspector.so -ldl -lpthread
|
|
```
|
|
Windows example:
|
|
```bat
|
|
cl /nologo /std:c++20 /EHsc /MD /Zi /Od /I ..\\src /I ..\\include /c SampleInspector.cpp /Fo ..\\Cache\\ScriptBin\\SampleInspector.obj
|
|
link /nologo /DLL ..\\Cache\\ScriptBin\\SampleInspector.obj /OUT:..\\Cache\\ScriptBin\\SampleInspector.dll User32.lib Advapi32.lib
|
|
```
|