Pygame Rotated Shooting

前端 未结 3 1774
Happy的楠姐
Happy的楠姐 2020-12-01 22:42

Me and a few friends have been coding an intresting new shooting mechanic. For It to work, we need to shoot in the direction the player is facing. The Sprite is being rotate

相关标签:
3条回答
  • 2020-12-01 23:27

    Here's a quick'n'dirty executable example of how to use vector math to do what you want.

    import pygame
    
    class Player(pygame.sprite.Sprite):
        def __init__(self):
            super().__init__()
            self.image = pygame.Surface((32, 32))
            self.image.fill((0, 0, 0))
            self.image.set_colorkey((0, 0, 0))
            pygame.draw.polygon(self.image, pygame.Color('dodgerblue'), ((0, 0), (32, 16), (0, 32)))
            self.org_image = self.image.copy()
            self.angle = 0
            self.direction = pygame.Vector2(1, 0)
            self.rect = self.image.get_rect(center=(200, 200))
            self.pos = pygame.Vector2(self.rect.center)
    
        def update(self, events, dt):
            for e in events:
                if e.type == pygame.KEYDOWN:
                    if e.key == pygame.K_SPACE:
                        self.groups()[0].add(Projectile(self.rect.center, self.direction.normalize()))
            pressed = pygame.key.get_pressed()
            if pressed[pygame.K_a]:
                self.angle += 3
            if pressed[pygame.K_d]:
                self.angle -= 3
    
            self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
            self.image = pygame.transform.rotate(self.org_image, self.angle)
            self.rect = self.image.get_rect(center=self.rect.center)
    
    class Projectile(pygame.sprite.Sprite):
        def __init__(self, pos, direction):
            super().__init__()
            self.image = pygame.Surface((8, 8))
            self.image.fill((0, 0, 0))
            self.image.set_colorkey((0, 0, 0))
            pygame.draw.circle(self.image, pygame.Color('orange'), (4, 4), 4)
            self.rect = self.image.get_rect(center=pos)
            self.direction = direction
            self.pos = pygame.Vector2(self.rect.center)
    
        def update(self, events, dt):
            self.pos += self.direction * dt
            self.rect.center = self.pos
            if not pygame.display.get_surface().get_rect().contains(self.rect):
                self.kill()
    
    def main():
        pygame.init()
        screen = pygame.display.set_mode((500, 500))
        sprites = pygame.sprite.Group(Player())
        clock = pygame.time.Clock()
        dt = 0
    
        while True:
            events = pygame.event.get()
            for e in events:
                if e.type == pygame.QUIT:
                    return
            sprites.update(events, dt)
            screen.fill((30, 30, 30))
            sprites.draw(screen)
            pygame.display.update()
            dt = clock.tick(60)
    
    if __name__ == '__main__':
        main()
    

    Note: it seems that you're loading the image of your player every frame. You should not do that, as this is very slow. Just load each image once. Also, it's better to have only one spot in your code that calls pygame.display.update(), as you should make sure it's called only once each frame.

    0 讨论(0)
  • 2020-12-01 23:38

    You have angle in degrees so try this:

    import math
    
    # angle examples 
    for angle in [0, 30, 45, 60, 0+90, 30+90, 45+90, 60+90, 0+180, 30+180, 45+180, 60+180, 0+270, 30+270, 45+270, 60+270]: 
    
        bullet_speed = 10
    
        bullet_move_x = bullet_speed * math.cos( math.radians(angle) )
        bullet_move_y = -bullet_speed * math.sin( math.radians(angle) )
    
        print angle, bullet_move_x, bullet_move_y
    

    Now you can add bullet_move_x, bullet_move_y to bullet positon.

    For better results keep bullet position as float and convert to int when you blit bullet

    0 讨论(0)
  • 2020-12-01 23:41

    This example demonstrates how vectors can be utilized to control the position, velocity and also the start offset of the bullets.

    In the while loop we use math.atan2 to calculate the angle to the target which is then used to rotate the cannon image and passed to the Bullet instances. In the __init__ method of the Bullets we rotate the offset vector, velocity vector and the sprite image by the angle.

    To move the bullet, we add the (rotated) velocity vector to the position vector and set the rect position to the pos vector. The rect has to be moved, because it holds the blit position and is used for collision detection.

    import math
    import pygame as pg
    from pygame.math import Vector2
    
    
    pg.init()
    screen = pg.display.set_mode((640, 480))
    FONT = pg.font.Font(None, 24)
    BLACK = pg.Color('black')
    BULLET_IMAGE = pg.Surface((20, 11), pg.SRCALPHA)
    pg.draw.polygon(BULLET_IMAGE, pg.Color('grey11'), [(0, 0), (20, 5), (0, 11)])
    
    
    class Bullet(pg.sprite.Sprite):
    
        def __init__(self, pos, angle):
            super(Bullet, self).__init__()
            self.image = pg.transform.rotate(BULLET_IMAGE, -angle)
            self.rect = self.image.get_rect(center=pos)
            # To apply an offset to the start position,
            # create another vector and rotate it as well.
            offset = Vector2(40, 0).rotate(angle)
            # Add the offset vector to the position vector.
            self.pos = Vector2(pos) + offset  # Center of the sprite.
            # Rotate the velocity vector (9, 0) by the angle.
            self.velocity = Vector2(9, 0).rotate(angle)
    
        def update(self):
            # Add velocity to pos to move the sprite.
            self.pos += self.velocity
            self.rect.center = self.pos
    
    
    def main():
        clock = pg.time.Clock()
        # The cannon image and rect.
        cannon_img = pg.Surface((60, 22), pg.SRCALPHA)
        pg.draw.rect(cannon_img, pg.Color('grey19'), [0, 0, 35, 22])
        pg.draw.rect(cannon_img, pg.Color('grey19'), [35, 6, 35, 10])
        orig_cannon_img = cannon_img  # Store orig image to preserve quality.
        cannon = cannon_img.get_rect(center=(320, 240))
        angle = 0
        # Add bullets to this group.
        bullet_group = pg.sprite.Group()
    
        playing = True
        while playing:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    playing = False
                elif event.type == pg.MOUSEBUTTONDOWN:
                    # Left button fires a bullet from cannon center with
                    # current angle. Add the bullet to the bullet_group.
                    if event.button == 1:
                        bullet_group.add(Bullet(cannon.center, angle))
    
            bullet_group.update()
            # Find angle to target (mouse pos).
            x, y = Vector2(pg.mouse.get_pos()) - cannon.center
            angle = math.degrees(math.atan2(y, x))
            # Rotate the cannon image.
            cannon_img = pg.transform.rotate(orig_cannon_img, -angle)
            cannon = cannon_img.get_rect(center=cannon.center)
    
            # Draw
            screen.fill(pg.Color('darkseagreen4'))
            bullet_group.draw(screen)
            screen.blit(cannon_img, cannon)
            txt = FONT.render('angle {:.1f}'.format(angle), True, BLACK)
            screen.blit(txt, (10, 10))
            pg.draw.line(
                screen, pg.Color(150, 60, 20),
                cannon.center, pg.mouse.get_pos(), 2)
            pg.display.update()
    
            clock.tick(30)
    
    if __name__ == '__main__':
        main()
        pg.quit()
    
    0 讨论(0)
提交回复
热议问题