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

如何拆分QPainter,实现游戏中Space类仅绘制自身对应屏幕区域?

实现方案

1. 调整Space绘制逻辑

保持Space的render方法签名不变,让它只按**本地坐标系(0,0 → 100,100)**绘制内容,无需关心实际屏幕位置:

class Space
{
     // ...
public:
     virtual void render(QPainter *painter);
};

2. 实现Board的坐标变换与绘制分发

在Board的render方法中,遍历所有Space,计算每个Space对应的屏幕矩形,通过QPainter的坐标变换将本地坐标系映射到屏幕区域,复用同一个QPainter实例完成绘制:

void Board::render(QPainter *painter)
{
    // 示例:每个Space在屏幕上的实际尺寸,可根据需求动态调整
    const int tileScreenSize = 60;
    const int rowCount = mLstBoard.size();
    if (rowCount == 0) return;
    const int colCount = mLstBoard.first().size();

    for (int row = 0; row < rowCount; ++row) {
        for (int col = 0; col < colCount; ++col) {
            // 计算当前Space的屏幕绘制区域
            QRect screenRect(col * tileScreenSize, row * tileScreenSize, 
                            tileScreenSize, tileScreenSize);
            
            // 保存当前Painter状态,避免变换影响后续绘制
            painter->save();

            // 坐标变换:平移到目标区域左上角 + 缩放适配屏幕尺寸
            painter->translate(screenRect.topLeft());
            painter->scale(static_cast<qreal>(screenRect.width()) / 100.0,
                          static_cast<qreal>(screenRect.height()) / 100.0);

            // 调用Space的render,此时它的(0,0)对应屏幕区域的左上角
            mLstBoard[row][col].render(painter);

            // 恢复Painter原始状态
            painter->restore();
        }
    }
}

3. GamePanel的绘制入口

在GamePanel中重写paintEvent,创建QPainter并传递给Board的render方法:

void GamePanel::paintEvent(QPaintEvent *event)
{
    QPainter painter(this);
    // 可在此绘制棋盘背景等全局元素
    if (mBoard) {
        mBoard->render(&painter);
    }
}

核心优势

  • 复用QPainter:全程使用同一个实例,通过save()/restore()隔离每个Space的绘制状态,避免资源浪费与状态污染。
  • 解耦绘制逻辑:Space只需关注自身本地坐标系内的绘制,无需适配屏幕尺寸;调整棋盘布局或Space大小只需修改Board中的屏幕区域计算逻辑。
  • 扩展性强:后续支持不同大小的Space、棋盘缩放等需求时,无需修改Space的绘制代码。

内容的提问来源于stack exchange,提问作者Seth D. Fulmer

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.13 11:25:02