2

In my game the player can drop a bomb anywhere on the screen by pressing space. After 3 seconds the bomb image is replaced by an explosion image. I want to reduce 5 health from my player if he collides with the explosion image. I have tried several methods however, because of some looping mistake(which I can't figure out) the player keeps losing health while he is on the explosion. I want to just reduce 5 health once i.e if his health is 100 and he is on the explosion it should just reduce to 95 and not keep going down. I'm attaching my full code below. Thank you for your help.

import pygame
import random
import math

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))

pics = [bomb_pic, bomb_explosion]
shop = pygame.transform.scale(pygame.image.load("shop.png"), (60, 60))
boss = pygame.image.load("enemyboss.png")

player = [walkLeft, walkRight, char]

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')]

boss = pygame.image.load('pixel_monster.png')

position = [60, 60]
x = 50  # same as position
y = 50  # same as position
width = 40
height = 60
vel = 5
isJump = False
jumpCount = 10
left = False
right = False
down = False
up = False
walkCount = 0
run_once = False

enemy_vel = 2
enemy_list = []

clock = pygame.time.Clock()
FPS = 60

font = pygame.font.Font('freesansbold.ttf', 32)
items_font = pygame.font.Font('freesansbold.ttf', 16)
font_small = pygame.font.Font('freesansbold.ttf', 18)

bombs = []
explosions = []

bag = {'bomb': 0}
# print(bag["bomb"])
health = 100
got_hit = []


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 font_small
    global bag
    global items_font
    global enemy_list
    global pics
    global position
    global health
    global run_once
    global explosions
    global got_hit

    current_time = pygame.time.get_ticks()

    dx = []
    dy = []
    dist = []
    screen.fill([166, 166, 166])

    pygame.draw.rect(screen, (220, 0, 0), (700, 500, 100, 100))
    for five_enemies in range(5):
        random_enemy_location_y = random.randrange(50, 500)
        random_enemy_location_x = random.randrange(700, 840)
        enemy_list.append([random_enemy_location_x, random_enemy_location_y])

    for enemies in range(5):
        screen.blit(enemy_Left[enemies], enemy_list[enemies])
        dx.append(position[0] - enemy_list[enemies][0])
        dy.append(position[1] - enemy_list[enemies][1])
        dist.append(math.hypot(dx[enemies], dy[enemies]))
        dx[enemies], dy[enemies] = dx[enemies] / dist[enemies], dy[enemies] / dist[enemies]

        enemy_list[enemies][0] += dx[enemies] * 2
        enemy_list[enemies][1] += dy[enemies] * 2

    # for i in range(len(enemy_list)):
    #     for j in range(i + 1, len(enemy_list)):
    #         if enemy_list[i][0] - enemy_list[j][0] < 60:
    #             enemy_list[i][0] += 10

    #         elif enemy_list[i][1] - enemy_list[j][1]< 60:
    #            enemy_list[i][1] += 10

    pygame.draw.rect(screen, (70, 0, 220), (0, 170, 100, 300))  # main base
    pygame.draw.rect(screen, (220, 0, 0), (50, 200, 5, 250))
    pygame.draw.rect(screen, (0, 220, 0), (50, 200, 5, 250))
    screen.blit(font.render("B", True, (0, 0, 0)), (10, 200 + 40))
    screen.blit(font.render("A", True, (0, 0, 0)), (10, 235 + 40))
    screen.blit(font.render("S", True, (0, 0, 0)), (10, 270 + 40))
    screen.blit(font.render("E", True, (0, 0, 0)), (10, 305 + 40))

    pygame.draw.rect(screen, (220, 0, 0), (position[0] - 3, position[1], 50, 5))
    pygame.draw.rect(screen, (0, 220, 0), (position[0] - 3, position[1], 50, 5))

    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_small.render("Shop", True, (0, 0, 0)), (5, 5))

    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))
    # screen.blit(boss, (450, 300))

    if walkCount + 1 >= 27:
        walkCount = 0

    if left:
        screen.blit(player[0][walkCount // 3], (x, y))
        walkCount += 1

    elif right:
        screen.blit(player[1][walkCount // 3], (x, y))
        walkCount += 1

    elif down:
        screen.blit(player[2], (x, y))
        walkcount = 0

    elif up:
        screen.blit(player[2], (x, y))
        walkcount = 0

    else:
        screen.blit(player[2], (x, y))
        walkCount = 0

    for i in reversed(range(len(bombs))):
        pos, end_time = bombs[i]
        if current_time > end_time:
            bombs.pop(i)
        else:
            screen.blit(pics[0], pos)

    for j in reversed(range(len(explosions))):
        pos = explosions[j][0]
        end_time_2 = explosions[j][1]
        if current_time > end_time_2:
            explosions.pop(j)


        elif current_time > (end_time_2 - 2000):
            screen.blit(pics[1], pos)

        else:
            continue

    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
    global explosions
    global position
    global got_hit

    global pos2list

    while run:

        current_time = pygame.time.get_ticks()
        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:
                    current_time_2 = pygame.time.get_ticks()
                    pos = x + char.get_width() / 2, y + char.get_height() - 20
                    pos2 = ((x + char.get_width() / 2) - 10), (y + char.get_height() - 30)
                    end_time = current_time + 3000  # 3000 milliseconds = 3 seconds
                    end_time_2 = current_time_2 + 5000
                    explosions.append((pos2, end_time_2))
                    # print(explosions[-1][0][0])
                    got_hit.append(False)
                    bombs.append((pos, end_time))
                    bag["bomb"] -= 1

        redrawGameWindow()

        keys = pygame.key.get_pressed()

        if keys[pygame.K_LEFT] and x > vel - 15:
            x -= vel
            position[0] -= vel
            left = True
            right = False
            down = False
            up = False
            # print(position)

        elif keys[pygame.K_RIGHT] and x < 800 - vel - width:
            x += vel
            position[0] += vel
            left = False
            right = True
            down = False
            up = False
            # print(position)

        elif keys[pygame.K_DOWN] and y < 600 - height:
            y += vel
            position[1] += vel
            left = False
            right = False
            down = True
            up = False
            # print(position)

        elif keys[pygame.K_UP] and y > vel - 15:
            y -= vel
            position[1] -= vel
            left = False
            right = False
            down = False
            up = True
            # print(position)

        else:
            left = False
            right = False
            down = False
            up = False
            walkCount = 0

        clock.tick(FPS)
        pygame.display.flip()


main()
rishi
  • 643
  • 5
  • 21

1 Answers1

1

First of all do not add the explosion when the bomb is created:

if event.type == pygame.KEYDOWN:
    if event.key == pygame.K_SPACE and bag["bomb"] >= 1:
        current_time_2 = pygame.time.get_ticks()
        pos = x + char.get_width() / 2, y + char.get_height() - 20
        pos2 = ((x + char.get_width() / 2) - 10), (y + char.get_height() - 30)
        end_time = current_time + 3000  # 3000 milliseconds = 3 seconds

        # end_time_2 = current_time_2 + 2000      <--- DELETE
        # explosions.append((pos2, end_time_2))   <--- DELETE

        got_hit.append(False)
        bombs.append((pos, end_time))
        bag["bomb"] -= 1

Create the explosion when bomb threshold exceeds. Add an additional boolean attribute to the tuple which indicates if the plyer was hurt by the bomb ((pos2, end_time_2, False)):

for i in reversed(range(len(bombs))):
    pos, end_time = bombs[i]
    if current_time > end_time:
        end_time_2 = end_time + 5000
        pos2 = (pos[0] - 10, pos[1] - 30
        explosions.append((pos2, end_time_2, False))
        bombs.pop(i)
    else:
        screen.blit(pics[0], pos)

Create a pygame.Rect for the bomb and the player and evaluate if the plyer collides with the bomb. Change the hurt indicator in the tuple if the plyer collides with the explosion. The pygame.Rect objects can be get created by pygame.Surface.get_rect. The position can be set by a keyword argument (for instance player_rect = player[0][0].get_rect(topleft = (x, y))):

for j in reversed(range(len(explosions))):
    pos, end_time_2, hurt = explosions[j]
    if current_time > end_time_2:
        explosions.pop(j)
    else:
        screen.blit(pics[1], pos)

        if not hurt:
            explosion_rect = pics[1].get_rect(topleft = pos)
            player_rect = player[0][0].get_rect(topleft = (x, y))
            if player_rect.colliderect(explosion_rect):
                explosions[j] = (pos, end_time_2, True)
                health -= 5

Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • 1
    @rishi An image has not location it just has a size. `get_rect` gets a `pygame.Rect` object withe the size of the image and a position of (0, 0). Hence the position can be set by an keyword argument (e.g. `topleft`). The size of the image is the overall size, including the transparent area. – Rabbid76 Jun 07 '20 at 17:30