2

In my game the problem is that bullets are coming only from one place i.e, from the center. As my player rotates in direction of cursor, I want the bullets to be shot from top of the player even if the player is rotated and travel in a straight line in the direction player is facing towards, As the player rotates in the direction of cursor.

As you can view here the the bullets are always in same direction and always come out of same place.

Image 1 Image 2

I tried to use getpos() method to get cursor position and tried to subtract from the player coordinates but failed to get the result.

I think the problem is within the def shoot(self) method of Rotator class, I need to get the coordinates spaceship's tip even when it is rotating all time.

import math 
import random 
import os 
import pygame as pg 
import sys

pg.init()
height=650
width=1200

os_x = 100
os_y = 45
os.environ['SDL_VIDEO_WINDOW_POS'] = "%d,%d" % (os_x,os_y)

screen = pg.display.set_mode((width,height),pg.NOFRAME)
screen_rect = screen.get_rect()
background=pg.image.load('background.png').convert()
background = pg.transform.smoothscale(pg.image.load('background.png'), (width,height))
clock = pg.time.Clock()
running = True


class Mob(pg.sprite.Sprite):
    def __init__(self):
        pg.sprite.Sprite.__init__(self)
        self.image = pg.image.load('enemy.png').convert_alpha()
        self.image = pg.transform.smoothscale(pg.image.load('enemy.png'), (33,33))
        self.rect = self.image.get_rect()
        self.rect.x = random.randrange(width - self.rect.width)
        self.rect.y = random.randrange(-100, -40)
        self.speedy = random.randrange(1, 8)
        self.speedx = random.randrange(-3, 3)

    def update(self):
        self.rect.x += self.speedx
        self.rect.y += self.speedy
        if self.rect.top > height + 10 or self.rect.left < -25 or self.rect.right > width + 20:
            self.rect.x = random.randrange(width - self.rect.width)
            self.rect.y = random.randrange(-100, -40)
            self.speedy = random.randrange(1, 8)


class Rotator(pg.sprite.Sprite):
    def __init__(self, screen_rect):
        pg.sprite.Sprite.__init__(self)
        self.screen_rect = screen_rect
        self.master_image = pg.image.load('spaceship.png').convert_alpha()
        self.master_image = pg.transform.smoothscale(pg.image.load('spaceship.png'), (33,33))
        self.image = self.master_image.copy()
        self.rect = self.image.get_rect(center=[width/2,height/2])
        self.delay = 10
        self.timer = 0.0
        self.angle = 0
        self.distance = 0
        self.angle_offset = 0

    def get_angle(self):
      mouse = pg.mouse.get_pos()
      offset = (self.rect.centerx - mouse[0], self.rect.centery - mouse[1])
      self.angle = math.degrees(math.atan2(*offset)) - self.angle_offset
      old_center = self.rect.center
      self.image = pg.transform.rotozoom(self.master_image, self.angle,1)
      self.rect = self.image.get_rect(center=old_center)
      self.distance = math.sqrt((offset[0] * offset[0]) + (offset[1] * offset[1]))


    def update(self):
      self.get_angle()
      self.display = 'angle:{:.2f} distance:{:.2f}'.format(self.angle, self.distance)
      self.dx = 1
      self.dy = 1
      self.rect.clamp_ip(self.screen_rect)


    def draw(self, surf):
        surf.blit(self.image, self.rect)

    def shoot(self):
        bullet = Bullet(self.rect.centerx, self.rect.centery)
        all_sprites.add(bullet)
        bullets.add(bullet)


class Bullet(pg.sprite.Sprite):
    def __init__(self, x, y):
        pg.sprite.Sprite.__init__(self)
        self.image = pg.image.load('bullet.png').convert_alpha()
        self.image = pg.transform.smoothscale(pg.image.load('bullet.png'), (10,10))
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x
        self.speedy = -8

    def update(self):
        self.rect.y += self.speedy
        # kill if it moves off the top of the screen
        if self.rect.bottom < 0:
            self.kill()


all_sprites = pg.sprite.Group()
bullets = pg.sprite.Group()
mobs = pg.sprite.Group()
rotator = Rotator(screen_rect)
all_sprites.add(rotator)

for i in range(5):
    m = Mob()
    all_sprites.add(m)
    mobs.add(m)

while running:
    keys = pg.key.get_pressed()
    for event in pg.event.get():
        if event.type == pg.QUIT:
            sys.exit()
            pygame.quit()
        if event.type == pg.MOUSEBUTTONDOWN:
            rotator.shoot()


    screen.blit(background, [0, 0])
    all_sprites.update()

    hits = pg.sprite.groupcollide(mobs, bullets, True, True)
    for hit in hits:
        m = Mob()
        all_sprites.add(m)
        mobs.add(m)

    hits = pg.sprite.spritecollide(rotator, mobs, False)
    if hits:
        running = False

    all_sprites.draw(screen)
    clock.tick(60)
    pg.display.update()

1 Answers1

2

See Shooting a bullet in pygame in the direction of mouse and calculating direction of the player to shoot pygame. Pass the mouse position to rotator.shoot(), when the mouse button is pressed:

if event.type == pg.MOUSEBUTTONDOWN:
    rotator.shoot(event.pos)

Calculate the direction of from the rotator to the mouse position and pass it the constructor of the new bullet object:

def shoot(self, mousepos):
    dx = mousepos[0] - self.rect.centerx
    dy = mousepos[1] - self.rect.centery
    if abs(dx) > 0 or abs(dy) > 0:
        bullet = Bullet(self.rect.centerx, self.rect.centery, dx, dy)
        all_sprites.add(bullet)
        bullets.add(bullet)

Use pygame.math.Vector2 to store the current positon of the bullet and the normalized direction of the bullet (Unit vector):

class Bullet(pg.sprite.Sprite):
    def __init__(self, x, y, dx, dy):
        pg.sprite.Sprite.__init__(self)
        self.image = pg.transform.smoothscale(pg.image.load('bullet.png').convert_alpha(), (10,10))
        self.rect = self.image.get_rect()
        self.rect.center = (x, y)
        self.speed = 8
        self.pos = pg.math.Vector2(x, y)
        self.dir = pg.math.Vector2(dx, dy).normalize()

Calcualate the new position of the bullet in update() (self.pos += self.dir * self.speed) and update the .rect attribute by the new position.
.kill() the bullet when it leaves the screen. This can be checked by self.rect.colliderect():

class Bullet(pg.sprite.Sprite):

    # [...]

     def update(self):
        
        self.pos += self.dir * self.speed
        self.rect.center = (round(self.pos.x), round(self.pos.y))

        if not self.rect.colliderect(0, 0, width, height):
            self.kill()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174