Reputation: 713
I currently have a projectile firing from a tank. At the moment it works just fine, but I am unable to "re-use" projectiles once they have either hit their target, or gone off the screen. This is the code I am using at the moment;
//Laser Shape
sf::Texture LaserTexture;
LaserTexture.loadFromFile("images/laser.png");
std::vector<sf::Sprite>Laser(1000, sf::Sprite(LaserTexture));
This is my if statement for when the keyboard is pressed:
if (Event.key.code == sf::Keyboard::Space)
{
if (laserCount==1000)
{
laserCount=0;
}
/*if (sf::Keyboard::isKeyPressed(sf::Keyboard::Space))
{
}*/
laserSpeed=4;
laserCount++;
laser.play();
std::cout << "laser count = " << laserCount << std::endl;
}
And my clock counter for actually firing the missile:
static float laserTimer =0.0;
laserTimer+=Clock.getElapsedTime().asSeconds();
if (laserTimer<Ldelay)
{
laserTimer = 3;
}
else {
laserTimer = 0;
}
for (int i = 0; i < laserCount; i++)
{
Laser[i].move(0, -laserSpeed);
}
This is a very bad way of doing it and is poorly optimised, and I know this. Originally I tried to only have 50 projectiles in my vector, and when they reach the top of the screen or hits their target, they go back to the tank. This didn't work, at all... Even if I set them relative to the tank they would just appear at the side of the screen and carry on firing.
for (int i=0; i<laserCount; i++)
{
if (Laser[i].getPosition().y==0)
{
Laser[i].setPosition(xTank, yTank);
laserSpeed=0;
}
}
This would put the laser at the side of the screen (Even though the tank was at the middle of the screen). I tried it with an actual position (300,200) but this just gave the same issue, and all the other sprites on the screen would just freeze.
I just don't want to have unnecessary amounts of sprites when frankly they just aren't needed!
Upvotes: 1
Views: 2005
Reputation:
Why do you want to reuse particles? You can simply remove them from the list once they have gone off the screen or hit a target. If you want to limit the amount of particles, a shoot timer would do just that. The way you're doing it, there are always 1000 objects, and they are loaded whether or not you use them. That just isn't very efficient.
Since I am more versed in C# and XNA than in SFML, I will use C# code, but you should be able to apply the same concepts.
// global variables
List<Particle> particles = new List<Particle>(); // empty list
KeyboardState oldKeyState;
float shootTimer = 0.0f;
bool justShot = false;
// ... in update function
float elapsed = (float)gameTime.ElapsedGameTime.TotalSeconds; // delta time
KeyboardState curKeyState = Keyboard.GetState();
// Don't let the user hold down the space key. Has to tap it.
if (curKeyState.isKeyDown(Keys.Space) && oldKeyState.isKeyUp(Keys.Space))
{
if (!justShot)
{
particles.Add(new Particle(tank.Position));
justShot = true;
}
}
if (justShot)
{
if (shotTimer < shotDelay)
{
shotTimer += elapsed; // in seconds
} else { justShot = false; shotTimer = 0; }
}
for (int i = 0; i < particles.Count; i++)
{
particles[i].update();
// if (collision or past end of screen)
particles.remove(particles[i]); // one way
particles[i].active = false; // another way
}
oldKeyState = curKeyState;
This way, you are only using as many particles as is constrained by your game logic. Note that is is kind of pseudo-code. Of course you would put this code in your update/main game loop. Adapt it as you wish.
edit
Remove this --> (1000, sf::Sprite(LaserTexture))
That way you have an empty vector. Whenever you need to add particles, use push_back.
An example of a particle class in C#:
class Particle
{
public Particle(Texture2D texture, Vector2 position) {
Texture = texture;
Position = position;
}
public Texture2D Texture;
public Vector2 Position;
public void Update(GameTime gameTime) {
// get delta time here
Position += new Vector2(speedX, speedY) * elapsed;
}
}
Upvotes: 2