【问题标题】:Sprites not drawing in SFML - Being stored and retrieved from a vector未在 SFML 中绘制的精灵 - 从矢量中存储和检索
【发布时间】:2013-12-30 10:58:03
【问题描述】:

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

我实现子弹的想法是有一个以下结构的向量:

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

每次用户按键时都会将这个结构的新实例添加到向量中。我的想法是可以更新向量中每个对象的帧值,然后我可以使用 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;
}

【问题讨论】:

标签: c++ vector sfml


【解决方案1】:

我不能完全确定问题出在哪里,但我认为有几件事是有问题的:

为了简短起见,我删掉了一点:

void shoot(sf::Texture texture) { //creates a copy of your texture you pass

bulletSprite.setTexture(texture); //actually takes the address of your texture 

(setTexture(sf::Texture&)) <-- that's how the method probably looks like


onScreenBullets.push_back(newBullet); // I think this is okay since newBullet is bein copied into the vector so when the object runs out of scope it doesn't matter but

// here your texture object is gone now and the address your Sprite holds is not valid anymore
}

哎呀,

拍摄方法是问题

    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. 您的 intersects 方法可能已损坏,您只需立即擦除子弹(将其注释掉以查看子弹飞)

  3. 总的来说,你复制了很多子弹对象之类的东西。我认为您正在从事一些需要更基本了解的事情。对不起;x

【讨论】:

  • 我会尝试通过引用函数来传递纹理。
  • 这是个好主意 ;) 因为你已经在上面了,所以也传递了“战斗机”精灵作为参考(不需要每次都复制它;))
  • 没有区别。
  • 你的 onScreenBullets 在添加了一个镜头后仍然是空的 我想找出原因 ;)
  • 啊,你是对的;这是因为我正在创建一个全新的精灵,而不是在结构中调用精灵上的方法。谢谢
猜你喜欢
  • 1970-01-01
  • 2013-05-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-08-19
  • 2023-03-19
  • 2019-03-10
  • 1970-01-01
相关资源
最近更新 更多