summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaweł Redman <pawel.redman@gmail.com>2018-03-26 14:19:50 +0200
committerPaweł Redman <pawel.redman@gmail.com>2018-03-26 14:19:50 +0200
commita016a156e76f7394c5632da325ab0b453cfb3b37 (patch)
treed25fe29ebe10f0d921b06d1860565fedd577ca72
parent2ae4b0ff77a2b2be2c485ac3ba6c1ef3facb874c (diff)
Independent game timing.
-rw-r--r--src/common.hpp24
-rw-r--r--src/game/game.cpp65
-rw-r--r--src/game/interface.cpp16
-rw-r--r--src/main.cpp29
-rw-r--r--src/render.cpp4
5 files changed, 94 insertions, 44 deletions
diff --git a/src/common.hpp b/src/common.hpp
index 846b166..df9c8d1 100644
--- a/src/common.hpp
+++ b/src/common.hpp
@@ -35,6 +35,11 @@ extern bool debug_draw_paths;
extern bool debug_draw_tile_coords;
extern bool debug_AI;
+// time in nanoseconds
+// nclock() never returns 0, so it can be used as a null value
+typedef uint64_t ntime_t;
+ntime_t nclock(void);
+
namespace procgen {
class prng_t {
uint32_t state = 0;
@@ -240,15 +245,23 @@ namespace game {
public:
world::world_t world;
interface::state_t *interface;
- double now = 0.0, dt;
- bool paused = false;
procgen::prng_t dice_prng;
std::unordered_set<entity_t*> awake_entities;
std::unordered_set<unit_t*> selected_units;
+ ntime_t time; // game time
+ double now, dt; // FIXME: refactor the code, use ntime_t everywhere
+
+ // frame timing data (game runs at a different frequency than the renderer)
+ bool paused;
+ ntime_t t0;
+ size_t frames = 0, frames_since_t0, frames_behind = 0;
+
void start(void);
void stop(void);
- void tick(double now_, double dt_);
+ void tick(ntime_t time);
+ void pause(void);
+ void resume(void);
// These are called by the interface.
void select(rectf_t rect);
@@ -355,14 +368,15 @@ namespace render {
void drender_text(rectf_t rect, std::string str);
void drender_entity(world::entity_t *ent);
public:
- double now, dt;
+ ntime_t time;
+ double dt;
struct {
size_t sectors, tiles, entities;
} stats;
state_t(sf::RenderWindow *window_);
- void begin_frame(double time_, double dt_);
+ void begin_frame(ntime_t time_, double dt);
void end_frame(void);
void render(game::state_t *game);
diff --git a/src/game/game.cpp b/src/game/game.cpp
index f76b478..44ea95d 100644
--- a/src/game/game.cpp
+++ b/src/game/game.cpp
@@ -92,6 +92,8 @@ void state_t::start(void)
soldier = new unit_soldier_t(this);
soldier->place(&world, v2f_t(2.5, 0.5));
select(rectf_t(v2f_t(0.5, 0.5), v2f_t(2.5, 0.5)));
+
+ resume();
}
void state_t::stop(void)
@@ -179,34 +181,57 @@ void state_t::spawn_soldier(v2f_t x)
soldier->destroy();
}
-void state_t::tick(double now_, double dt_)
+void state_t::pause(void)
+{
+ paused = true;
+}
+
+void state_t::resume(void)
+{
+ t0 = nclock();
+ frames_since_t0 = 0;
+
+ paused = false;
+}
+
+
+#define TIME_DELTA ((ntime_t)1000000000 / 60)
+
+void state_t::tick(ntime_t time_)
{
- union {
- double d;
- uint32_t i;
- } u;
+ size_t target, frames_this_tick = 0;
if (paused)
return;
- if (dt > 0.05)
- dt = 0.05;
- else
- dt = dt_;
+ target = (time_ - t0) / TIME_DELTA;
+
+ while (frames_since_t0 < target) {
+ // FIXME: Is this non-deterministic enough?
+ dice_prng.seed(dice_prng.next() ^ time);
- now += dt;
+ // setting up old variables (refactor them out eventually)
+ now = time * 1.0e-9;
+ dt = TIME_DELTA * 1.0e-9;
- // FIXME: Is this non-deterministic enough?
- u.d = now;
- dice_prng.seed(dice_prng.next() ^ u.i);
- u.d = dt;
- dice_prng.seed(dice_prng.next() ^ u.i);
+ // on_think can insert/erase elements of awake_entities so iterate
+ // over a copy of it.
+ auto copy = awake_entities;
+ for (entity_t *ent : copy)
+ ent->on_think();
- // on_think can insert/erase elements of awake_entities so iterate
- // over a copy of it.
- auto copy = awake_entities;
- for (entity_t *ent : copy)
- ent->on_think();
+ frames++;
+ frames_since_t0++;
+ frames_this_tick++;
+ time += TIME_DELTA;
+
+ if (frames_this_tick == 3) {
+ t0 = time_;
+ frames_since_t0 = 0;
+ frames_behind++;
+ break;
+ }
+ }
}
die_t::die_t(size_t sides_)
diff --git a/src/game/interface.cpp b/src/game/interface.cpp
index 7697a22..262c3ae 100644
--- a/src/game/interface.cpp
+++ b/src/game/interface.cpp
@@ -160,11 +160,13 @@ void state_t::tick(double dt)
case sf::Event::KeyPressed:
switch (event.key.code) {
case sf::Keyboard::Key::Space:
- game->paused ^= 1;
- if (game->paused)
+ if (!game->paused) {
+ game->pause();
print(text::get(text::PAUSED));
- else
+ } else {
+ game->resume();
print(text::get(text::UNPAUSED));
+ }
break;
case sf::Keyboard::Key::F:
@@ -239,7 +241,7 @@ void state_t::render_to(render::state_t *render)
x[1] += em;
}
- x = v2f_t(0.0f, h - em * 4.5);
+ x = v2f_t(0.0f, h - em * 5.5);
ss << "World S/T:";
ss << game->world.stats.sectors << "/";
ss << game->world.stats.tiles;
@@ -271,6 +273,12 @@ void state_t::render_to(render::state_t *render)
ss << std::fixed << std::setprecision(1);
ss << "FPS: " << fps;
render->render_text(x, em, ss.str(), render::ALIGN_LEFT_TOP, sf::Color::White);
+
+ x[1] += em;
+ ss.str(std::string());
+ ss << std::fixed << std::setprecision(3);
+ ss << "Game t/F/B: " << game->time * 1.0e-9 << "/" << game->frames << "/" << game->frames_behind;
+ render->render_text(x, em, ss.str(), render::ALIGN_LEFT_TOP, sf::Color::White);
}
} // namespace interface
diff --git a/src/main.cpp b/src/main.cpp
index 71e47be..3f60f25 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -24,20 +24,23 @@ bool debug_draw_tile_coords = false;
bool debug_AI = false;
render::state_t *debug_render;
-uint64_t nano_clock(void)
+static ntime_t nclock_ref;
+
+// always > 0
+ntime_t nclock(void)
{
- return std::chrono::high_resolution_clock::now().time_since_epoch() / std::chrono::nanoseconds(1);
+ return std::chrono::high_resolution_clock::now().time_since_epoch() /
+ std::chrono::nanoseconds(1) - nclock_ref;
}
int main()
{
- uint64_t t0 = nano_clock();
+ nclock_ref = nclock() - 1;
+
sf::RenderWindow window(sf::VideoMode(800, 600), "Minitrem");
render::state_t render(&window);
game::state_t game;
interface::state_t interface(&window, &game);
- size_t frame = 0;
- double before = NAN;
game.interface = &interface;
debug_render = &render;
@@ -47,14 +50,17 @@ int main()
game.start();
while (1) {
- double now = (nano_clock() - t0) * 1.0e-9, dt;
+ static ntime_t before = 0;
+ ntime_t now = nclock();
+ double dt;
- if (frame)
- dt = now - before;
+ if (before)
+ dt = (now - before) * 1.0e-9;
else
- dt = 0.01;
+ dt = 0.1;
+ before = now;
- game.tick(now, dt);
+ game.tick(now);
interface.tick(dt);
if (!window.isOpen())
break;
@@ -64,9 +70,6 @@ int main()
render.render(&game);
interface.render_to(&render);
render.end_frame();
-
- before = now;
- frame++;
}
game.stop();
diff --git a/src/render.cpp b/src/render.cpp
index 8ad0e25..7a798ab 100644
--- a/src/render.cpp
+++ b/src/render.cpp
@@ -55,9 +55,9 @@ void register_tile(uint8_t type, const char *top, const char *side, float height
}
-void state_t::begin_frame(double now_, double dt_)
+void state_t::begin_frame(ntime_t time_, double dt_)
{
- now = now_;
+ time = time_;
dt = dt_;
window->clear();