njin
Engine 2D gọn nhẹ để tự tay làm game theo ý mình. Vibe coding cũng ổn luôn
Loading...
Searching...
No Matches
Script Lua

Chạy script Lua, gọi hàm qua lại giữa C++ và Lua, script gắn trên entity, hot reload. Tiếp...

Classes

struct  njin::script_desc
 Tùy chọn của máy Lua, cho script_init(). Tiếp...
struct  njin::script_result
 Kết quả của script_call(). Tiếp...

Typedefs

using njin::script_value = std::variant<std::monostate, bool, f64, std::string, vec2, vec3, entt::entity>
 Một giá trị đi qua lại giữa C++ và Lua: nil, bool, số, chuỗi, vec2, vec3 hay entity.
using njin::script_fn = std::function<script_value(context &, std::span<const script_value>)>
 Hàm của game gọi được từ Lua, dạng chung: nhận mọi tham số, trả một giá trị.

Các hàm

void njin::script_init (context &ctx, const script_desc &desc={})
 Tạo máy Lua với tùy chọn desc.
bool njin::script_run_file (context &ctx, const char *path)
 Chạy một file Lua (đường dẫn như mọi tài nguyên: cạnh file chạy hay thư mục làm việc).
bool njin::script_run_string (context &ctx, const char *code, const char *name="string")
 Chạy một đoạn mã Lua.
script_result njin::script_call (context &ctx, const char *function, std::initializer_list< script_value > args={})
 Gọi một hàm Lua toàn cục theo tên.
script_result njin::script_call (context &ctx, const char *function, std::span< const script_value > args)
 Như bản trên, với tham số trong một mảng.
void njin::script_register (context &ctx, const char *name, script_fn fn)
 Đăng ký một hàm C++ dưới tên name (toàn cục bên Lua; có dấu chấm thì đặt trong bảng, tạo bảng khi cần).
template<class F>
requires (!std::is_convertible_v<F, script_fn>)
void njin::script_register (context &ctx, const char *name, F &&fn)
 Đăng ký một hàm C++ với tham số và kiểu trả về thường: bool, số, std::string, vec2, vec3, entt::entity hay script_value, có thể nhận context & ở đầu.
void njin::script_set_global (context &ctx, const char *name, const script_value &value)
 Đặt một biến toàn cục bên Lua (tên có dấu chấm đặt trong bảng).
script_value njin::script_get_global (context &ctx, const char *name)
 Đọc một biến toàn cục bên Lua.
bool njin::script_attach (context &ctx, entt::entity entity, const char *path)
 Gắn một script vào entity.
void njin::script_detach (context &ctx, entt::entity entity)
 Gỡ script khỏi entity (gọi on_destroy).
bool njin::script_attached (const context &ctx, entt::entity entity)
 Entity có script không.
script_value njin::script_field (context &ctx, entt::entity entity, const char *key)
 Đọc trường key của bảng self của script gắn trên entity.
void njin::script_set_field (context &ctx, entt::entity entity, const char *key, const script_value &value)
 Ghi trường key của bảng self.
i32 njin::script_count (const context &ctx)
 Số entity đang có script.
void njin::script_set_save_id (context &ctx, entt::entity entity, const char *id)
 Đặt tên lưu (self.save_id) cho script gắn trên entity: khóa để script_load_state() tìm lại đúng entity khi nạp game, vì entity tạo lại có số khác.
std::string njin::script_save_id (context &ctx, entt::entity entity)
 Tên lưu của script gắn trên entity.
json_value njin::script_save_state (context &ctx)
 Trạng thái của mọi script có tên lưu, để ghi vào save game: các trường của self (số, bool, chuỗi, vec2, vec3 và bảng lồng nhau của chúng), theo tên lưu, kèm file script.
i32 njin::script_load_state (context &ctx, const json_value &state)
 Đổ trạng thái đã lưu bằng script_save_state() vào các script đang gắn có cùng tên lưu, rồi gọi on_load(self) của chúng.

Mô tả chi tiết

Chạy script Lua, gọi hàm qua lại giữa C++ và Lua, script gắn trên entity, hot reload.

Thông tin về Typedef

◆ script_value

using njin::script_value = std::variant<std::monostate, bool, f64, std::string, vec2, vec3, entt::entity>

Một giá trị đi qua lại giữa C++ và Lua: nil, bool, số, chuỗi, vec2, vec3 hay entity.

Số của Lua (nguyên hay thực) đều thành f64; entity là số nguyên bên Lua.

Thông tin về hàm

◆ script_init()

void njin::script_init ( context & ctx,
const script_desc & desc = {} )

Tạo máy Lua với tùy chọn desc.

Không bắt buộc: lần dùng đầu của mọi hàm script_* tự tạo máy với tùy chọn mặc định. Gọi lần hai thì bỏ qua (máy đã có).

Các tham số
ctxContext của engine.
descTùy chọn.

◆ script_run_file()

bool njin::script_run_file ( context & ctx,
const char * path )

Chạy một file Lua (đường dẫn như mọi tài nguyên: cạnh file chạy hay thư mục làm việc).

Hàm và biến toàn cục nó tạo dùng được bằng script_call() và script_get_global(). Lỗi (cú pháp hay lúc chạy) được ghi log kèm file và dòng, không làm game dừng.

Các tham số
ctxContext của engine.
pathFile .lua.
Giá trị trả về
true nếu chạy hết không lỗi.

◆ script_run_string()

bool njin::script_run_string ( context & ctx,
const char * code,
const char * name = "string" )

Chạy một đoạn mã Lua.

Như script_run_file().

Các tham số
ctxContext của engine.
codeMã Lua.
nameTên hiện trong thông báo lỗi.
Giá trị trả về
true nếu chạy hết không lỗi.

◆ script_call() [1/2]

script_result njin::script_call ( context & ctx,
const char * function,
std::initializer_list< script_value > args = {} )

Gọi một hàm Lua toàn cục theo tên.

Tên có dấu chấm ("enemy.spawn") tìm trong bảng. Không có hàm hay hàm lỗi thì ghi log và ok là false.

Các tham số
ctxContext của engine.
functionTên hàm.
argsTham số.
Giá trị trả về
Kết quả.

◆ script_call() [2/2]

script_result njin::script_call ( context & ctx,
const char * function,
std::span< const script_value > args )

Như bản trên, với tham số trong một mảng.

Các tham số
ctxContext của engine.
functionTên hàm.
argsTham số.
Giá trị trả về
Kết quả.

◆ script_register() [1/2]

void njin::script_register ( context & ctx,
const char * name,
script_fn fn )

Đăng ký một hàm C++ dưới tên name (toàn cục bên Lua; có dấu chấm thì đặt trong bảng, tạo bảng khi cần).

Lỗi C++ ném ra trong hàm thành lỗi Lua có file và dòng của chỗ gọi.

Các tham số
ctxContext của engine.
nameTên bên Lua.
fnHàm.

◆ script_register() [2/2]

template<class F>
requires (!std::is_convertible_v<F, script_fn>)
void njin::script_register ( context & ctx,
const char * name,
F && fn )

Đăng ký một hàm C++ với tham số và kiểu trả về thường: bool, số, std::string, vec2, vec3, entt::entity hay script_value, có thể nhận context & ở đầu.

Tham số Lua thiếu hay sai kiểu thành giá trị mặc định của kiểu đó.

njin::script_register(ctx, "add_score", [](njin::context &c, int points) { score += points; });
njin::script_register(ctx, "distance", [](njin::vec2 a, njin::vec2 b) { return njin::length(b - a); });
f32 length(vec2 v)
Độ dài.
Definition _math.h:63
void script_register(context &ctx, const char *name, script_fn fn)
Đăng ký một hàm C++ dưới tên name (toàn cục bên Lua; có dấu chấm thì đặt trong bảng,...
Vector 2 chiều. Dùng cho vị trí, kích thước, độ dời.
Definition _types.h:39
Các tham số
ctxContext của engine.
nameTên bên Lua.
fnHàm, lambda hay con trỏ hàm (không phải lambda generic).

◆ script_set_global()

void njin::script_set_global ( context & ctx,
const char * name,
const script_value & value )

Đặt một biến toàn cục bên Lua (tên có dấu chấm đặt trong bảng).

Các tham số
ctxContext của engine.
nameTên.
valueGiá trị.

◆ script_get_global()

script_value njin::script_get_global ( context & ctx,
const char * name )

Đọc một biến toàn cục bên Lua.

Bảng, hàm và giá trị không đổi được thì là nil.

Các tham số
ctxContext của engine.
nameTên (có dấu chấm thì tìm trong bảng).
Giá trị trả về
Giá trị.

◆ script_attach()

bool njin::script_attach ( context & ctx,
entt::entity entity,
const char * path )

Gắn một script vào entity.

File phải trả về một bảng (như một lớp); mỗi entity có một bảng self riêng mà các hàm của bảng đó nhận làm tham số đầu:

  • on_start(self): một lần, ở lần cập nhật đầu tiên sau khi gắn (trước on_fixed_update hay on_update, cái nào chạy trước).
  • on_fixed_update(self, dt): theo nhịp cố định, trong phase_fixed_update, 0 hoặc nhiều lần mỗi frame (dt là bước cố định, như config::fixed_hz đặt). Chạy ngay trước bước vật lý 3D: vận tốc đặt ở đây có hiệu lực trong cùng bước. Dùng cho chuyển động và vật lý cần chạy như nhau ở mọi FPS. Không có script nào có hàm này thì không tốn gì.
  • on_update(self, dt): mỗi frame, trong phase_update (dt là delta()).
  • on_render(self): mỗi frame, trong phase_render, để vẽ (njin.draw_*).
  • on_destroy(self): khi entity bị hủy hay script bị gỡ. Đừng hủy entity khác ở đây.
  • on_reload(self): sau khi file được nạp lại (hot reload).
  • on_load(self): sau khi script_load_state() đổ dữ liệu đã lưu vào self.

self.entity là entity. Mọi trường game ghi vào self được giữ qua hot reload: file nạp lại chỉ thay các hàm. Nhiều entity dùng chung một file thì file chỉ nạp một lần. Gắn lần hai thì script cũ được gỡ trước (có on_destroy).

Các tham số
ctxContext của engine.
entityEntity.
pathFile .lua.
Giá trị trả về
true nếu file nạp được và trả về một bảng.

◆ script_detach()

void njin::script_detach ( context & ctx,
entt::entity entity )

Gỡ script khỏi entity (gọi on_destroy).

Không có script thì bỏ qua.

Các tham số
ctxContext của engine.
entityEntity.

◆ script_attached()

bool njin::script_attached ( const context & ctx,
entt::entity entity )

Entity có script không.

Các tham số
ctxContext của engine.
entityEntity.
Giá trị trả về
true nếu có.

◆ script_field()

script_value njin::script_field ( context & ctx,
entt::entity entity,
const char * key )

Đọc trường key của bảng self của script gắn trên entity.

Các tham số
ctxContext của engine.
entityEntity.
keyTên trường.
Giá trị trả về
Giá trị, nil nếu không có script hay trường.

◆ script_set_field()

void njin::script_set_field ( context & ctx,
entt::entity entity,
const char * key,
const script_value & value )

Ghi trường key của bảng self.

Không có script thì bỏ qua.

Các tham số
ctxContext của engine.
entityEntity.
keyTên trường.
valueGiá trị.

◆ script_count()

i32 njin::script_count ( const context & ctx)

Số entity đang có script.

Các tham số
ctxContext của engine.
Giá trị trả về
Số entity.

◆ script_set_save_id()

void njin::script_set_save_id ( context & ctx,
entt::entity entity,
const char * id )

Đặt tên lưu (self.save_id) cho script gắn trên entity: khóa để script_load_state() tìm lại đúng entity khi nạp game, vì entity tạo lại có số khác.

Script tự đặt được bằng self.save_id = "cua_kho". Tên phải khác nhau giữa các entity được lưu; nullptr hay chuỗi rỗng là bỏ tên (không lưu).

Các tham số
ctxContext của engine.
entityEntity có script.
idTên lưu.

◆ script_save_id()

std::string njin::script_save_id ( context & ctx,
entt::entity entity )

Tên lưu của script gắn trên entity.

Các tham số
ctxContext của engine.
entityEntity.
Giá trị trả về
Tên, hoặc chuỗi rỗng nếu không có.

◆ script_save_state()

json_value njin::script_save_state ( context & ctx)

Trạng thái của mọi script có tên lưu, để ghi vào save game: các trường của self (số, bool, chuỗi, vec2, vec3 và bảng lồng nhau của chúng), theo tên lưu, kèm file script.

self.entity không được lưu (gắn lại sẽ có). Hàm, userdata khác, vòng tham chiếu, số không hữu hạn và khóa không phải chuỗi hay số nguyên bị bỏ, mỗi chỗ một cảnh báo kèm đường dẫn (cua_kho.self.inventory[3]). Hai trường cùng trỏ tới một bảng thành hai bản sao. Số entity trong self được lưu như số thường, không đổi theo entity mới.

save.set("level", level).set("scripts", njin::script_save_state(ctx));
njin::json_save(njin::save_path(ctx, "save.json").c_str(), save);
std::string save_path(const context &ctx, const char *file_name)
Đường dẫn đầy đủ của một file lưu game, trong thư mục riêng của người dùng.
bool json_save(const char *path, const json_value &value, bool pretty=true)
Ghi một giá trị ra file JSON, tạo thư mục cha nếu cần.
json_value script_save_state(context &ctx)
Trạng thái của mọi script có tên lưu, để ghi vào save game: các trường của self (số,...
Một giá trị JSON: null, bool, số, chuỗi, mảng hoặc object.
Definition njin_json.h:33
static json_value make_object()
Một object rỗng.
Definition njin_json.h:69
json_value & set(std::string_view key, json_value value)
Đặt thành viên key (thay nếu đã có, thêm vào cuối nếu chưa).
Các tham số
ctxContext của engine.
Giá trị trả về
Object {"version": 1, "entities": {tên: {"script": file, "self": {...}}}}.

◆ script_load_state()

i32 njin::script_load_state ( context & ctx,
const json_value & state )

Đổ trạng thái đã lưu bằng script_save_state() vào các script đang gắn có cùng tên lưu, rồi gọi on_load(self) của chúng.

Gọi sau khi đã tạo lại entity, gắn script và đặt tên lưu. Các trường đã lưu ghi đè trường cùng tên; trường không có trong bản lưu giữ nguyên. on_start của script vừa gắn vẫn chạy ở lần cập nhật đầu (sau on_load), nên đặt giá trị mặc định trong bảng của file (M.hp = 10) hay bằng self.hp = self.hp or 10 để không đè lên dữ liệu vừa nạp.

if (njin::json_load(njin::save_path(ctx, "save.json").c_str(), save))
njin::script_load_state(ctx, save["scripts"]);
bool json_load(const char *path, json_value &out)
Đọc và phân tích một file JSON.
i32 script_load_state(context &ctx, const json_value &state)
Đổ trạng thái đã lưu bằng script_save_state() vào các script đang gắn có cùng tên lưu,...
Các tham số
ctxContext của engine.
stateGiá trị script_save_state() trả về (đã qua json_save()/json_load()).
Giá trị trả về
Số entity được đổ dữ liệu.