Skip to content

Commit 610e001

Browse files
committed
frame skipping works
crashes were savegame related in fact... only enabled in main battlescape state, for walking an shooting and stuff
1 parent d33d730 commit 610e001

7 files changed

Lines changed: 65 additions & 13 deletions

File tree

‎src/Battlescape/BattlescapeState.cpp‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -334,11 +334,11 @@ BattlescapeState::BattlescapeState(Game *game) : State(game), _popups()
334334
// Set music
335335
_game->getResourcePack()->getRandomMusic("GMTACTIC")->play();
336336

337-
_animTimer = new Timer(DEFAULT_ANIM_SPEED);
337+
_animTimer = new Timer(DEFAULT_ANIM_SPEED, true);
338338
_animTimer->onTimer((StateHandler)&BattlescapeState::animate);
339339
_animTimer->start();
340340

341-
_gameTimer = new Timer(DEFAULT_ANIM_SPEED);
341+
_gameTimer = new Timer(DEFAULT_ANIM_SPEED, true);
342342
_gameTimer->onTimer((StateHandler)&BattlescapeState::handleState);
343343
_gameTimer->start();
344344

‎src/Engine/Game.cpp‎

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,4 +549,17 @@ bool Game::getShiftKeyDown()
549549
{
550550
return _shiftKeyDown;
551551
}
552+
553+
554+
/**
555+
* @brief Returns whether current state is *state
556+
* @param state The state to test against the stack state
557+
*/
558+
const bool Game::isState(State *state) const
559+
{
560+
return _states.size() > 0 && _states.back() == state;
561+
}
562+
563+
564+
552565
}

‎src/Engine/Game.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ class Game
111111
static void setShiftKeyDown(bool shiftKey);
112112
/// Returns whether the Shift key is down
113113
static bool getShiftKeyDown();
114+
/// Returns whether current state is the param state
115+
const bool isState(State *state) const;
114116
};
115117

116118
}

‎src/Engine/Options.cpp‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ void createDefault()
6666
setBool("asyncBlit", true);
6767
setInt("keyboardMode", KEYBOARD_ON);
6868
#endif
69+
setInt("maxFrameSkip", 8);
6970
setBool("traceAI", false);
7071
setBool("sneakyAI", false);
7172
setInt("baseXResolution", 320);

‎src/Engine/State.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ class State
7676
const LocalizedText &tr(const std::string &id) const;
7777
/// Get the localized text.
7878
LocalizedText tr(const std::string &id, unsigned n) const;
79+
80+
friend class Timer;
7981
};
8082

8183
}

‎src/Engine/Timer.cpp‎

Lines changed: 35 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,28 +17,35 @@
1717
* along with OpenXcom. If not, see <http://www.gnu.org/licenses/>.
1818
*/
1919
#include "Timer.h"
20+
#include "Game.h"
21+
#include "Options.h"
22+
#include <assert.h>
2023

2124
namespace OpenXcom
2225
{
2326

2427
const Uint32 accurate = 4;
25-
Uint32 slownes = 1;
28+
Uint32 slowness = 1;
2629
Uint32 slowTick()
2730
{
2831
static Uint32 old_time = SDL_GetTicks();
2932
static Uint64 false_time = old_time << accurate;
30-
Uint32 new_time = SDL_GetTicks() << accurate;
31-
false_time += (new_time - old_time) / slownes;
33+
Uint64 new_time = ((Uint64)SDL_GetTicks()) << accurate;
34+
false_time += (new_time - old_time) / slowness;
3235
old_time = new_time;
3336
return false_time >> accurate;
3437
}
38+
39+
int Timer::maxFrameSkip = 8; // this is a pretty good default at 60FPS.
40+
3541

3642
/**
3743
* Initializes a new timer with a set interval.
3844
* @param interval Time interval in milliseconds.
3945
*/
40-
Timer::Timer(Uint32 interval) : _start(0), _interval(interval), _running(false), _state(0), _surface(0)
46+
Timer::Timer(Uint32 interval, bool frameSkipping) : _start(0), _interval(interval), _running(false), _state(0), _surface(0), _frameSkipping(frameSkipping)
4147
{
48+
Timer::maxFrameSkip = Options::getInt("maxFrameSkip");
4249
}
4350

4451
/**
@@ -53,7 +60,7 @@ Timer::~Timer()
5360
*/
5461
void Timer::start()
5562
{
56-
_start = slowTick();
63+
_frameSkipStart = _start = slowTick();
5764
_running = true;
5865
}
5966

@@ -96,19 +103,31 @@ bool Timer::isRunning() const
96103
*/
97104
void Timer::think(State* state, Surface* surface)
98105
{
106+
Sint64 now = slowTick(); // must be signed to permit negative numbers
107+
Game *game = state ? state->_game : 0; // this is used to make sure we stop calling *_state on *state in the loop once *state has been popped and deallocated
108+
//assert(!game || game->isState(state));
109+
99110
if (_running)
100111
{
101-
if (getTime() >= _interval)
112+
if ((now - _frameSkipStart) >= _interval)
102113
{
103-
if (state != 0 && _state != 0)
114+
for (int i = 0; i < maxFrameSkip && isRunning() && (now - _frameSkipStart) >= _interval; ++i)
104115
{
105-
(state->*_state)();
116+
if (state != 0 && _state != 0)
117+
{
118+
(state->*_state)();
119+
}
120+
_frameSkipStart += _interval;
121+
// breaking here after one iteration effectively returns this function to its old functionality:
122+
if (!game || !_frameSkipping || !game->isState(state)) break; // if game isn't set, we can't verify *state
106123
}
107-
if (surface != 0 && _surface != 0)
124+
125+
if (_running && surface != 0 && _surface != 0)
108126
{
109127
(surface->*_surface)();
110128
}
111129
_start = slowTick();
130+
if (_start > _frameSkipStart) _frameSkipStart = _start; // don't play animations in ffwd to catch up :P
112131
}
113132
}
114133
}
@@ -140,4 +159,11 @@ void Timer::onTimer(SurfaceHandler handler)
140159
_surface = handler;
141160
}
142161

162+
163+
/// Sets frame skipping on or off
164+
void Timer::setFrameSkipping(bool skip)
165+
{
166+
_frameSkipping = skip;
167+
}
168+
143169
}

‎src/Engine/Timer.h‎

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,20 @@ typedef void (Surface::* SurfaceHandler)();
3636
*/
3737
class Timer
3838
{
39+
public:
40+
static int maxFrameSkip;
41+
3942
private:
40-
Uint32 _start, _interval;
43+
Uint32 _start;
44+
Uint32 _frameSkipStart;
45+
int _interval;
4146
bool _running;
47+
bool _frameSkipping;
4248
StateHandler _state;
4349
SurfaceHandler _surface;
4450
public:
4551
/// Creates a stopped timer.
46-
Timer(Uint32 interval);
52+
Timer(Uint32 interval, bool frameSkipping = false);
4753
/// Cleans up the timer.
4854
~Timer();
4955
/// Starts the timer.
@@ -62,6 +68,8 @@ class Timer
6268
void onTimer(StateHandler handler);
6369
/// Hooks a surface action handler to the timer interval.
6470
void onTimer(SurfaceHandler handler);
71+
/// Turns frame skipping on or off
72+
void setFrameSkipping(bool skip);
6573
};
6674

6775
}

0 commit comments

Comments
 (0)