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

如何将三个方形Sprite组合为立方体并实现平滑移动?

问题描述

我希望通过组合三个Sprite(其中两个经过剪切和缩放变换)来实现如下立方体效果:
立方体效果

我已实现剪切变换函数:

sf::Transform createShearTransform(float shearX, float shearY) {
    sf::Transform transform;
    transform = sf::Transform(
        1, shearX, 0.f,
        shearY, 1, 0.f,
        0.f, 0.f, 1.f
    );
    return transform;
}

但无法完成预期效果,也没法让整个立方体平滑移动,以下是我的代码:

#include <SFML/Graphics.hpp>

sf::Transform createShearTransform(float shearX, float shearY) {

    sf::Transform transform;
    transform = sf::Transform(
        1, shearX, 0.f,
        shearY, 1, 0.f,
        0.f, 0.f, 1.f
    );
    return transform;
}

int main() {
    sf::Texture texture; texture.loadFromFile("tex.png");
    sf::Sprite front(texture);
    sf::Sprite top(texture);
    sf::Sprite right(texture);

    float offset = 64 + 32;
    float size = 64;

    top  .setPosition({ offset       , offset        });
    front.setPosition({ offset       , offset + size });
    right.setPosition({ offset + size, offset + size });

    sf::Transform shear1 = createShearTransform(-1, 0);
    sf::Transform shear2 = createShearTransform(0, -1);
    sf::RenderWindow window( sf::VideoMode(800, 800), "" );
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        auto mousepos = sf::Vector2f(sf::Mouse::getPosition(window));
        front.setPosition(mousepos);
        right.setPosition(mousepos);
        top.setPosition(mousepos);

        window.clear();
        window.draw(front);
        sf::Transform f1;
        f1.translate({ 64, -128 });
        sf::Transform s1;
        s1.scale({ 1, 0.75 });
        sf::Transform s2;
        s2.scale({ 0.75 , 1 });
        sf::Transform f2;
        f2.translate({ 16, -60 });
        window.draw(top, f1 * top.getTransform() * shear1 * s1);
        window.draw(right, f2 * right.getTransform() * shear2 * s2);
        window.display();
    }
}
解决方案

核心问题在于变换顺序错误和各面未绑定统一基准点。SFML变换是右结合的,且要实现整体移动,所有面必须基于同一个中心位置计算偏移。以下是修正后的代码:

#include <SFML/Graphics.hpp>

sf::Transform createShearTransform(float shearX, float shearY) {
    sf::Transform transform;
    transform = sf::Transform(
        1, shearX, 0.f,
        shearY, 1, 0.f,
        0.f, 0.f, 1.f
    );
    return transform;
}

int main() {
    sf::Texture texture;
    if (!texture.loadFromFile("tex.png")) {
        // 纹理加载失败处理
        return 1;
    }
    sf::Sprite front(texture);
    sf::Sprite top(texture);
    sf::Sprite right(texture);

    const float cubeSize = 64.f;
    // 将所有Sprite原点设为中心,简化变换与定位逻辑
    front.setOrigin(cubeSize / 2, cubeSize / 2);
    top.setOrigin(cubeSize / 2, cubeSize / 2);
    right.setOrigin(cubeSize / 2, cubeSize / 2);

    // 预定义顶面和右侧面的固定变换(缩放→剪切,符合SFML右结合顺序)
    const sf::Transform topTransform = createShearTransform(-1.f, 0.f) * sf::Transform().scale(1.f, 0.75f);
    const sf::Transform rightTransform = createShearTransform(0.f, -1.f) * sf::Transform().scale(0.75f, 1.f);

    sf::RenderWindow window(sf::VideoMode(800, 800), "SFML Cube");
    while (window.isOpen()) {
        sf::Event event;
        while (window.pollEvent(event)) {
            if (event.type == sf::Event::Closed)
                window.close();
        }

        // 以鼠标位置作为立方体的中心基准点
        sf::Vector2f cubeCenter = sf::Vector2f(sf::Mouse::getPosition(window));

        window.clear();

        // 绘制正面:直接定位到中心
        front.setPosition(cubeCenter);
        window.draw(front);

        // 绘制顶面:基于中心向上偏移,应用预定义变换
        top.setPosition(cubeCenter + sf::Vector2f(0.f, -cubeSize * 0.75f));
        window.draw(top, topTransform);

        // 绘制右侧面:基于中心向右偏移,应用预定义变换
        right.setPosition(cubeCenter + sf::Vector2f(cubeSize * 0.75f, 0.f));
        window.draw(right, rightTransform);

        window.display();
    }
    return 0;
}

关键修正说明

  • 原点设置:将Sprite原点设为纹理中心,避免变换时出现非预期偏移,让定位逻辑更直观。
  • 变换顺序:SFML变换组合遵循右结合规则,正确顺序为缩放 → 剪切,确保形变符合立方体面的透视逻辑。
  • 统一基准点:所有面的位置都基于立方体中心(鼠标位置)计算偏移,保证整体移动时同步。
  • 层级绘制:先绘制正面,再绘制顶面和右侧面,保证正确的遮挡关系。

内容的提问来源于stack exchange,提问作者Signup Thanks

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 09:34:57