我正在使用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;
}
答案 0 :(得分: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) { //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
}
Ooookay,
拍摄方法是问题
做这样的事情:
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
}
setTexture方法: http://sfml-dev.org/documentation/2.0/classsf_1_1Sprite.php#a3729c88d88ac38c19317c18e87242560
其他一些人认为我注意到了:
使结构中的“框架”成为一个int(它不能用于char)
您的交叉方法可能已被破坏,您只需立即擦除子弹(注释掉它以查看子弹飞行)
总的来说,你经常复制子弹对象和类似的东西。我认为你需要更基本的理解。对不起; x