- pass timestamp of frame start time to all update functions
- use timestamp instead of SDL_GetTicks to keep time in Timer class - use seconds instead of milliseconds in Timer class
This commit is contained in:
parent
1ca956b5ac
commit
355ab4d8c4
|
@ -2,7 +2,7 @@
|
|||
|
||||
Animation::Animation()
|
||||
{
|
||||
timer.toggle(sb::Timer::OFF);
|
||||
timer.off();
|
||||
}
|
||||
|
||||
void Animation::play(float delay, bool play_once)
|
||||
|
@ -10,12 +10,12 @@ void Animation::play(float delay, bool play_once)
|
|||
this->delay = delay;
|
||||
play_state = true;
|
||||
paused = false;
|
||||
previous_step_time = timer.ms_elapsed();
|
||||
previous_step_time = timer.elapsed();
|
||||
overflow = 0;
|
||||
ending = play_once;
|
||||
if (delay <= 0)
|
||||
{
|
||||
timer.toggle(true);
|
||||
timer.on();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -31,19 +31,19 @@ void Animation::play_once(float delay)
|
|||
|
||||
void Animation::pause()
|
||||
{
|
||||
timer.toggle(false);
|
||||
timer.off();
|
||||
paused = true;
|
||||
}
|
||||
|
||||
void Animation::unpause()
|
||||
{
|
||||
timer.toggle(true);
|
||||
timer.on();
|
||||
paused = false;
|
||||
}
|
||||
|
||||
void Animation::reset()
|
||||
{
|
||||
timer.toggle(false);
|
||||
timer.off();
|
||||
play_state = false;
|
||||
timer.reset();
|
||||
}
|
||||
|
@ -53,25 +53,25 @@ bool Animation::playing(bool include_delay) const
|
|||
return play_state && !paused && (include_delay || delay <= 0);
|
||||
}
|
||||
|
||||
void Animation::update()
|
||||
void Animation::update(float timestamp)
|
||||
{
|
||||
timer.update();
|
||||
timer.update(timestamp);
|
||||
if (playing() && containing_object->is_active())
|
||||
{
|
||||
if (delay > 0)
|
||||
{
|
||||
delay -= timer.ms_last_frame();
|
||||
delay -= timer.frame();
|
||||
if (delay <= 0)
|
||||
{
|
||||
timer.toggle(true);
|
||||
timer.on();
|
||||
}
|
||||
}
|
||||
if (delay <= 0)
|
||||
{
|
||||
if (timer.ms_elapsed() - previous_step_time + overflow > frame_length)
|
||||
if (timer.elapsed() - previous_step_time + overflow > frame_length)
|
||||
{
|
||||
overflow = timer.ms_elapsed() - previous_step_time + overflow - frame_length;
|
||||
previous_step_time = timer.ms_elapsed();
|
||||
overflow = timer.elapsed() - previous_step_time + overflow - frame_length;
|
||||
previous_step_time = timer.elapsed();
|
||||
step();
|
||||
if (ending)
|
||||
{
|
||||
|
|
|
@ -25,8 +25,7 @@ class Animation
|
|||
private:
|
||||
|
||||
bool play_state = false, ending = false, paused = false;
|
||||
int previous_step_time = 0;
|
||||
float delay = 0, overflow = 0, frame_length = 0;
|
||||
float delay = 0.0f, overflow = 0.0f, frame_length = 0.0f, previous_step_time = 0.0f;
|
||||
callback step = nullptr;
|
||||
Node* containing_object = nullptr;
|
||||
sb::Timer timer = sb::Timer();
|
||||
|
@ -35,19 +34,22 @@ public:
|
|||
|
||||
Animation();
|
||||
|
||||
/* Constructor that allows passing a pointer to an object and a pointer to one of its
|
||||
/*!
|
||||
* Constructor that allows passing a pointer to an object and a pointer to one of its
|
||||
* member functions that will be used as the animation function. Frame length can be supplied
|
||||
* in milliseconds, representing how often the animation function will run. If omitted, the
|
||||
* animation function will run every time the Animation object is updated (generally, once per
|
||||
* frame of the application). */
|
||||
* in seconds, representing how often the animation function will run. If omitted, the
|
||||
* animation function will run every time the Animation object is updated.
|
||||
*/
|
||||
template<typename T>
|
||||
Animation(void(T::*member_function)(), T* object, float frame_length = 0) : frame_length(frame_length)
|
||||
{
|
||||
bind(member_function, object);
|
||||
timer.toggle(sb::Timer::OFF);
|
||||
timer.off();
|
||||
}
|
||||
|
||||
/* Set the animation function by supplying an object and one of its member functions */
|
||||
/*!
|
||||
* Set the animation function by supplying an object and one of its member functions.
|
||||
*/
|
||||
template<typename T>
|
||||
void bind(void(T::*f)(), T* o)
|
||||
{
|
||||
|
@ -62,7 +64,7 @@ public:
|
|||
void unpause();
|
||||
void reset();
|
||||
bool playing(bool = true) const;
|
||||
void update();
|
||||
void update(float timestamp);
|
||||
|
||||
};
|
||||
|
||||
|
|
|
@ -104,9 +104,9 @@ bool SoundEffect::playing(bool include_delay) const
|
|||
return false;
|
||||
}
|
||||
|
||||
void SoundEffect::update()
|
||||
void SoundEffect::update(float timestamp)
|
||||
{
|
||||
play_animation.update();
|
||||
play_animation.update(timestamp);
|
||||
}
|
||||
|
||||
SoundEffect::~SoundEffect()
|
||||
|
@ -126,10 +126,10 @@ void Audio::load_bgm()
|
|||
load_directory(configuration()["audio"]["default-bgm-root"], bgm, this);
|
||||
}
|
||||
|
||||
void Audio::update()
|
||||
void Audio::update(float timestamp)
|
||||
{
|
||||
for (auto& [name, sound_effect] : sfx)
|
||||
{
|
||||
sound_effect.update();
|
||||
sound_effect.update(timestamp);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -56,7 +56,7 @@ struct SoundEffect : Node
|
|||
void set_loop_count(int);
|
||||
void set_loop_forever();
|
||||
bool playing(bool = false) const;
|
||||
void update();
|
||||
void update(float timestamp);
|
||||
~SoundEffect();
|
||||
|
||||
};
|
||||
|
@ -70,7 +70,7 @@ struct Audio : Node
|
|||
Audio(Node*);
|
||||
void load_sfx();
|
||||
void load_bgm();
|
||||
void update();
|
||||
void update(float timestamp);
|
||||
|
||||
template <typename T>
|
||||
void load_directory(const fs::path& root, std::map<std::string, T>& storage, Node* parent = nullptr)
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#include "glm/common.hpp"
|
||||
#include "glm/gtx/integer.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace sb
|
||||
{
|
||||
|
||||
|
|
|
@ -34,7 +34,7 @@ void Configuration::set_defaults()
|
|||
{"suppress-any-key-on-mods", true},
|
||||
{"system-any-key-ignore-commands", {"fullscreen", "screenshot", "record", "quit"}},
|
||||
{"any-key-ignore-commands", nlohmann::json::array()},
|
||||
{"default-unsuppress-delay", 700},
|
||||
{"default-unsuppress-delay", 0.7},
|
||||
{"ignore-repeat-keypress", true}
|
||||
};
|
||||
config["display"] = {
|
||||
|
@ -69,10 +69,10 @@ void Configuration::set_defaults()
|
|||
{"screenshot-extension", ".png"},
|
||||
{"screenshot-zfill", 5},
|
||||
{"screenshot-directory", "."},
|
||||
{"gif-frame-length", 100},
|
||||
{"gif-frame-length", 0.1},
|
||||
{"video-directory", "."},
|
||||
{"write-mp4", false},
|
||||
{"max-stash-length", 5000},
|
||||
{"max-stash-length", 5.0},
|
||||
{"max-in-game-stashes", 3},
|
||||
{"max-video-stashes", 40},
|
||||
{"max-video-memory", 1000},
|
||||
|
@ -92,7 +92,7 @@ void Configuration::set_defaults()
|
|||
};
|
||||
config["configuration"] = {
|
||||
{"auto-refresh", false},
|
||||
{"auto-refresh-interval", 1000}
|
||||
{"auto-refresh-interval", 1.0}
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -156,6 +156,7 @@ void Configuration::merge(const fs::path& path)
|
|||
sb::Log::log(message, sb::Log::WARN);
|
||||
}
|
||||
#ifndef __ANDROID__
|
||||
config_file_modification_time = fs::last_write_time(path);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -208,9 +209,9 @@ void Configuration::refresh()
|
|||
}
|
||||
}
|
||||
|
||||
void Configuration::update()
|
||||
void Configuration::update(float timestamp)
|
||||
{
|
||||
auto_refresher.update();
|
||||
auto_refresher.update(timestamp);
|
||||
}
|
||||
|
||||
std::ostream& std::operator<<(std::ostream& out, const Configuration& configuration)
|
||||
|
|
|
@ -102,10 +102,10 @@ public:
|
|||
|
||||
/*!
|
||||
* Enable auto refresh. Auto refresh watches the file at the given path for changes and loads them automatically every interval given
|
||||
* in milliseconds.
|
||||
* in seconds.
|
||||
*
|
||||
* @param file_to_refresh path to a configuration JSON
|
||||
* @param interval amount of milliseconds between each refresh
|
||||
* @param interval amount of seconds between each refresh
|
||||
*/
|
||||
void enable_auto_refresh(const fs::path& file_to_refresh, float interval);
|
||||
|
||||
|
@ -120,9 +120,11 @@ public:
|
|||
void refresh();
|
||||
|
||||
/*!
|
||||
* Update the auto refresher.
|
||||
* Update the auto refresher with the given timestamp, which should be the timestamp passed to Game::update.
|
||||
*
|
||||
* @param timestamp seconds elapsed since the program started
|
||||
*/
|
||||
void update();
|
||||
void update(float timestamp);
|
||||
|
||||
};
|
||||
|
||||
|
|
23
src/Game.cpp
23
src/Game.cpp
|
@ -565,26 +565,27 @@ void Game::run()
|
|||
#endif
|
||||
}
|
||||
|
||||
void Game::frame(float ticks)
|
||||
void Game::frame(float timestamp)
|
||||
{
|
||||
if (ticks - last_frame_timestamp + frame_time_overflow >= frame_length)
|
||||
if (timestamp - last_frame_timestamp + frame_time_overflow >= frame_length)
|
||||
{
|
||||
last_frame_length = ticks - last_frame_timestamp;
|
||||
last_frame_length = timestamp - last_frame_timestamp;
|
||||
if (frame_length_history.size() == 5000)
|
||||
{
|
||||
frame_length_history.pop_back();
|
||||
}
|
||||
frame_length_history.insert(frame_length_history.begin(), last_frame_length);
|
||||
frame_time_overflow = last_frame_length + frame_time_overflow - frame_length;
|
||||
last_frame_timestamp = ticks;
|
||||
last_frame_timestamp = timestamp;
|
||||
if (last_frame_length < 1000)
|
||||
{
|
||||
recorder.update();
|
||||
float timestamp_seconds = timestamp / 1000.0f;
|
||||
recorder.update(timestamp_seconds);
|
||||
_delegate.dispatch();
|
||||
audio.update();
|
||||
input.unsuppress_animation.update();
|
||||
update();
|
||||
_configuration.update();
|
||||
audio.update(timestamp_seconds);
|
||||
input.unsuppress_animation.update(timestamp_seconds);
|
||||
update(timestamp_seconds);
|
||||
_configuration.update(timestamp_seconds);
|
||||
if (!is_gl_context)
|
||||
{
|
||||
SDL_SetRenderTarget(renderer, nullptr);
|
||||
|
@ -597,10 +598,10 @@ void Game::frame(float ticks)
|
|||
// frame_time_overflow = 0;
|
||||
// }
|
||||
frame_count_this_second++;
|
||||
if (ticks - last_frame_count_timestamp >= 1000)
|
||||
if (timestamp - last_frame_count_timestamp >= 1000)
|
||||
{
|
||||
current_frames_per_second = frame_count_this_second;
|
||||
last_frame_count_timestamp = ticks;
|
||||
last_frame_count_timestamp = timestamp;
|
||||
frame_count_this_second = 0;
|
||||
std::ostringstream message;
|
||||
message << "Counted " << current_frames_per_second << " frames last second";
|
||||
|
|
|
@ -148,7 +148,7 @@ public:
|
|||
void run();
|
||||
void frame(float);
|
||||
void flag_to_end();
|
||||
virtual void update() {};
|
||||
virtual void update(float timestamp) {};
|
||||
void set_framerate(int);
|
||||
float get_frame_length() const;
|
||||
void handle_quit_event(SDL_Event&);
|
||||
|
@ -165,9 +165,9 @@ public:
|
|||
* @return weighted value
|
||||
*/
|
||||
template<typename T>
|
||||
T weight(T amount)
|
||||
T weight(T amount) const
|
||||
{
|
||||
return (last_frame_length / (1000.0 / 60)) * amount;
|
||||
return (last_frame_length / 1000.0f) * amount;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
|
@ -125,10 +125,10 @@ void Node::suppress_input()
|
|||
get_root()->get_input().suppress();
|
||||
}
|
||||
|
||||
void Node::suppress_input_temporarily(int length)
|
||||
void Node::suppress_input_temporarily(float length)
|
||||
{
|
||||
suppress_input();
|
||||
if (length == 0)
|
||||
if (length == 0.0f)
|
||||
{
|
||||
length = configuration()["input"]["default-unsuppress-delay"];
|
||||
}
|
||||
|
|
|
@ -78,7 +78,7 @@ public:
|
|||
const Game* get_root() const;
|
||||
Box window_box(bool = false);
|
||||
void suppress_input();
|
||||
void suppress_input_temporarily(int = 0);
|
||||
void suppress_input_temporarily(float length = 0.0f);
|
||||
void unsuppress_input();
|
||||
const std::string get_branch_as_string() const;
|
||||
virtual std::string class_name() const { return "Node"; };
|
||||
|
|
|
@ -17,7 +17,7 @@ Recorder::Recorder(Node* parent) : Node(parent)
|
|||
* been configured by the user. */
|
||||
float Recorder::frame_length()
|
||||
{
|
||||
return configuration()["recording"].value("video-frame-length", get_root()->get_frame_length());
|
||||
return configuration()["recording"].value("video-frame-length", get_root()->get_frame_length() / 1000.0f);
|
||||
}
|
||||
|
||||
/* Handle commands for screenshot, record video and save video */
|
||||
|
@ -259,7 +259,7 @@ void Recorder::write_stash_frames(Stash* stash)
|
|||
if (ii == stash->frame_offset)
|
||||
{
|
||||
GifBegin(&gif_writer, gif_path.string().c_str(), frame->w,
|
||||
frame->h, gif_frame_length / 10);
|
||||
frame->h, gif_frame_length * 100);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -269,7 +269,7 @@ void Recorder::write_stash_frames(Stash* stash)
|
|||
SDL_Surface* converted = SDL_ConvertSurfaceFormat(
|
||||
frame, SDL_PIXELFORMAT_ABGR8888, 0);
|
||||
GifWriteFrame(&gif_writer, (const uint8_t*) converted->pixels,
|
||||
frame->w, frame->h, gif_frame_length / 10);
|
||||
frame->w, frame->h, gif_frame_length * 100);
|
||||
}
|
||||
elapsed += frame_length();
|
||||
delete[] stash->pixel_buffers.front();
|
||||
|
@ -343,7 +343,7 @@ void Recorder::write_mp4()
|
|||
std::string pixel_format = configuration()["recording"]["mp4-pixel-format"].get<std::string>();
|
||||
fs::path images_match = current_video_directory / "%05d.png";
|
||||
mp4_command << "ffmpeg -f s16le -ac 2 -ar 22050 -i " << current_audio_path.string() <<
|
||||
" -f image2 -framerate " << (1000 / frame_length()) <<
|
||||
" -f image2 -framerate " << (1.0f / frame_length()) <<
|
||||
" -i " << images_match.string() << " -s " << size.x << "x" << size.y <<
|
||||
" -c:v libx264 -crf 17 -pix_fmt " << pixel_format << " " <<
|
||||
current_video_directory.string() << ".mp4";
|
||||
|
@ -357,14 +357,14 @@ void Recorder::write_audio(Uint8* stream, int len)
|
|||
audio_file.write(reinterpret_cast<char*>(stream), len);
|
||||
}
|
||||
|
||||
void Recorder::update()
|
||||
void Recorder::update(float timestamp)
|
||||
{
|
||||
if (is_recording and get_memory_size() > configuration()["recording"]["max-video-memory"])
|
||||
{
|
||||
end_recording();
|
||||
}
|
||||
animation.set_frame_length(frame_length());
|
||||
animation.update();
|
||||
animation.update(timestamp);
|
||||
}
|
||||
|
||||
void Recorder::process_audio(void* context, Uint8* stream, int len)
|
||||
|
|
|
@ -75,7 +75,7 @@ public:
|
|||
void finish_writing_video();
|
||||
void write_mp4();
|
||||
void write_audio(Uint8*, int);
|
||||
void update();
|
||||
void update(float timestamp);
|
||||
virtual std::string class_name() const { return "Recorder"; }
|
||||
|
||||
};
|
||||
|
|
|
@ -51,13 +51,6 @@ public:
|
|||
std::vector<Segment> subsegments(int) const;
|
||||
inline bool operator<(const Segment& segment) const { return operator<(segment.length()); }
|
||||
|
||||
/*
|
||||
std::cout << (a < b) << (a > b) << (b < c) << (b <= c) << (c > b) << (c >= b) << (d < 1) << (d < 2) <<
|
||||
(d >= a) << (d > c) << std::endl;
|
||||
|
||||
should print 0101010101
|
||||
*/
|
||||
|
||||
template<typename N>
|
||||
inline bool operator<(const N& other) const { return length() < other; }
|
||||
|
||||
|
@ -76,3 +69,11 @@ namespace std
|
|||
{
|
||||
std::ostream& operator<<(std::ostream&, const Segment&);
|
||||
}
|
||||
|
||||
/* Add Segment class to the sb namespace. This should be the default location, but Segment is left in the global namespace
|
||||
* for backward compatibility.
|
||||
*/
|
||||
namespace sb
|
||||
{
|
||||
using ::Segment;
|
||||
}
|
||||
|
|
|
@ -17,8 +17,6 @@
|
|||
#include "glm/common.hpp"
|
||||
#include "glm/gtx/integer.hpp"
|
||||
|
||||
#include "utility.hpp"
|
||||
|
||||
namespace sb
|
||||
{
|
||||
|
||||
|
|
|
@ -830,7 +830,7 @@ void Sprite::set_draw_children_on_frame(bool on_frame)
|
|||
draw_children_on_frame = on_frame;
|
||||
}
|
||||
|
||||
void Sprite::update(const std::vector<Box>& subsections)
|
||||
void Sprite::update(float timestamp, const std::vector<Box>& subsections)
|
||||
{
|
||||
if (is_active())
|
||||
{
|
||||
|
@ -838,10 +838,10 @@ void Sprite::update(const std::vector<Box>& subsections)
|
|||
{
|
||||
move_weighted(step);
|
||||
}
|
||||
frame_animation.update();
|
||||
blink_animation.update();
|
||||
wipe_animation.update();
|
||||
toggle_hidden_animation.update();
|
||||
frame_animation.update(timestamp);
|
||||
blink_animation.update(timestamp);
|
||||
wipe_animation.update(timestamp);
|
||||
toggle_hidden_animation.update(timestamp);
|
||||
SDL_Texture* texture = get_current_frame();
|
||||
if (is_loaded() && !is_hidden() && get_current_frameset().get_frame_count())
|
||||
{
|
||||
|
@ -892,7 +892,7 @@ void Sprite::update(const std::vector<Box>& subsections)
|
|||
child_relative_position = child.sprite.get_nw();
|
||||
child.sprite.move(get_nw());
|
||||
}
|
||||
child.sprite.update();
|
||||
child.sprite.update(timestamp);
|
||||
if (!draw_children_on_frame)
|
||||
{
|
||||
child.sprite.set_nw(child_relative_position);
|
||||
|
@ -901,9 +901,9 @@ void Sprite::update(const std::vector<Box>& subsections)
|
|||
}
|
||||
}
|
||||
|
||||
void Sprite::update()
|
||||
void Sprite::update(float timestamp)
|
||||
{
|
||||
update({});
|
||||
update(timestamp, {});
|
||||
}
|
||||
|
||||
void Sprite::render_subsection(SDL_Renderer* renderer, SDL_Texture* texture, const Box& subsection, const Box& box)
|
||||
|
|
|
@ -140,8 +140,8 @@ public:
|
|||
bool has_child(std::string) const;
|
||||
void remove_child(std::string);
|
||||
void set_draw_children_on_frame(bool);
|
||||
virtual void update(const std::vector<Box>&);
|
||||
virtual void update();
|
||||
virtual void update(float timestamp, const std::vector<Box>&);
|
||||
virtual void update(float timestamp);
|
||||
void render_subsection(SDL_Renderer*, SDL_Texture*, const Box&, const Box&);
|
||||
void set_to_leave_memory_allocated();
|
||||
void set_to_deallocate_memory();
|
||||
|
|
|
@ -84,10 +84,8 @@ namespace sb
|
|||
private:
|
||||
|
||||
using Reaction = std::function<return_type(bool, arguments...)>;
|
||||
inline static const bool STATE_OFF = false;
|
||||
inline static const bool STATE_ON = true;
|
||||
|
||||
bool state = STATE_OFF;
|
||||
bool state = false;
|
||||
Reaction reaction;
|
||||
|
||||
public:
|
||||
|
@ -102,6 +100,12 @@ namespace sb
|
|||
|
||||
Switch(bool state, Reaction reaction = Reaction()) : state(state), reaction(reaction) {}
|
||||
|
||||
/*!
|
||||
* Toggle state, triggering the reaction function.
|
||||
*
|
||||
* @param args arbitrary list of arguments that are expected by the reaction function
|
||||
* @return return the return value of the reaction function
|
||||
*/
|
||||
return_type flip(arguments... args)
|
||||
{
|
||||
state = !state;
|
||||
|
@ -121,13 +125,14 @@ namespace sb
|
|||
/*!
|
||||
* @return when called as a boolean, return state
|
||||
*/
|
||||
operator bool()
|
||||
operator bool() const
|
||||
{
|
||||
return on();
|
||||
return state;
|
||||
}
|
||||
|
||||
/*!
|
||||
* Assign the switch object's state using the assignment operator with a boolean value.
|
||||
* Assign the switch object's state using the assignment operator with a boolean value, without triggering the reaction function.
|
||||
* To trigger the reaction function, use `Switch::flip` instead.
|
||||
*
|
||||
* @param state state the switch will be set to
|
||||
*/
|
||||
|
@ -137,14 +142,6 @@ namespace sb
|
|||
return *this;
|
||||
}
|
||||
|
||||
/*!
|
||||
* @return true if state is Switch::STATE_ON, false otherwise
|
||||
*/
|
||||
bool on()
|
||||
{
|
||||
return state;
|
||||
}
|
||||
|
||||
operator std::string() const
|
||||
{
|
||||
return state ? "true" : "false";
|
||||
|
|
|
@ -1,77 +1,55 @@
|
|||
#include "Timer.hpp"
|
||||
|
||||
/* Initialize a Timer object for keeping a general time count in milliseconds or seconds which can be paused
|
||||
* arbitrarily. The time initializes to zero. By default, the timer begins timing at initialization (this
|
||||
* may change in the future). The ticks and previous_ticks parameters are initially synchronized with the SDL
|
||||
* ticks function, which returns the number of milliseconds since the program began, and the SDL ticks function
|
||||
* is used to keep the time updated. */
|
||||
sb::Timer::Timer()
|
||||
{
|
||||
ticks = SDL_GetTicks();
|
||||
ticks_previous = ticks;
|
||||
}
|
||||
|
||||
/* Check whether Timer is keeping time or not */
|
||||
bool sb::Timer::state()
|
||||
sb::Timer::operator bool() const
|
||||
{
|
||||
return timing;
|
||||
}
|
||||
|
||||
/* Toggle timing on/off */
|
||||
void sb::Timer::toggle()
|
||||
{
|
||||
toggle(!state());
|
||||
toggle(!*this);
|
||||
}
|
||||
|
||||
/* Set state explicitly to sb::Timer::ON (true) or sb::Timer::OFF (false) */
|
||||
void sb::Timer::toggle(bool state)
|
||||
{
|
||||
timing = state;
|
||||
}
|
||||
|
||||
/* Reset time elapsed to zero */
|
||||
void sb::Timer::on()
|
||||
{
|
||||
toggle(ON);
|
||||
}
|
||||
|
||||
void sb::Timer::off()
|
||||
{
|
||||
toggle(OFF);
|
||||
}
|
||||
|
||||
void sb::Timer::reset()
|
||||
{
|
||||
ticks_elapsed = 0;
|
||||
ticks = SDL_GetTicks();
|
||||
ticks_previous = ticks;
|
||||
frame_duration = 0;
|
||||
_elapsed = 0;
|
||||
}
|
||||
|
||||
/* Return milliseconds elapsed on timer */
|
||||
float sb::Timer::ms_elapsed()
|
||||
float sb::Timer::elapsed() const
|
||||
{
|
||||
return ticks_elapsed;
|
||||
return _elapsed;
|
||||
}
|
||||
|
||||
/* Return seconds elapsed on timer */
|
||||
float sb::Timer::seconds_elapsed()
|
||||
{
|
||||
return ms_elapsed() / 1000.0f;
|
||||
}
|
||||
|
||||
/* Return the length of the previous frame in milliseconds (the time between the last two calls to
|
||||
* the timer update function) */
|
||||
float sb::Timer::ms_last_frame()
|
||||
float sb::Timer::frame() const
|
||||
{
|
||||
return frame_duration;
|
||||
}
|
||||
|
||||
/* Return the length of the previous frame in seconds (the time between the last two calls to the
|
||||
* timer update function) */
|
||||
float sb::Timer::seconds_last_frame()
|
||||
void sb::Timer::update(float timestamp)
|
||||
{
|
||||
return ms_last_frame() / 1000.0f;
|
||||
}
|
||||
|
||||
/* Add time to the timer by measuring the time between this call and the previous call to update */
|
||||
void sb::Timer::update()
|
||||
{
|
||||
ticks = SDL_GetTicks();
|
||||
frame_duration = ticks - ticks_previous;
|
||||
if (state())
|
||||
if (previous_is_recorded)
|
||||
{
|
||||
ticks_elapsed += frame_duration;
|
||||
frame_duration = timestamp - timestamp_previous;
|
||||
if (*this)
|
||||
{
|
||||
_elapsed += frame();
|
||||
}
|
||||
}
|
||||
ticks_previous = ticks;
|
||||
timestamp_previous = timestamp;
|
||||
previous_is_recorded = true;
|
||||
}
|
||||
|
|
|
@ -10,17 +10,20 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "SDL.h"
|
||||
|
||||
namespace sb
|
||||
{
|
||||
/*!
|
||||
* Timer in seconds which can be paused arbitrarily.
|
||||
*
|
||||
* It must be updated every frame with the timestamp passed to Game::update, regardless of whether it is actively timing or not.
|
||||
*/
|
||||
class Timer
|
||||
{
|
||||
|
||||
private:
|
||||
|
||||
bool timing = Timer::ON;
|
||||
int ticks = 0, ticks_previous = 0, frame_duration = 0, ticks_elapsed = 0;
|
||||
bool timing = false, previous_is_recorded = false;
|
||||
float timestamp = 0.0f, timestamp_previous = 0.0f, frame_duration = 0.0f, _elapsed = 0.0f;
|
||||
|
||||
public:
|
||||
|
||||
|
@ -30,16 +33,58 @@ namespace sb
|
|||
ON
|
||||
};
|
||||
|
||||
Timer();
|
||||
bool state();
|
||||
/*!
|
||||
* @return boolean indicating whether timer object is keeping time or not
|
||||
*/
|
||||
operator bool() const;
|
||||
|
||||
/*!
|
||||
* Toggle timing on/off
|
||||
*/
|
||||
void toggle();
|
||||
void toggle(bool);
|
||||
|
||||
/*!
|
||||
* @param state set timing state explictly by passing a boolean
|
||||
*/
|
||||
void toggle(bool state);
|
||||
|
||||
/*!
|
||||
* Start timing.
|
||||
*/
|
||||
void on();
|
||||
|
||||
/*!
|
||||
* Stop timing.
|
||||
*/
|
||||
void off();
|
||||
|
||||
/*!
|
||||
* Reset time elapsed to zero.
|
||||
*/
|
||||
void reset();
|
||||
float ms_elapsed();
|
||||
float seconds_elapsed();
|
||||
float ms_last_frame();
|
||||
float seconds_last_frame();
|
||||
void update();
|
||||
|
||||
/*!
|
||||
* @return seconds elapsed on timer
|
||||
*/
|
||||
float elapsed() const;
|
||||
|
||||
|
||||
/*!
|
||||
* @return length of the previous frame in seconds
|
||||
*/
|
||||
float frame() const;
|
||||
|
||||
/*!
|
||||
* Update the timer's elapsed time, using the amount of seconds elapsed in the program at the start of the frame to keep track.
|
||||
*
|
||||
* The timer should be updated every frame to keep track of the timestamp, regardless of whether it is currently timing or not.
|
||||
*
|
||||
* The timestamp should be forwarded from the value passed to Game::update, so that it is consistently the timestamp at the
|
||||
* beginning of the frame.
|
||||
*
|
||||
* @param timestamp seconds elapsed since the start of the program
|
||||
*/
|
||||
void update(float timestamp);
|
||||
|
||||
/*!
|
||||
* Applies delta timing to a value: returns the value as weighted by the amount of time passed since the
|
||||
|
@ -50,9 +95,9 @@ namespace sb
|
|||
* @return weighted value
|
||||
*/
|
||||
template<typename Type>
|
||||
Type weigh(Type amount)
|
||||
Type delta(Type amount) const
|
||||
{
|
||||
return seconds_last_frame() * amount;
|
||||
return frame() * amount;
|
||||
}
|
||||
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue