Search code examples
pythonpygame

How can I show explosion image when collision happens?


I don't know why explosion effect doesn't happen.
The other images were drawn well, but only explosion image didn't

explosion = pygame.image.load(os.path.join(image_path, "explosion.png"))
explosion_size = explosion.get_rect().size
explosion_width = explosion_size[0]
for missile_idx, missile_val in enumerate(missiles):
    missile_pos_x = missile_val[0]
    missile_pos_y = missile_val[1]

    #weapon information upgrade
    missile_rect = missile.get_rect()
    missile_rect.left = missile_pos_x
    missile_rect.top = missile_pos_y

    if missile_rect.colliderect(rock_rect):
        explosion_sound.play()
        **explosion_pos_x = missile_pos_x
        explosion_pos_y = missile_pos_y
        screen.blit(explosion,(explosion_pos_x,explosion_pos_y))**
        del(rock)
        del(missiles)
        missiles = []

        # missile position coordination
        missiles = [[m[0], m[1] - missile_speed] for m in missiles]

        # top missile elimination
        missiles = [[m[0], m[1]] for m in missiles if m[1]>0]

Solution

  • The explosion is just shown for a short moment. Use pygame.time.get_ticks() to return the number of milliseconds since pygame.init() was called. Calculate the point in time after that the explosion image has to be removed. Add the coordinates of the explosion and the end time point to the head of a list (explosionList ). Draw the explosion(s) in the main application loop. Remove the expired explosions from the tail of the list:

    explosionList = []
    
    while run:
        current_time = pygame.time.get_ticks()
        # [...]
    
        for missile_idx, missile_val in enumerate(missiles)
            # [...]
    
            if missile_rect.colliderect(rock_rect):
                explosion_sound.play()
    
                explosion_pos_x = missile_pos_x
                explosion_pos_y = missile_pos_y
                end_time = current_time + 2000 # 2000 milliseconds = 2 seconds
                explosionList.insert(0, (end_time, explosion_pos_x, explosion_pos_y))
    
                # [...]
    
        for i in range(len(explosionList)):
            if current_time < explosionList[i][0]:
                screen.blit(explosion, (explosionList[i][1], explosionList[i][2]))
            else:
                explosionList = explosionList[:i]
                break
        
        # [...]
    

    With this algorithm it is possible to manage multiple explosions.

    See Time, timer event and clock


    Minimal example PYGBAG demo

    import pygame
    pygame.init()
    window = pygame.display.set_mode((210, 210))
    
    def create_rectangles():
        global rectangles
        w, h = window.get_size()
        rectangles = []
        for x in range(0, w - 60, 60):
            for y in range(0, h - 60, 60):
                rectangles.append(pygame.Rect(x + 30, y + 30, 30, 30))
    
    create_rectangles()
    hit_list = []
    fade_out_time = 3000
    
    run = True
    while run:
        current_time = pygame.time.get_ticks()
        
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                run = False
    
        point = pygame.mouse.get_pos()
        collideindex = pygame.Rect(point, (1, 1)).collidelist(rectangles)
        if collideindex >= 0:
            end_time = current_time + fade_out_time
            hit_list.insert(0, (end_time, rectangles[collideindex].center))
            del rectangles[collideindex]
        if not hit_list and not rectangles:
            create_rectangles()
    
        window.fill(0)
        for r in rectangles:
            pygame.draw.rect(window, (255, 0, 0), r)
        for i in range(len(hit_list)):
            delta_time = hit_list[i][0] - current_time
            if delta_time > 0:
                radius = round(30 * delta_time / fade_out_time)
                pygame.draw.circle(window, (255, 255, 0), hit_list[i][1], radius)
            else:
                hit_list = hit_list[:i]
                break
        pygame.display.flip()