/** * Initiates the display of movement for the supplied unit. * This should be called before attempting to display moving to a new hex. */ void unit_mover::start(unit_ptr u) { // Nothing to do here if there is nothing to animate. if ( !can_draw_ ) return; // If no animation then hide unit until end of movement if ( !animate_ ) { was_hidden_ = u->get_hidden(); u->set_hidden(true); 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); // Initialize our temporary unit for the move. temp_unit_ptr_->set_location(path_[0]); temp_unit_ptr_->set_facing(path_[0].get_relative_dir(path_[1])); temp_unit_ptr_->anim_comp().set_standing(false); disp_->invalidate(path_[0]); // If the unit can be seen here by the viewing side: if ( !is_enemy_ || !temp_unit_ptr_->invisible(path_[0]) ) { // Scroll to the path, but only if it fully fits on screen. // If it does not fit we might be able to do a better scroll later. disp_->scroll_to_tiles(path_, game_display::ONSCREEN, true, true, 0.0, false); } // We need to clear big invalidation before the move and have a smooth animation // (mainly black stripes and invalidation after canceling attack dialog). // Two draw calls are needed to also redraw the previously invalidated hexes. // We use update=false because we don't need delay here (no time wasted) // and no screen refresh (will be done by last 3rd draw() and it optimizes // the double blitting done by these invalidations). disp_->draw(false); disp_->draw(false); // The last draw() was still slow, and its initial new_animation_frame() call // is now old, so we do another draw() to get a fresh one // TODO: replace that by a new_animation_frame() before starting anims // don't forget to change the previous draw(false) to true disp_->draw(true); // extra immobile movement animation for take-off animator_.add_animation(temp_unit_ptr_.get(), "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()); u->anim_comp().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); }
/* Note: Hide the unit in its current location; do not actually remove it. * Otherwise the status displays will be wrong during the movement. */ void unit_mover::replace_temporary(unit_ptr u) { if ( disp_ == nullptr ) // No point in creating a temp unit with no way to display it. return; // Save the hidden state of the unit. was_hidden_ = u->get_hidden(); // Make our temporary unit mostly match u... temp_unit_ptr_ = fake_unit_ptr(unit_ptr(new unit(*u)), resources::fake_units); // ... but keep the temporary unhidden and hide the original. temp_unit_ptr_->set_hidden(false); u->set_hidden(true); // Update cached data. is_enemy_ = (*resources::teams)[u->side()-1].is_enemy(disp_->viewing_side()); }