Python Forum
[PyGame] Getting projectiles into pygame.
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
[PyGame] Getting projectiles into pygame.
#1
Hey all,

I'm really new to Python, this is only really my 5th or 6th day using the language (or really any major language). When I was younger I used Scratch a lot so if I'm using the wrong terminology or I am being unclear I'm sorry I can clear things up if you would like me to:).

Right now this I'm trying to create a space-invaders-type clone, this is my first project without the direct help of a guide. So I want to have bullets come out of my plane sprite. I'm trying to figure out how to do two things really, one is to get a 'clone' of the bullet sprite to spawn at an x and y relative to the plane. I know how to use .blit((x, y)) but I can't figure out how to get a clone of the sprite to spawn in so I can have multiple bullets coming out of the plane. The next thing I want to figure out is how to get that new spawned clone of the sprite to keep going towards y = 0 and stopping either when it gets there or collides with the enemy(ies)

I've googled some guides and posts and I either can't figure out how it could apply to my project or I can't understand what is happening. I saw a lot of ideas including classes and lists and while I understand what lists are I don't see/understand how they apply here, I am also starting to understand the usefulness of classes but they still are a bit confusing to me.
Thanks for any help:)

# imports and initializations
import pygame
import random
pygame.init()



# game start

running = True


gametick = 100
px = 250 # player x and y
py = 275
pvel = 25 # player velocity and bullet vel
bvel = 40
mod = 1
clock = pygame.time.Clock()

# window
window_height = 600
window_width = 800
window = pygame.display.set_mode((window_width, window_height))
pygame.display.set_caption("Game")


# sprite imports.
playerImg = pygame.image.load("images\player.png")
backgroundImg = pygame.image.load("images\Background.png")
bulletImg = pygame.image.load("images\Bullet.png")




# Definitions

def player(px, py):
    window.blit(playerImg, (px, py))
    pygame.transform.scale(playerImg, (10, 10))


def background():
    window.blit(backgroundImg, (0, 0))


def borders():
    global px
    if px <= 0:
        px = 0
    elif px >= 704:
        px = 704



# Gameloop
while running:

    clock.tick(30)
    # Stop command
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            running = False
    # Showing sprites and background
    background()
    player(px, py)
    # bullets
    # nothing here yet

    # Controls
    keys = pygame.key.get_pressed()
    if keys[pygame.K_LEFT]:
        borders()
        px -= pvel * mod
    if keys[pygame.K_RIGHT]:
        borders()
        px += pvel * mod
    if keys[pygame.K_UP]:
        pass # this will be for the bullets


    pygame.display.update()
Reply
#2
The short answer is to use the Pygame Sprite Class.

class Player(pygame.sprite.Sprite):
    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.transform.scale(player_img, (60, 48))
        self.image.set_colorkey(black)
        self.rect = self.image.get_rect()
        self.radius = 25
        self.rect.center = (width / 2, height - 30)
        self.speedx = 0
        self.shield = 100
        self.shoot_delay = 250
        self.last_shot = pygame.time.get_ticks()
        self.lives = 1
        self.hidden = False
        self.hide_timer = pygame.time.get_ticks()
        self.power = 1
        self.power_time = pygame.time.get_ticks()
        
        
    def update(self):
        
        if self.power >= 2 and pygame.time.get_ticks() - self.power_time > POWERUP_TIME:
            self.power -= 1
            self.power_time = pygame.time.get_ticks()
            
        if self.hidden and pygame.time.get_ticks() - self.hide_timer > 1000:
            self.hidden = False
            self.rect.center = (width / 2, height - 30)
        self.speedx = 0
        keystate = pygame.key.get_pressed()
        self.rect.x += self.speedx
        if keystate[pygame.K_LEFT]:
            self.speedx = -10
        if keystate[pygame.K_RIGHT]:
            self.speedx = 10
        
        if keystate[pygame.K_SPACE]:
            self.shoot()
        self.rect.x += self.speedx
        if self.rect.right > width:
            self.rect.right = width
        if self.rect.left < 0:
            self.rect.left = 0
    
    def powerup(self):
        self.power += 1
        
        self.power_time = pygame.time.get_ticks()
        
    def shoot(self):
        now = pygame.time.get_ticks()
        if now - self.last_shot > self.shoot_delay:
            self.last_shot = now
            if self.power == 1:
                bullet = Bullet(self.rect.centerx, self.rect.top)
                all_sprites.add(bullet)
                bullets.add(bullet)
                shoot_sound.play()
            if self.power >= 2:
                bullet1 = Bullet(self.rect.left, self.rect.centery)
                bullet2 = Bullet(self.rect.right, self.rect.centery)
                all_sprites.add(bullet1)
                bullets.add(bullet1)
                all_sprites.add(bullet2)
                bullets.add(bullet2)
                shoot_sound.play()
     
    def hide(self):
        self.hidden = True
        self.hide_timer = pygame.time.get_ticks()
        self.rect.center = (width / 2, height + 200)
         

class Bullet(pygame.sprite.Sprite):
    def __init__(self, x, y):
        pygame.sprite.Sprite.__init__(self)
        self.image = bullet_img
        self.image.set_colorkey(black)
        self.rect = self.image.get_rect()
        self.rect.bottom = y
        self.rect.centerx = x
        self.speedy = -50
        
        
    def update(self):
        self.rect.y += self.speedy
        
        
        if self.rect.bottom < 0:
            self.kill()
This is cut from a vertical shooter I made from a tutorial. Specifically Player.shoot() refers to what you ask.

A great video about classes can be seen here.
Reply
#3
For now just use classes as container. There two level to a class. Class level for a single instance. Objects for multiply instances. Class is a namespace you use to access variables.
player_x = 250
player_y = 270
player_velocity = 25
You could just use a class level instance. Only one instance can be made this way.
class Player:
    x = 250
    y = 275
    velocity = 25
# To access variable of class instance. You use the namespace
print(Player.x)
print(Player.y)
print(Player.velocity)
If you wanted many different players. Then you use class object instances.
class Player:
    # Class object initializer
    def __init__(self, x, y, velocity):
        self.x = x
        self.y = y
        self.velocity = velocity

# Create a player. Argument match the __init__ method.
player_a = Player(250, 270, 25)
# Now player_a point to are new player class object. 
# player_a will be are namespace to the object.
print(player_a.x)

# Create are second player
player_b = Player(450, 470, 25)
print(player_a.x)
print(player_b.x)
What does self mean in a class. It standard word that point to your object. Uses self.x create a variable x in your object.

Bullets. Use a list to store bullets positions. Only need list if shooting more than on bullet.
bullets = []
bullets_remover = []
bullet_next_tick = 0
bullet_interval = 100 # how fast it can shoot
Use pygame.time.get_ticks() to control bullet shooting speed.
ticks = pygame.time.get_ticks()
if keys[pygame.K_UP]:
    if ticks > bullet_next_tick:
        bullet_next_tick = ticks + bullet_interval
        bullets.append([px, py])

for bullet in bullets:
    # Move bullet
    bullet[1] -= 5
    if bullet[y] < 0:
        bullet_remover.append(bullet)
    else:
        window.blit(bulletImg, bullet)

for bullet in bullet_remover:
    bullets.remove(bullet)

bullet_remover = []
99 percent of computer problems exists between chair and keyboard.
Reply
#4
Wow I'm new in this forum but I love it, i had same problem since I got used to scratch clones... Thank you!
Here my first try with pygame. Heart
Reply
#5
Thank you all this is really helpful! :)
Reply
#6
Hey boys, I've successfully created a space invaders clone with pygame thanks to you!

I've used the "list method" and if you want to use a Rect instead an Img with windows.blit, you have to write the for loop after the pygame.draw(things) like this (note I've used some variables like colors that are not declared!):

    screen.fill(bgcolor)
    pygame.draw.rect(screen, color, ship)

    for bullet in bullets:
        bullet.y -= 5
        if bullet.y < 0:
            bullet_remover.append(bullet)
        else:
            pygame.draw.rect(screen, color, bullet
    pygame.display.flip()
    clock.tick(60)
Put this after the whole thing
This is the code for the bullets, but with enemies is the same.
To CONTROL the bullet shoot, you can simply append a Rect to the list in the while loop like this:
while True:
    ticks = pygame.time.get_ticks()
    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            pygame.mixer.music.stop()
            pygame.quit()
            print('Thanks for playing Space invaders! \nclosing...')
            sys.exit()

        if event.type == pygame.KEYDOWN:

            if event.key == pygame.K_UP:
                if ticks > bullet_next_tick:
                    bullet_next_tick = ticks + bullet_interval
                    bullets.append(pygame.Rect(ship.x, ship.y, 5, 20))

            if event.key == pygame.K_RIGHT:
                x_spid += 5

            if event.key == pygame.K_LEFT:
                x_spid -= 5

        if event.type == pygame.KEYUP:

            if event.key == pygame.K_RIGHT:
                x_spid -= 5

            if event.key == pygame.K_LEFT:
                x_spid += 5
Obviously you still need to remove bullets
    
    for bullet in bullet_remover:
        bullets.remove(bullet)

    bullet_remover = []
I'm really happy and proud of that. Thank you. Relly, thank you.
(Tell me if you'd like to see the project ;))

(May-24-2020, 04:41 PM)lolloiltizio Wrote: Hey boys, I've successfully created a space invaders clone with pygame thanks to you!

I've used the "list method" and if you want to use a Rect instead an Img with windows.blit, you have to write the for loop after the pygame.draw(things) like this (note I've used some variables like colors that are not declared!):

    screen.fill(bgcolor)
    pygame.draw.rect(screen, color, ship)

    for bullet in bullets:
        bullet.y -= 5
        if bullet.y < 0:
            bullet_remover.append(bullet)
        else:
            pygame.draw.rect(screen, color, bullet
    pygame.display.flip()
    clock.tick(60)
Put this after the whole thing
This is the code for the bullets, but with enemies is the same.
To CONTROL the bullet shoot, you can simply append a Rect to the list in the while loop like this:
while True:
    ticks = pygame.time.get_ticks()
    for event in pygame.event.get():

        if event.type == pygame.QUIT:
            pygame.mixer.music.stop()
            pygame.quit()
            print('Thanks for playing Space invaders! \nclosing...')
            sys.exit()

        if event.type == pygame.KEYDOWN:

            if event.key == pygame.K_UP:
                if ticks > bullet_next_tick:
                    bullet_next_tick = ticks + bullet_interval
                    bullets.append(pygame.Rect(ship.x, ship.y, 5, 20))

            if event.key == pygame.K_RIGHT:
                x_spid += 5

            if event.key == pygame.K_LEFT:
                x_spid -= 5

        if event.type == pygame.KEYUP:

            if event.key == pygame.K_RIGHT:
                x_spid -= 5

            if event.key == pygame.K_LEFT:
                x_spid += 5
Obviously you still need to remove bullets
    
    for bullet in bullet_remover:
        bullets.remove(bullet)

    bullet_remover = []
I'm really happy and proud of that. Thank you. Relly, thank you.
(Tell me if you'd like to see the project ;))

*really Wall
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020