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
Thời gian, fixed update, timer và tween

Các loại thời gian

Hàm Trả về Bị tốc độ và tạm dừng ảnh hưởng
njin::delta() Thời gian của frame (giây) Có
njin::delta_real() Thời gian thật của frame Không
njin::elapsed() Thời gian từ lúc mở game Không
njin::fixed_delta() Độ dài một nhịp cố định Không đổi

Hầu hết code dùng njin::delta(). Dùng njin::delta_real() cho thứ vẫn phải chạy khi game dừng: menu tạm dừng, hiệu ứng UI.

Tốc độ và tạm dừng

  • njin::time_set_scale(): 1 là bình thường, 0.5 là chậm một nửa. Ảnh hưởng delta(), fixed update và animation sprite. Dùng cho slow motion.
  • njin::time_set_paused(): njin::delta() về 0 và fixed update ngừng. Mọi phase khác vẫn chạy, nên input vẫn đọc được và menu vẫn vẽ được.

Fixed update

phase_fixed_update chạy theo nhịp cố định, mặc định 60 lần mỗi giây (config::fixed_hz). Mỗi frame nó chạy 0, 1 hoặc vài lần tùy FPS, sao cho tổng số nhịp khớp thời gian thật.

flowchart LR
  A["tích lũy += delta()"]:::engine --> B{"tích lũy >= nhịp?"}:::decide
  B -- có --> C["chạy phase_fixed_update<br/>tích lũy -= nhịp"]:::fixed --> B
  B -- không --> D["phase_update"]:::update

Trong phase này, njin::delta() trả về đúng một nhịp. Đặt vật lý ở đây: kết quả giống nhau dù máy chạy 30 hay 144 FPS, và va chạm không bị xuyên qua khi FPS tụt.

Nếu một frame quá dài (ví dụ dừng ở breakpoint), phần dư quá 8 nhịp bị bỏ, để game không phải chạy dồn hàng trăm nhịp một lúc.

njin::fixed_alpha() cho biết phần nhịp còn dư (0..1). Dùng để nội suy vị trí khi vẽ, cho chuyển động mượt khi FPS cao hơn nhịp vật lý:

const njin::vec2 draw_pos = njin::lerp(prev_pos, pos, njin::fixed_alpha(ctx));
constexpr vec3 lerp(vec3 a, vec3 b, f32 t)
Nội suy tuyến tính giữa hai vector.
Definition _math.h:158
f32 fixed_alpha(const context &ctx)
Phần nhịp cố định còn dư sau phase_fixed_update của frame này, từ 0 đến 1.
Vector 2 chiều. Dùng cho vị trí, kích thước, độ dời.
Definition _types.h:39

Timer và tween

#include <njin.h>
namespace {
njin::timer spawn_every{.duration = 2.0f, .repeat = true};
njin::timer invincible{.duration = 1.5f};
njin::tween<njin::vec2> slide_in{.from = {-200, 40},
.to = {20, 40},
.duration = 0.6f,
bool paused = false;
void update(njin::context &ctx) {
const njin::f32 dt = njin::delta(ctx); // 0 khi tạm dừng
if (spawn_every.tick(dt))
NJIN_INFO("sinh một con quái");
// Tạm dừng: delta() về 0, phase_fixed_update ngừng, nhưng system vẫn chạy
// nên vẫn đọc được phím để bỏ tạm dừng.
njin::time_set_paused(ctx, paused);
}
// Chậm lại khi giữ Shift: cả delta() lẫn phase cố định đều chậm theo.
const bool slow = njin::key_held(ctx, njin::key_left_shift);
njin::time_set_scale(ctx, slow ? 0.3f : 1.0f);
invincible.reset();
invincible.tick(dt);
}
void draw_ui(njin::context &ctx) {
// Bảng trượt vào màn hình. Dùng delta_real để vẫn chạy khi tạm dừng.
const njin::vec2 pos = slide_in.tick(njin::delta_real(ctx));
njin::draw_text(ctx, paused ? "TAM DUNG" : "Dang choi", pos, 30,
// Nhấp nháy khi bất tử: tiến độ timer quyết định tần số.
if (!invincible.finished) {
const bool on = (int)(invincible.progress() * 12.0f) % 2 == 0;
if (on)
njin::draw_text(ctx, "Bat tu", {20, 80}, 24, njin::colors::yellow);
}
}
void setup(njin::context &ctx) {
}
} // namespace
njin::mod_desc time_module() { return {.name = "time", .setup = setup}; }
bool key_pressed(const context &ctx, key_code key)
Đúng ở frame mà phím vừa được nhấn xuống (chỉ một frame).
bool key_held(const context &ctx, key_code key)
Đúng khi phím đã được giữ từ frame trước và vẫn đang giữ.
@ key_p
Phím P.
Definition _types.h:359
@ key_h
Phím H.
Definition _types.h:351
@ key_left_shift
Shift trái.
Definition _types.h:437
#define NJIN_INFO(...)
Ghi log mức info. Tham số giống printf.
Definition njin_log.h:98
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.
@ phase_update
Mỗi frame, logic chính của game.
Definition _mod.h:35
@ phase_post_render
Mỗi frame, vẽ trong không gian màn hình (UI).
Definition _mod.h:39
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.
f32 delta_real(const context &ctx)
Thời gian thật của frame trước, không bị tốc độ thời gian hay tạm dừng ảnh hưởng.
void time_set_scale(context &ctx, f32 scale)
Đặt tốc độ thời gian của game.
void time_set_paused(context &ctx, bool paused)
Tạm dừng hoặc chạy tiếp thời gian của game.
f32 delta(const context &ctx)
Thời gian của frame trước, tính bằng giây, đã nhân với tốc độ thời gian.
@ out_back
Vượt quá đích một chút rồi quay về.
Definition _tween.h:66
float f32
Số thực 32 bit.
Definition _types.h:28
constexpr rgba yellow
Vàng.
Definition _math.h:239
constexpr rgba white
Trắng.
Definition _math.h:234
post_fx paused()
Menu pause: thế giới mờ và tối phía sau UI.
Definition njin_post.h:186
Mô tả một module: một nhóm system có tên.
Definition _mod.h:67
Bộ đếm thời gian: báo khi hết giờ.
Definition _tween.h:12
bool finished
Đã hết giờ (chỉ dùng khi không lặp).
Definition _tween.h:16
bool tick(f32 dt)
Cho thời gian trôi.
Definition _tween.h:22
void reset()
Bắt đầu lại từ 0.
Definition _tween.h:45
f32 progress() const
Tiến độ từ 0 đến 1.
Definition _tween.h:40
Chuyển mượt một giá trị từ from đến to trong duration giây.
Definition _tween.h:141
T tick(f32 dt)
Cho thời gian trôi rồi trả về giá trị mới.
Definition _tween.h:158

njin::timer đếm ngược rồi báo. tick(dt) trả về true đúng một lần khi hết giờ (hoặc mỗi vòng nếu repeat). progress() cho tiến độ 0..1.

njin::tween chuyển mượt một giá trị (f32, vec2 hoặc rgba) từ from đến to trong duration giây, theo một đường cong njin::ease. tick(dt) trả về giá trị hiện tại.

Đường cong Cảm giác
linear Đều, máy móc
out_quad, out_cubic Giảm tốc khi đến đích: tự nhiên nhất cho UI
in_out_sine Mềm cả hai đầu: chuyển camera
out_back Vượt quá rồi quay về: bảng bật ra
out_bounce Nảy như quả bóng rơi
out_elastic Rung như lò xo

Timer và tween là struct thường, không phải component. Giữ chúng ở đâu tùy bạn: trong component, trong biến của module.