Search code examples
pythonpygamebulletphysics

Shoot problem: How to show a bullet before shoot?


I would like the 'banana' to be shown when the space bar is pressed, while it follows the character movement, and then to be fired upon the release of the same.

    import pygame
    from pygame.locals import *
    
    
    #inizializzazione
    pygame.init()
    screen=pygame.display.set_mode((400,750))
    pygame.display.set_caption('MonkeyBanana')
    FPS=60
    
    
    
    #load image
    img_ground = pygame.image.load('Surf/sfondo.jpg').convert_alpha()
    surf_ground=pygame.transform.scale(img_ground,(img_ground.get_width(),screen.get_height()))
    
    
    class Monkey (pygame.sprite.Sprite):
        def __init__(self):
            super().__init__()
            self.sprites = [pygame.transform.scale((pygame.image.load('Surf/Animazioni/monkey_idle_00.png').convert_alpha()),
                                                   (screen.get_width() / 5, screen.get_height() / 7)),
                            pygame.transform.scale((pygame.image.load('Surf/Animazioni/monkey_idle_01.png').convert_alpha()),
                                                   (screen.get_width() / 5, screen.get_height() / 7)),
                            pygame.transform.scale((pygame.image.load('Surf/Animazioni/monkey_idle_02.png').convert_alpha()),
                                                   (screen.get_width() / 5, screen.get_height() / 7)),
                            pygame.transform.scale((pygame.image.load('Surf/Animazioni/monkey_idle_03.png').convert_alpha()),
                                                   (screen.get_width() / 5, screen.get_height() / 7))
                            ]
    
            self.launch_monkey=[]
            for i in range(0, 19):
                filename = "Surf/Animazioni/monkey_{:0>3}.png".format(i)
                img = pygame.image.load(filename).convert_alpha()
                img_reduced = pygame.transform.scale(img, (screen.get_width() / 5, screen.get_height() / 7))
                self.launch_monkey.append(img_reduced)
    
            self.count=0
            self.count1 = 0
    
    
            self.image = self.sprites[self.count]
            self.rect = self.image.get_rect()
            self.rect.midbottom = (screen.get_width() / 2, screen.get_height())
            all_sprites.add(self)
    
        def update(self):
            self.count += 0.08
            if self.count >= 3:
                self.count = 0
            self.image = self.sprites[int(self.count)]
            if move_right and monkey.rect.right < screen.get_width():
                monkey.rect.x += 5
            elif move_left and monkey.rect.left > 0:
                monkey.rect.x -= 5
    
        def launch(self):
            global launch
    
            if launch:
                self.count1 += 1
                if self.count1 >= 19:
                    self.count1 = 0
                    launch = False
                self.image = self.launch_monkey[int(self.count1)]
    
    
    class Banana (pygame.sprite.Sprite):
        def __init__(self):
            super().__init__()
            self.image= pygame.transform.scale((pygame.image.load('Surf/banana.png').convert_alpha()),
                                               (screen.get_width() / 10, screen.get_height() / 15))
            self.rect=self.image.get_rect()
            self.rect.center = monkey.rect.center
            all_banana.add(self)
    

here is the problem. Everything works fine on the first launch. The second time I press the space bar, the banana returns to the character's hands instead of continuing the run.

        def update(self):
            global new_banana
            if keep_banana:
                self.rect.center = monkey.rect.center
                new_banana=False
    
            if launch_banana:
                self.rect.y -= 5
    
            if self.rect.top<50:
                self.kill()
    
    
    #create sprite and Group
    
    all_sprites = pygame.sprite.Group()
    all_banana= pygame.sprite.Group()
    monkey=Monkey()
    
    
    #other variables
    move_right=False
    move_left=False
    launch=False
    launch_banana=False
    keep_banana=False
    new_banana=False
    
    
    
    #principal cicle
    done=False
    while not done:
    
        for ev in pygame.event.get():
            if ev.type == QUIT:
                done = True
            if ev.type ==KEYDOWN:
                if ev.key== K_RIGHT:
                    move_right=True
                    idle = False
                if ev.key== K_LEFT:
                    move_left = True
                    idle = False
                if ev.key==K_SPACE:
                    keep_banana = True
                    new_banana=True
    
            elif ev.type ==KEYUP:
                if ev.key== K_RIGHT:
                    move_right=False
                    idle = True
                if ev.key== K_LEFT:
                    move_left=False
                    idle = True
                if ev.key==K_SPACE:
                    launch_banana=True
                    keep_banana = False
                    launch = True
    
        #Game logic
        if new_banana:
            banana=Banana()
    
        #screen update
    
    
        screen.blit(surf_ground, (0, 0))
        all_sprites.draw(screen)
        all_banana.draw(screen)
        all_banana.update()
        all_sprites.update()
        monkey.launch()
        pygame.display.flip()
        pygame.time.Clock().tick(FPS)
    
    #end principal cicle
    pygame.quit()

It works to me in another version without classes,by adding the banana to a new group every time it is fired, but I can't get it to work on the classes. I have tried so many times, but nothing seems to work


Solution

  • launch_banana makes the banana fly:

    if launch_banana:
       self.rect.y -= 5
    

    launch_banana is False at the beginning, but it is never set False again once it has become True. You have to set launch_banana to False when keep_banana is set True:

    launch_banana=False
    keep_banana=False
    new_banana=False
    
    # [...]
    
    while not done:
    
        for ev in pygame.event.get():
            # [...]
    
            if ev.type == KEYDOWN:
                # [...]
    
                if ev.key == K_SPACE:
                    launch_banana = False        # <---
                    keep_banana = True
                    new_banana = True
    
            elif ev.type == KEYUP:
                # [...]
    
                if ev.key == K_SPACE:
                    launch_banana = True
                    keep_banana = False
                    launch = True
    

    Anyway, instead of all these Boolean variables, I propose to add a state to the Banana class. The state can be "keep" at the beginning and can be changed to "launched" after the banana is started.

    class Banana (pygame.sprite.Sprite):
        def __init__(self):
            super().__init__()
            self.image= pygame.transform.scale((pygame.image.load('Surf/banana.png').convert_alpha()),
                                                   (screen.get_width() / 10, screen.get_height() / 15))
            self.rect=self.image.get_rect()
            self.rect.center = monkey.rect.center
            all_banana.add(self)
    
            self.state = "keep"
    
        def start(self):
            self.state = "launched"
    
        def update(self):
            if self.state == "keep":
                self.rect.center = monkey.rect.center
        
            elif self.state == "launched":
                self.rect.y -= 5
        
            if self.rect.top<50:
                self.kill()