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
Cài đặt của người chơi

Âm lượng, phím, toàn màn hình, ngôn ngữ: những thứ người chơi tự chỉnh và mong game nhớ.

#include <njin.h>
namespace {
bool open_settings = true;
void startup(njin::context &ctx) {
jump = njin::action_register(ctx, "jump");
// Sau khi đăng ký hết action và nạp ngôn ngữ: phím người chơi đã đổi, âm
// lượng, toàn màn hình, ngôn ngữ thay cho giá trị mặc định.
}
void settings_menu(njin::context &ctx) {
if (!open_settings)
return;
njin::ui_begin(ctx, {.id = "settings", .title = "Cài đặt"});
// Âm lượng từng kênh. Kênh master nhân vào tất cả.
if (njin::ui_slider(ctx, "Nhạc", music, 0.0f, 1.0f, 0.1f, true))
// Đổi phím: bấm vào dòng rồi bấm phím mới. Dòng thứ hai cho tay cầm.
njin::ui_keybind(ctx, "Nhảy", jump);
njin::ui_keybind(ctx, "Nhảy##pad", jump, true);
// Không coi Esc là "đóng menu" khi đang chờ phím.
if (njin::ui_button(ctx, "Xong") || (!njin::ui_keybind_listening(ctx) && njin::ui_back(ctx))) {
njin::settings_save(ctx); // ghi vào thư mục lưu game của người dùng
open_settings = false;
}
}
// Rung tay cầm khi trúng đòn.
void on_hit(njin::context &ctx) { njin::pad_rumble(ctx, 0, 0.6f, 0.8f, 0.25f); }
// Chuyển nhạc mượt giữa hai bản, theo giờ thật nên chạy cả khi game pause.
void enter_boss(njin::context &ctx, njin::music_handle boss) { njin::music_crossfade(ctx, boss, 1.5f); }
void setup(njin::context &ctx) {
}
} // namespace
int main() {
njin::context *ctx = njin::create({.title = "Settings", .width = 1280, .height = 720, .target_fps = 60});
njin::mod_register(*ctx, {.name = "game", .setup = setup});
(void)on_hit;
(void)enter_boss;
njin::run(*ctx);
}
void run(context &ctx)
Chạy vòng lặp chính cho đến khi cửa sổ đóng.
context * create(const config &cfg)
Mở cửa sổ và trả về context của engine.
void destroy(context *ctx)
Giải phóng mọi tài nguyên của engine và đóng cửa sổ.
void pad_rumble(context &ctx, i32 pad, f32 low, f32 high, f32 seconds)
Rung tay cầm.
void action_bind_pad(context &ctx, action_handle handle, gamepad_button button)
Gắn một nút tay cầm vào action.
void action_bind_key(context &ctx, action_handle handle, key_code key)
Gắn một phím vào action.
action_handle action_register(context &ctx, const char *name)
Đăng ký một action có tên.
@ pad_face_down
Nút mặt dưới (A trên Xbox, Chéo trên PlayStation).
Definition _types.h:497
@ key_space
Phím cách.
Definition _types.h:411
void ecs_register(context &ctx, sys_phase phase, sys_fnc fnc, const char *name=nullptr)
Thêm một system vào lịch chạy của một phase.
void mod_register(context &ctx, const mod_desc &desc)
Chạy setup của module và đưa các system của nó vào lịch chạy.
@ phase_startup
Một lần, trước frame đầu tiên.
Definition _mod.h:32
@ phase_post_render
Mỗi frame, vẽ trong không gian màn hình (UI).
Definition _mod.h:39
void music_crossfade(context &ctx, music_handle handle, f32 seconds)
Chuyển nhạc: mọi music khác đang phát nhỏ dần rồi dừng, trong lúc handle to dần.
bool settings_save(const context &ctx, const char *file="settings.json", const json_value *game=nullptr)
Lưu cài đặt vào file trong thư mục lưu game (save_path()), kèm dữ liệu riêng của game nếu có (độ khó,...
bool settings_load(context &ctx, const char *file="settings.json", json_value *game=nullptr)
Nạp và áp dụng cài đặt đã lưu.
void audio_set_bus_volume(context &ctx, audio_bus bus, f32 volume)
Đặt âm lượng một kênh, từ 0 trở lên (1 là nguyên).
f32 audio_bus_volume(const context &ctx, audio_bus bus)
Âm lượng một kênh.
@ bus_music
Nhạc nền (mọi music).
Definition njin_audio.h:19
float f32
Số thực 32 bit.
Definition _types.h:28
bool ui_slider(context &ctx, const char *label, f32 &value, f32 min, f32 max, f32 step=0.0f, bool percent=false)
Một thanh trượt.
void ui_begin(context &ctx, const ui_panel_desc &desc={})
Bắt đầu một panel.
bool ui_back(context &ctx)
true ở frame người chơi bấm quay lại (Esc, Backspace, nút B) trong lúc có panel đang hiện.
void ui_end(context &ctx)
Kết thúc panel và vẽ nó.
bool ui_keybind_listening(const context &ctx)
Có dòng ui_keybind() nào đang chờ phím không.
bool ui_keybind(context &ctx, const char *label, action_handle action, bool pad=false)
Một dòng đổi phím cho màn hình cài đặt: bên trái là tên, bên phải là phím đang gắn vào action.
bool ui_button(context &ctx, const char *label, bool enabled=true)
Một nút bấm.
Định danh của một action nhập liệu, tạo bởi action_register().
Definition _types.h:85
Định danh của một bản nhạc stream (music), tạo bởi music_load().
Definition _types.h:123

Kênh âm thanh

njin::audio_bus chia âm thanh thành kênh, như thanh trượt trong menu cài đặt. Âm lượng thật của một âm là âm lượng riêng của nó, nhân âm lượng kênh, nhân kênh bus_master.

Kênh Dùng cho
bus_master Nhân vào tất cả
bus_music Mọi music
bus_sfx Hiệu ứng trong game (mặc định của sound)
bus_ui Tiếng menu; đưa vào bằng sound_set_bus()
bus_voice Lồng tiếng

audio_set_bus_volume() và audio_set_bus_muted() có hiệu lực ngay, cả với âm đang phát. music_crossfade() chuyển nhạc mượt (theo giờ thật, nên chạy cả khi game pause); music_fade_in() và music_fade_out() cho từng bản.

Đổi phím

Một action có thể gắn phím, nút chuột và nút tay cầm. Để người chơi đổi:

  • ui_keybind(): một dòng trong menu, "Nhảy | Space". Bấm vào rồi bấm phím mới (Esc hủy). Dùng ui_keybind(ctx, "Nhảy##pad", action, true) cho dòng nút tay cầm. Trong lúc chờ, UI không điều hướng; kiểm tra ui_keybind_listening() để không coi Esc là "đóng menu".
  • action_rebind() là phép đổi phím ở dưới: nguồn mới thay nguồn cùng thiết bị của action, và bị gỡ khỏi mọi action khác để một phím không làm hai việc. Nhận phím bằng input_any_pressed().
  • input_source_name() cho chữ hiện ("Space", "Left Shift", "Pad A"), và action_sources() liệt kê phím đang gắn: dùng để vẽ gợi ý "Bấm E để nói chuyện" đúng với phím người chơi đã đổi.

Lưu và nạp

njin::settings_load(ctx); // sau khi đăng ký hết action, axis và nạp ngôn ngữ
njin::settings_save(ctx); // khi rời menu cài đặt

File là JSON trong thư mục lưu game (settings.json, xem save_path()): âm lượng và tắt tiếng từng kênh, phím của mọi action và axis, toàn màn hình, ngôn ngữ. Phần nào không có trong file thì giữ nguyên, nên game thêm action mới trong bản cập nhật vẫn có phím mặc định. Dữ liệu riêng của game (độ khó, độ sáng) đi kèm dưới khóa game: settings_save(ctx, "settings.json", &data).

Nếu cần tự lưu phím vào chỗ khác: input_bindings_save() và input_bindings_load().

Rung tay cầm

pad_rumble() cho hai motor (trầm và nhanh) trong một khoảng thời gian; tay cầm không có motor thì không làm gì. Kết hợp với camera_shake() và hitstop() khi trúng đòn.