Adjust the timing of when animations are played during movement.
This is (at least) a first step in resolving bug #20324 (choppy movement on fogged maps).
This commit is contained in:
parent
b4b32ca00c
commit
dbeba84088
3 changed files with 126 additions and 38 deletions
|
@ -501,7 +501,7 @@ namespace { // Private helpers for move_unit()
|
|||
// Show this move.
|
||||
const size_t current_tracking = game_events::wml_tracking();
|
||||
animator.proceed_to(*move_it_, step_to - begin_,
|
||||
current_tracking != do_move_track_);
|
||||
current_tracking != do_move_track_, false);
|
||||
do_move_track_ = current_tracking;
|
||||
disp.redraw_minimap();
|
||||
}
|
||||
|
@ -921,10 +921,10 @@ namespace { // Private helpers for move_unit()
|
|||
|
||||
// We can leave *step_from. Make the move to *real_end_.
|
||||
do_move(step_from, real_end_, animator);
|
||||
|
||||
// Update the fog.
|
||||
if ( current_uses_fog_ )
|
||||
handle_fog(*real_end_, ally_interrupts);
|
||||
animator.wait_for_anims();
|
||||
|
||||
// Fire the events for this step.
|
||||
// (These return values are not checked since real_end_ still
|
||||
|
|
|
@ -86,17 +86,33 @@ static void teleport_unit_between( const map_location& a, const map_location& b,
|
|||
events::pump();
|
||||
}
|
||||
|
||||
static void move_unit_between(const map_location& a, const map_location& b, unit& temp_unit,unsigned int step_num,unsigned int step_left)
|
||||
/**
|
||||
* Animates a single step between hexes.
|
||||
* This will return before the animation actually finishes, allowing other
|
||||
* processing to occur during the animation.
|
||||
*
|
||||
* @param a The starting hex.
|
||||
* @param b The ending hex.
|
||||
* @param temp_unit The unit to animate (historically, a temporary unit).
|
||||
* @param step_num The number of steps taken so far (used to pick an animation).
|
||||
* @param step_left The number of steps remaining (used to pick an animation).
|
||||
* @param animator The unit_animator to use. This is assumed clear when we start,
|
||||
* but will likely not be clear when we return.
|
||||
* @returns The animation potential until this animation will finish.
|
||||
* INT_MIN indicates that no animation is pending.
|
||||
*/
|
||||
static int move_unit_between(const map_location& a, const map_location& b,
|
||||
unit& temp_unit, unsigned int step_num,
|
||||
unsigned int step_left, unit_animator & animator)
|
||||
{
|
||||
display* disp = display::get_singleton();
|
||||
if(!disp || disp->video().update_locked() || disp->video().faked() || (disp->fogged(a) && disp->fogged(b))) {
|
||||
return;
|
||||
return INT_MIN;
|
||||
}
|
||||
|
||||
temp_unit.set_location(a);
|
||||
disp->invalidate(temp_unit.get_location());
|
||||
temp_unit.set_facing(a.get_relative_dir(b));
|
||||
unit_animator animator;
|
||||
animator.replace_anim_if_invalid(&temp_unit,"movement",a,b,step_num,
|
||||
false,"",0,unit_animation::INVALID,NULL,NULL,step_left);
|
||||
animator.start_animations();
|
||||
|
@ -108,7 +124,6 @@ static void move_unit_between(const map_location& a, const map_location& b, unit
|
|||
// new_animation_frame();
|
||||
|
||||
int target_time = animator.get_animation_time_potential();
|
||||
|
||||
// target_time must be short to avoid jumpy move
|
||||
// std::cout << "target time: " << target_time << "\n";
|
||||
// we round it to the next multile of 200
|
||||
|
@ -119,19 +134,7 @@ static void move_unit_between(const map_location& a, const map_location& b, unit
|
|||
// which will not match with the following -1.0
|
||||
// if( target_time - animator.get_animation_time_potential() < 100 ) target_time +=200;
|
||||
|
||||
animator.wait_until(target_time);
|
||||
// debug code, see unit_frame::redraw()
|
||||
// std::cout << " end\n";
|
||||
map_location arr[6];
|
||||
get_adjacent_tiles(a, arr);
|
||||
unsigned int i;
|
||||
for (i = 0; i < 6; ++i) {
|
||||
disp->invalidate(arr[i]);
|
||||
}
|
||||
get_adjacent_tiles(b, arr);
|
||||
for (i = 0; i < 6; ++i) {
|
||||
disp->invalidate(arr[i]);
|
||||
}
|
||||
return target_time;
|
||||
}
|
||||
|
||||
namespace unit_display
|
||||
|
@ -145,6 +148,9 @@ unit_mover::unit_mover(const std::vector<map_location>& path, bool animate) :
|
|||
can_draw_(disp_ && !disp_->video().update_locked() &&
|
||||
!disp_->video().faked() && path.size() > 1),
|
||||
animate_(animate),
|
||||
animator_(),
|
||||
wait_until_(INT_MIN),
|
||||
shown_unit_(NULL),
|
||||
path_(path),
|
||||
current_(0),
|
||||
temp_unit_ptr_(NULL),
|
||||
|
@ -162,9 +168,12 @@ unit_mover::unit_mover(const std::vector<map_location>& path, bool animate) :
|
|||
|
||||
unit_mover::~unit_mover()
|
||||
{
|
||||
if ( temp_unit_ptr_ != NULL )
|
||||
// Its destructor will remove the temp unit from the display.
|
||||
delete temp_unit_ptr_;
|
||||
// Make sure a unit hidden for movement is unhidden.
|
||||
update_shown_unit();
|
||||
// For safety, clear the animator before deleting the temp unit.
|
||||
animator_.clear();
|
||||
// The temp unit's destructor will remove it from the display.
|
||||
delete temp_unit_ptr_;
|
||||
}
|
||||
|
||||
|
||||
|
@ -203,6 +212,22 @@ void unit_mover::replace_temporary(unit & u)
|
|||
}
|
||||
|
||||
|
||||
/**
|
||||
* Switches the display back to *shown_unit_ after animating.
|
||||
* This uses temp_unit_ptr_, so (in the destructor) call this before deleting
|
||||
* temp_unit_ptr_.
|
||||
*/
|
||||
void unit_mover::update_shown_unit()
|
||||
{
|
||||
if ( shown_unit_ != NULL ) {
|
||||
// Switch the display back to the real unit.
|
||||
shown_unit_->set_hidden(was_hidden_);
|
||||
temp_unit_ptr_->set_hidden(true);
|
||||
shown_unit_ = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Initiates the display of movement for the supplied unit.
|
||||
* This should be called before attempting to display moving to a new hex.
|
||||
|
@ -213,6 +238,9 @@ void unit_mover::start(unit& u)
|
|||
if ( !can_draw_ || !animate_ )
|
||||
return;
|
||||
|
||||
// This normally does nothing, but just in case...
|
||||
wait_for_anims();
|
||||
|
||||
// Visually replace the original unit with the temporary.
|
||||
// (Original unit is left on the map, so the unit count is correct.)
|
||||
replace_temporary(u);
|
||||
|
@ -245,10 +273,10 @@ void unit_mover::start(unit& u)
|
|||
disp_->draw(true);
|
||||
|
||||
// extra immobile movement animation for take-off
|
||||
unit_animator animator;
|
||||
animator.add_animation(temp_unit_ptr_, "pre_movement", path_[0], path_[1]);
|
||||
animator.start_animations();
|
||||
animator.wait_for_end();
|
||||
animator_.add_animation(temp_unit_ptr_, "pre_movement", path_[0], path_[1]);
|
||||
animator_.start_animations();
|
||||
animator_.wait_for_end();
|
||||
animator_.clear();
|
||||
|
||||
// Switch the display back to the real unit.
|
||||
u.set_facing(temp_unit_ptr_->facing());
|
||||
|
@ -264,13 +292,20 @@ void unit_mover::start(unit& u)
|
|||
* The moving unit will only be updated if update is set to true; otherwise,
|
||||
* the provided unit is merely hidden during the movement and re-shown after.
|
||||
* (Not updating the unit can produce smoother animations in some cases.)
|
||||
* If @a wait is set to false, this returns without waiting for the final
|
||||
* animation to finish. Call wait_for_anims() to explicitly get this final
|
||||
* wait (another call to proceed_to() or finish() will implicitly wait). The
|
||||
* unit must remain valid until the wait is finished.
|
||||
*/
|
||||
void unit_mover::proceed_to(unit& u, size_t path_index, bool update)
|
||||
void unit_mover::proceed_to(unit& u, size_t path_index, bool update, bool wait)
|
||||
{
|
||||
// Nothing to do here if animations can/should not be shown.
|
||||
if ( !can_draw_ || !animate_ )
|
||||
return;
|
||||
|
||||
// Handle pending visibility issues before introducing new ones.
|
||||
wait_for_anims();
|
||||
|
||||
if ( update || temp_unit_ptr_ == NULL )
|
||||
// Replace the temp unit (which also hides u and shows our temporary).
|
||||
replace_temporary(u);
|
||||
|
@ -289,6 +324,9 @@ void unit_mover::proceed_to(unit& u, size_t path_index, bool update)
|
|||
if ( !is_enemy_ || !temp_unit_ptr_->invisible(path_[current_]) ||
|
||||
!temp_unit_ptr_->invisible(path_[current_+1]) )
|
||||
{
|
||||
// Wait for the previous step to complete before drawing the next one.
|
||||
wait_for_anims();
|
||||
|
||||
if ( !disp_->tile_fully_on_screen(path_[current_]) ||
|
||||
!disp_->tile_fully_on_screen(path_[current_+1]))
|
||||
{
|
||||
|
@ -306,19 +344,61 @@ void unit_mover::proceed_to(unit& u, size_t path_index, bool update)
|
|||
}
|
||||
|
||||
if ( tiles_adjacent(path_[current_], path_[current_+1]) )
|
||||
move_unit_between(path_[current_], path_[current_+1],
|
||||
*temp_unit_ptr_, current_,
|
||||
path_.size() - (current_+2));
|
||||
wait_until_ =
|
||||
move_unit_between(path_[current_], path_[current_+1],
|
||||
*temp_unit_ptr_, current_,
|
||||
path_.size() - (current_+2), animator_);
|
||||
else if ( path_[current_] != path_[current_+1] )
|
||||
teleport_unit_between(path_[current_], path_[current_+1],
|
||||
*temp_unit_ptr_);
|
||||
}
|
||||
|
||||
// Switch the display back to the real unit.
|
||||
// Update the unit's facing.
|
||||
u.set_facing(temp_unit_ptr_->facing());
|
||||
u.set_standing(false); // Need to reset u's animation so the new facing takes effect.
|
||||
u.set_hidden(was_hidden_);
|
||||
temp_unit_ptr_->set_hidden(true);
|
||||
// Remember the unit to unhide when the animation finishes.
|
||||
shown_unit_ = &u;
|
||||
if ( wait )
|
||||
wait_for_anims();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Waits for the final animation of the most recent proceed_to() to finish.
|
||||
* It is not necessary to call this unless you want to wait before the next
|
||||
* call to proceed_to() or finish().
|
||||
*/
|
||||
void unit_mover::wait_for_anims()
|
||||
{
|
||||
if ( wait_until_ == INT_MAX )
|
||||
// Wait for end (not currently used, but still supported).
|
||||
animator_.wait_for_end();
|
||||
else if ( wait_until_ != INT_MIN ) {
|
||||
// Wait until the specified time (used for normal movement).
|
||||
animator_.wait_until(wait_until_);
|
||||
// debug code, see unit_frame::redraw()
|
||||
// std::cout << " end\n";
|
||||
|
||||
/// @todo Are these invalidations really (or still) necessary?
|
||||
/// A quick check suggested they are not needed, but that was
|
||||
/// not comprehensive.
|
||||
if ( disp_ ) { // Should always be true if we get here.
|
||||
// Invalidate the hexes around the move that prompted this wait.
|
||||
map_location arr[6];
|
||||
get_adjacent_tiles(path_[current_-1], arr);
|
||||
for ( unsigned i = 0; i < 6; ++i )
|
||||
disp_->invalidate(arr[i]);
|
||||
get_adjacent_tiles(path_[current_], arr);
|
||||
for ( unsigned i = 0; i < 6; ++i )
|
||||
disp_->invalidate(arr[i]);
|
||||
}
|
||||
}
|
||||
|
||||
// Reset data.
|
||||
wait_until_ = INT_MIN;
|
||||
animator_.clear();
|
||||
|
||||
update_shown_unit();
|
||||
}
|
||||
|
||||
|
||||
|
@ -342,16 +422,18 @@ void unit_mover::finish(unit &u, map_location::DIRECTION dir)
|
|||
|
||||
if ( animate_ )
|
||||
{
|
||||
wait_for_anims(); // In case proceed_to() did not wait for the last animation.
|
||||
|
||||
// Make sure the displayed unit is correct.
|
||||
replace_temporary(u);
|
||||
temp_unit_ptr_->set_location(end_loc);
|
||||
temp_unit_ptr_->set_facing(final_dir);
|
||||
|
||||
// Animation
|
||||
unit_animator animator;
|
||||
animator.add_animation(temp_unit_ptr_, "post_movement", end_loc);
|
||||
animator.start_animations();
|
||||
animator.wait_for_end();
|
||||
animator_.add_animation(temp_unit_ptr_, "post_movement", end_loc);
|
||||
animator_.start_animations();
|
||||
animator_.wait_for_end();
|
||||
animator_.clear();
|
||||
|
||||
// Switch the display back to the real unit.
|
||||
u.set_hidden(was_hidden_);
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#ifndef UNIT_DISPLAY_HPP_INCLUDED
|
||||
#define UNIT_DISPLAY_HPP_INCLUDED
|
||||
|
||||
#include "unit_animation.hpp"
|
||||
#include "unit_map.hpp"
|
||||
#include "gamestatus.hpp"
|
||||
#include "game_display.hpp"
|
||||
|
@ -48,16 +49,21 @@ public:
|
|||
~unit_mover();
|
||||
|
||||
void start(unit& u);
|
||||
void proceed_to(unit& u, size_t path_index, bool update = false);
|
||||
void proceed_to(unit& u, size_t path_index, bool update=false, bool wait=true);
|
||||
void wait_for_anims();
|
||||
void finish(unit &u, map_location::DIRECTION dir = map_location::NDIRECTIONS);
|
||||
|
||||
private: // functions
|
||||
void replace_temporary(unit & u);
|
||||
void update_shown_unit();
|
||||
|
||||
private: // data
|
||||
game_display * const disp_;
|
||||
const bool can_draw_;
|
||||
const bool animate_;
|
||||
unit_animator animator_;
|
||||
int wait_until_; /// The animation potential to wait until. INT_MIN for no wait; INT_MAX to wait for end.
|
||||
unit * shown_unit_; /// The unit to be (re-)shown after an animation finishes.
|
||||
const std::vector<map_location>& path_;
|
||||
size_t current_;
|
||||
game_display::fake_unit * temp_unit_ptr_;
|
||||
|
|
Loading…
Add table
Reference in a new issue