You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++ SFML中采用过程式编程检测被点击按钮的实现方法

过程式SFML扫雷通用点击检测方案

全程不需要重构为OOP风格,完全兼容你已有的过程式游戏逻辑,所有点击检测逻辑只需要写一次,适配所有场景。

核心思路

定义通用的可点击元素结构体,每个场景维护一张当前场景所有可点击元素的列表,点击时统一遍历列表做碰撞检测,根据返回的元素类型触发对应逻辑。

实现步骤

1. 定义通用数据结构

不需要类和成员函数,纯C风格结构体即可:

#include <vector>

// 所有可点击元素的类型枚举,新增按钮只需要在这里加项
enum ClickableType {
    CLICK_CELL,    // 棋盘单元格
    CLICK_RESTART, // 重启按钮
    CLICK_SAVE,    // 保存按钮
    CLICK_EXIT     // 退出按钮
};

// 可点击元素结构,存储边界、类型和附加参数
typedef struct {
    int x;          // 左上角X坐标
    int y;          // 左上角Y坐标
    int width;      // 宽度
    int height;     // 高度
    ClickableType type;
    int extra_row;  // 单元格专属:存储行号,功能按钮可留空
    int extra_col;  // 单元格专属:存储列号,功能按钮可留空
} Clickable;

// 全局变量存储当前场景的所有可点击元素
std::vector<Clickable> current_clickables;

2. 编写统一的点击检测函数

整个项目只需要写这一次检测逻辑,所有场景通用:

// 传入鼠标坐标,返回是否命中可点击元素,同时返回命中元素的类型和附加参数
bool check_click(int mouse_x, int mouse_y, ClickableType* out_type, int* out_row, int* out_col) {
    // 倒序遍历保证上层元素优先被命中(比如弹出菜单比底层元素优先级高)
    for (auto it = current_clickables.rbegin(); it != current_clickables.rend(); ++it) {
        const Clickable& item = *it;
        if (mouse_x >= item.x && mouse_x <= item.x + item.width &&
            mouse_y >= item.y && mouse_y <= item.y + item.height) {
            *out_type = item.type;
            *out_row = item.extra_row;
            *out_col = item.extra_col;
            return true;
        }
    }
    return false;
}

3. 场景切换时更新可点击元素列表

不需要修改检测逻辑,只需要在切换场景时重新填充current_clickables即可:

菜单场景加载示例

void load_menu_scene() {
    current_clickables.clear();
    // 添加菜单页的功能按钮
    current_clickables.push_back({100, 200, 200, 50, CLICK_RESTART, 0, 0});
    current_clickables.push_back({100, 300, 200, 50, CLICK_SAVE, 0, 0});
    current_clickables.push_back({100, 400, 200, 50, CLICK_EXIT, 0, 0});
}

游戏场景加载示例

// rows为棋盘行数,cols为列数,cell_size为单元格像素尺寸
void load_game_scene(int rows, int cols, int cell_size) {
    current_clickables.clear();
    // 先加顶部功能按钮
    current_clickables.push_back({10, 10, 100, 30, CLICK_RESTART, 0, 0});
    current_clickables.push_back({120, 10, 100, 30, CLICK_SAVE, 0, 0});
    // 再加所有棋盘单元格
    const int board_top_offset = 50; // 棋盘顶部偏移,避开功能按钮
    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols; c++) {
            int cell_x = c * cell_size;
            int cell_y = board_top_offset + r * cell_size;
            current_clickables.push_back({cell_x, cell_y, cell_size, cell_size, CLICK_CELL, r, c});
        }
    }
}

4. SFML事件中统一调用处理

不需要分场景写检测逻辑,事件处理代码全局通用:

// SFML窗口事件循环中处理鼠标点击
if (event.type == sf::Event::MouseButtonPressed) {
    int mouse_x = event.mouseButton.x;
    int mouse_y = event.mouseButton.y;
    ClickableType hit_type;
    int hit_row, hit_col;
    if (check_click(mouse_x, mouse_y, &hit_type, &hit_row, &hit_col)) {
        switch (hit_type) {
            case CLICK_CELL:
                // 直接调用你已经写好的过程式扫雷逻辑即可
                process_cell_click(hit_row, hit_col);
                break;
            case CLICK_RESTART:
                restart_game();
                break;
            case CLICK_SAVE:
                save_game();
                break;
            case CLICK_EXIT:
                window.close();
                break;
        }
    }
}

优势

  • 完全兼容已有过程式代码,不需要重构现有游戏逻辑
  • 新增按钮/场景只需要修改对应场景的列表填充代码,不需要修改检测逻辑
  • 支持元素层级控制,倒序遍历可以保证后加入的上层元素优先响应点击

内容的提问来源于stack exchange,提问作者Sang Phạm

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.25 03:15:06