Bullet Doesen't Fire Correctly

Started by
9 comments, last by LeftyGuitar 7 years ago

Hello, I am trying to make it where you can shoot bullets, however, it only shoots one bullet. Also, you keep having to press down the space key in order to make

the bullet move. How do I make it so that I only need to press the spacebar once in order to make the bullet move on its own?


#include <iostream>
#include <vector>

#include <SFML\System.hpp>
#include <SFML\Graphics.hpp>

using namespace std;

sf::RenderWindow GameWin;
sf::Event event;

sf::RectangleShape bullet;
sf::RectangleShape rect;



bool GameRunning = true;
bool Fired = false;

typedef struct BULLET
{
	float x, y, speed;
};

BULLET gBullet;
vector <BULLET> bullets;

int main(int argc, char* argv[])
{
	GameWin.create(sf::VideoMode(800, 600), "Shooter");
	rect.setSize(sf::Vector2f(50, 50));
	rect.setPosition(sf::Vector2f(800 / 2, 600 / 2));
	rect.setFillColor(sf::Color(255, 0, 0));

	gBullet.x = 10.0f, gBullet.y = 10.0f;
	gBullet.speed = 3.0f;

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

			if (event.type == sf::Event::KeyPressed)
			{
				if (event.key.code == sf::Keyboard::Escape)
				{
					GameRunning = false;
					GameWin.close();
				}

				if (event.key.code == sf::Keyboard::Space)
				{
					Fired = true;
				}
			}

			if (Fired == true)
			{
				bullet.setSize(sf::Vector2f(10, 10));
				bullet.setFillColor(sf::Color(0, 255, 0));
				//bullet.setPosition(sf::Vector2f(gBullet.x, gBullet.y));
				bullet.move(gBullet.x * gBullet.speed, 0);

				bullets.push_back(gBullet);
			}
		}

		GameWin.clear();

		GameWin.draw(rect);

		if (Fired == true)
		{
			GameWin.draw(bullet);
		}

		GameWin.display();
	}

	return 0;
}
Advertisement

A few things come to mind. Does the fire boolean get flagged as false else where in this loop iteration? One change I can recommend is removing the bullet move code from that conditional, and instead when space is pressed add a bullet to the vector, and just have it;s move method called in the outer loop for all active bullets on screen. Maybe share your move method as well?

I removed a bit of your code just to highlight the important parts.

Something Like this (excuse the formatting):


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

			if (event.type == sf::Event::KeyPressed)
			{
				if (event.key.code == sf::Keyboard::Escape)
				{
					GameRunning = false;
					GameWin.close();
				}

				if (event.key.code == sf::Keyboard::Space)
				{
					Fired = true;
				}
			}

			if (Fired == true)
			{
			     bullets.push_back(new bullet());
			}
		}
              
                //for all active bullets, move
                for (int i = 0; i < bullets.size(); i++) bullets.at(i)->move(gBullet.x * gBullet.speed, 0);
        }
                

Once the bullet passes past some arbitrary boundary you could then remove it.

Marcus Hansen

Where is the loop that runs over the'bullets' vector and moves all bullets that you created? Likely you also need to deal with bullets that fly out the game play area, and remove them from 'bullets'.

Also, where is 'Fired' ever reset to false?

Edit: Ninja-ed

Bah! Your response was 3x more concise. That deserves +1.

Well I'm just trying to get it to fire a bullet. Getting it to be able to fire multiple bullets would be nice, but I seem to be having trouble with just firing one bullet. I tried this code, but it still didn't work correctly. The bullet just stays there idle. Is there a better way of making a bullet class or struct?


//set initial position of bullet
gBullet.x = rect.getPosition().x, gBullet.y = rect.getPosition().y;
	gBullet.speed = 0.0f;

//update the bullet
if (Fired == true)
			{
				bullet.setSize(sf::Vector2f(10, 10));
				bullet.setFillColor(sf::Color(0, 255, 0));
				bullet.setPosition(rect.getPosition().x, rect.getPosition().y);
				
				gBullet.speed = 30.0f;
				gBullet.x = gBullet.speed;

				bullet.move(gBullet.x, 0);
			}
//draw the bullet
if (Fired == true)
		{
			GameWin.draw(bullet);
		}

This leads me to a few conclusions. One, that the "Fired" boolean is being tripped somewhere in your code, that we do not see, causing this code in the conditional to only get hit once by the instruction pointer, or that's not the case, and something is going with the move, or draw method, which again, we cannot see from the code provided.

You call setPosition(), but than follow that up with a method named move(). What's the difference between these methods? The names are practically analogous to one another making it difficult to discern what's actually going on with that projectile when your condition's body is hit. What does bullet.move do? Does it increment the bullets position? If so (and in the case this conditional is only called once, and promptly flipped back to false) you're going to want to find a way to move it from that if statement block.

To be honest this looks mostly like a flow control issue. You got the code, you got the methods/structures, now you have to debug. I'd advise stepping through your entire loop body in debug mode for several iterations, and see where your logic may have err'ed.

Marcus

OK, so I re-did the bullet code. However when I press the space key nothing comes up. Not sure if put the code in the wrong place or what. When I press the space key, it should fire a bullet and go off the screen, however, no bullet appears.


#include <iostream>
#include <vector>

#include <SFML\System.hpp>
#include <SFML\Graphics.hpp>

#define MAX_BULLETS 100

using namespace std;

sf::RenderWindow GameWin;
sf::Event event;

sf::RectangleShape bullet;
sf::RectangleShape rect;

bool GameRunning = true;
bool Fired = false;

typedef struct BULLET
{
	float x, y,speed;
	struct BULLET *next;
} BULLET;

BULLET* bullets[MAX_BULLETS] = { NULL };

void addBullet(float x, float y, float speed)
{
	int found = -1;
	for (int i = 0; i < MAX_BULLETS; i++)
	{
		if (bullets[i] == NULL)
		{
			found = i;
			break;
		}
	}

	if (found >= 0)
	{
		int i = found;
		bullets[i] = (BULLET*)malloc(sizeof(BULLET));
		bullets[i]->x = x;
		bullets[i]->y = y;
		bullets[i]->speed = speed;
	}
}

void removebullet(int i)
{
	if (bullets[i])
	{
		free(bullets[i]);
		bullets[i] = NULL;
	}
}

int main(int argc, char* argv[])
{
	GameWin.create(sf::VideoMode(800, 600), "Shooter");
	rect.setSize(sf::Vector2f(50, 50));
	rect.setPosition(sf::Vector2f(800 / 2, 600 / 2));
	rect.setFillColor(sf::Color(255, 0, 0));

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

			if (event.type == sf::Event::KeyPressed)
			{
				if (event.key.code == sf::Keyboard::Escape)
				{
					GameRunning = false;
					GameWin.close();
				}

				if (event.type == sf::Keyboard::Space)
				{
					addBullet(rect.getPosition().x + 35, rect.getPosition().y + 20, 3);
					bullet.setFillColor(sf::Color(0, 255, 0));
				}
			}	

			for (int i = 0; i < MAX_BULLETS; i++) if (bullets[i])
			{
				bullets[i]->x += bullets[i]->speed;

				if (bullets[i]->x < -100 || bullets[i]->x > 100)
				{
					removebullet(i);
				}
			}
		}

		GameWin.clear();

		GameWin.draw(rect);

		for (int i = 0; i < MAX_BULLETS; i++) if (bullets[i])
		{
			bullet.setPosition(sf::Vector2f(bullets[i]->x, bullets[i]->y));
			GameWin.draw(bullet);
		}

		GameWin.display();
	}

	for (int i = 0; i < MAX_BULLETS; i++)
	{
		removebullet(i);
	}

	return 0;
}

If you shorten your code by taking out the details, you get this:


    while (GameRunning)
    {
        while (GameWin.pollEvent(event))
        {
            /* some event handling for keys */

            /* move bullets (and remove them) */
        }

        GameWin.clear();
        GameWin.draw(rect);

        /* draw bullets at current position */

        GameWin.display();
    }

You move bullets inside the "pollEvent" loop. That loop only runs when there is input (keybaord, mouse, etc). See also https://www.sfml-dev.org/documentation/2.4.2/classsf_1_1Window.php#a338e996585faf82e93069858e3b531b7

In other words, if you press space, and then do nothing and watch the screen, the "pollEvent" constantly returns false, the "move bullet" code is never run, and instead, it draws the bullets at the same position forever!

The code looks very C-ish, I would recommend cleaning it all up to C++ standard, as that's much cleaner and safer (no malloc/free but new/delete, no typedef struct (not needed at all), no struct but class with a proper constructor, no bare pointers but std::unique_ptr, would be a good start). Also, you can move separate code to functions, so the main loop is easier to read.

I did figure this problem out. I wasn't updating the bullet movement in the correct part of my code. I had to move that code into the update method, I was trying to do it inside the event loop.

Nice to hear you found out by yourself. Next step, add something to shoot at?

This topic is closed to new replies.

Advertisement