c++ - 不在 SFML 中绘制的 Sprite - 从 vector 中存储和检索

标签 c++ vector sfml

我正在使用 SFML 制作一个有趣的滚动空间射击游戏。

我实现项目符号的想法是使用以下结构的 vector :

struct bullet
{
    sf::Sprite sprite;
    char frame;
};

每次用户按下一个键时,都会将这个结构的一个新实例添加到一个 vector 中。我的想法是可以更新 vector 中每个对象的帧值,然后我可以使用 switch 语句根据每个弹丸在动画序列中的移动距离来更改应用于每个弹丸的 textureRect。

然而,这是行不通的,当按下空格键时,什么也不会绘制。正在触发事件,但由于没有错误,我无法弄清楚问题出在哪里。其他一切都完美无缺。

拍摄功能:

void shoot(sf::Texture texture, std::vector<bullet>& onScreenBullets, sf::Sprite fighter)
{
    bullet newBullet;
    sf::Sprite bulletSprite = newBullet.sprite;
    bulletSprite.setTexture(texture);
    bulletSprite.setTextureRect(sf::IntRect(48,0,4,4));
    bulletSprite.setPosition(fighter.getPosition().x + 6, fighter.getPosition().y + 6);
    newBullet.frame = 0;
    onScreenBullets.push_back(newBullet);
}

函数调用:

while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
            {
                window.close();
            }

            if(event.type == sf::Event::KeyPressed)
            {
                if(event.key.code == sf::Keyboard::Return && play == false)
                {
                    play = true;
                    clock.restart();
                }

                if(event.key.code == sf::Keyboard::Space && play == true)
                {
                    shoot(texture,onScreenBullets,fighter);
                }
            }
        }

弹射物动画逻辑:

for(int i = 0; i < onScreenBullets.size(); i++)
            {
                currentBullet = onScreenBullets.at(i).sprite;
                switch(onScreenBullets[i].frame)
                {
                    case 0:
                        currentBullet.setTextureRect(sf::IntRect(48,4,4,8));
                        break;
                    case 15:
                        currentBullet.setTextureRect(sf::IntRect(48,12,4,8));
                        break;
                    case 30:
                        currentBullet.setTextureRect(sf::IntRect(48,4,4,8));
                        break;
                    case 45:
                        currentBullet.setTextureRect(sf::IntRect(48,12,4,8));
                        break;
                    case 60:
                        onScreenBullets.at(i).frame = 0;
                        break;
                }

                currentBullet.move(0, -1*(projectileSpeed + scrollSpeed));
                window.draw(currentBullet);
                onScreenBullets.at(i).frame++;

                if(!currentView.intersects(currentBullet.getGlobalBounds()));
                {
                    onScreenBullets.erase(onScreenBullets.begin() + i);
                }
            }

完整来源:

#include<SFML/Graphics.hpp>
#include<iostream>
#include<string>
#include<vector>

void rollLeft(sf::Sprite& s, sf::RenderWindow& rw, int frame, char& rollDir, bool& rstatus)
{
    switch(frame)
    {
        case 0:
            s.setTextureRect(sf::IntRect(32,0,8,16));
            s.move(sf::Vector2f(-32.0f,0.0f));
            rw.draw(s);
            rw.display();
            break;

        case 4:
            s.setTextureRect(sf::IntRect(16,0,16,16));
            s.move(sf::Vector2f(-64.0f,0.0f));
            rw.draw(s);
            rw.display();
            break;

        case 8:
            s.setTextureRect(sf::IntRect(40,0,8,16));
            s.move(sf::Vector2f(-32.0f,0.0f));
            rw.draw(s);
            rw.display();
            break;

        case 12:
            s.setTextureRect(sf::IntRect(0,0,16,16));
            s.move(sf::Vector2f(-64.0f,0.0f));
            rw.draw(s);
            rw.display();
            rollDir = 'N';
            rstatus = false;
            break;

        default:
            break;
    }
}

void rollRight(sf::Sprite& s, sf::RenderWindow& rw, int frame, char& rollDir, bool& rstatus)
{
    switch(frame)
    {
        case 0:
            s.setTextureRect(sf::IntRect(40,0,8,16));
            s.move(sf::Vector2f(32.0f,0.0f));
            rw.draw(s);
            rw.display();
            break;

        case 4:
            s.setTextureRect(sf::IntRect(16,0,16,16));
            s.move(sf::Vector2f(64.0f,0.0f));
            rw.draw(s);
            rw.display();
            break;

        case 8:
            s.setTextureRect(sf::IntRect(32,0,8,16));
            s.move(sf::Vector2f(32.0f,0.0f));
            rw.draw(s);
            rw.display();
            break;

        case 12:
            s.setTextureRect(sf::IntRect(0,0,16,16));
            s.move(sf::Vector2f(64.0f,0.0f));
            rw.draw(s);
            rw.display();
            rollDir = 'N';
            rstatus = false;
            break;

        default:
            break;
    }
}

void init(sf::Text& text,sf::Sprite& fighter,sf::Sprite& barLeft,sf::Sprite&     barMiddle,sf::Sprite& barRight,sf::Sprite& marker,sf::RectangleShape& background1,
            sf::RectangleShape& background2,sf::View& view,sf::RenderWindow& window)
{
    text.setPosition(20,240);
    fighter.setPosition(304,448);
    barLeft.setPosition(72,10);
    barMiddle.setPosition(80,10);
    barRight.setPosition(560,10);
    marker.setPosition(88,10);
    background1.setPosition(0,0);
    background2.setPosition(0,-480);
    view.setCenter(320,240);
    window.setView(view);
             }

struct bullet
{
    sf::Sprite sprite;
    char frame;
};

void shoot(sf::Texture texture, std::vector<bullet>& onScreenBullets, sf::Sprite fighter)
{
    bullet newBullet;
    sf::Sprite bulletSprite = newBullet.sprite;
    bulletSprite.setTexture(texture);
    bulletSprite.setTextureRect(sf::IntRect(48,0,4,4));
    bulletSprite.setPosition(fighter.getPosition().x + 6, fighter.getPosition().y + 6);
    newBullet.frame = 0;
    onScreenBullets.push_back(newBullet);
}

int main()
{
    int frame = 0;
    char rollDir = 'N';
    bool roll,move,play,activeBackground = false;
    int timeLimit = 10000;
    int scrollSpeed = 2;
    int projectileSpeed = 5;
    std::vector<bullet> onScreenBullets;
    sf::Sprite currentBullet;
    sf::FloatRect currentView;

    sf::Time time;
    int timeInt;
    sf::Clock clock;

    sf::RenderWindow window(sf::VideoMode(640,480), "Test Window");
    window.setFramerateLimit(60);

    sf::Texture texture;
    if(!texture.loadFromFile("spritesheet.png"))
    {
        std::cout << "Error loading texture from file";
    }

    sf::Font font;
    if(!font.loadFromFile("font.ttf"))
    {
        std::cout << "Error loading font from file";
     }

    sf::Text text;
    text.setFont(font);
    text.setString("Press ENTER to start");
    text.setCharacterSize(24);
    text.setColor(sf::Color::White);

    sf::Sprite fighter;
    fighter.setTexture(texture);
    fighter.setTextureRect(sf::IntRect(0,0,16,16));
    fighter.setScale(sf::Vector2f(2,2));

    sf::Sprite barLeft,barRight,barMiddle;
    barLeft.setTexture(texture);
    barRight.setTexture(texture);
    barMiddle.setTexture(texture);

    barLeft.setTextureRect(sf::IntRect(0,16,8,16));
    barRight.setTextureRect(sf::IntRect(39,16,8,16));
    barMiddle.setTextureRect(sf::IntRect(9,16,30,16));

    barMiddle.setScale(sf::Vector2f(16,1));

    sf::Sprite marker;
    marker.setTexture(texture);
    marker.setTextureRect(sf::IntRect(0,0,16,16));
    marker.setRotation(90);

    sf::RectangleShape background1(sf::Vector2f(640,480));
    background1.setTexture(&texture);
    background1.setTextureRect(sf::IntRect(0,32,640,480));

    sf::RectangleShape background2(sf::Vector2f(640,480));
    background2.setTexture(&texture);
    background2.setTextureRect(sf::IntRect(0,32,640,480));

    sf::View view(sf::FloatRect(0,0,640,480));
    window.setView(view);

    while(window.isOpen())
    {
        sf::Event event;
        while(window.pollEvent(event))
        {
            if(event.type == sf::Event::Closed)
            {
                window.close();
            }

            if(event.type == sf::Event::KeyPressed)
            {
                if(event.key.code == sf::Keyboard::Return && play == false)
                {
                    play = true;
                    clock.restart();
                }

                if(event.key.code == sf::Keyboard::Space && play == true)
                {
                    shoot(texture,onScreenBullets,fighter);
                }
            }
        }

        if(!play)
        {
            window.clear(sf::Color::Black);
            window.draw(text);
                init(text,fighter,barLeft,barMiddle,barRight,marker,background1,background2,view,window);
            window.display();
        }

        if(play)
        {

            move = false;

            if(!roll)
            {
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                {
                    fighter.move(sf::Vector2f(0.0f,-4.0f));
                    move = true;
                }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                {
                    fighter.move(sf::Vector2f(0.0f,4.0f));
                    move = true;
                }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                {
                    fighter.move(sf::Vector2f(-4.0f,0.0f));
                    move = true;
                }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                {
                    fighter.move(sf::Vector2f(4.0f,0.0f));
                    move = true;
                }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::A) &&     sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) && rollDir == 'N')
                {
                    frame = 0;
                    rollDir = 'L';
                    roll = true;
                }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::D) &&     sf::Keyboard::isKeyPressed(sf::Keyboard::LShift) && rollDir == 'N')
                {
                    frame = 0;
                    rollDir = 'R';
                    roll = true;
                }
            }

            switch(rollDir)
            {
                case 'L':
                    rollLeft(fighter,window,frame,rollDir,roll);
                    break;

                case 'R':
                    rollRight(fighter,window,frame,rollDir,roll);
                    break;
            }

            window.clear(sf::Color::Black);
            window.draw(background1);
            window.draw(background2);

            time = clock.getElapsedTime();
            timeInt = time.asMilliseconds();

            view.move(0,-1*scrollSpeed);
            window.setView(view);

            fighter.move(0,-1*scrollSpeed);
            window.draw(fighter);

            currentView.left = view.getCenter().x - view.getSize().x / 2;
            currentView.top = view.getCenter().y - view.getSize().y / 2;
            currentView.width = view.getSize().x;
            currentView.height = view.getSize().y;

            for(int i = 0; i < onScreenBullets.size(); i++)
            {
                currentBullet = onScreenBullets.at(i).sprite;
                switch(onScreenBullets[i].frame)
                {
                    case 0:
                        currentBullet.setTextureRect(sf::IntRect(48,4,4,8));
                        break;
                    case 15:
                        currentBullet.setTextureRect(sf::IntRect(48,12,4,8));
                        break;
                    case 30:
                        currentBullet.setTextureRect(sf::IntRect(48,4,4,8));
                        break;
                    case 45:
                        currentBullet.setTextureRect(sf::IntRect(48,12,4,8));
                        break;
                    case 60:
                        onScreenBullets.at(i).frame = 0;
                        break;
                }

                currentBullet.move(0, -1*(projectileSpeed + scrollSpeed));
                window.draw(currentBullet);
                onScreenBullets.at(i).frame++;

                if(!currentView.intersects(currentBullet.getGlobalBounds()));
                {
                    onScreenBullets.erase(onScreenBullets.begin() + i);
                }
            }

            barLeft.move(0,-1*scrollSpeed);
            barRight.move(0,-1*scrollSpeed);
            barMiddle.move(0,-1*scrollSpeed);
            window.draw(barLeft);
            window.draw(barRight);
            window.draw(barMiddle);

            if(int (view.getCenter().y - 240) % 480 == 0)
            {
                if(!activeBackground)
                {
                    activeBackground = true;
                    background1.move(0,-960);
                } else {
                    activeBackground = false;
                    background2.move(0,-960);
                }
            }

            marker.move(480.0f/(timeLimit/1000)/60,-1*scrollSpeed);
            window.draw(marker);

            text.move(0,-1*scrollSpeed);

            if(timeInt >= timeLimit+250)
            {
                play = false;
                text.setString("End");
            }

            window.display();
            frame++;
        }
    }
    return 0;
}

最佳答案

我不能完全确定问题出在哪里,但我认为有一些问题:

为了缩短这段时间,我删除了一点:

void shoot(sf::Texture texture) {//创建您传递的纹理的拷贝

bulletSprite.setTexture(纹理);//实际上获取了你的纹理的地址

(setTexture(sf::Texture&)) <-- 这就是该方法的样子


onScreenBullets.push_back(newBullet);//我认为这没问题,因为 newBullet 被复制到 vector 中,所以当对象超出范围时,这无关紧要,但是

//这里你的纹理对象现在不见了,你的 Sprite 持有的地址不再有效
}

好的,

拍摄方式有问题

    void shoot(sf::Texture& texture, std::vector<bullet>& onScreenBullets, sf::Sprite& fighter)
    {
        bullet newBullet;
        sf::Sprite bulletSprite = newBullet.sprite; // this makes no sense
        bulletSprite.setTexture(texture); // you set the texture to the local Sprite object
        bulletSprite.setTextureRect(sf::IntRect(48,0,4,4)); // and this as well and the next line as well
        bulletSprite.setPosition(fighter.getPosition().x + 6, fighter.getPosition().y + 6);
        newBullet.frame = 0;
        onScreenBullets.push_back(newBullet); //but here you push back your struct and the sprite in the struct
//That you haven't used at all :O
}

做这样的事情:

void shoot(sf::Texture& texture, std::vector<bullet>& onScreenBullets, sf::Sprite& fighter)
    {
bullet newBullet;
newBullet.sprite.setTexture(texture);
newBullet.sprite.setTextureRect(sf::IntRect(48,0,4,4));
newBullet.sprite.setPosition(fighter.getPosition().x + 6, fighter.getPosition().y - 6);
// btw. above your "fighter" the y-position is lower so if the bullet is supposed to spawn above your fighter you have to go -6 and then keep subtracting from y to make it go up
newBullet.frame = 0;
onScreenBullets.push_back(newBullet);
}

setTexture方法: http://sfml-dev.org/documentation/2.0/classsf_1_1Sprite.php#a3729c88d88ac38c19317c18e87242560

其他一些人认为我注意到了:

  1. 将结构中的“框架”设为 int(它不适用于 char)

  2. 您的相交方法可能已损坏,您只需立即删除子弹即可(将其注释掉以查看子弹飞行)

  3. 总的来说,你复制了很多项目符号对象之类的东西。我认为您正在做一些需要更基本的了解的事情。抱歉;x

关于c++ - 不在 SFML 中绘制的 Sprite - 从 vector 中存储和检索,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20838115/

相关文章:

c++ - vector 插入和分配之间的区别

c++ - 在 VS2017 中使用 SFML 安装 CMake

c++ - SFML如何使形状移动到特定点

c++ - 使用CMake和GCC(MacOS Sierra)进行编译时找不到SFML header

c++ - 使用 this->,::and ordering members 会提高编译速度吗?

c++ - 如何在 C++ 中声明 wchar_t[] 的 vector ?

c++ - 如何递归查找最大数组元素的索引

c++将 vector 指针分配给 vector 指针的映射

c++ - 如何在不更改其他 channel 的情况下有效地将 cv::Mat 的给定 channel 设置为给定值?

c++ - 使用我的 DLL 的应用程序中新建/删除的奇怪问题