feat: hot reload and draw text example

This commit is contained in:
2025-11-05 23:07:40 +13:00
parent a753f21589
commit e925faf21e
3 changed files with 134 additions and 30 deletions

6
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,6 @@
{
"files.associations": {
"*.h": "c",
"xstring": "cpp"
}
}

144
main.cpp
View File

@@ -1,9 +1,22 @@
#include "raylib.h"
#include <angelscript.h>
#include <scriptstdstring.h>
#include <cassert>
#include <iostream>
#include <string>
#include <filesystem>
#include <chrono>
#include <thread>
#include "raylib.h"
#include "angelscript.h"
#include "scriptstdstring.h"
#include <fstream>
#include <sstream>
#include <assert.h>
namespace fs = std::filesystem;
asIScriptEngine* engine = nullptr;
std::string scriptFile = "scripts/test.as";
std::time_t lastWriteTime = 0;
// Cached script functions
asIScriptFunction* updateFunc = nullptr;
asIScriptFunction* drawFunc = nullptr;
// -------------------------
// Functions exposed to AngelScript
@@ -12,6 +25,19 @@ void Print(const std::string &msg) {
std::cout << "[Script] " << msg << std::endl;
}
Color ColorFromUInt(unsigned int c) {
Color col;
col.r = (c >> 24) & 0xFF;
col.g = (c >> 16) & 0xFF;
col.b = (c >> 8) & 0xFF;
col.a = c & 0xFF;
return col;
}
void AS_DrawText(const std::string &text, int x, int y, int fontSize, unsigned int color) {
DrawText(text.c_str(), x, y, fontSize, ColorFromUInt(color));
}
// -------------------------
// AngelScript message callback
// -------------------------
@@ -19,6 +45,74 @@ void AngelScriptMessageCallback(const asSMessageInfo* msg, void* param) {
std::cout << msg->section << " (" << msg->row << "): " << msg->message << std::endl;
}
// -------------------------
// Utility to read script files
// -------------------------
std::string ReadFile(const std::string &filename) {
std::ifstream file(filename);
if (!file) return "";
std::stringstream ss;
ss << file.rdbuf();
return ss.str();
}
// -------------------------
// Compile script and cache Update/Draw
// -------------------------
bool compileScript(const std::string& filename) {
engine->GarbageCollect();
asIScriptModule* mod = engine->GetModule("main", asGM_ALWAYS_CREATE);
std::string code = ReadFile(filename);
if (code.empty()) {
std::cerr << "Failed to read script file: " << filename << "\n";
return false;
}
int r = mod->AddScriptSection(filename.c_str(), code.c_str());
if (r < 0) return false;
r = mod->Build();
if (r < 0) return false;
// Cache Update(float dt) and Draw() functions if they exist
updateFunc = mod->GetFunctionByName("Update");
drawFunc = mod->GetFunctionByName("Draw");
std::cout << "Script compiled and cached: " << filename << "\n";
return true;
}
// -------------------------
// Hot reload check
// -------------------------
void checkHotReload() {
auto ftime = fs::last_write_time(scriptFile);
auto sctp = std::chrono::time_point_cast<std::chrono::system_clock::duration>(ftime - fs::file_time_type::clock::now() + std::chrono::system_clock::now());
std::time_t t = std::chrono::system_clock::to_time_t(sctp);
if (t != lastWriteTime) {
lastWriteTime = t;
compileScript(scriptFile);
}
}
// -------------------------
// Call a cached script function
// -------------------------
void callScriptFunction(asIScriptFunction* func, float dt = 0.0f) {
if (!func) return;
asIScriptContext* ctx = engine->CreateContext();
ctx->Prepare(func);
if (func->GetParamCount() == 1) {
ctx->SetArgFloat(0, dt);
}
ctx->Execute();
ctx->Release();
}
// -------------------------
// Main
// -------------------------
@@ -28,45 +122,41 @@ int main() {
SetTargetFPS(60);
// Initialize AngelScript
asIScriptEngine* engine = asCreateScriptEngine();
engine = asCreateScriptEngine();
assert(engine);
RegisterStdString(engine);
engine->RegisterGlobalFunction("void DrawText(const string &in, int, int, int, uint)",
asFUNCTION(AS_DrawText), asCALL_CDECL);
// Register the message callback
int r = engine->SetMessageCallback(asFUNCTION(AngelScriptMessageCallback), nullptr, asCALL_CDECL);
assert(r >= 0);
// Register the Print function for scripts
r = engine->RegisterGlobalFunction("void Print(const string &in)", asFUNCTION(Print), asCALL_CDECL);
assert(r >= 0);
// Create a module and add a simple script
asIScriptModule* mod = engine->GetModule("Game", asGM_ALWAYS_CREATE);
const char* scriptCode =
"void main() { "
" Print('Hello from AngelScript!'); "
"}";
mod->AddScriptSection("test", scriptCode);
r = mod->Build();
if (r < 0) std::cerr << "Failed to build script.\n";
// Prepare and execute the script
asIScriptFunction* func = mod->GetFunctionByDecl("void main()");
asIScriptContext* ctx = engine->CreateContext();
ctx->Prepare(func);
ctx->Execute();
ctx->Release();
compileScript(scriptFile);
// Main loop
while (!WindowShouldClose()) {
float dt = GetFrameTime();
checkHotReload();
callScriptFunction(updateFunc, dt);
BeginDrawing();
ClearBackground(RAYWHITE);
DrawText("Raylib + AngelScript running!", 180, 280, 20, DARKGRAY);
DrawText("Modify scripts/test.as to hot-reload!", 50, 50, 20, DARKGRAY);
callScriptFunction(drawFunc);
EndDrawing();
std::this_thread::sleep_for(std::chrono::milliseconds(10));
}
// Clean up
CloseWindow();
engine->Release();
engine->ShutDownAndRelease();
}

View File

@@ -1,3 +1,11 @@
void main() {
Print("Hello from file script!");
}
float x = 50;
float y = 100;
void Update(float dt) {
x += 50 * dt; // move text horizontally
if (x > 800) x = 0;
}
void Draw() {
DrawText("Hello from AngelScript!", int(x), int(y), 20, 0xFF0000FF);
}