Skip to content

Commit

Permalink
Fix ingame viewport scrolling
Browse files Browse the repository at this point in the history
Previously ingame map scrolling was processed inside the doInput() function, which meant that each received SDL event (input or otherwise) would trigger an accumulation of a viewport scroll step.

This caused viewport scrolling to behave erratically and often jump around very large quantas.

Fix the issue by moving scroll handling into the main game loop, where a 60msec timer is used to pace scrolling to occur at a regular speed. Holding down shift key will result in 3x fast speed scrolling.
  • Loading branch information
juj authored and henricj committed Jun 7, 2022
1 parent 01e9541 commit 568c317
Show file tree
Hide file tree
Showing 2 changed files with 71 additions and 45 deletions.
14 changes: 10 additions & 4 deletions include/Game.h
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,11 @@ class Game final {
*/
void doInput(const GameContext& context, SDL_Event& event);

/**
Pans the in-game viewport based on mouse or keyboard control.
*/
void scrollViewport();

public:
/**
Returns the current game cycle number.
Expand Down Expand Up @@ -594,10 +599,11 @@ class Game final {
bool chatMode_ = false; ///< chat mode on?
std::string typingChatMessage_; ///< currently typed chat message

bool scrollDownMode_ = false; ///< currently scrolling the map down?
bool scrollLeftMode_ = false; ///< currently scrolling the map left?
bool scrollRightMode_ = false; ///< currently scrolling the map right?
bool scrollUpMode_ = false; ///< currently scrolling the map up?
int mapVerticalScroll_; ///< Specifies the speed at which map is being scrolled vertically (0: no scroll, +: scroll
///< down, -: scroll up)
int mapHorizontalScroll_; ///< Same for horizontal scrolling. Fast scrolling is performed with holding shift key down.
dune::dune_clock::time_point
lastScrollTime_; ///< Tracks the timestamp of when previous map scroll occurred. Used to pace scrolling speed.

bool selectionMode_ = false; ///< currently selection multiple units with a selection rectangle?
SDL_Rect selectionRect_{}; ///< the drawn rectangle while selection multiple units
Expand Down
102 changes: 61 additions & 41 deletions src/Game.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -868,41 +868,64 @@ void Game::doInput(const GameContext& context, SDL_Event& event) {
&& (SDL_GetWindowFlags(dune::globals::window.get()) & SDL_WINDOW_INPUT_FOCUS)) {

const auto* keystate = SDL_GetKeyboardState(nullptr);
scrollDownMode_ =
(dune::globals::drawnMouseY >= getRendererHeight() - 1 - SCROLLBORDER) || keystate[SDL_SCANCODE_DOWN];
scrollLeftMode_ = (dune::globals::drawnMouseX <= SCROLLBORDER) || keystate[SDL_SCANCODE_LEFT];
scrollRightMode_ =
(dune::globals::drawnMouseX >= getRendererWidth() - 1 - SCROLLBORDER) || keystate[SDL_SCANCODE_RIGHT];
scrollUpMode_ = (dune::globals::drawnMouseY <= SCROLLBORDER) || keystate[SDL_SCANCODE_UP];

auto* const screenborder = dune::globals::screenborder.get();

if (scrollLeftMode_ && scrollRightMode_) {
// do nothing
} else if (scrollLeftMode_) {
scrollLeftMode_ = screenborder->scrollLeft();
} else if (scrollRightMode_) {
scrollRightMode_ = screenborder->scrollRight();
}

if (scrollDownMode_ && scrollUpMode_) {
// do nothing
} else if (scrollDownMode_) {
scrollDownMode_ = screenborder->scrollDown();
} else if (scrollUpMode_) {
scrollUpMode_ = screenborder->scrollUp();
// Update map scrolling speed state. Using both keyboard and mouse to scroll at the same time is intended to
// accumulate together.
mapVerticalScroll_ = (dune::globals::drawnMouseY >= getRendererHeight() - 1 - SCROLLBORDER ? 1 : 0)
+ (keystate[SDL_SCANCODE_DOWN] ? 1 : 0)
+ (dune::globals::drawnMouseY <= SCROLLBORDER ? -1 : 0)
+ (keystate[SDL_SCANCODE_UP] ? -1 : 0);
mapHorizontalScroll_ = (dune::globals::drawnMouseX <= SCROLLBORDER ? -1 : 0)
+ (keystate[SDL_SCANCODE_LEFT] ? -1 : 0)
+ (dune::globals::drawnMouseX >= getRendererWidth() - 1 - SCROLLBORDER ? 1 : 0)
+ (keystate[SDL_SCANCODE_RIGHT] ? 1 : 0);

// Holding down shift enables 3x fast speed scrolling.
if (keystate[SDL_SCANCODE_LSHIFT] || keystate[SDL_SCANCODE_RSHIFT]) {
mapVerticalScroll_ *= 3;
mapHorizontalScroll_ *= 3;
}
} else {
scrollDownMode_ = false;
scrollLeftMode_ = false;
scrollRightMode_ = false;
scrollUpMode_ = false;
mapVerticalScroll_ = mapHorizontalScroll_ = 0;
}

if (sdl_handler_ && Window::isBroadcastEvent(event))
sdl_handler_(event);
}

void Game::scrollViewport() {
using namespace std::chrono_literals;

if (mapVerticalScroll_ || mapHorizontalScroll_) {
static constexpr auto scrollInterval = 60ms; // TODO: This might possibly go into an ingame menu setting.
const auto now = dune::dune_clock::now();

if (now > lastScrollTime_ + scrollInterval || lastScrollTime_ > now) {
auto* const screenborder = dune::globals::screenborder.get();

// N.b. Currently the game implements a "quantized" scrolling mode that is faithful to the original Dune 2
// game, i.e. the viewport will scroll by ~1 grid unit jumps, rather than in a smooth pixel perfect fashion.
// If smooth scrolling were to be desired, the above scrollInterval timer could be removed and instead the
// following functions could be adjusted to scroll the viewport by much smaller increments, resulting in a
// more modern style scrolling.
for (int i = 0; i < mapVerticalScroll_; ++i)
if (!screenborder->scrollDown())
mapVerticalScroll_ = 0;
for (int i = 0; i > mapVerticalScroll_; --i)
if (!screenborder->scrollUp())
mapVerticalScroll_ = 0;

for (int i = 0; i < mapHorizontalScroll_; ++i)
if (!screenborder->scrollRight())
mapHorizontalScroll_ = 0;
for (int i = 0; i > mapHorizontalScroll_; --i)
if (!screenborder->scrollLeft())
mapHorizontalScroll_ = 0;

lastScrollTime_ = now;
}
}
}

void Game::drawCursor(const SDL_Rect& map_rect) const {
if (!(SDL_GetWindowFlags(dune::globals::window.get()) & SDL_WINDOW_MOUSE_FOCUS)) {
return;
Expand All @@ -914,20 +937,14 @@ void Game::drawCursor(const SDL_Rect& map_rect) const {
const DuneTexture* pCursor = nullptr;
SDL_FRect dest{};

if (scrollLeftMode_ || scrollRightMode_ || scrollUpMode_ || scrollDownMode_) {
if (scrollLeftMode_ && !scrollRightMode_) {
hardware_cursor = gfx->getCursor(UI_CursorLeft);
} else if (scrollRightMode_ && !scrollLeftMode_) {
hardware_cursor = gfx->getCursor(UI_CursorRight);
} else {
if (scrollUpMode_ && !scrollDownMode_) {
hardware_cursor = gfx->getCursor(UI_CursorUp);
} else if (scrollDownMode_ && !scrollUpMode_) {
hardware_cursor = gfx->getCursor(UI_CursorDown);
} else {
hardware_cursor = gfx->getCursor(UI_CursorNormal);
}
}
if (mapHorizontalScroll_ < 0) {
hardware_cursor = gfx->getCursor(UI_CursorLeft);
} else if (mapHorizontalScroll_ > 0) {
hardware_cursor = gfx->getCursor(UI_CursorRight);
} else if (mapVerticalScroll_ < 0) {
hardware_cursor = gfx->getCursor(UI_CursorUp);
} else if (mapVerticalScroll_ > 0) {
hardware_cursor = gfx->getCursor(UI_CursorDown);
} else {
const SDL_Point mouse_point{dune::globals::drawnMouseX, dune::globals::drawnMouseY};
if ((pInGameMenu_ != nullptr) || (pInGameMentat_ != nullptr) || (pWaitingForOtherPlayers_ != nullptr)
Expand Down Expand Up @@ -1450,6 +1467,9 @@ void Game::runMainLoop(const GameContext& context, MenuBase::event_handler_type
while (SDL_PollEvent(&event))
doInput(context, event);

// Process ingame map scrolling.
scrollViewport();

dune::globals::musicPlayer->musicCheck(); // if song has finished, start playing next one

if (bWaitForNetwork || bPause_ || gameCycleCount_ >= skipToGameCycle_) {
Expand Down

0 comments on commit 568c317

Please sign in to comment.