mirror of
https://github.com/rwengine/openrw.git
synced 2024-09-15 15:02:34 +02:00
Improved game loop to support game speed
This commit is contained in:
parent
5f85de5bd3
commit
214095ba02
@ -11,7 +11,7 @@ BasicState::BasicState()
|
|||||||
, gameMinute{0}
|
, gameMinute{0}
|
||||||
, padMode{0}
|
, padMode{0}
|
||||||
, timeMS{0}
|
, timeMS{0}
|
||||||
, timeScale{0}
|
, timeScale{1.f}
|
||||||
, timeStep{0}
|
, timeStep{0}
|
||||||
, timeStep_unclipped{0}
|
, timeStep_unclipped{0}
|
||||||
, frameCounter{0}
|
, frameCounter{0}
|
||||||
|
@ -32,9 +32,8 @@ std::map<GameRenderer::SpecialModel, std::string> kSpecialModels = {
|
|||||||
{GameRenderer::Arrow, "arrow.dff"}};
|
{GameRenderer::Arrow, "arrow.dff"}};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
constexpr float kPhysicsTimeStep = 1.0f/30.0f;
|
constexpr float kMaxPhysicsSubSteps = 2;
|
||||||
constexpr float kMaxPhysicsSubSteps = 4;
|
} // namespace
|
||||||
}
|
|
||||||
|
|
||||||
#define MOUSE_SENSITIVITY_SCALE 2.5f
|
#define MOUSE_SENSITIVITY_SCALE 2.5f
|
||||||
|
|
||||||
@ -75,7 +74,8 @@ RWGame::RWGame(Logger& log, int argc, char* argv[])
|
|||||||
btIDebugDraw::DBG_DrawConstraintLimits);
|
btIDebugDraw::DBG_DrawConstraintLimits);
|
||||||
debug.setShaderProgram(renderer.worldProg.get());
|
debug.setShaderProgram(renderer.worldProg.get());
|
||||||
|
|
||||||
data.loadDynamicObjects((config.getGameDataPath() / "data/object.dat").string()); // FIXME: use path
|
data.loadDynamicObjects((config.getGameDataPath() / "data/object.dat")
|
||||||
|
.string()); // FIXME: use path
|
||||||
|
|
||||||
data.loadGXT("text/" + config.getGameLanguage() + ".gxt");
|
data.loadGXT("text/" + config.getGameLanguage() + ".gxt");
|
||||||
|
|
||||||
@ -249,9 +249,9 @@ void RWGame::handleCheatInput(char symbol) {
|
|||||||
// The iPod / Android version of the game (10th year anniversary) spawns random
|
// The iPod / Android version of the game (10th year anniversary) spawns random
|
||||||
// (?) vehicles instead of always rhino
|
// (?) vehicles instead of always rhino
|
||||||
#ifdef RW_GAME_GTA3_ANNIVERSARY
|
#ifdef RW_GAME_GTA3_ANNIVERSARY
|
||||||
// uint16_t vehicleModel = 110; // @todo Which cars are spawned?!
|
// uint16_t vehicleModel = 110; // @todo Which cars are spawned?!
|
||||||
#else
|
#else
|
||||||
// uint16_t vehicleModel = 122;
|
// uint16_t vehicleModel = 122;
|
||||||
#endif
|
#endif
|
||||||
// @todo Spawn rhino
|
// @todo Spawn rhino
|
||||||
// @todo ShowHelpMessage("CHEAT1"); // III / VC: Inputting most
|
// @todo ShowHelpMessage("CHEAT1"); // III / VC: Inputting most
|
||||||
@ -364,7 +364,9 @@ void RWGame::handleCheatInput(char symbol) {
|
|||||||
|
|
||||||
int RWGame::run() {
|
int RWGame::run() {
|
||||||
namespace chrono = std::chrono;
|
namespace chrono = std::chrono;
|
||||||
|
|
||||||
auto lastFrame = chrono::steady_clock::now();
|
auto lastFrame = chrono::steady_clock::now();
|
||||||
|
float deltaTime = GAME_TIMESTEP;
|
||||||
float accumulatedTime = 0.0f;
|
float accumulatedTime = 0.0f;
|
||||||
|
|
||||||
// Loop until we run out of states.
|
// Loop until we run out of states.
|
||||||
@ -412,37 +414,48 @@ int RWGame::run() {
|
|||||||
}
|
}
|
||||||
RW_PROFILE_END();
|
RW_PROFILE_END();
|
||||||
|
|
||||||
auto now = chrono::steady_clock::now();
|
auto currentFrame = chrono::steady_clock::now();
|
||||||
auto deltaTime = chrono::duration<float>(now - lastFrame).count();
|
auto frameTime =
|
||||||
lastFrame = now;
|
chrono::duration<float>(currentFrame - lastFrame).count();
|
||||||
|
lastFrame = currentFrame;
|
||||||
|
|
||||||
if(!world->isPaused()) {
|
// Clamp frameTime, so we won't freeze completely
|
||||||
accumulatedTime += deltaTime;
|
if (frameTime > 0.1f) {
|
||||||
world->dynamicsWorld->stepSimulation(deltaTime * timescale, kMaxPhysicsSubSteps, kPhysicsTimeStep);
|
frameTime = 0.1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
accumulatedTime += frameTime;
|
||||||
|
|
||||||
|
auto deltaTimeWithTimeScale = deltaTime * world->state->basic.timeScale;
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("Update");
|
RW_PROFILE_BEGIN("Update");
|
||||||
while (accumulatedTime >= GAME_TIMESTEP && !world->isPaused()) {
|
while (accumulatedTime >= deltaTime && !world->isPaused()) {
|
||||||
if (!StateManager::currentState()) {
|
if (!StateManager::currentState()) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
accumulatedTime -= GAME_TIMESTEP;
|
|
||||||
|
RW_PROFILE_BEGIN("physics");
|
||||||
|
world->dynamicsWorld->stepSimulation(
|
||||||
|
deltaTimeWithTimeScale, kMaxPhysicsSubSteps, deltaTime);
|
||||||
|
RW_PROFILE_END();
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("state");
|
RW_PROFILE_BEGIN("state");
|
||||||
StateManager::get().tick(GAME_TIMESTEP * timescale);
|
StateManager::get().tick(deltaTimeWithTimeScale);
|
||||||
RW_PROFILE_END();
|
RW_PROFILE_END();
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("engine");
|
RW_PROFILE_BEGIN("engine");
|
||||||
tick(GAME_TIMESTEP * timescale);
|
tick(deltaTimeWithTimeScale);
|
||||||
RW_PROFILE_END();
|
RW_PROFILE_END();
|
||||||
|
|
||||||
getState()->swapInputState();
|
getState()->swapInputState();
|
||||||
|
|
||||||
|
accumulatedTime -= deltaTime;
|
||||||
}
|
}
|
||||||
RW_PROFILE_END();
|
RW_PROFILE_END();
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("Render");
|
RW_PROFILE_BEGIN("Render");
|
||||||
RW_PROFILE_BEGIN("engine");
|
RW_PROFILE_BEGIN("engine");
|
||||||
render(1, deltaTime);
|
render(1, frameTime);
|
||||||
RW_PROFILE_END();
|
RW_PROFILE_END();
|
||||||
|
|
||||||
RW_PROFILE_BEGIN("state");
|
RW_PROFILE_BEGIN("state");
|
||||||
@ -514,7 +527,6 @@ void RWGame::tick(float dt) {
|
|||||||
|
|
||||||
state.text.tick(dt);
|
state.text.tick(dt);
|
||||||
|
|
||||||
|
|
||||||
if (vm) {
|
if (vm) {
|
||||||
try {
|
try {
|
||||||
vm->execute(dt);
|
vm->execute(dt);
|
||||||
@ -528,7 +540,7 @@ void RWGame::tick(float dt) {
|
|||||||
/// @todo this doesn't make sense as the condition
|
/// @todo this doesn't make sense as the condition
|
||||||
if (state.playerObject) {
|
if (state.playerObject) {
|
||||||
currentCam.frustum.update(currentCam.frustum.projection() *
|
currentCam.frustum.update(currentCam.frustum.projection() *
|
||||||
currentCam.getView());
|
currentCam.getView());
|
||||||
// Use the current camera position to spawn pedestrians.
|
// Use the current camera position to spawn pedestrians.
|
||||||
world->cleanupTraffic(currentCam);
|
world->cleanupTraffic(currentCam);
|
||||||
// Only create new traffic outside cutscenes
|
// Only create new traffic outside cutscenes
|
||||||
@ -683,7 +695,7 @@ void RWGame::renderDebugPaths(float time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw Garage bounds
|
// Draw Garage bounds
|
||||||
for (const auto &garage : state.garages) {
|
for (const auto& garage : state.garages) {
|
||||||
btVector3 minColor(1.f, 0.f, 0.f);
|
btVector3 minColor(1.f, 0.f, 0.f);
|
||||||
btVector3 maxColor(0.f, 1.f, 0.f);
|
btVector3 maxColor(0.f, 1.f, 0.f);
|
||||||
btVector3 min(garage.min.x, garage.min.y, garage.min.z);
|
btVector3 min(garage.min.x, garage.min.y, garage.min.z);
|
||||||
@ -698,7 +710,7 @@ void RWGame::renderDebugPaths(float time) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw vehicle generators
|
// Draw vehicle generators
|
||||||
for (const auto &generator : state.vehicleGenerators) {
|
for (const auto& generator : state.vehicleGenerators) {
|
||||||
btVector3 color(1.f, 0.f, 0.f);
|
btVector3 color(1.f, 0.f, 0.f);
|
||||||
btVector3 position(generator.position.x, generator.position.y,
|
btVector3 position(generator.position.x, generator.position.y,
|
||||||
generator.position.z);
|
generator.position.z);
|
||||||
@ -808,23 +820,25 @@ void RWGame::renderProfile() {
|
|||||||
ti.font = 2;
|
ti.font = 2;
|
||||||
ti.size = lineHeight - 2.f;
|
ti.size = lineHeight - 2.f;
|
||||||
ti.baseColour = glm::u8vec3(255);
|
ti.baseColour = glm::u8vec3(255);
|
||||||
std::function<void(const perf::ProfileEntry&, int)> renderEntry = [&](
|
std::function<void(const perf::ProfileEntry&, int)> renderEntry =
|
||||||
const perf::ProfileEntry& entry, int depth) {
|
[&](const perf::ProfileEntry& entry, int depth) {
|
||||||
int g = 0;
|
int g = 0;
|
||||||
for (auto& event : entry.childProfiles) {
|
for (auto& event : entry.childProfiles) {
|
||||||
auto duration = event.end - event.start;
|
auto duration = event.end - event.start;
|
||||||
float y = 60.f + (depth * (lineHeight + 5.f));
|
float y = 60.f + (depth * (lineHeight + 5.f));
|
||||||
renderer.drawColour(
|
renderer.drawColour(
|
||||||
perf_colours[(std::hash<std::string>()(entry.label) * (g++)) %
|
perf_colours[(std::hash<std::string>()(entry.label) *
|
||||||
perf_colours.size()],
|
(g++)) %
|
||||||
{xscale * event.start, y, xscale * duration, lineHeight});
|
perf_colours.size()],
|
||||||
ti.screenPosition.x = xscale * (event.start);
|
{xscale * event.start, y, xscale * duration, lineHeight});
|
||||||
ti.screenPosition.y = y + 2.f;
|
ti.screenPosition.x = xscale * (event.start);
|
||||||
ti.text = GameStringUtil::fromString(event.label + " " + std::to_string(duration) + " us ");
|
ti.screenPosition.y = y + 2.f;
|
||||||
renderer.text.renderText(ti);
|
ti.text = GameStringUtil::fromString(
|
||||||
renderEntry(event, depth + 1);
|
event.label + " " + std::to_string(duration) + " us ");
|
||||||
}
|
renderer.text.renderText(ti);
|
||||||
};
|
renderEntry(event, depth + 1);
|
||||||
|
}
|
||||||
|
};
|
||||||
renderEntry(frame, 0);
|
renderEntry(frame, 0);
|
||||||
ti.screenPosition = glm::vec2(xscale * (16000), 40.f);
|
ti.screenPosition = glm::vec2(xscale * (16000), 40.f);
|
||||||
ti.text = GameStringUtil::fromString(".16 ms");
|
ti.text = GameStringUtil::fromString(".16 ms");
|
||||||
@ -845,10 +859,10 @@ void RWGame::globalKeyEvent(const SDL_Event& event) {
|
|||||||
world->offsetGameTime(30);
|
world->offsetGameTime(30);
|
||||||
break;
|
break;
|
||||||
case SDLK_9:
|
case SDLK_9:
|
||||||
timescale *= 0.5f;
|
world->state->basic.timeScale *= 0.5f;
|
||||||
break;
|
break;
|
||||||
case SDLK_0:
|
case SDLK_0:
|
||||||
timescale *= 2.0f;
|
world->state->basic.timeScale *= 2.0f;
|
||||||
break;
|
break;
|
||||||
case SDLK_F1:
|
case SDLK_F1:
|
||||||
toggle_debug(DebugViewMode::General);
|
toggle_debug(DebugViewMode::General);
|
||||||
|
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
//FIXME: should be in rwengine, deeply hidden
|
// FIXME: should be in rwengine, deeply hidden
|
||||||
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
|
#include <BulletDynamics/Dynamics/btDiscreteDynamicsWorld.h>
|
||||||
|
|
||||||
#include <engine/GameData.hpp>
|
#include <engine/GameData.hpp>
|
||||||
@ -47,8 +47,6 @@ class RWGame : public GameBase {
|
|||||||
|
|
||||||
std::string cheatInputWindow = std::string(32, ' ');
|
std::string cheatInputWindow = std::string(32, ' ');
|
||||||
|
|
||||||
float timescale = 1.f;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
RWGame(Logger& log, int argc, char* argv[]);
|
RWGame(Logger& log, int argc, char* argv[]);
|
||||||
~RWGame() override;
|
~RWGame() override;
|
||||||
@ -76,7 +74,7 @@ public:
|
|||||||
return renderer;
|
return renderer;
|
||||||
}
|
}
|
||||||
|
|
||||||
ScriptMachine *getScriptVM() const {
|
ScriptMachine* getScriptVM() const {
|
||||||
return vm.get();
|
return vm.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user