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

如何在SFML中生成无重叠的随机平台?——Doodle Jump类游戏开发

Fixing Platform Overlaps in Your SFML Doodle Jump Clone

Hey there! Nice start on your Doodle Jump-style game—three platform types is such a fun touch. The overlapping issue makes total sense right now because you’re generating positions completely randomly without checking if they clash with existing platforms. Let’s fix that with collision checks during spawn.

The Core Idea

Every time you generate a new platform’s position, you need to:

  • Calculate the bounding box of the new platform (accounting for its scaled Sprite size)
  • Check if this box overlaps with the bounding boxes of all previously generated platforms (regardless of type)
  • If it overlaps, generate a new position and repeat the check until you find a clear spot

Step 1: Add a Collision Check Helper Function

First, create a reusable function to check if two platforms overlap. This uses SFML’s FloatRect and intersects() method to handle the collision math for you:

#include <SFML/Graphics.hpp>
#include <cstdlib>
#include <ctime>

// Assuming your point struct looks like this:
struct point {
    int x, y;
};

bool doPlatformsOverlap(const point& pPos, const sf::Sprite& pSprite, const point& otherPos, const sf::Sprite& otherSprite) {
    // Calculate the actual bounds of each platform (accounting for scale)
    sf::FloatRect platformBounds(
        pPos.x, 
        pPos.y, 
        pSprite.getLocalBounds().width * pSprite.getScale().x, 
        pSprite.getLocalBounds().height * pSprite.getScale().y
    );
    sf::FloatRect otherPlatformBounds(
        otherPos.x, 
        otherPos.y, 
        otherSprite.getLocalBounds().width * otherSprite.getScale().x, 
        otherSprite.getLocalBounds().height * otherSprite.getScale().y
    );
    
    return platformBounds.intersects(otherPlatformBounds);
}

Step 2: Rewrite Platform Generation with Collision Checks

Modify your platform spawn loop to use the helper function and retry until a non-overlapping position is found. We’ll handle each platform type one by one, checking against all already spawned platforms:

int main() { 
    srand(time(NULL)); 
    sf::RenderWindow app(sf::VideoMode(600, 600), "Doodle Game!"); 
    app.setFramerateLimit(60); 

    sf::Texture t1,t2,t3,t4,t5; 
    t1.loadFromFile("4.png"); 
    t2.loadFromFile("platform.png"); 
    t3.loadFromFile("cartoon.png"); 
    t4.loadFromFile("rock.png"); 
    t5.loadFromFile("wood.png"); 

    sf::Sprite sBackground(t1), sPlat(t2), sPlat1(t4), sPlat2(t5), sPers(t3); 
    sPers.setScale(0.3f, 0.3f); 
    sPlat.setScale(0.06f, 0.06f); 
    sPlat1.setScale(0.06f, 0.06f); 
    sPlat2.setScale(0.06f, 0.06f); 

    point plat[20]; 
    point plat1[20]; 
    point plat2[20]; 

    // Generate regular platforms first
    for (int i=0;i<10;i++) { 
        bool isOverlapping = true;
        while (isOverlapping) {
            // Generate a new random position
            plat[i].x = rand() % 600; 
            plat[i].y = rand() % 600; 
            isOverlapping = false;

            // Check against all previously spawned regular platforms
            for (int j = 0; j < i; j++) {
                if (doPlatformsOverlap(plat[i], sPlat, plat[j], sPlat)) {
                    isOverlapping = true;
                    break; // No need to check further—we found an overlap
                }
            }
        }
    }

    // Generate rock platforms (check against regular platforms and previous rocks)
    for (int i=0;i<10;i++) { 
        bool isOverlapping = true;
        while (isOverlapping) {
            plat1[i].x = rand() % 600; 
            plat1[i].y = rand() % 600; 
            isOverlapping = false;

            // Check against regular platforms
            for (int j = 0; j < 10; j++) {
                if (doPlatformsOverlap(plat1[i], sPlat1, plat[j], sPlat)) {
                    isOverlapping = true;
                    break;
                }
            }

            // If no overlap with regulars, check against previous rocks
            if (!isOverlapping) {
                for (int j = 0; j < i; j++) {
                    if (doPlatformsOverlap(plat1[i], sPlat1, plat1[j], sPlat1)) {
                        isOverlapping = true;
                        break;
                    }
                }
            }
        }
    }

    // Generate wood platforms (check against regular, rocks, and previous woods)
    for (int i=0;i<10;i++) { 
        bool isOverlapping = true;
        while (isOverlapping) {
            plat2[i].x = rand() % 600; 
            plat2[i].y = rand() % 600; 
            isOverlapping = false;

            // Check against regular platforms
            for (int j = 0; j < 10; j++) {
                if (doPlatformsOverlap(plat2[i], sPlat2, plat[j], sPlat)) {
                    isOverlapping = true;
                    break;
                }
            }

            // Check against rock platforms
            if (!isOverlapping) {
                for (int j = 0; j < 10; j++) {
                    if (doPlatformsOverlap(plat2[i], sPlat2, plat1[j], sPlat1)) {
                        isOverlapping = true;
                        break;
                    }
                }
            }

            // Check against previous wood platforms
            if (!isOverlapping) {
                for (int j = 0; j < i; j++) {
                    if (doPlatformsOverlap(plat2[i], sPlat2, plat2[j], sPlat2)) {
                        isOverlapping = true;
                        break;
                    }
                }
            }
        }
    }

    // Rest of your game loop goes here...
    while (app.isOpen()) {
        sf::Event e;
        while (app.pollEvent(e)) {
            if (e.type == sf::Event::Closed)
                app.close();
        }

        app.clear();
        app.draw(sBackground);
        // Draw all platforms and player here
        app.display();
    }

    return 0;
}

Optional: Clean Up with a Platform Container

For even cleaner code (especially if you add more platform types later), you could store all platforms in a single vector of a custom struct. This way you only need one check loop instead of multiple:

struct Platform {
    point pos;
    sf::Sprite sprite;
};

std::vector<Platform> allPlatforms;

// When spawning a new platform:
bool isOverlapping;
do {
    isOverlapping = false;
    Platform newPlat;
    newPlat.pos.x = rand() % 600;
    newPlat.pos.y = rand() % 600;
    newPlat.sprite = sPlat; // Or whichever sprite type you need

    // Check against all existing platforms
    for (const auto& plat : allPlatforms) {
        if (doPlatformsOverlap(newPlat.pos, newPlat.sprite, plat.pos, plat.sprite)) {
            isOverlapping = true;
            break;
        }
    }

    if (!isOverlapping) {
        allPlatforms.push_back(newPlat);
    }
} while (isOverlapping);

This approach keeps your code scalable and easier to maintain as your game grows.

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 04:49:21