0

I am attempting to create a bullet for my 2d shooter game.

I have created the bullet and it is displayed on the screen when the user presses the left mouse button, however I must now make it move.

Each bullet is added to the bullet group.

What would be the easiest way to update the position of the bullet?

This is the while loop. GameClass.Game.getevent is called, which states that if lmb is pressed, then the code below it will be run.

   while play:
    display.fill(WHITE)
    GameClass.Game.getevent(player1)
    platforms.draw(display)
    sprites.draw(display)
    bullets.draw(display)
    pygame.display.update()

The following is part of a different file. The shoot function is part of the 'player' class, which has been cut off due to irrelevance.

    def shoot(self):
        bullet=Bullet(5,self.bullets,self.x,self.y)
        self.bullets.add(bullet)


class Bullet(pygame.sprite.Sprite):

    def __init__(self,speed,bullets,x,y):
        super().__init__()

        self.speed=speed
        self.image=pygame.Surface((10,10))
        self.rect=self.image.get_rect()
        self.bullets=bullets

        self.x=x
        self.y=y

        Bullet.movebullet(self)

    def movebullet(self):
        self.rect.center=((self.x+self.speed),self.y)

What would be the best way of updating the position of each individual bullet in the group?

eyllanesc
  • 235,170
  • 19
  • 170
  • 241
Link
  • 317
  • 1
  • 5
  • 17
  • 1
    Give your `Bullet` class an `update` method in which you move the sprite by updating the `self.x` and `self.y` attributes first and then assign these attributes to the `self.rect.center`. To update the sprites just call the `update` method of the group each frame and it will call the `update` method of all contained sprites. Should the bullets all move in the same direction or arbitrary directions? – skrx Dec 29 '17 at 01:42
  • use button `{}` to correctly format code – furas Dec 29 '17 at 02:06
  • all sprites don't need `self.x` - you have `self.rect.x` for this. And then you can move bullet using `self.rect.x += self.speed` instead of `self.rect.center=((self.x+self.speed),self.y)` – furas Dec 29 '17 at 02:09
  • instead of `Bullet.movebullet(self)` you should do `self.movebullet()` – furas Dec 29 '17 at 02:10
  • add spaces around `=` to make code more readable. See more in [PEP 8 -- Style Guide for Python Code](https://www.python.org/dev/peps/pep-0008/) – furas Dec 29 '17 at 02:11
  • Thank-you for your help. I have coded the sprite update as: self.rect.x += self.speed. I do not know what code is required to get this to be called and repeated for every item in the group in the while loop.The user can face either left or right, and the bullet is supposed to shoot in the direction they are facing. This method seems that it will always shoot the bullet from left to right, no matter what. – Link Dec 29 '17 at 16:07
  • @skrx The only thing I have left to do is to get the bullet position to update every frame. As you quite rightly stated, I need to put the code in the main file while loop. But what code exactly do I put? If I call playerclasses.Bullets.update(), what exactly do I put in the self parameter? I need to update the entire group. – Link Jan 02 '18 at 01:34
  • def update(self): if self.right==True: self.rect.x += self.speed elif self.right==False: self.rect.x -= self.speed – Link Jan 02 '18 at 01:35
  • ^ If OOP works as a believe it does, each bullet that is added to the group has a boolean self.right value. If the user was facing right when they shot, this will be true, if not, it will be false. This determines if the x value is being taken away or added to that sprite. – Link Jan 02 '18 at 01:37

1 Answers1

0

Here's a complete solution. The player has a direction attribute which I change to 'left' or 'right' when the player presses one of the corresponding keys. When a bullet is created, I pass the player.direction to the bullet instance and then set its image and velocity depending on the direction.

In order to move the sprites, I add the velocity to the position (which are lists in this example) and finally I update the rect because it's needed for the blitting and collision detection. Actually, I'd use pygame.math.Vector2s for the pos and velocity, but I'm not sure if you are familiar with vectors.

import pygame as pg


pg.init()
screen = pg.display.set_mode((640, 480))
screen_rect = screen.get_rect()
PLAYER_IMG = pg.Surface((30, 50))
PLAYER_IMG.fill(pg.Color('dodgerblue1'))
BULLET_IMG = pg.Surface((16, 8))
pg.draw.polygon(BULLET_IMG, pg.Color('sienna1'), [(0, 0), (16, 4), (0, 8)])
BULLET_IMG_LEFT = pg.transform.flip(BULLET_IMG, True, False)


class Player(pg.sprite.Sprite):

    def __init__(self, pos):
        super().__init__()
        self.image = PLAYER_IMG
        self.rect = self.image.get_rect(center=pos)
        self.velocity = [0, 0]
        self.pos = [pos[0], pos[1]]
        self.direction = 'right'

    def update(self):
        self.pos[0] += self.velocity[0]
        self.pos[1] += self.velocity[1]
        self.rect.center = self.pos


class Bullet(pg.sprite.Sprite):

    def __init__(self, pos, direction):
        super().__init__()
        if direction == 'right':
            self.image = BULLET_IMG
            self.velocity = [9, 0]
        else:
            self.image = BULLET_IMG_LEFT
            self.velocity = [-9, 0]
        self.rect = self.image.get_rect(center=pos)
        self.pos = [pos[0], pos[1]]

    def update(self):
        # Add the velocity to the pos to move the sprite.
        self.pos[0] += self.velocity[0]
        self.pos[1] += self.velocity[1]
        self.rect.center = self.pos  # Update the rect as well.
        # Remove bullets if they're outside of the screen area.
        if not screen_rect.contains(self.rect):
            self.kill()


def main():
    clock = pg.time.Clock()
    all_sprites = pg.sprite.Group()
    bullets = pg.sprite.Group()
    player = Player((100, 300))
    all_sprites.add(player)

    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True
            elif event.type == pg.MOUSEBUTTONDOWN:
                if event.button == 1:
                    bullet = Bullet(player.rect.center, player.direction)
                    bullets.add(bullet)
                    all_sprites.add(bullet)
            elif event.type == pg.KEYDOWN:
                if event.key == pg.K_d:
                    player.velocity[0] = 5
                    player.direction = 'right'
                elif event.key == pg.K_a:
                    player.velocity[0] = -5
                    player.direction = 'left'
            elif event.type == pg.KEYUP:
                if event.key == pg.K_d and player.velocity[0] > 0:
                    player.velocity[0] = 0
                elif event.key == pg.K_a and player.velocity[0] < 0:
                    player.velocity[0] = 0

        all_sprites.update()
        screen.fill((30, 30, 30))
        all_sprites.draw(screen)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    main()
    pg.quit()
skrx
  • 19,980
  • 5
  • 34
  • 48
  • Here's [an example](https://stackoverflow.com/a/42281315/6220679) with vectors and a rotating gun if you're interested. – skrx Jan 02 '18 at 02:23