1

With the help of some person now I can press key to shoot bullet in Pygame but I have met another new issue. I define this in class Bullet:

def move(self):
    self.y -= self.speed
    self.bullet.y=self.y
def draw(self,setting):
    p.draw.rect(setting.screen,self.color,self.bullet)
def bullet_blit(self,bullets,setting):
    for bullet in bullets.sprites():
        p.draw.rect(setting.screen,self.color,self.bullet)
        self.y -= self.speed
        self.bullet.y=self.y

Finally when I just use the code bullet.bullet_blit(bullets,setting) it will only one bullet when I press the key. Instead I use

for bullet in bullets.sprites():
    bullet.draw(setting)
    bullet.move()

It worked correctly. I don't know why. They are the same, but their effect is not the same. Here's the code:

#! /usr/bin/python
import pygame as p
import sys

class Setting():
    def __init__(self,width,height):
        self.w=width
        self.h=height
        self.flag=p.RESIZABLE
        self.color=(255,255,255)
        self.speed=1
        self.screen=p.display.set_mode((self.w,self.h),self.flag)
        p.display.set_caption("Bullet")
        self.bullet_s=1
        self.bullet_w=5
        self.bullet_h=30
        self.bullet_c=(0,0,0)

class Bullet(p.sprite.Sprite):
    def __init__(self,setting):
        super().__init__()
        self.screen_rect=setting.screen.get_rect()
        self.screen_center=self.screen_rect.center
        self.bullet=p.Rect((0,0),(setting.bullet_w,setting.bullet_h))
        self.bullet.center=self.screen_center
        self.bullet.bottom=self.screen_rect.bottom
        self.color=setting.bullet_c
        self.speed=setting.bullet_s
        self.y=float(self.bullet.centery)
    def bullet_check(self,bullets,setting):
        for event in p.event.get():
            if event.type == p.QUIT:
                sys.exit()
            elif event.type == p.KEYDOWN:
                if event.key ==p.K_SPACE:
                    bullets.add(Bullet(setting))
    def move(self):
        self.y -= self.speed
        self.bullet.y=self.y
    def draw(self,setting):
        p.draw.rect(setting.screen,self.color,self.bullet)
    def bullet_blit(self,bullets,setting):
        for bullet in bullets.sprites():
            p.draw.rect(setting.screen,self.color,self.bullet)
            self.y -= self.speed
            self.bullet.y=self.y



def game():
    p.init()
    setting=Setting(1200,800)
    bullet=Bullet(setting)
    bullets=p.sprite.Group()                

    while True:
        bullet.bullet_check(bullets,setting)
        setting.screen.fill((255,0,0))
        bullet.bullet_blit(bullets,setting)      <—--this cant create many bullets,only one bullet
#        for bullet in bullets.sprites():
#            bullet.draw(setting)
#            bullet.move()
        p.display.flip()
game()
khelwood
  • 55,782
  • 14
  • 81
  • 108
M_Sea
  • 389
  • 4
  • 13
  • 1
    because you're referencing `self.bullet` in that entire method? I'm not sure why its in there as an instance method anyway, one bullet should not be handling all the other bullets drawing too (I'd be surprised if you didn't get a stack overflow from it anyway) – Sayse Nov 22 '19 at 10:22

1 Answers1

1

The issue is the instance method

class Bullet(p.sprite.Sprite):

   # [...]
   def bullet_blit(self,bullets,setting):
       for bullet in bullets.sprites():
           p.draw.rect(setting.screen,self.color,self.bullet)
           self.y -= self.speed
           self.bullet.y=self.y

You want to iterate through all bullets and to move and blit each single bullet, but you just use the attributes of the instance (self) rather than object from the list bullet.

Turn bullet_blit to a class method:

class Bullet(p.sprite.Sprite):   

    def bullet_blit(bullets,setting):
        for bullet in bullets.sprites():
            p.draw.rect(setting.screen,bullet.color,bullet.bullet)
            bullet.y -= bullet.speed
            bullet.bullet.y=bullet.y

and call it:

while True:

    # [...]

    Bullet.bullet_blit(bullets,setting) 

pygame.event.get() get all the messages and remove them from the queue. So this function should be called once per frame, in the main application loop.

Turn bullet_check to a class method and pass the list of events to the method:

class Bullet(p.sprite.Sprite):

    # [...]

   def bullet_check(events, bullets, setting):
        for event in events:
            if event.type == p.KEYDOWN:
                if event.key ==p.K_SPACE:
                    bullets.add(Bullet(setting))

Get the events in the main application loop and pass it to the function:

def game():
    p.init()
    setting=Setting(1200,800)
    bullets=p.sprite.Group()                

    while True:
        events = p.event.get()
        for event in events:
            if event.type == p.QUIT:
                sys.exit()

        Bullet.bullet_check(events, bullets, setting)
        setting.screen.fill((255,0,0))
        Bullet.bullet_blit(bullets,setting)
        p.display.flip()

Another option is to create a BulletsGroup class, derived from pygame.sprite.Group:

import pygame as p
import sys

class Setting():
    def __init__(self,width,height):
        self.w=width
        self.h=height
        self.flag=p.RESIZABLE
        self.color=(255,255,255)
        self.speed=1
        self.screen=p.display.set_mode((self.w,self.h),self.flag)
        p.display.set_caption("Bullet")
        self.bullet_s=1
        self.bullet_w=5
        self.bullet_h=30
        self.bullet_c=(0,0,0)

class BulletsGroup(p.sprite.Group):
    def __init__(self):
        super().__init__()
    def move_bullets(self):
        for bullet in self:
            bullet.move()
    def draw_bullets(self, setting):
        for bullet in self:
            bullet.draw(setting) 
    def bullet_check(self, events, setting):
        for event in events:
            if event.type == p.KEYDOWN:
                if event.key ==p.K_SPACE:
                    self.add(Bullet(setting))

class Bullet(p.sprite.Sprite):
    def __init__(self,setting):
        super().__init__()
        self.screen_rect=setting.screen.get_rect()
        self.screen_center=self.screen_rect.center
        self.bullet=p.Rect((0,0),(setting.bullet_w,setting.bullet_h))
        self.bullet.center=self.screen_center
        self.bullet.bottom=self.screen_rect.bottom
        self.color=setting.bullet_c
        self.speed=setting.bullet_s
        self.y=float(self.bullet.centery)
    def move(self):
        self.y -= self.speed
        self.bullet.y=self.y
    def draw(self, setting):
        p.draw.rect(setting.screen,self.color,self.bullet)

def game():
    p.init()
    setting = Setting(1200,800)
    bullets = BulletsGroup()                

    while True:
        events = p.event.get()
        for event in events:
            if event.type == p.QUIT:
                sys.exit()

        bullets.bullet_check(events, setting)
        bullets.move_bullets()

        setting.screen.fill((255,0,0))
        bullets.draw_bullets(setting)
        p.display.flip()
game()
Rabbid76
  • 202,892
  • 27
  • 131
  • 174
  • I modify the `def bullet_blit(bullets,setting):` and replace self to bullet ,then exe `Bullet.bullet_blit(bullets,setting)` but it show me some error `**bullet.bullet_check(bullets,setting) TypeError: bullet_check() takes 2 positional arguments but 3 were given **` – M_Sea Nov 22 '19 at 12:39
  • yes,when i replace bullet to Bullet it worked, but `def game():bullet=Bullet(setting)` i make it euqal why i cant use `bullet.bullet_check(bullets,setting)` – M_Sea Nov 22 '19 at 12:52
  • @M_Sea Read about [Class and Instance Variables](https://docs.python.org/3/tutorial/classes.html#class-and-instance-variables). The name of the class is `Bullet` and the name of the object instance is `bullet`. `def bullet_blit(bullets,setting):` is a class method (no `self`), so it has to be called by the class: `Bullet.bullet_blit(...)`. `def bullet_blit(self,bullets,setting):` would be an instance method (`self` parameter) and has to be called by an instance of the class `Bullet`, e.g. `bullet.bullet_blit(bullets,setting)`, because `bullet` is an object instance of the class `Bullet`. – Rabbid76 Nov 22 '19 at 13:11
  • Really really thanks, you are a angel, figure out my two issue, i meet so many issue in this project, so sad – M_Sea Nov 22 '19 at 13:35