-1

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 enemies are moving towards the left able to drop bombs able to drop bombs able to buy bombs from the shop able to buy bombs from 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()
rishi
  • 643
  • 5
  • 21
  • @Torxed Sorry this is not what I'm looking for. I need a way to replace my bomb image with an explosion image after 3 seconds. Then I need to check whether the explosion is colliding with the enemy. After this need the explosion image to be popped after 2 seconds. – rishi May 28 '20 at 22:20
  • What problem do you have when you tried implementing this? What is the concrete problem you've encountered? – Ted Klein Bergman May 28 '20 at 22:52
  • @Ted Klein Bergman I have given a comment below InstaK0's answer which species what i need. – rishi May 29 '20 at 05:32
  • @rishi You're asking like 3 questions in one post, which is kind of not the purpose of SO. The links we've given solves your question of "replacing the image". The rest is just vectors (distance between two points) and you'll simply just have to do the math. The problem is quite simple so try solving each piece on it's own, don't try to solve one big problem at the same time.Hope that makes sense. – Torxed May 29 '20 at 07:12
  • Please keep all requirements in the question itself. Comments get deleted, but the question remain. Specify all your needs and restrictions in your question so we can better help you and future users. – Ted Klein Bergman May 29 '20 at 10:18

1 Answers1

1

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:

  1. 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.

  2. 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.

  3. 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.

InstaK0
  • 342
  • 3
  • 9
  • Thank you for your answer but this doesn't seem to be working. I need a way to handle multiple bombs(the number of bombs keeps changing depending on how many are bought). Also the bombs have to be replaced, they just overlapping right now. This code will works perfectly for managing one bomb at a time. One little correction - get_time() works in milliseconds so it'll be ```bomb_timer >= 5000``` – rishi May 29 '20 at 05:30
  • Thank you for that example, I'll play around with the code a bit to see what works. However there is no limit to how many bombs the player can place. – rishi May 29 '20 at 19:35
  • With more than 8 or so bombs I would suggest setting it up differently so It changes based on how many bombs appear. Ill add an idea to my answer. – InstaK0 May 30 '20 at 00:12
  • I didn't quite understand what's happening in your edited answer. – rishi May 30 '20 at 12:40
  • Ah yes, now I understand what's happening but where do i draw my images because in my code all my drawing is done under redrawGameWindow. – rishi May 30 '20 at 18:39
  • I have added another code with some changes to my original code using some of the concepts that you provided. Please help me troubleshoot and debug it. – rishi May 30 '20 at 19:58
  • Please elaborate on any problems you have. I wrote some initial thoughts in my answer – InstaK0 May 31 '20 at 01:58
  • Look at the tips/thoughts I wrote at the bottom of my answer. If you have any further questions, make a new post! The topic is way different from the initial title and that isn't fair to the people who are trying to learn from this post based on the title. I'll look at questions tagged "[pygame]" and try to find it. – InstaK0 May 31 '20 at 02:10