Placing Flags

Touch Support in Minesweeper

How would we add support for touch screens, allowing both flag placement and cell clearing with touch gestures?

Abstract art representing computer programming

Adding touch screen support to our Minesweeper game is an excellent way to make it more accessible on mobile devices and tablets.

We'll need to modify our existing code to interpret touch gestures for both clearing cells and placing flags. Let's explore how we can implement this feature.

Touch Gestures

For our touch-enabled Minesweeper, we'll use the following gestures:

  1. Single tap: Clear a cell (equivalent to left-click)
  2. Long press: Place/remove a flag (equivalent to right-click)

Implementation

We'll need to modify our MinesweeperCell class to handle touch events. SDL2 provides touch event handling through its event system. Here's how we might implement this:

#include <SDL2/SDL.h>
#include <iostream>

class MinesweeperCell : public Engine::Button {
public:
  MinesweeperCell(int x, int y, int w, int h)
    : Button{ x, y, w, h }
      , longPressStartTime{ 0 } {}

  void HandleEvent(
    const SDL_Event& e) override {
    switch (e.type) {
      case SDL_FINGERDOWN:
        HandleFingerDown(e.tfinger);
        break;
      case SDL_FINGERUP:
        HandleFingerUp(e.tfinger);
        break;
      default:
        Button::HandleEvent(e);
        break;
    }
  }

private:
  Uint32 longPressStartTime;
  static constexpr Uint32 LONG_PRESS_DURATION =
    500; // 500ms

  void HandleFingerDown(
    const SDL_TouchFingerEvent& e) {
    if (IsPointInside(e.x * SCREEN_WIDTH,
      e.y * SCREEN_HEIGHT)) {
      longPressStartTime = SDL_GetTicks();
    }
  }

  void HandleFingerUp(
    const SDL_TouchFingerEvent& e) {
    if (IsPointInside(e.x * SCREEN_WIDTH,
      e.y * SCREEN_HEIGHT)) {
      Uint32 pressDuration =
        SDL_GetTicks() - longPressStartTime;
      if (pressDuration
        >= LONG_PRESS_DURATION) {
        HandleLongPress();
      } else { HandleTap(); }
    }
    longPressStartTime = 0;
  }

  void HandleTap() {
    std::cout << "Cell tapped (clear cell)\n";
    ClearCell();
  }

  void HandleLongPress() {
    std::cout
      << "Cell long-pressed (toggle flag)\n";
    ToggleFlag();
  }

  void ClearCell() {
    // Existing cell clearing logic
  }

  void ToggleFlag() {
    // Existing flag toggling logic
  }

  bool IsPointInside(float x, float y) const {
    return x >= GetX()
      && x < GetX() + GetWidth() && y >= GetY()
      && y < GetY() + GetHeight();
  }
};

int main() {
  // SDL initialization code...

  MinesweeperCell cell{ 100, 100, 50, 50 };

  SDL_Event e;
  bool quit = false;

  while (!quit) {
    while (SDL_PollEvent(&e) != 0) {
      if (e.type == SDL_QUIT) { quit = true; }
      cell.HandleEvent(e);
    }

    // Rendering code...
  }

  // SDL cleanup code...
  return 0;
}

Let's break down the key components of this implementation:

  1. We've added SDL_FINGERDOWN and SDL_FINGERUP event handling to our HandleEvent() method.
  2. HandleFingerDown() records the start time of a touch.
  3. HandleFingerUp() calculates the duration of the touch and determines whether it was a tap or a long press.
  4. We use SDL_GetTicks() to measure the duration of a touch.
  5. The IsPointInside() method checks if a touch point is within the cell's boundaries.
  6. We've defined LONG_PRESS_DURATION as 500ms, but you can adjust this value based on user testing.
  7. The HandleTap() and HandleLongPress() methods can be implemented to clear the cell or toggle the flag, respectively.

Considerations

  1. Screen Size: Note that touch coordinates are normalized (0.0 to 1.0), so we multiply by SCREEN_WIDTH and SCREEN_HEIGHT to get pixel coordinates.
  2. Multi-touch: This implementation doesn't handle multi-touch scenarios. You might want to add logic to track multiple touches if that's a requirement.
  3. Accessibility: Consider adding visual or haptic feedback for long presses to help users understand when they've held long enough to place a flag.
  4. Testing: Thoroughly test on various devices to ensure the touch timings feel natural across different hardware.

By implementing touch support, we make our Minesweeper game more accessible to a wider range of devices and users. This implementation maintains the core gameplay while adapting it to touch interfaces, allowing players to enjoy the game on tablets and smartphones just as they would on desktop computers.

Answers to questions are automatically generated and may not have been reviewed.

sdl2-promo.jpg
Part of the course:

Game Dev with SDL2

Learn C++ and SDL development by creating hands on, practical projects inspired by classic retro games

Free, unlimited access

This course includes:

  • 67 Lessons
  • 100+ Code Samples
  • 91% Positive Reviews
  • Regularly Updated
  • Help and FAQ
Free, Unlimited Access

Professional C++

Comprehensive course covering advanced concepts, and how to use them on large-scale projects.

Screenshot from Warhammer: Total War
Screenshot from Tomb Raider
Screenshot from Jedi: Fallen Order
Contact|Privacy Policy|Terms of Use
Copyright © 2024 - All Rights Reserved