pythonmathpygamebulletphysicsbullet

How to shoot a bullet at an angle in pygame?


I am making a game in pygame, and when you shoot a bullet, the bullet travels in the same direction that your mouse is. Here is my code for my Player class:

class Player(pygame.sprite.Sprite):
    def __init__(self, game, x, y):
        self.game = game
        pygame.sprite.Sprite.__init__(self, game.all_sprites)
        self.image = pygame.Surface((50, 50))
        self.image.fill(settings.player_color)

        self.rect = self.image.get_rect()
        self.rect.x, self.rect.y = x, y
        self.pos = Vector2(x, y)

        self.speed = Vector2(0, 0)

        self.is_shooting = False

    def update(self):
        self.pos += self.speed
        self.rect.x, self.rect.y = self.pos.x, self.pos.y

    def shoot(self):
        self.is_shooting = True
        m_x, m_y = pygame.mouse.get_pos()
        b_m_x, b_m_y = m_x - self.pos.x, m_y - self.pos.y
        b = Bullet(self.game, self.rect.x - 50, self.rect.y - 50 / 2, b_m_x, b_m_y)
        _, angle = (pygame.mouse.get_pos() - self.pos).as_polar()
        b.rotate(_)

The way I am making the bullet path is I am making it so that the bullet has a slope just like a line. b_m_x and b_m_y is the change in x and the change in y.

I am only just starting to learn algebra this year (I am 13), and I learned how to graph linear lines last year, so if there is an easier way to make the bullet path, please let me know.

Here is my code for my Bullet Class

class Bullet(pygame.sprite.Sprite):
    def __init__(self, game, x, y, run, rise):
        pygame.sprite.Sprite.__init__(self, game.all_sprites)
        self.image = pygame.Surface((15, 50))
        self.image.fill((255, 0, 0))

        self.rect = self.image.get_rect()
        self.rect.x, self.rect.y = x, y
        self.pos = pygame.math.Vector2(self.rect.x, self.rect.y)
        self.speed = pygame.math.Vector2(x=run / settings.bullet_speed_offset, y=rise / settings.bullet_speed_offset)

    def update(self):
        self.pos += self.speed
        self.rect.x, self.rect.y = self.pos.x, self.pos.y

    def rotate(self, angle):
        self.image = pygame.transform.rotozoom(self.image, angle, 1)
        self.rect = self.image.get_rect()

My problem is that the farther my mouse is away from the Player sprite, the faster the bullet travels (because when I find the slope of the line, the bigger the difference is between the mouse and the player, the faster the speed of the bullet will be). How can I make a better system of firing bullets?


Solution

  • You should normalize the distance to the mouse if you want the speed not to depend on the mouse distance.

    In other words, regardless of where the mouse is, use the coordinates of the point which is in that same direction, but at a fixed distance from the starting position, e.g. when you calculate your b_m_xand b_m_y, do this:

    b_m_x, b_m_y = m_x - self.pos.x, m_y - self.pos.y
    
    distance = (b_m_x ** 2 + b_m_y ** 2) ** .5
    
    if distance != 0:
        # if distance is 0, nothing can be done
    
        NORMALIZED_DISTANCE = 100
        mutiplier = NORMALIZED_DISTANCE / distance
    
        b_m_x *= multipler
        b_m_y *= multipler