How do I stop more than 1 bullet firing at once?
The general approach to firing bullets is to store the positions of the bullets in a list (bullet_list
). When a bullet is fired, add the bullet's starting position ([start_x, start_y]
) to the list. The starting position is the position of the object (player or enemy) that fires the bullet. Use a for
-loop to iterate through all the bullets in the list. Move position of each individual bullet in the loop. Remove a bullet from the list that leaves the screen (bullet_list.remove(bullet_pos)
). For this reason, a copy of the list (bullet_list[:]
) must be run through (see How to remove items from a list while iterating?). Use another for
-loop to blit
the remaining bullets on the screen:
bullet_list = []
while run == True:
# [...]
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bullet_list.append([start_x, start_y])
for bullet_pos in bullet_list[:]:
bullet_pos[0] += move_bullet_x
bullet_pos[1] += move_bullet_y
if not screen.get_rect().colliderect(bullet_image.get_rect(center = bullet_pos))
bullet_list.remove(bullet_pos)
# [...]
for bullet_pos in bullet_list[:]
screen.blit(bullet_image, bullet_image.get_rect(center = bullet_pos))
# [...]
See also Shoot bullet.
The states which are returned by pygame.key.get_pressed()
are, set, as long a key is hold down. That is useful for the movement of a player. The player keeps moving as long a key is hold down.
But it contradicts your intention, when you want to fire a bullet. If you want to fire a bullet when a key is pressed, then can use the KEYDOWN
event. The event occurs only once when a key is pressed:
while run == True:
clock.tick(27)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if player1.left == True: ## handles the direction of the bullet
facing = -1
else:
facing = 1
if len(bullets) < 5: ## max amounts of bullets on screen
bx, by = player1.x + player1.width //2 ,player1.y + player1.height//2
bullets.append(projectile(bx, by, 6, black, facing))
# [...]
If you want to implement some kind of rapid fire, then the things get more tricky. If you would use the state of pygame.key.get_pressed()
then you would spawn one bullet in every frame. That is far too fast. You have to implement some timeout.
When a bullet is fired, the get the current time by pygame.time.get_ticks()
. Define a number of milliseconds for the delay between to bullets. Add the dela to the time and state the time in a variable (next_bullet_threshold
). Skip bullets, as long the time is not exceeded:
next_bullet_threshold = 0
run = True
while run == True:
# [...]
current_time = pygame.time.get_ticks()
if keys[pygame.K_SPACE] and current_time > next_bullet_threshold:
bullet_delay = 500 # 500 milliseconds (0.5 seconds)
next_bullet_threshold = current_time + bullet_delay
if player1.left == True: ## handles the direction of the bullet
facing = -1
else:
facing = 1
if len(bullets) < 5:
bx, by = player1.x + player1.width //2 ,player1.y + player1.height//2
bullets.append(projectile(bx, by, 6, black, facing))
Minimal example: repl.it/@Rabbid76/PyGame-ShootBullet
import pygame
pygame.init()
window = pygame.display.set_mode((500, 200))
clock = pygame.time.Clock()
tank_surf = pygame.Surface((60, 40), pygame.SRCALPHA)
pygame.draw.rect(tank_surf, (0, 96, 0), (0, 00, 50, 40))
pygame.draw.rect(tank_surf, (0, 128, 0), (10, 10, 30, 20))
pygame.draw.rect(tank_surf, (32, 32, 96), (20, 16, 40, 8))
tank_rect = tank_surf.get_rect(midleft = (20, window.get_height() // 2))
bullet_surf = pygame.Surface((10, 10), pygame.SRCALPHA)
pygame.draw.circle(bullet_surf, (64, 64, 62), bullet_surf.get_rect().center, bullet_surf.get_width() // 2)
bullet_list = []
max_bullets = 4
next_bullet_time = 0
bullet_delta_time = 200 # milliseconds
run = True
while run:
clock.tick(60)
current_time = pygame.time.get_ticks()
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if len(bullet_list) < max_bullets and current_time >= next_bullet_time:
next_bullet_time = current_time + bullet_delta_time
bullet_list.insert(0, tank_rect.midright)
for i, bullet_pos in enumerate(bullet_list):
bullet_list[i] = bullet_pos[0] + 5, bullet_pos[1]
if bullet_surf.get_rect(center = bullet_pos).left > window.get_width():
del bullet_list[i:]
break
window.fill((224, 192, 160))
window.blit(tank_surf, tank_rect)
for bullet_pos in bullet_list:
window.blit(bullet_surf, bullet_surf.get_rect(center = bullet_pos))
pygame.display.flip()
pygame.quit()
exit()
pygame shooting multiple bullets
To reload, just reset the shoot flag and bullet position.
Try this update:
if shoot:
draw()
if b_x > 1300: # off screen
b_x = 0
shoot=False # wait for space to re-shoot
For rapid fire, use a list to store the bullet positions. The space key adds to the bullet list. When the bullet goes off screen, remove it from the list.
import pygame
import sys
pygame.init()
bg=pygame.display.set_mode((1300,640))
FPS=pygame.time.Clock()
p=x,y,width,height=(0,0,100,100)
b=b_x,b_y,b_width,b_height=(x,y,25,25)
bullets=[] # all active bullets
shoot=False
def draw():
global bullets,bullet,b_x,shoot,m
#b_x+=50
m=b_y+50
for i in range(len(bullets)):
b_x = bullets[i] # x position of bullets
bullet=pygame.draw.rect(bg,(0,0,255),(b_x+100,m,b_width,b_height))
bullets[i] += 50 # move each bullet
bullets = [b for b in bullets if b < 1300] # only keep bullets on screen
while True:
for event in pygame.event.get():
if event.type==pygame.QUIT:
pygame.quit()
sys.exit()
if event.type==pygame.KEYDOWN:
if event.key==pygame.K_LEFT:
x-=50
if event.key==pygame.K_RIGHT:
x+=50
if event.key==pygame.K_SPACE:
bullets.append(0) # add new bullets
bg.fill((0,0,0))
player1=pygame.draw.rect(bg,(255,0,0),(x,y,width,height))
if len(bullets): # if any active bullets
draw()
pygame.display.update()
FPS.tick(30)
Is there a way to make sure that two events do not repeat too close together in pygame?
pygame.key.get_pressed()
is not an event. Use the KEYDOWN
event.
pygame.key.get_pressed()
returns a sequence with the state of each key. If a key is held down, the state for the key is True
, otherwise False
. Use pygame.key.get_pressed()
to evaluate the current state of a button and get continuous movement.
The keyboard events (see pygame.event module) occur only once when the state of a key changes. The KEYDOWN
event occurs once every time a key is pressed. KEYUP
occurs once every time a key is released. Use the keyboard events for a single action:
def main():
# [...]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
bullet_group.add(player.create_bullet())
# [...]
If you want continuous fire, in which the projectiles can be fired at a certain interval, see How do I stop more than 1 bullet firing at once?.
how to shoot bullets in pygame?
You just need to set bulletX = characterX + 20
once - when the bullet is fired. Currently you set it to that with each while run
loop iteration, which is why its position is getting updated constantly. So, if you removed that, and updated the X position only when needed, this is how that part of your code could look:
if event.key == pygame.K_SPACE:
y_speed_bullet = y_speed * -1 * 2.3
bulletX = characterX + 20
Although you'll want something to keep track of if the bullet is currently fired or not, so that holding down or repeatedly pressing space doesn't reset the bullet's position.
Related Topics
Python: Justifying Numpy Array
What Is the Formal Difference Between "Print" and "Return"
How to Prevent Tensorflow from Allocating the Totality of a Gpu Memory
Adding Python to Path on Windows
Why Does Integer Division Yield a Float Instead of Another Integer
How to Change the Order of Dataframe Columns
How to Convert All Strings in a List of Lists to Integers
How to Get the Source Code of a Python Function
"Pip Install Unroll": "Python Setup.Py Egg_Info" Failed With Error Code 1
How to Print a Single Backslash
Using @Property Versus Getters and Setters
Converting Between Datetime, Timestamp and Datetime64
"Unicode Error "Unicodeescape" Codec Can't Decode Bytes... Cannot Open Text Files in Python 3
How to Expand the Output Display to See More Columns of a Pandas Dataframe