Scene là một trạng thái lớn của game: menu, đang chơi, tạm dừng, game over. Mỗi lúc chỉ có một scene chạy.
#include <njin.h>
namespace {
void enter_play(njin::context &ctx) {
for (int i = 0; i < 10; i++) {
const entt::entity e = reg.create();
}
}
void menu_update(njin::context &ctx) {
}
void play_update(njin::context &ctx) {
}
void draw_menu(njin::context &ctx) {
}
void setup(njin::context &ctx) {
}
}
njin::mod_desc scenes_module() {
return {.name =
"scenes", .setup = setup}; }
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.
entt::registry & world(context &ctx)
Trả về registry của EnTT chứa mọi entity và component của game.
@ phase_update
Mỗi frame, logic chính của game.
Definition _mod.h:35
@ 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
scene_handle scene_register(context &ctx, const scene_desc &desc)
Đăng ký một scene.
void scene_set(context &ctx, scene_handle scene)
Chuyển sang một scene khác.
void draw_text(const context &ctx, const char *text, vec2 pos, f32 size, rgba color, font_handle font={})
Vẽ chữ với góc trên trái tại pos.
constexpr rgba white
Trắng.
Definition _math.h:234
Mô tả một module: một nhóm system có tên.
Definition _mod.h:67
Định danh của một scene, tạo bởi scene_register().
Definition _types.h:139
Gắn entity vào một scene.
Definition _comps.h:122
Mô tả một system kèm ràng buộc thứ tự, dùng với ecs_register().
Definition _mod.h:47
Ba việc scene làm cho bạn
1. System chỉ chạy trong một scene. Đặt scene trong njin::sys_desc. System không đặt scene (handle id 0) chạy ở mọi scene.
2. Gọi hàm khi vào và rời scene. on_enter và on_exit trong njin::scene_desc, mỗi hàm chạy đúng một lần mỗi lần chuyển. Đây là chỗ tạo thế giới của màn chơi và lưu điểm.
3. Tự hủy entity của scene. Gắn njin::scene_owned vào entity; khi rời scene đó, engine hủy nó. Không phải tự dọn.
Chuyển scene
njin::scene_set() không chuyển ngay mà ở đầu frame sau, trước mọi system của frame đó. Frame hiện tại vì thế chạy trọn vẹn trong một scene.
Khi chuyển, engine lần lượt:
- gọi on_exit của scene cũ,
- hủy mọi entity có njin::scene_owned trỏ tới scene cũ,
- gọi on_enter của scene mới.
Scene đầu tiên cũng được đặt bằng njin::scene_set(), thường trong phase_startup. Trước đó chưa có scene nào: chỉ system không gắn scene chạy.
Chuyển cảnh mờ dần
njin::scene_fade() đổi scene sau một hiệu ứng mờ dần, và có thể hiện màn hình loading:
#include <njin.h>
namespace {
void draw_loading(njin::context &ctx) {
}
void enter_level(njin::context &ctx) {
}
void startup(njin::context &ctx) {
.on_exit = exit_level});
}
void menu_input(njin::context &ctx) {
.draw_loading = draw_loading});
}
void level_input(njin::context &ctx) {
}
void setup(njin::context &ctx) {
}
}
njin::mod_desc scene_fade_module() {
return {.name =
"scene_fade", .setup = setup}; }
vec2 screen_size(const context &ctx)
Trả về kích thước màn hình mà game vẽ lên, tính bằng pixel.
void scene_fade(context &ctx, scene_handle scene, const scene_transition &transition={})
Chuyển sang scene khác với hiệu ứng mờ dần (fade).
bool scene_transitioning(const context &ctx)
Có đang chuyển scene bằng scene_fade() không.
void texture_unload(context &ctx, texture_handle handle)
Giải phóng texture.
texture_handle texture_load(context &ctx, const char *path)
Nạp một texture từ file ảnh.
Định danh của một texture, tạo bởi texture_load().
Definition _types.h:146
Vector 2 chiều. Dùng cho vị trí, kích thước, độ dời.
Definition _types.h:39
f32 y
Thành phần dọc (trong không gian màn hình, y tăng khi đi xuống).
Definition _types.h:41
f32 x
Thành phần ngang.
Definition _types.h:40
flowchart LR
A["Phủ dần<br/>fade_out giây"]:::engine --> B["Phủ kín:<br/>vẽ màn loading<br/>ít nhất một frame"]:::engine --> C["on_exit cũ,<br/>on_enter mới<br/>(nạp tài nguyên)"]:::update --> D["Giữ kín<br/>ít nhất hold giây"]:::engine --> E["Mở dần<br/>fade_in giây"]:::engine
- Màn hình loading (draw_loading) được vẽ trước khi on_enter của scene mới chạy, nên on_enter nạp tài nguyên nặng thì người chơi vẫn thấy nó, không thấy cửa sổ đứng hình.
- Thời gian tính theo giờ thật: pause và time_set_scale() không ảnh hưởng.
- Game vẫn chạy trong lúc chuyển. Dùng njin::scene_transitioning() để bỏ qua nhập liệu nếu cần.
- Gọi lại njin::scene_fade() khi đang chuyển thì chỉ đổi scene đích. njin::scene_set() khi đang chuyển thì hủy hiệu ứng và đổi ngay frame sau.
- Lớp phủ nằm trên mọi thứ, kể cả UI.
Scene hay tạm dừng?
Menu tạm dừng thường không nên là một scene riêng: chuyển scene sẽ hủy thế giới đang chơi. Hãy giữ scene "play" và dùng njin::time_set_paused() (xem Thời gian, fixed update, timer và tween), rồi vẽ menu khi đang dừng. Game Pong trong src/games/pong làm theo cách này.