Related
I'm practising at pygame and I was trying to implement block id detection in my code, but after I finished it I noticed that my character is shaking. For seeing if block id detection was the problem I temporarely removed it, but nothing changed. I checked what type of collisions is the character facing and saw that he detects whatever collision type only in 1 of 2 frames. So how can I fix it ?
import pygame
from pygame.locals import *
import os
pygame.init()
pygame.mixer.pre_init(4410, -16, 2, 512)
def check_collision(rect, tiles):
hit_list = []
for tile in tiles:
if rect.colliderect(tile):
hit_list.append(tile)
return hit_list
def move(rect, movement, tiles):
collision_types = {"top" : False, "bottom" : False, "right" : False, "left" : False}
rect.x += movement[0]
hit_list = check_collision(rect, tiles)
for hit in hit_list:
if movement[0] > 0:
collision_types["right"] = True
rect.right = hit.left
elif movement[0] < 0:
collision_types["left"] = True
rect.left = hit.right
rect.y += movement[1]
hit_dict = check_collision(rect, tiles)
for hit in hit_list:
if movement[1] > 0:
collision_types["bottom"] = True
rect.bottom = hit.top
elif movement[1] < 0:
collision_types["top"] = True
rect.top = hit.bottom
return rect, collision_types
def load_map(path):
map_file = open(path, "r")
content = map_file.read()
map_file.close()
content = content.split("\n")
game_map = []
for row in content:
game_map.append(list(row))
return game_map
def check_walk_frame(image_list, walking_counter, current):
if walking_counter%60 <= 20 and walking_counter%60 != 0:
current = image_list[0]
elif walking_counter%60 > 20 and walking_counter%60 <= 40:
current = image_list[1]
elif walking_counter%60 > 40 and walking_counter%60 < 60:
current = image_list[2]
elif walking_counter == 60:
walking_counter = 1
else:
current = image_list[1]
return current, walking_counter
game_map = load_map("game_map.txt")
class Player(object):
def __init__(self, x, y, image):
self.image = image
self.x = x
self.y = y
self.width = self.image.get_width()
self.height = self.image.get_height()
self.hitbox = pygame.Rect(self.x, self.y, self.width, self.height)
self.momentum = 0
self.speed = 6
self.moving_left = False
self.moving_right = False
WINDOW_WIDTH, WINDOW_HEIGHT = 1300, 650
FPS = 60
TILE_SIZE = 100
def main():
window = pygame.display.set_mode((WINDOW_WIDTH, WINDOW_HEIGHT))
display = pygame.Surface((1200, 600))
Slid_animations = [pygame.transform.scale(pygame.image.load(os.path.join("Slid_anim\\Slid_anim2.png")).convert_alpha(), (82, 128)),
pygame.transform.scale(pygame.image.load(os.path.join("Slid_anim\\Slid_anim1.png")).convert_alpha(), (82, 128)),
pygame.transform.scale(pygame.image.load(os.path.join("Slid_anim\\Slid_anim3.png")).convert_alpha(), (82, 128))]
Slid_Current_Image = Slid_animations[1]
Dirt = pygame.image.load(os.path.join("dirt.png")).convert_alpha()
Grass = pygame.image.load(os.path.join("grass.png")).convert_alpha()
Dirt_image = pygame.transform.scale(Dirt, (TILE_SIZE, TILE_SIZE))
Grass_image = pygame.transform.scale(Grass, (TILE_SIZE, TILE_SIZE))
Sounds = {"grass_1" : pygame.mixer.Sound(os.path.join("grass_1.mp3")),
"grass_2" : pygame.mixer.Sound(os.path.join("grass_2.mp3")),
"jump" : pygame.mixer.Sound(os.path.join("jump.wav"))}
float_scroll = [0, 0]
scroll = [0, 0]
Walking_Counter = 0
Slid = Player(0, 100, Slid_Current_Image)
Cloud_Layer_1 = [pygame.Rect(200, 50, 150, 90), pygame.Rect(800, 150, 100, 60)]
Cloud_Layer_2 = [pygame.Rect(100, 80, 230, 110)]
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
display.fill((145, 255, 255))
cloud_1 = pygame.Rect(200-scroll[0]*0.8, 50-scroll[1]*0.5, 150, 90)
cloud_2 = pygame.Rect(100-scroll[0]*0.6, 80-scroll[1]*0.3, 230, 110)
cloud_3 = pygame.Rect(800-scroll[0]*0.8, 150-scroll[1]*0.5, 100, 60)
pygame.draw.rect(display, (50, 200, 200), cloud_1)
pygame.draw.rect(display, (0, 200, 200), cloud_2)
pygame.draw.rect(display, (50, 200, 200), cloud_3)
float_scroll[0] += (Slid.hitbox.x-scroll[0]-600) / 20
float_scroll[1] += (Slid.hitbox.y-scroll[1]-300) / 20
scroll = float_scroll.copy()
scroll[0] = int(scroll[0])
scroll[1] = int(scroll[1])
Slid_Current_Image, Walking_Counter = check_walk_frame(Slid_animations, Walking_Counter, Slid_Current_Image)
display.blit(Slid_Current_Image, (Slid.hitbox.x - scroll[0], Slid.hitbox.y - scroll[1]))
Tile_rects = []
y = 0
for tile_row in game_map:
x = 0
for tile in tile_row:
if tile == "1":
display.blit(Dirt_image, (x * TILE_SIZE - scroll[0], y * TILE_SIZE - scroll[1]))
Tile_rects.append(pygame.Rect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE))
elif tile == "2":
display.blit(Grass_image, (x * TILE_SIZE - scroll[0], y * TILE_SIZE - scroll[1]))
Tile_rects.append(pygame.Rect(x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE))
x += 1
y += 1
Slid_Movement = [0, 0]
if Slid.moving_left:
Slid_Movement[0] = -Slid.speed
if Slid.moving_right:
Slid_Movement[0] = Slid.speed
Slid_Movement[1] += Slid.momentum
Slid.momentum += 0.4
if Slid.momentum > 5:
Slid.momentum = 5
Slid.hitbox, collisions = move(Slid.hitbox, Slid_Movement, Tile_rects)
keys_pressed = pygame.key.get_pressed()
if keys_pressed[K_a]:
Slid.moving_left = True
Walking_Counter += 1
else:
Slid.moving_left = False
if keys_pressed[K_d]:
Slid.moving_right = True
Walking_Counter += 1
else:
Slid.moving_right = False
if not Slid.moving_right and not Slid.moving_left:
Walking_Counter = 0
if keys_pressed[K_SPACE] and collisions["bottom"]:
Slid.momentum = -15
Sounds["jump"].play()
if collisions["top"]:
Slid.momentum = 0
surface = pygame.transform.scale(display, (WINDOW_WIDTH, WINDOW_HEIGHT))
window.blit(surface, (0, 0))
print(collisions)
pygame.display.update()
pygame.quit()
if __name__ == "__main__":
main()
The problem is actually the collision system in your move function. You somehow wrote hit_dict = check_collision instead of hit_list = check_collision but you never used hit_dict (which isn't a dict). The collision system works by first moving the player on the x-axis and checking for any collisions, then it does the same for the y-axis. It's important to split the movement for both axes, otherwise it won't know where to go when the player is in a block - e.g. move to the left or to the top of the block? Therefore you also have to update your hit_list for both axis.
def move(rect, movement, tiles):
collision_types = {"top" : False, "bottom" : False, "right" : False, "left" : False}
rect.x += movement[0]
hit_list = check_collision(rect, tiles)
for hit in hit_list:
if movement[0] > 0:
collision_types["right"] = True
rect.right = hit.left
elif movement[0] < 0:
collision_types["left"] = True
rect.left = hit.right
rect.y += movement[1]
hit_list = check_collision(rect, tiles) # hit_list not hit_dict
for hit in hit_list:
if movement[1] > 0:
collision_types["bottom"] = True
rect.bottom = hit.top
elif movement[1] < 0:
collision_types["top"] = True
rect.top = hit.bottom
return rect, collision_types
I'm pretty sure you copied that collision system from somewhere...
I've been trying to make Space Invaders using PyGame in Python and make a list for the enemy images, and I make a for loop twice to load the images in and append them to the lists; 2 times for 2 rows. Though, the only pictures that appear are the ones from the first for loop.
There are no errors either, so it seems it is working. I also checked to see if the two rows were overlapping each other, but from the way I tested it, I found that they weren't.
I made this before here without using OOP and now I'm using OOP to learn it better, and it isn't working properly, please help.
For Loops Below
EnemyRowBottom = EnemyClass()
EnemyRowTop = EnemyClass()
for i in range(EnemyRowBottom.numEnemies):
EnemyImage1 = pygame.image.load('enemy.png')
EnemyRowBottom.EnemyImage.append( pygame.transform.scale(EnemyImage1, (70, 70)) )
y = i * 10
x = y * 10
EnemyRowBottom.EnemyX.append( x )
EnemyRowBottom.EnemyY.append( 150 )
for i in range(EnemyRowTop.numEnemies):
EnemyImage1 = pygame.image.load('enemy.png')
EnemyRowTop.EnemyImage.append( pygame.transform.scale(EnemyImage1, (70, 70)) )
y = i * 10
x = y * 10
EnemyRowTop.EnemyX.append( x )
EnemyRowTop.EnemyY.append( 50 )
Full Code below
import pygame
import random
import math
from pygame import mixer
import time
# initialize pygame
pygame.init()
# create screen
screenX = 800
screenY = 800
screen = pygame.display.set_mode( (screenX, screenY) )
# background
background = pygame.image.load("background.jpg")
#sounds
mixer.music.load('bgMusic.mp3')
mixer.music.play(-1)
# title and icon
pygame.display.set_caption("Space Invaders")
icon = pygame.image.load('Icon.jpg')
pygame.display.set_icon(icon)
# score
scoreValue = 0
font = pygame.font.Font('freesansbold.ttf', 32)
textX = 10
textY = 10
def show_score(x, y):
global scoreValue
score = font.render("Score: " + str(scoreValue), True, (255, 255, 255))
screen.blit(score, (x, y))
# player
PlayerImage = pygame.image.load('SpaceShip.png')
PlayerImage = pygame.transform.scale(PlayerImage, (84, 84))
playerX = 370
playerY = 650
xChangePlayer = 0
def player(x, y):
screen.blit(PlayerImage, (x, y))
# check collision
def Collision(EX, EX2, EY, EY2, LX, LY):
distance = math.sqrt((math.pow(EX - LX, 2) + math.pow(EY - LY, 2)))
distance2 = math.sqrt((math.pow(EX2 - LX, 2) + math.pow(EY2 - LY, 2)))
if distance <= 35:
return 1
elif distance2 <= 35:
return 2
def DistanceEnemy(EX, EX2, EY, EY2):
distance = math.sqrt((math.pow(EX2 - EX, 2) + math.pow(EY2 - EY, 2)))
if distance <= 70:
return True
# bottom line
Line = pygame.image.load('BottomLine.jpg')
LineX = 0
LineY = 655
def BottomLine(x, y):
global Line
screen.blit(Line, (x, y))
# Laser
LaserImage = pygame.image.load('PlayerLaser.png')
LaserImage = pygame.transform.scale(LaserImage, (50, 50))
LaserX = random.randint(15, (screenX - 85) )
LaserY = 750
xLaserChange = 0
yLaserChange = 1
# can't see bullet on screen until Ready changes to Fire
LaserState = "Ready"
def Firelaser(x, y):
global LaserState
LaserState = "Fire"
screen.blit(LaserImage, (x+17, y+10))
GameOverfont = pygame.font.Font('freesansbold.ttf', 82)
def GameOver():
global GameOverfont
text = GameOverfont.render("GAME OVER", True, (255, 255, 255))
screen.blit(text, (140, 250))
# enemy
class EnemyClass:
EnemyImage = []
EnemyX = []
EnemyY = []
numEnemies = 4
xEnemyChange = 0.2
yEnemyChange = 50
def enemyMovement(self, i):
EnemyClass.EnemyX[i] += EnemyClass.xEnemyChange
if EnemyClass.EnemyX[i] >= 736:
EnemyClass.xEnemyChange = -EnemyClass.xEnemyChange
for x in range(len(EnemyClass.EnemyY)):
EnemyClass.EnemyY[x] += EnemyClass.yEnemyChange
elif EnemyClass.EnemyX[i] <= 0:
EnemyClass.xEnemyChange = .2
for x in range(len(EnemyClass.EnemyY)):
EnemyClass.EnemyY[x] += EnemyClass.yEnemyChange
def enemy(self, i):
screen.blit(EnemyClass.EnemyImage[i], (EnemyClass.EnemyX[i], EnemyClass.EnemyY[i]))
def enemyGameOver(self, x, y):
screen.blit(EnemyClass.EnemyImage[i], (x, y))
def CollisionDetection(self, i, scoreValue, lasery, laserstate):
global LaserY, LaserState
ExplosionSound = mixer.Sound('explosion.wav')
ExplosionSound.play()
LaserY = lasery
LaserState = laserstate
scoreValue += 1
# enemy respawn
OldEnemyY = EnemyClass.EnemyY[i]
EnemyClass.EnemyY[i] = -20
if EnemyClass.EnemyY[i] >= OldEnemyY:
EnemyClass.EnemyY[i] -= 40
EnemyRowBottom = EnemyClass()
EnemyRowTop = EnemyClass()
for i in range(EnemyRowBottom.numEnemies):
EnemyImage1 = pygame.image.load('enemy.png')
EnemyRowBottom.EnemyImage.append( pygame.transform.scale(EnemyImage1, (70, 70)) )
y = i * 10
x = y * 10
EnemyRowBottom.EnemyX.append( x )
EnemyRowBottom.EnemyY.append( 150 )
for i in range(EnemyRowTop.numEnemies):
EnemyImage1 = pygame.image.load('enemy.png')
EnemyRowTop.EnemyImage.append( pygame.transform.scale(EnemyImage1, (70, 70)) )
y = i * 10
x = y * 10
EnemyRowTop.EnemyX.append( x )
EnemyRowTop.EnemyY.append( 50 )
# game loop
running = True
while running:
# setting background
screen.fill( (0, 0, 0) )
screen.blit(background, (0, 0))
# make function that closes program when x pressed
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
# keystroke detection
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
xChangePlayer = -0.4
if event.key == pygame.K_RIGHT:
xChangePlayer = +0.4
if event.key == pygame.K_SPACE:
if LaserState == "Ready":
LaserSound = mixer.Sound('shoot.wav')
LaserSound.play()
LaserX = playerX
LaserY = 600
Firelaser(LaserX, LaserY)
LaserY -= yLaserChange
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT or event.key == pygame.K_RIGHT:
xChangePlayer = 0
# player movement
playerX += xChangePlayer
# setting boudries for the player
if playerX < 0:
playerX = 0
elif playerX >= 736:
playerX = 735
# setting boudries for the enemy
for i in range(EnemyRowTop.numEnemies):
BlitEnemy1 = EnemyRowTop.enemy(i)
BlitEnemy2 = EnemyRowBottom.enemy(i)
gameSoundPlayed = 0
if EnemyRowTop.EnemyY[i] >= 600 or EnemyRowBottom.EnemyY[i] >= 600 and (gameSoundPlayed == 0):
GameOver()
BottomLine(LineX, LineY)
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
gameSoundPlayed += 1
EnemyRowTop.xEnemyChange = 0
EnemyRowTop.yEnemyChange = 0
EnemyRowBottom.xEnemyChange = 0
EnemyRowBottom.yEnemyChange = 0
mixer.music.stop()
mixer.music.load('GameOverSound.wav')
mixer.music.play()
time.sleep(3)
break
EnemyRowTop.enemyMovement(i)
EnemyRowBottom.enemyMovement(i)
# collision detection
collision = Collision(EnemyRowTop.EnemyX[i], EnemyRowBottom.EnemyX[i], EnemyRowTop.EnemyY[i], EnemyRowBottom.EnemyY[i], LaserX, LaserY)
if collision == 1:
EnemyRowTop.CollisionDetection(i, scoreValue, 600, "Ready")
EnemyDistance = DistanceEnemy(EnemyRowTop.EnemyX[i], EnemyRowBottom.EnemyX[i], EnemyRowTop.EnemyY[i], EnemyRowBottom.EnemyY[i])
if EnemyDistance == True:
EnemyClass.EnemyY[i] -= 50
if collision == 2:
EnemyRowBottom.CollisionDetection(i, scoreValue, 600, "Ready")
EnemyDistance = DistanceEnemy(EnemyRowTop.EnemyX[i], EnemyRowBottom.EnemyX[i], EnemyRowTop.EnemyY[i], EnemyRowBottom.EnemyY[i])
if EnemyDistance == True:
EnemyClass.EnemyY[i] -= 50
BlitEnemy1
BlitEnemy2
# laser movement
if LaserY <= -20:
LaserY = 750
LaserState = "Ready"
if LaserState == "Fire":
Firelaser(LaserX, LaserY)
LaserY -= yLaserChange
# outputting characters
BottomLine(LineX, LineY)
player(playerX, playerY)
show_score(textX, textY)
pygame.display.update()
if gameSoundPlayed == 1:
break
I cant test it but I think I found the problem. You should add a _init_ method to your EnemyClass. There you can define these variables so each row has its own lists of enemies. Because your enemies have the same image you dont need to load the image more than once.
EnemyImage = []
EnemyX = []
EnemyY = []
numEnemies = 4
xEnemyChange = 0.2
yEnemyChange = 50
class EnemyClass:
EnemyImage = pygame.transform.scale(pygame.image.load('enemy.png'), (70, 70))
def __init__(self):
self.EnemyX = []
self.EnemyY = []
self.numEnemies = 4
self.xEnemyChange = 0.2
self.yEnemyChange = 50
EnemyRowBottom = EnemyClass()
EnemyRowTop = EnemyClass()
But it would make more sense to have an object for each enemy instead of the enemy rows.
The problem of your code is, that the list containing the images in your EnemyClass is a class-attribute of your EnemyClass. As a result, every instance of that class accesses the same list of EnemyClass, and has not its own list in EnemyRowBottom and EnemyRowTop.
You can fix this problem by making EnemyImage an object-attribute:
class EnemyClass:
def __init__(self):
self.EnemyImage = []
self.EnemyX = []
self.EnemyY = []
self.numEnemies = 4
self.xEnemyChange = 0.2
self.yEnemyChange = 50
You can then access your images with "self.EnemyImage" inside the methods.
Moreover, to avoid the same image twice, you can put your pygame.image.load-method outside and before the loops, so that the game starts quicker.
So I am doing a project where I have to make a game that gives the user three lives and each time the beamrect's rectangle collides with the player's, it subtracts a life and puts them in the original position. When lives == 0: there will be a death screen displayed. But for some reason, the death screen isn't being displayed even though I made sure that every time the player rect (being zonicrect) and the beamrect collided, it would subtract 1 from the life variable.
# Your header should go here, each comment should be initialed -DK
import pygame, sys
import os
# https://youtu.be/jO6qQDNa2UY
pygame.init()
FPS = 60
# Useful Variables
# Size
size = height, width = 900, 500
zonhw = zheight, zwidth = 70, 70
scale2 = height2, width2 = 600, 300
lscale = lheight, lwidth = 80, 80
beamsz = bheight, bwidth = 50,25
platz = pheight, pwidth = 10, 70
# RGB
white = (255, 255, 255)
black = (0,0,0)
blue = (0, 0, 128)
green = (0, 255, 0)
brown = (165,42,42)
# Speed
VEL = 5
beamspeed = 3
# Position
laserpos = posx, posy = 500,250
#other
i = 0
life = 3
score = 0
# graphics
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Zonic bootleg")
font = pygame.font.Font('freesansbold.ttf', 32)
zonic = pygame.image.load(os.path.join("image","zonic.gif"))
zonic = pygame.transform.scale(zonic, zonhw)
bg = pygame.image.load(os.path.join("image","sonic-back.jpg"))
bg = pygame.transform.scale(bg, size)
gg = pygame.image.load(os.path.join("image","gg.jpg"))
gg= pygame.transform.scale(gg, size)
lazerz = pygame.image.load(os.path.join("image","Lazerz.gif"))
lazerz = pygame.transform.scale(lazerz, lscale)
beam = pygame.image.load(os.path.join("image","laserbeam.jpg"))
beam = pygame.transform.scale(beam, beamsz)
lives = pygame.image.load(os.path.join("image","health.png"))
lives = pygame.transform.scale(lives,(40,40))
# zoncz = pygame.image.load(os.path.join("image","zoncz.png"))
# zoncz = pygame.transform.scale(zoncz, scale2)
#coalitions
def collider(life,beamrect,zonicrect,lazerect):
beamrect.x -= beamspeed
if zonicrect.colliderect(beamrect):
beamrect.x = lazerect.x+21
zonicrect.x = 0
if beamrect.x <-60:
#screen.blit(beam, (posx, posy))
beamrect.x += 550
def updating(score, beamrect):
if beamrect.x == 0:
score += 1
#Death
def death():
while life <= 0:
death = font.render("Death", True, white)
screen.fill(black)
screen.blit(death,(250, 250))
# zonic movement
def KWS(keyvar, zonicrect,flip):
if keyvar[pygame.K_RIGHT]: # right
zonicrect.x += VEL
flip = False
if zonicrect.x > 500:
zonicrect.x -= VEL
if keyvar[pygame.K_LEFT] and zonicrect.x + VEL > 0: # left
zonicrect.x -= VEL
flip = True
def flipx(flip,zonicrect):
if flip:
screen.blit(pygame.transform.flip(zonic,True,False),(zonicrect.x,zonicrect.y))
if flip == False:
screen.blit(pygame.transform.flip(zonic,False,False),(zonicrect.x,zonicrect.y))
# text = font.render('Lives: {0}'.format(life), True, green, blue)
def heart(beamrect,zonicrect,lazerect):
x = 1
i = -33
while life >= x:
x +=1
i+=32
screen.blit(lives, (2+i,0))
# draw
def drawingfunc(zonicrect,lazerect, beamrect,flip, zonczrect):
#screen.blit(death,(0,0))
screen.blit(bg, (0, 0))
heart(beamrect,zonicrect,lazerect)
flipx(flip,zonicrect)
#screen.blit(zonic,(zonicrect.x, zonicrect.y))
screen.blit(beam, (beamrect.x, beamrect.y+15))
screen.blit(lazerz, (lazerect.x+21,lazerect.y))
# score = font.render('Score: ')
# screen.blit(zonic, (zonczrect.x, zonczrect.y))
sore = font.render("Score: {0}".format(score), True, black, white)
screen.blit(sore, (30, 70))
pygame.draw.rect(screen, brown, pygame.Rect(200, 200, 100, 50))
pygame.display.update()
# mainloop and refresh rate
def main():
jump = False
jumpCount = 0
jumpMax = 15
flip = False
zonicrect = pygame.Rect(10, 250, zheight, zwidth)
lazerect = pygame.Rect(posx, posy, lheight, lwidth)
beamrect = pygame.Rect(posx, posy, bheight, bwidth)
zonczrect = pygame.Rect(50, 25, height2, width2)
# (30,0,32,32)
# livesrect = pygame.Rect(0,0,10,10)
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if not jump and event.key == pygame.K_SPACE:
jump = True
jumpCount = jumpMax
death()
collider(life,beamrect,zonicrect,lazerect)
keyspressed = pygame.key.get_pressed()
KWS(keyspressed, zonicrect,flip)
updating(score, beamrect)
drawingfunc(zonicrect,lazerect, beamrect,flip, zonczrect)
flipx(flip, zonicrect)
if jump:
zonicrect.y -= jumpCount
if jumpCount > -jumpMax:
jumpCount -= 1
else:
jump = False
pygame.quit()
# calling function NOTE: needs to always be at the end of file
if __name__ == "__main__":
main()
Solution
In your death function, you forgot to call pygame.display.update() at the bottom of your loop. That's why you cannot see the death screen even when life is less than or equal to zero. Also, you need to add an event loop in your death function, so that the window will keep responding to events while the loop is running.
So change this:
def death():
while life <= 0:
death = font.render("Death", True, white)
screen.fill(black)
screen.blit(death, (250, 250))
To this:
def death():
while life <= 0:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(0)
death = font.render("Death", True, white)
screen.fill(black)
screen.blit(death, (250, 250))
pygame.display.update()
Full Modified Code
# Your header should go here, each comment should be initialed -DK
import pygame, sys
import os
# https://youtu.be/jO6qQDNa2UY
pygame.init()
FPS = 60
# Useful Variables
# Size
size = height, width = 900, 500
zonhw = zheight, zwidth = 70, 70
scale2 = height2, width2 = 600, 300
lscale = lheight, lwidth = 80, 80
beamsz = bheight, bwidth = 50, 25
platz = pheight, pwidth = 10, 70
# RGB
white = (255, 255, 255)
black = (0, 0, 0)
blue = (0, 0, 128)
green = (0, 255, 0)
brown = (165, 42, 42)
# Speed
VEL = 5
beamspeed = 3
# Position
laserpos = posx, posy = 500, 250
# other
i = 0
life = 3
score = 0
# graphics
screen = pygame.display.set_mode(size)
pygame.display.set_caption("Zonic bootleg")
font = pygame.font.Font('freesansbold.ttf', 32)
zonic = pygame.image.load(os.path.join("image", "zonic.gif"))
zonic = pygame.transform.scale(zonic, zonhw)
bg = pygame.image.load(os.path.join("image", "sonic-back.jpg"))
bg = pygame.transform.scale(bg, size)
gg = pygame.image.load(os.path.join("image", "gg.jpg"))
gg = pygame.transform.scale(gg, size)
lazerz = pygame.image.load(os.path.join("image", "Lazerz.gif"))
lazerz = pygame.transform.scale(lazerz, lscale)
beam = pygame.image.load(os.path.join("image", "laserbeam.jpg"))
beam = pygame.transform.scale(beam, beamsz)
lives = pygame.image.load(os.path.join("image", "health.png"))
lives = pygame.transform.scale(lives, (40, 40))
# zoncz = pygame.image.load(os.path.join("image","zoncz.png"))
# zoncz = pygame.transform.scale(zoncz, scale2)
# coalitions
def collider(life, beamrect, zonicrect, lazerect):
beamrect.x -= beamspeed
if zonicrect.colliderect(beamrect):
beamrect.x = lazerect.x + 21
zonicrect.x = 0
if beamrect.x < -60:
# screen.blit(beam, (posx, posy))
beamrect.x += 550
def updating(score, beamrect):
if beamrect.x == 0:
score += 1
# Death
def death():
while life <= 0:
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit(0)
death = font.render("Death", True, white)
screen.fill(black)
screen.blit(death, (250, 250))
pygame.display.update()
# zonic movement
def KWS(keyvar, zonicrect, flip):
if keyvar[pygame.K_RIGHT]: # right
zonicrect.x += VEL
flip = False
if zonicrect.x > 500:
zonicrect.x -= VEL
if keyvar[pygame.K_LEFT] and zonicrect.x + VEL > 0: # left
zonicrect.x -= VEL
flip = True
def flipx(flip, zonicrect):
if flip:
screen.blit(pygame.transform.flip(zonic, True, False), (zonicrect.x, zonicrect.y))
if flip == False:
screen.blit(pygame.transform.flip(zonic, False, False), (zonicrect.x, zonicrect.y))
# text = font.render('Lives: {0}'.format(life), True, green, blue)
def heart(beamrect, zonicrect, lazerect):
x = 1
i = -33
while life >= x:
x += 1
i += 32
screen.blit(lives, (2 + i, 0))
# draw
def drawingfunc(zonicrect, lazerect, beamrect, flip, zonczrect):
# screen.blit(death,(0,0))
screen.blit(bg, (0, 0))
heart(beamrect, zonicrect, lazerect)
flipx(flip, zonicrect)
# screen.blit(zonic,(zonicrect.x, zonicrect.y))
screen.blit(beam, (beamrect.x, beamrect.y + 15))
screen.blit(lazerz, (lazerect.x + 21, lazerect.y))
# score = font.render('Score: ')
# screen.blit(zonic, (zonczrect.x, zonczrect.y))
sore = font.render("Score: {0}".format(score), True, black, white)
screen.blit(sore, (30, 70))
pygame.draw.rect(screen, brown, pygame.Rect(200, 200, 100, 50))
pygame.display.update()
# mainloop and refresh rate
def main():
jump = False
jumpCount = 0
jumpMax = 15
flip = False
zonicrect = pygame.Rect(10, 250, zheight, zwidth)
lazerect = pygame.Rect(posx, posy, lheight, lwidth)
beamrect = pygame.Rect(posx, posy, bheight, bwidth)
zonczrect = pygame.Rect(50, 25, height2, width2)
# (30,0,32,32)
# livesrect = pygame.Rect(0,0,10,10)
clock = pygame.time.Clock()
run = True
while run:
clock.tick(FPS)
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if event.type == pygame.KEYDOWN:
if not jump and event.key == pygame.K_SPACE:
jump = True
jumpCount = jumpMax
death()
collider(life, beamrect, zonicrect, lazerect)
keyspressed = pygame.key.get_pressed()
KWS(keyspressed, zonicrect, flip)
updating(score, beamrect)
drawingfunc(zonicrect, lazerect, beamrect, flip, zonczrect)
flipx(flip, zonicrect)
if jump:
zonicrect.y -= jumpCount
if jumpCount > -jumpMax:
jumpCount -= 1
else:
jump = False
pygame.quit()
sys.exit(0)
# calling function NOTE: needs to always be at the end of file
if __name__ == "__main__":
main()
im fairly new to coding and python, i was messing around with pygame and i was wondering if theres a way i could limit the amount of circles that spawn in this game im making? when i run the code, it just spawns in circles all over the place really fast. i tried doing the time.sleep thing, but all it does is slow down the entire game.
import pygame
import random
import time
pygame.init()
y = 0
x = 0
point = 0
is_blue = True
WHITE = (255, 255, 255)
clock = pygame.time.Clock()
screen = pygame.display.set_mode([500, 500])
def food():
pygame.draw.circle(screen, WHITE, (random.randint(1, 400), random.randint(1, 400)), 5)
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
is_blue = not is_blue
pygame.display.set_caption("Collect the balls to win!")
pressed = pygame.key.get_pressed()
if pressed[pygame.K_UP]:
y -= 3
if pressed[pygame.K_DOWN]:
y += 3
if pressed[pygame.K_LEFT]:
x -= 3
if pressed[pygame.K_RIGHT]:
x += 3
if x <= -1:
x = 0
if x >= 441:
x = 440
if y <= -1:
y = 0
if y >= 441:
y = 440
screen.fill((0, 0, 0))
if is_blue:
color = (0, 128, 255)
else:
color = (255, 100, 0)
pygame.draw.rect(screen, color, pygame.Rect(x, y, 30, 30))
food()
pygame.display.flip()
clock.tick(144)
You have to use a list. Create a list for the food positions:
food_list = []
Fill the list in a loop:
while len(food_list) < 10:
food_list.append((random.randint(1, 400), random.randint(1, 400)))
Draw the foods in the list in a loop:
for food_pos in food_list:
pygame.draw.circle(screen, WHITE, food_pos, 5)
You can also spawn the food with an time interval. Use pygame.time.get_ticks() to measure the time. Define a time interval after which a new object should appear. Create an object when the point in time is reached and calculate the point in time for the next object:
food_list = []
time_interval = 1000 # 1000 milliseconds == 1 seconds
next_food_time = pygame.time.get_ticks()
done = False
while not done:
# [...]
current_time = pygame.time.get_ticks()
if current_time > next_food_time and len(food_list) < 10:
next_food_time += time_interval
food_list.append((random.randint(1, 400), random.randint(1, 400)))
See also Spawning multiple instances of the same object concurrently in python
Complete example:
import pygame
import random
import time
pygame.init()
y = 0
x = 0
point = 0
is_blue = True
WHITE = (255, 255, 255)
clock = pygame.time.Clock()
screen = pygame.display.set_mode([500, 500])
food_list = []
time_interval = 1000 # 1000 milliseconds == 1 seconds
next_food_time = pygame.time.get_ticks()
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN and event.key == pygame.K_SPACE:
is_blue = not is_blue
pygame.display.set_caption("Collect the balls to win!")
pressed = pygame.key.get_pressed()
if pressed[pygame.K_UP]:
y -= 3
if pressed[pygame.K_DOWN]:
y += 3
if pressed[pygame.K_LEFT]:
x -= 3
if pressed[pygame.K_RIGHT]:
x += 3
if x <= -1:
x = 0
if x >= 441:
x = 440
if y <= -1:
y = 0
if y >= 441:
y = 440
current_time = pygame.time.get_ticks()
if current_time > next_food_time and len(food_list) < 10:
next_food_time += time_interval
food_list.append((random.randint(1, 400), random.randint(1, 400)))
screen.fill((0, 0, 0))
if is_blue:
color = (0, 128, 255)
else:
color = (255, 100, 0)
pygame.draw.rect(screen, color, pygame.Rect(x, y, 30, 30))
for food_pos in food_list:
pygame.draw.circle(screen, WHITE, food_pos, 5)
pygame.display.flip()
clock.tick(144)
This question already has answers here:
Animated sprite from few images
(4 answers)
how to make image/images disappear in pygame?
(1 answer)
Closed 2 years ago.
I'm making a pygame game where a player is moving around on a screen and can buy items from a shop(bombs). I'm able to drop the bombs, now I need to replace the bomb image with an explosion image after 3 secs and check for collision with the enemy. I'm attaching my whole code along with some screenshots for reference. Any help is appreciated, thank you
import pygame
import random
pygame.font.init()
width = 900
height = 600
screen = pygame.display.set_mode([width, height])
walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'),
pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'),
pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'),
pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'),
pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
char = pygame.image.load('standing.png')
bomb_pic = pygame.transform.scale(pygame.image.load('bomb.png'), (20,20))
bomb_explosion = pygame.transform.scale(pygame.image.load('explosion1.png'), (40,40))
# char_rect = char.get_rect()
enemy_Left = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'),
pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'),
pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png')]
x = 50
y = 50
width = 40
height = 60
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
down = False
up = False
walkCount = 0
enemy_vel = 2
enemy_list = []
shop = pygame.transform.scale(pygame.image.load("shop.png"), (60, 60))
clock = pygame.time.Clock()
FPS = 60
font = pygame.font.Font('freesansbold.ttf', 32)
items_font = pygame.font.Font('freesansbold.ttf', 16)
bombs =[]
bag = {'bomb': 0}
print(bag["bomb"])
class Button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 20)
text = font.render(self.text, 1, (0, 0, 0))
win.blit(text, (
self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def shop_run():
shop_bomb = Button((0, 200, 0), 820, 150, 60, 20, text="Bomb_b")
bright_green = (0, 255, 0)
green = (0, 200, 0)
shop_bomb.draw(screen)
def redrawGameWindow():
global walkCount
global font
global bag
global items_font
global enemy_list
screen.fill([166, 166, 166])
for five_enemies in range(6):
random_enemy_location_y = random.randrange(100, 400)
random_enemy_location_x = random.randrange(800, 840)
enemy_list.append([random_enemy_location_x, random_enemy_location_y])
for enemies in range(6):
screen.blit(enemy_Left[enemies], enemy_list[enemies])
enemy_list[enemies][0] -= 0.3
pygame.draw.rect(screen, (0, 0, 0), (800, 0, 100, 600))
if x + char.get_width() < 60 and y + char.get_height() < 60:
shop_run()
screen.blit(shop, (0, 0))
screen.blit(font.render("Menu", True, (255,255,255)),(805, 10))
screen.blit(items_font.render("Bombs: "+ str(bag["bomb"]), True, (255, 255, 255)), (805, 550))
# screen.blit(bomb_explosion, (450, 300))
if walkCount + 1 >= 27:
walkCount = 0
if left:
screen.blit(walkLeft[walkCount // 3], (x, y))
walkCount += 1
elif right:
screen.blit(walkRight[walkCount // 3], (x, y))
walkCount += 1
elif down:
screen.blit(char, (x, y))
walkcount = 0
elif up:
screen.blit(char, (x, y))
walkcount = 0
else:
screen.blit(char, (x, y))
walkCount = 0
for pos in bombs:
screen.blit(bomb_pic, pos)
pygame.display.update()
def main():
run = True
# shopper()
pygame.display.set_caption("bomb-mania")
global x
global y
global width
global height
global vel
global isJump
global jumpCount
global left
global right
global down
global up
global walkCount
global bomb_pic
global font
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if x + char.get_width() < 60 and y + char.get_height() < 60:
buy = pygame.key.get_pressed()
if buy[pygame.K_b]:
bag["bomb"] += 1
print(bag["bomb"])
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and bag["bomb"] >= 1:
bombs.append(((x + (char.get_width()/2)),( y + (char.get_height() - 20))))
bag["bomb"] -= 1
redrawGameWindow()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel - 15:
x -= vel
left = True
right = False
down = False
up = False
elif keys[pygame.K_RIGHT] and x < 800 - vel - width:
x += vel
left = False
right = True
down = False
up = False
elif keys[pygame.K_DOWN] and y < 600 - height:
y += vel
left = False
right = False
down = True
up = False
elif keys[pygame.K_UP] and y > vel - 15:
y -= vel
left = False
right = False
down = False
up = True
else:
left = False
right = False
down = False
up = False
walkCount = 0
clock.tick(FPS)
pygame.display.flip()
main()
enemies are moving towards the left
able to drop bombs
able to buy bombs from the shop
I'm adding a code below please help me troubleshoot and debug this
import pygame
import random
pygame.font.init()
width = 900
height = 600
screen = pygame.display.set_mode([width, height])
walkRight = [pygame.image.load('R1.png'), pygame.image.load('R2.png'), pygame.image.load('R3.png'),
pygame.image.load('R4.png'), pygame.image.load('R5.png'), pygame.image.load('R6.png'),
pygame.image.load('R7.png'), pygame.image.load('R8.png'), pygame.image.load('R9.png')]
walkLeft = [pygame.image.load('L1.png'), pygame.image.load('L2.png'), pygame.image.load('L3.png'),
pygame.image.load('L4.png'), pygame.image.load('L5.png'), pygame.image.load('L6.png'),
pygame.image.load('L7.png'), pygame.image.load('L8.png'), pygame.image.load('L9.png')]
char = pygame.image.load('standing.png')
bomb_pic = pygame.transform.scale(pygame.image.load('bomb.png'), (20,20))
bomb_explosion = pygame.transform.scale(pygame.image.load('explosion1.png'), (40,40))
# char_rect = char.get_rect()
enemy_Left = [pygame.image.load('L1E.png'), pygame.image.load('L2E.png'), pygame.image.load('L3E.png'),
pygame.image.load('L4E.png'), pygame.image.load('L5E.png'), pygame.image.load('L6E.png'),
pygame.image.load('L7E.png'), pygame.image.load('L8E.png'), pygame.image.load('L9E.png')]
x = 50
y = 50
width = 40
height = 60
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
down = False
up = False
walkCount = 0
enemy_vel = 2
enemy_list = []
shop = pygame.transform.scale(pygame.image.load("shop.png"), (60, 60))
clock = pygame.time.Clock()
FPS = 60
font = pygame.font.Font('freesansbold.ttf', 32)
items_font = pygame.font.Font('freesansbold.ttf', 16)
bombs =[]
bag = {'bomb': 0}
bomb_timer = {"bomb0":0}
bomb_placed = False
bombCount = 1
bombs_dict = {"bomb0": False}
bombTimers = []
explosion_dict = {"explosion0": False}
print(bag["bomb"])
class Button():
def __init__(self, color, x, y, width, height, text=''):
self.color = color
self.x = x
self.y = y
self.width = width
self.height = height
self.text = text
def draw(self, win, outline=None):
# Call this method to draw the button on the screen
if outline:
pygame.draw.rect(win, outline, (self.x - 2, self.y - 2, self.width + 4, self.height + 4), 0)
pygame.draw.rect(win, self.color, (self.x, self.y, self.width, self.height), 0)
if self.text != '':
font = pygame.font.SysFont('comicsans', 20)
text = font.render(self.text, 1, (0, 0, 0))
win.blit(text, (
self.x + (self.width / 2 - text.get_width() / 2), self.y + (self.height / 2 - text.get_height() / 2)))
def shop_run():
shop_bomb = Button((0, 200, 0), 820, 150, 60, 20, text="Bomb_b")
bright_green = (0, 255, 0)
green = (0, 200, 0)
shop_bomb.draw(screen)
def redrawGameWindow():
global walkCount
global font
global bag
global items_font
global enemy_list
global bomb_timer
global bomb_placed
global explosion_dict
screen.fill([166, 166, 166])
for five_enemies in range(6):
random_enemy_location_y = random.randrange(100, 400)
random_enemy_location_x = random.randrange(800, 840)
enemy_list.append([random_enemy_location_x, random_enemy_location_y])
for enemies in range(6):
screen.blit(enemy_Left[enemies], enemy_list[enemies])
enemy_list[enemies][0] -= 0.3
pygame.draw.rect(screen, (0, 0, 0), (800, 0, 100, 600))
if x + char.get_width() < 60 and y + char.get_height() < 60:
shop_run()
screen.blit(shop, (0, 0))
screen.blit(font.render("Menu", True, (255,255,255)),(805, 10))
screen.blit(items_font.render("Bombs: "+ str(bag["bomb"]), True, (255, 255, 255)), (805, 550))
# screen.blit(bomb_explosion, (450, 300))
if walkCount + 1 >= 27:
walkCount = 0
if left:
screen.blit(walkLeft[walkCount // 3], (x, y))
walkCount += 1
elif right:
screen.blit(walkRight[walkCount // 3], (x, y))
walkCount += 1
elif down:
screen.blit(char, (x, y))
walkcount = 0
elif up:
screen.blit(char, (x, y))
walkcount = 0
else:
screen.blit(char, (x, y))
walkCount = 0
for pos in bombs:
for i in bombs_dict:
if bombs_dict["bomb"+str(bag["bomb"])]:
screen.blit(bomb_pic, pos)
bomb_timer["bomb"+str(bag["bomb"])] += clock.get_time()
if bomb_timer["bomb"+str(bag["bomb"])] >= 3000:
bombs_dict["bomb"+str(bag["bomb"])] = False
explosion_dict["explosion" + str(bag["bomb"])] = True
del bombs_dict["bomb"+str(bag["bomb"])]
else:
if explosion_dict["explosion" + str(bag["bomb"])]:
screen.blit(bomb_explosion, (pos))
if bomb_timer["bomb"+str(bag["bomb"])] >= 5000:
explosion_dict["explosion" + str(bag["bomb"])] = False
del explosion_dict["explosion" + str(bag["bomb"])]
pygame.display.update()
def main():
run = True
pygame.display.set_caption("bomb-mania")
global x
global y
global width
global height
global vel
global isJump
global jumpCount
global left
global right
global down
global up
global walkCount
global bomb_pic
global font
global bombs_dict
while run:
for event in pygame.event.get():
if event.type == pygame.QUIT:
run = False
if x + char.get_width() < 60 and y + char.get_height() < 60:
buy = pygame.key.get_pressed()
if buy[pygame.K_b]:
bag["bomb"] += 1
bombs_dict["bomb"+str(bag["bomb"])] = False
print(bag["bomb"])
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE and bag["bomb"] >= 1:
bombs.append(((x + (char.get_width()/2)),( y + (char.get_height() - 20))))
bombs_dict["bomb"+str(bag["bomb"])] = True
bag["bomb"] -= 1
redrawGameWindow()
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT] and x > vel - 15:
x -= vel
left = True
right = False
down = False
up = False
elif keys[pygame.K_RIGHT] and x < 800 - vel - width:
x += vel
left = False
right = True
down = False
up = False
elif keys[pygame.K_DOWN] and y < 600 - height:
y += vel
left = False
right = False
down = True
up = False
elif keys[pygame.K_UP] and y > vel - 15:
y -= vel
left = False
right = False
down = False
up = True
else:
left = False
right = False
down = False
up = False
walkCount = 0
clock.tick(FPS)
pygame.display.flip()
main()
Look at pygame.time.Clock(). If you set an FPS rate (say 20), All you have to do is:
myClock = pg.time.Clock()
FPS = 20
bomb_placed = True
bomb_timer = 0
main_loop():
myClock.tick(FPS) # This will keep your FPS at 20 or below so you can estimate time
if bomb_placed:
bomb_timer += myClock.get_time()
if bomb_timer >= 3000:
# Draw the bomb explosion to the screen
if bomb_timer >= 5000:
bomb_timer = 0
bomb_placed = False # Stops displaying the bomb explosion
Hope that helped. Feel free to check out the pygame docs on the subject:
https://www.pygame.org/docs/ref/time.html#pygame.time.Clock.get_time
Example for multiple bombs:
myClock = pg.time.Clock()
FPS = 20
bombA, bombB, bombC = False, False, False
bombA_timer, bombB_timer, bombC_timer = 0, 0, 0
bombs = [bombA, bombB, bombC]
bomb_timers = [bombA_timer, bombB_timer, bombC_timer]
main_loop():
myClock.tick(FPS)
for i in len(bombs):
if bombs[i]:
bomb_timers[i] += myClock.get_time()
if bomb_timers[i] >= 3000:
draw_explosion()
if bomb_timer >= 5000:
bomb_timers[i] = 0
bomb_placed[i] = False
This example simply loops through each of the bomb variables that represent the possible bombs on the screen- in this case a max of 3.
For lots of bombs, first create two dictionaries to hold the values of the bombs (active or not active) and their respective timers. Then loop through each of the bombs and, if the bomb is active, update the timer accordingly:
bombs = {"bomb0": False} # Create dictionaries for the bombs and their timers, with 0-1 entries. (I did one to show you what it looks like).
bombTimers = {bombTimer0: 0}
main_loop():
myClock.tick(FPS)
for i in len(bombs): # For each bomb you have created
bombName = "bomb" + str(i) # get the name of the bomb and corresponding timer
timerName = "bombTimer" + str(i)
if bombs[bombName]: # If the bomg has a value of True:
bombTimers[timerName] += myClock.get_time() # Update the timer
if bombTimers[timerName] >= 3000: # Check if you need to draw the explosion
draw_explosion()
if bomb_timer >= 5000: # Check if the bomb animation is over, and reset the bomb so that it can be used again in the future
bombTimers[timerName] = 0
bombs[bombName] = False
This code works exactly the same as the previous example, but it is much easier to work with. You can easily add more bombs while not starting with an unnecessary amount, like so:
bombCount = 1
bombs = {"bomb0": False}
bombTimers = {"bombTimer0": 0}
main_loop():
if player_placed_bomb(): # When the player drops a bomb in your game:
placed = False # Make a variable saying that you have not activaded the bomb and timer yet
for key, val in bombs: # For each bomb in the bombs dictionary:
if not val: # If the value of that bomb is False (Not being used):
val = True # Activates the bomb that was already created
placed = True # Updates the placed variable indicating that you set a bomb to active
break
if not placed: # After looping through the dictionary, if there were no inactive bomb variables:
bombs["bomb" + str(bombCounter)] = True # Create a new bomb in your dictionary, with a unique name.
bombTimers["bombTimer" + str(bombCounter)] = 0 # Created a new corresponding timer
bombCounter += 1 # Add 1 to the bombCounter, which is used to create the unique name of the next bomb you create.
# Rest of main_loop()
This code ensures that you are working with the smallest dictionaries possible to reduce unneeded computation power. When a bomb explodes, it will become false and it's matching timer reset. The first if loop in the code above ensures that all existing bombs are active, and if not reuses the old bomb and timer. If all bombs are being used, It creates new entries in the dictionaries to allow for more bombs.
I added an unnecesarry amount of comments, but I hope it makes it more understandable for you. Let me know if you have more questions on how this works. If you are unfamiliar with python dict() objects, there are lots of resources on the internet that explain them thoughroughly.
Disclaimer: I haven't actually ran the code, but it should function how it is supposed to. Let me know if it doesn't.
Here are some thoughts on the reformed code:
You use "str(bag["bombs"])" quite a bit in your code- consider defining a variable: b = str(bag["bombs"]), and using that. It would make it much simpler.
I don't know why you delete the "bombs_dict" and "explosions_dict" entries after you are finished with them. The way your loop is set up, I will result in an error. I would suggest rather than deleting the entries, you keep them and attempt to reuse them, as shown in the code snippet above.
Or, if you like deleting them, you need to figure out a way to rename certain keys in your dictionaries so that the names are in order. (if you delete bomb2 from bombs_dict, and you have bomb1 and bomb3, you need to change bomb3 to bomb2 or the loop wont work as intended). You will also need to alter your bombCount variable accordingly.