2

I am trying to create my own game using pygame with classes and my problem is that I cannot understand why my program is not working properly

import pygame
import time
import random
import sys

pygame.init()
screen = pygame.display.set_mode((1280, 720))
pygame.display.set_caption("this game")


class Background:

    def __init__(self, x, y):
        self.xpos = x
        self.ypos = y

    picture = pygame.image.load("C:/images/dunes.jpg")
    picture = pygame.transform.scale(picture, (1280, 720))

    def draw(self):
        pygame.surface.Surface.blit(picture, (self.xpos, self.ypos))



class Monster:
    def __init__(self, x, y):
        self.xpos = x
        self.ypos = y

    def move_left(self):
        self.xpos =- 5

    def move_right(self):
        self.xpos =+ 5

    def jump(self):
        for x in range(1, 10):
            self.ypos =-1
            pygame.display.show()

        for x in range(1, 10):
            self.ypos =+1
            pygame.display.show()

    picture = pygame.image.load("C:/pics/hammerhood.png")
    picture = pygame.transform.scale(picture, (200, 200))

    def draw(self):
        pygame.surface.Surface.blit(picture, (self.xpos, self.ypos))




class enemy:
    def __init__(self, x, y):
        self.xpos = x
        self.ypos = y

    picture = pygame.image.load("C:/pics/dangler_fish.png")
    picture = pygame.transform.scale(picture, (200, 200))


    def teleport(self):
        self.xpos = random.randint(1, 1280)
        self.pos= random.randint(1, 720)

    def draw(self):
        pygame.surface.Surface.blit(picture, (self.xpos, self.ypos))






while True:
    ice = Background(720, 360)
    hammerhood = Monster(200, 500)
    fish = enemy(0, 0)
    fish.teleport()


    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        if pygame.event == pygame.K_d:
            hammerhood.move_right()

        if pygame.event == pygame.K_a:
            hammerhood.move_left()

        if pygame.event == pygame.K_w:
            hammerhood.jump()

    hammerhood.draw()
    ice.draw()
    fish.draw()

what it is saying to me is, line 49, in the draw

pygame.surface.Surface.blit(picture, (self.xpos, self.ypos))
NameError: name 'picture' is not defined

I have tried everything and there is another project I copied from the internet and this has the exact same way of blitting the picture in the class but in this one, it is not working

MBT
  • 21,733
  • 19
  • 84
  • 102
  • `pygame.surface.Surface.blit(Background.picture, (self.xpos, self.ypos))` [Python Class Members](https://stackoverflow.com/q/12409714/669576) – 001 Nov 10 '18 at 12:17
  • class attributes are accessible via the instance too (as long as they are not shadowed by an instance attribute) so better to use self. picture than to hardcode the class name. – bruno desthuilliers Nov 10 '18 at 12:23

2 Answers2

1

you define picture at the class top level which makes it a class attribute. To access it from a method you have to use self. picture

bruno desthuilliers
  • 75,974
  • 6
  • 88
  • 118
0

The picture attributes are class attributes (defined outside of the __init__ method) but they can be accessed like any other attributes by prepending them with self.. Also, you most likely want to blit the pictures onto the screen surface, so just call the blit method of this surface:

def draw(self):
    screen.blit(self.picture, (self.xpos, self.ypos))

Note that class attributes are shared between all instances, so if you modify one surface/image, they'll be changed for all sprites.

There are a few more problems:

  • The event handling doesn't work.
  • The sprites won't move continuously. Define some speed attributes and add them to the positions each frame.
  • You should almost always call the convert or convert_alpha methods to improve the blit performance of the surfaces.

Here's a fixed version (except for the jumping) with some comments:

import pygame
import random
import sys


pygame.init()
screen = pygame.display.set_mode((1280, 720))
clock = pygame.time.Clock()  # A clock to limit the frame rate.
pygame.display.set_caption("this game")


class Background:
    picture = pygame.image.load("C:/images/dunes.jpg").convert()
    picture = pygame.transform.scale(picture, (1280, 720))

    def __init__(self, x, y):
        self.xpos = x
        self.ypos = y

    def draw(self):
        # Blit the picture onto the screen surface.
        # `self.picture` not just `picture`.
        screen.blit(self.picture, (self.xpos, self.ypos))


class Monster:
    picture = pygame.image.load("C:/pics/hammerhood.png").convert_alpha()
    picture = pygame.transform.scale(picture, (200, 200))

    def __init__(self, x, y):
        self.xpos = x
        self.ypos = y
        # If you want to move continuously you need to set these
        # attributes to the desired speed and then add them to
        # self.xpos and self.ypos in an update method that should
        # be called once each frame.
        self.speed_x = 0
        self.speed_y = 0

    def update(self):
        # Call this method each frame to update the positions.
        self.xpos += self.speed_x
        self.ypos += self.speed_y

    # Not necessary anymore.
#     def move_left(self):
#         self.xpos -= 5  # -= not = -5 (augmented assignment).
# 
#     def move_right(self):
#         self.xpos += 5  # += not = +5 (augmented assignment).

    def jump(self):
        # What do you want to do here?
        for x in range(1, 10):
            self.ypos -= 1  # -= not =-
            # pygame.display.show()  # There's no show method.

        for x in range(1, 10):
            self.ypos += 1
            # pygame.display.show()

    def draw(self):
        screen.blit(self.picture, (self.xpos, self.ypos))


class Enemy:  # Use upper camelcase names for classes.
    picture = pygame.image.load("C:/pics/dangler_fish.png").convert_alpha()
    picture = pygame.transform.scale(picture, (200, 200))

    def __init__(self, x, y):
        self.xpos = x
        self.ypos = y

    def teleport(self):
        self.xpos = random.randint(1, 1280)
        self.pos= random.randint(1, 720)

    def draw(self):
        screen.blit(self.picture, (self.xpos, self.ypos))


# Create the instances before the while loop.
ice = Background(0, 0)  # I pass 0, 0 so that it fills the whole screen.
hammerhood = Monster(200, 500)
fish = Enemy(0, 0)

while True:
    # Handle events.
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            pygame.quit()
            sys.exit()
        # Check if the `event.type` is KEYDOWN first.
        elif event.type == pygame.KEYDOWN:
            # Then check which `event.key` was pressed.
            if event.key == pygame.K_d:
                hammerhood.speed_x = 5
            elif event.key == pygame.K_a:
                hammerhood.speed_x = -5
            elif event.key == pygame.K_w:
                hammerhood.jump()
        elif event.type == pygame.KEYUP:
            # Stop moving when the keys are released.
            if event.key == pygame.K_d and hammerhood.speed_x > 0:
                hammerhood.speed_x = 0
            elif event.key == pygame.K_a and hammerhood.speed_x < 0:
                hammerhood.speed_x = 0

    # Update the game.
    hammerhood.update()
    fish.teleport()

    # Draw everything.
    ice.draw()  # Blit the background to clear the screen.
    hammerhood.draw()
    fish.draw()
    pygame.display.flip()
    clock.tick(60)  # Limit the frame rate to 60 FPS.
skrx
  • 19,980
  • 5
  • 34
  • 48
  • when you mentioned what do you want to do here: I want to try and make the sprite jump. Because it currently does not work. when i try to work what i have currently done nothing happens –  Nov 12 '18 at 17:42
  • 1
    Have you checked out my examples [here](https://stackoverflow.com/a/47858300/6220679) and [here](https://stackoverflow.com/a/48069743/6220679)? I've answered your new question anyway, but you should better search for existing questions/answers before you post new questions. – skrx Nov 13 '18 at 22:10
  • By the way, please upvote helpful answers. You can also accept one by clicking on the checkmark below the arrows to mark the question as solved. – skrx Nov 13 '18 at 22:17
  • thank you this really useful and I have managed to achieve loads –  Dec 15 '18 at 12:44
  • do you know anyway how I can be able to repost questions again because I currently cannot it comes up with the error: You have reached your question limit Sorry, we are no longer accepting questions from this account. See the Help Center to learn more. –  Dec 15 '18 at 13:00
  • 1
    Read the paragraph "How long do I have to wait before I can post again? What can I do to release the ban? How can I reactivate my account?" here: https://meta.stackexchange.com/questions/86997/what-can-i-do-when-getting-we-are-no-longer-accepting-questions-answers-from-th – skrx Dec 15 '18 at 14:03
  • can you give me any tips of how to get out of this circle of terror –  Dec 15 '18 at 18:59
  • 1
    Read the ["asking" section](https://stackoverflow.com/help/asking) of the help center and try to improve your previous questions. You could also post your questions on https://old.reddit.com/r/pygame instead which is less restrictive. – skrx Dec 15 '18 at 19:55