1

So I'm loosely following a tutorial to add bullets and shooting and when I'm done I get a name error (NameError: name 'Bullet' is not defined) the only difference between his shooting code and mine is that mines split into two files/ parts (Main and Sprites) could this be affecting it or am I missing something very obvious.

Also, the error happens when you launch the code and click space to fire the bullet.

code below:

import random
import math
import pygame as py
from PlayerSprite import *

WIDTH = 800
HEIGHT = 600
FPS = 60

# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)

# initialize pygame and create window
py.init()
py.mixer.init()
screen = py.display.set_mode((WIDTH, HEIGHT))
py.display.set_caption("Dimensional Drifter")
clock = py.time.Clock()

all_sprites = py.sprite.Group()
NPCs = py.sprite.Group()
bullets = py.sprite.Group()
player = Player()
all_sprites.add(player)
for i in range(14):
    n = NPC(player)
    all_sprites.add(n)
    NPCs.add(n)
# Game loop
running = True
while running:
    # keep loop running at the right speed
    clock.tick(FPS)

    for event in py.event.get():
        # check for closing window
        if event.type == py.QUIT:
            running = False
        elif event.type == py.KEYDOWN:
            if event.key == py.K_SPACE:
                player.Shoot()

    # Update
    all_sprites.update()
    # check if there a collision between th player and NPC
    hits = py.sprite.spritecollide(player, NPCs, True)
    if hits:
        running = False

    # updates the position of of mouse and rotates it towards the mouse position
    mouse_x, mouse_y = py.mouse.get_pos()
    player.rotate(mouse_x, mouse_y)
    # render
    screen.fill(BLACK)
    all_sprites.draw(screen)
    # flip the display
    py.display.flip()

py.quit()
import pygame as py
import math
import random

WIDTH = 800
HEIGHT = 600
FPS = 60

# define colors
WHITE = (255, 255, 255)
BLACK = (0, 0, 0)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)
YELLOW = (255, 255, 0)


class Player(py.sprite.Sprite):
    def __init__(self):
        py.sprite.Sprite.__init__(self)
        self.image = py.Surface((50, 50), py.SRCALPHA)
        self.image.fill(GREEN)
        self.rect = self.image.get_rect()
        self.rect.centerx = WIDTH / 2
        self.rect.bottom = HEIGHT / 2
        self.Yspeed = 0
        self.rotatableimage = self.image

    def update(self):
        self.Xspeed = 0
        self.Yspeed = 0
        # line below allow for key press to equate to move of sprite
        keypreesed = py.key.get_pressed()
        if keypreesed[py.K_a]:
            self.Xspeed = - 11
        if keypreesed[py.K_d]:
            self.Xspeed = 11
        if keypreesed[py.K_w]:
            self.Yspeed = - 11
        if keypreesed[py.K_s]:
            self.Yspeed = 11
        self.rect.x += self.Xspeed
        self.rect.y += self.Yspeed
        # line below allow the sprite to wrap around the screen
        if self.rect.left > WIDTH:
            self.rect.right = 0
        if self.rect.right < 0:
            self.rect.left = WIDTH
        if self.rect.top > HEIGHT:
            self.rect.top = 0
        if self.rect.bottom < 0:
            self.rect.bottom = HEIGHT

    def rotate(self, mouse_x, mouse_y):
        rel_x = mouse_x - self.rect.x
        rel_y = mouse_y - self.rect.y
        angle = (180 / math.pi) * -math.atan2(rel_y, rel_x)

        self.image = py.transform.rotate(self.rotatableimage, int(angle))
        self.rect = self.image.get_rect(center=(self.rect.centerx, self.rect.centery))
        return

    def Shoot(self):
        bullet = Bullet(self.rect.centerx, self.rect.top)
        all_sprite.add(bullet)
        bullets.add(bullet)


class NPC(py.sprite.Sprite):
    def __init__(self, player):
        py.sprite.Sprite.__init__(self)
        self.player = player
        self.image = py.Surface((30, 30)).convert_alpha()
        self.image.fill(RED)
        self.originalimage = self.image
        self.rect = self.image.get_rect()
        self.spawn()

    # allows of spawning from all four side of the screen
    def spawn(self):
        self.direction = random.randrange(4)
        if self.direction == 0:
            self.rect.x = random.randrange(WIDTH - self.rect.width)
            self.rect.y = random.randrange(-100, -40)
            self.Xspeed = random.randrange(-2, 2)
            self.Yspeed = random.randrange(4, 8)
        elif self.direction == 1:
            self.rect.x = random.randrange(WIDTH - self.rect.width)
            self.rect.y = random.randrange(HEIGHT, HEIGHT + 60)
            self.Xspeed = random.randrange(-2, 2)
            self.Yspeed = -random.randrange(4, 8)
        elif self.direction == 2:
            self.rect.x = random.randrange(-100, -40)
            self.rect.y = random.randrange(HEIGHT - self.rect.height)
            self.Xspeed = random.randrange(4, 8)
            self.Yspeed = random.randrange(-2, 2)
        elif self.direction == 3:
            self.rect.x = random.randrange(WIDTH, WIDTH + 60)
            self.rect.y = random.randrange(HEIGHT - self.rect.height)
            self.Xspeed = -random.randrange(4, 8)
            self.Yspeed = random.randrange(-2, 2)

    def update(self):
        self.rect.x += self.Xspeed
        self.rect.y += self.Yspeed
        # makes it so that HPC point to wards the player as it passes from side to side
        dir_x, dir_y = self.player.rect.x - self.rect.x, self.player.rect.y - self.rect.y
        self.rot = (180 / math.pi) * math.atan2(-dir_x, -dir_y)
        self.image = py.transform.rotate(self.originalimage, self.rot)

        if self.direction == 0:
            if self.rect.top > HEIGHT + 10:
                self.spawn()
        elif self.direction == 1:
            if self.rect.bottom < -10:
                self.spawn()
        elif self.direction == 2:
            if self.rect.left > WIDTH + 10:
                self.spawn()
        elif self.direction == 3:
            if self.rect.right < -10:
                self.spawn()

    class Bullet(py.sprite.Sprite):
        def __init__(self, x, y):
            py.sprite.Sprite.__init__(self)
            self.image = py.Surface((5, 5))
            self.image.fill(BLUE)
            self.rect = self.image.get_rect()
            self.rect.bottom = y
            self.rect.centerx = x
            self.Yspeed = -10

        def update(self):
            self.rect.y += self.Yspeed
            # kill if moved of screen
            if self.rect.bottom > HEIGHT or self.rect.top < 0:
                self.kill()
            if self.rect.right > WIDTH or self.rect.left < 0:
                self.kill()

EDIT:

Ok, I've fixed up what Kingsley mention about my indentation error but I'm getting NameError: name 'all_sprites' is not defined now and I truly don't know why. I've tried importing all_sprites from main but it didn't work does anyone have solution? (haven't changed code above)

  • 1
    Bullet is a member class of `NPC` (indentation issue?) Plus a big *Huzzah!* for Roguelike. – Kingsley May 06 '20 at 03:59
  • ohhhh i seeee Thanks. And Yes Huzzah! Roguelike is best like!!! – Sir Braindmage May 06 '20 at 04:06
  • Ok so I'm Now getting NameError: name 'all_sprites' is not defined @Kingsley I tried i importing all_sprites from main but that doesn't help so idk you got any ideas – Sir Braindmage May 06 '20 at 04:24
  • 2
    It's not in scope. Change `Shoot()` to simply return the new bullet. Then in your event loop, `new_bullet = player.Shoot()`, and add `new_bullet` to `all_sprites` and `bullets`. – Kingsley May 06 '20 at 04:47
  • 2
    You forgot the s on `all_sprite` in `Shoot()` – The Big Kahuna May 06 '20 at 04:47
  • TheBigKahuna, I did realise that I missed the "s" but as for @Kingsley ima need you to clarify what you mean – Sir Braindmage May 06 '20 at 05:13
  • 1
    `Player.Shoot()` becomes a function of a single line `return Bullet(self.rect.centerx, self.rect.top)`. In your main loop, when `event.key == py.K_SPACE:`, say: `new_bullet = player.Shoot()`, and `all_sprites.add( new_bullet )`, and `bullets.add( new_bullet )` – Kingsley May 06 '20 at 05:20
  • Ok cool, I get what you're saying but I've got a question why is there a name error because I have defined `all_sprites = pygame.sprite.group` does it not transfer over the files? – Sir Braindmage May 06 '20 at 05:25
  • 1
    You're importing `PlayerSprite` into `main`(?) , and `all_sprites` is defined in `main`. But back in `PlayerSprite` it was never defined. It's kind of a one-way flow of definition. – Kingsley May 06 '20 at 05:32
  • oh I see idk why but I assumed it was two way – Sir Braindmage May 06 '20 at 05:33
  • anyway thanks for the help – Sir Braindmage May 06 '20 at 05:33
  • If you defined `all_sprites` before the import, it would be. But I don't think that's the right way to do it anyway. – Kingsley May 06 '20 at 05:33

0 Answers0