4个版本 (破坏性更新)
0.4.0 | 2022年2月19日 |
---|---|
0.3.0 | 2022年2月18日 |
0.2.0 | 2022年2月17日 |
0.1.0 | 2022年2月17日 |
#614 in 游戏开发
用于 min_gl
29KB
401 行
min_timer
随着事物的增长,这个库在过去的两天里增长了很多。现在它由三部分组成
- 计时器
- 分析器
- 主循环
每个部分都依赖于前一个部分。
计时器
这是一个提供基于 f64
的持续时间计时器的库。标准库的实现使用整数。因此,对于以 f64
提供时间的时钟,这个库应该有更高的性能。
此外,检查更少。尽管如此,对于SI单位(秒)有很强的类型安全性,希望编译器可以优化掉。
fn count(upto: u32) {
use min_timer::{Std, Sec, Timer};
let dur = Sec::MINUTE; // strong type safety.
let now = Std::new(); // there is a std::time implementation.
let mut timer = Timer::new(&now);
let mut count = 0;
while count < upto {
if timer >= dur { // straight-forward checking,
timer -= dur; // flexible manupilation.
count += 1;
println!("Counting {}...", count);
}
}
}
分析器
还提供了小型统计和分析功能。这些都是打算用于实时应用程序的。
fn subroutine() {}
fn main_routine() {
use min_timer::{Std, Prf, Stat};
let mut stat = Stat::new();
let now = Std::new();
for _ in 0..10 {
let _ = Prf::new(&now, &mut stat); // create and forget.
subroutine();
}
// End of cycle.
// This can be anything.
// For example: every second in a game engine.
// This way the rate will be the FPS counter.
stat.refresh();
for _ in 0..15 {
let _ = Prf::new(&now, &mut stat);
subroutine();
}
println!(
"Subroutine called {} times, with {} average runtime and {} times per cycle.",
stat.get_count(), // will be 25
stat.find_average(),
stat.get_rate() // will be 15
);
}
主循环
这是实时应用程序的 核心。设计是这样的,你提供一个状态类和一个可以绘制它的渲染器。滴答率和帧率不同;这样可以在不同的频率下更新以实现平滑的视觉效果。
这是通过在绘制之前插值程序的前一个和当前状态来完成的,使用剩余的滴答次数。因此,状态必须实现缩放和叠加;线性组合。
use min_timer::{Hrt, Now, Render, Std, Stt, Timer};
use std::ops::{Add, Mul};
struct Bar {
len: u32,
pre: Option<u32>,
}
impl Default for Bar {
// Creating the render
fn default() -> Self {
Self { len: 50, pre: None }
}
}
impl Bar {
fn print(&mut self, per: f64, len: u32) {
self.pre = Some(len);
print!("[");
for _ in 0..len {
print!("=");
}
if self.len != len {
print!(">");
for _ in 0..(self.len - len - 1) {
print!(" ");
}
}
println!("] {}%", per);
}
}
impl<T: Now> Render<T, Ex> for Bar {
// Rendering
fn render(&mut self, _: &Hrt<T>, stt: &Ex) {
let len = self.len as f64 * stt.0;
let len = len.floor() as u32;
let len = len.min(self.len);
let per = (stt.0 * 100.0).floor();
if let Some(pre) = self.pre {
if len != pre {
self.print(per, len);
}
} else {
self.print(per, len);
}
}
}
#[derive(Default, Clone, Copy)]
struct Ex(f64);
impl Mul<f64> for Ex {
type Output = Ex;
// Scaling
fn mul(self, rhs: f64) -> Self::Output {
Self(self.0 * rhs)
}
}
impl Add for Ex {
type Output = Ex;
// Superposing
fn add(self, rhs: Ex) -> Self::Output {
Self(self.0 + rhs.0)
}
}
impl<T: Now> Stt<T> for Ex {
// Initialization; timer provided for profiling
fn init(&mut self, _: &mut Hrt<T>, timer: Timer<T>) {
println!("Initialization done in {}!", timer);
}
// Updating; heart provided for manupilation
fn update(&mut self, hrt: &mut Hrt<T>) {
self.0 += 1e-1;
if self.0 >= 1.0 {
hrt.stop();
}
}
// Profiling every second; heart provided for manupilation
fn sec(&mut self, hrt: &mut Hrt<T>) {
println!(
"Tick Rate: {} Frame Rate: {}",
hrt.ticks().avg_rate(),
hrt.frames().avg_rate()
);
}
}
fn main() {
let now = Std::new(); // using the standard library's clock
let mut hrt = Hrt::new(1e2, &now); // target tick rate 100.0
hrt.start::<Ex, Bar>(); // creates from defaults
}
动机
为什么还要写这个,当已经有标准库的时候?
-
教育:我得以练习 Rust,特别是 newtype 模式与
Sec
。 -
在编写这个之前,我对
std::time
并不熟悉。 -
我将使用这个库与 GLFW 计时器一起,它以秒为单位的
double
返回时间。这样,我将使用 GLFW 实现Now
,并且与之前相比不会有转换。fn time(glfw: &Glfw) -> Duration { Duration::from_sec_f64(glfw.get_time()) // conversion! } let start = time(&glfw); let elapsed = time(&glfw) - start; let seconds = elapsed.as_sec_f64(); // conversion!
查看我的其他库,min_gl,以查看 GLFW 计时器的
Now
实现。 -
这个库提供了一个可以放置更多关于时间信息的空间,例如分析。
-
使用
f64
比较多;我在处理主循环时看到了这一点。
版权 (C) 2022 Cem Geçgel [email protected]