Search code examples
pythonpygamesprite

How to adjust the direction of movement of bullet sprites?


In my program, when the keys are pressed, the image of the ship is flipped. I decided to bind the direction of the bullets to the flags of the ship's position. But I ran into the problem that all bullets take the direction of the ship when they are already fired. I need to keep the coordinate of the sprite when it is drawn.

import sys
import pygame
from settings import Settings
from rocket import Rocket
from bullet import Bullet


class Cosmos:
    """Главный класс игры Cosmos"""

    def __init__(self):
        pygame.init()
        self.screen = pygame.display.set_mode((0, 0), pygame.FULLSCREEN)
        pygame.display.set_caption('Cosmos')
        self.fon_image = pygame.image.load('image/Fon.png')
        self.fon = self.fon_image.get_rect()
        self.settings = Settings()
        self.rocket = Rocket(self.screen, self.settings)
        self.bullets = pygame.sprite.Group()


    def key_event(self):
        """Обрабатывает нажатие клавиш"""
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    sys.exit()
                elif event.key == pygame.K_d:
                    self.rocket.move_RIGHT = True
                elif event.key == pygame.K_a:
                    self.rocket.move_LEFT = True
                elif event.key == pygame.K_w:
                    self.rocket.move_UP = True
                elif event.key == pygame.K_s:
                    self.rocket.move_DOWN = True
                elif event.key == pygame.K_SPACE:
                    self.fire_bullet()
            elif event.type == pygame.KEYUP:
                if event.key == pygame.K_d:
                    self.rocket.move_RIGHT = False
                elif event.key == pygame.K_a:
                    self.rocket.move_LEFT = False
                elif event.key == pygame.K_w:
                    self.rocket.move_UP = False
                elif event.key == pygame.K_s:
                    self.rocket.move_DOWN = False

    def fire_bullet(self):
        """Создание нового снаряда и включение его в группу"""
        new_bullet = Bullet(self.screen, self.settings, self.rocket)
        self.bullets.add(new_bullet)

    def run_game(self):
        """Обновляет события игры"""
        while True:
            self.screen.blit(self.fon_image, self.fon)
            self.key_event()
            self.rocket.update_rocket()
            for bullet in self.bullets.sprites():
                bullet.draw_bullet()
                self.bullets.update(bullet)
            self.rocket.draw_rocket()
            pygame.display.flip()


game = Cosmos()
game.run_game()
from pygame.sprite import Sprite


class Bullet(Sprite):
    """Класс для управления снарядами, выпущенными кораблем"""

    def __init__(self, screen, settings, rocket):
        super().__init__()
        self.screen = screen
        self.settings = settings
        self.rocket = rocket
        self.color = self.settings.bullets_color
        self.rect = pygame.Rect(0, 0, self.settings.bullets_width, self.settings.bullets_height)
        self.rect.midtop = rocket.rect.midtop
        self.y = float(self.rect.y)
        self.x = float(self.rect.x)

    def update(self, bullet):
        """Перемещение снаряда"""
        if self.rocket.image == self.rocket.image_right:
            bullet.x += 2
        if self.rocket.image == self.rocket.image_left:
            bullet.x -= 2
        if self.rocket.image == self.rocket.image_up:
            bullet.y -= 2
        if self.rocket.image == self.rocket.image_down:
            bullet.y += 2
        self.rect.x = self.x
        self.rect.y = self.y

    def draw_bullet(self):
        """Рисует снаряд"""
        pygame.draw.rect(self.screen, self.color, self.rect)
import pygame


class Rocket:
    """Класс для управления кораблём"""

    def __init__(self, screen, settings):
        self.screen = screen
        self.screen_rect = screen.get_rect()
        self.settings = settings
        self.image = pygame.image.load('image/pixil-frame-0.png')
        self.rect = self.image.get_rect()
        self.rect.center = self.screen_rect.center
        self.x = float(self.rect.x)
        self.y = float(self.rect.y)
        self.move_RIGHT = False
        self.move_LEFT = False
        self.move_UP = False
        self.move_DOWN = False
        self.image_right = pygame.transform.rotate(self.image, -90)
        self.image_left = pygame.transform.rotate(self.image, 90)
        self.image_up = pygame.transform.rotate(self.image, 0)
        self.image_down = pygame.transform.rotate(self.image, 180)


    def update_rocket(self):
        """Флаги управления кораблём"""
        if self.move_RIGHT and self.rect.right < self.screen_rect.right:
            self.image = self.image_right
            self.x += self.settings.rocket_speed
        if self.move_LEFT and self.rect.left > self.screen_rect.left:
            self.image = self.image_left
            self.x -= self.settings.rocket_speed
        if self.move_UP and self.rect.top > self.screen_rect.top:
            self.image = self.image_up
            self.y -= self.settings.rocket_speed
        if self.move_DOWN and self.rect.bottom < self.screen_rect.bottom:
            self.image = self.image_down
            self.y += self.settings.rocket_speed
        self.rect.x = self.x
        self.rect.y = self.y

    def draw_rocket(self):
        """Обновляет позицию корабля"""
        self.screen.blit(self.image, self.rect)

Solution

  • The problem here is that in Bullet.update, you use the current image of the rocket to determine in which direction the bullet is going. This means that any change of this image results in a change of direction. Instead of doing this, you should save the current direction upon creating a new Bullet instance and then use this saved direction to determine the direction of the rocket.

    A possible implementation:

    class Bullet(Sprite):
        """Класс для управления снарядами, выпущенными кораблем"""
    
        def __init__(self, screen, settings, rocket):
            super().__init__()
            self.screen = screen
            self.settings = settings
            self.rocket = rocket
            self.color = self.settings.bullets_color
            self.rect = pygame.Rect(0, 0, self.settings.bullets_width, self.settings.bullets_height)
            self.rect.midtop = rocket.rect.midtop
            self.y = float(self.rect.y)
            self.x = float(self.rect.x)
            if self.rocket.image == self.rocket.image_right:
                self.direction = "right"
            elif self.rocket.image == self.rocket.image_left:
                self.direction = "left"
            elif self.rocket.image == self.rocket.image_up:
                self.direction = "up"
            elif self.rocket.image == self.rocket.image_down:
                self.direction = "down"
    
        def update(self, bullet):
            """Перемещение снаряда"""
            if self.direction == "right":
                bullet.x += 2
            if self.direction == "left":
                bullet.x -= 2
            if self.direction == "up":
                bullet.y -= 2
            if self.direction == "down":
                bullet.y += 2
            self.rect.x = self.x
            self.rect.y = self.y
    
        def draw_bullet(self):
            """Рисует снаряд"""
            pygame.draw.rect(self.screen, self.color, self.rect)