1

I have tried everything I can think of to fix this, but I can't seem to find it. I know it is probably a simple fix, but I cannot find what is making this happen. This is the first part of my code :

import pygame, sys, time
from pygame.locals import *
pygame.init()
WINDOWWIDTH = 900
WINDOWHEIGHT = 400
MOVERATE = 5
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
TEXTCOLOR = (255, 255, 255)
BACKGROUNDCOLOR = (0, 0, 0)
FPS = 40
clock = pygame.time.Clock()
x = 200
y = 150
class player(pygame.sprite.Sprite):
def __init__(self, x, y):
    super(player, self).__init__()

    temp_image = pygame.image.load("stand_down.png").convert_alpha()
    self.image_down = pygame.transform.scale(temp_image, (100, 200))

    temp_image = pygame.image.load("standleft.png").convert_alpha()
    self.image_left = pygame.transform.scale(temp_image, (100, 200))

    temp_image = pygame.image.load("standright.png").convert_alpha()
    self.image_right = pygame.transform.scale(temp_image, (100, 200))

    self.image = self.image_down

    # keep position and size in pygame.Rect()
    # to use it in collision checking
    self.rect = self.image.get_rect(x=x, y=y)
def draw(self, x, y):
    screen.blit(self.image, self.rect)            
def handle_event(self):#, event)
    self.image = self.image_down.get_rect()
    self.image = pygame.Surface((x, y))
    key = pygame.key.get_pressed()
    if key[K_LEFT]:
        self.rect.x -= 50
        self.image = self.image_left
    if key[K_RIGHT]:
        self.rect.x += 50
        self.image = self.image_right
class room1():
#bedroom
    def __init__(self):
        self.x, self.y = 16, WINDOWHEIGHT/2
        self.speed = 3
    def draw(self):
        background = pygame.image.load("bedroom.jpg").convert()
        background = pygame.transform.scale(background, (WINDOWWIDTH, WINDOWHEIGHT))
        screen.blit(background, (0, 0))

And this is my main function :

def main():
     while True:
            for event in pygame.event.get():
                player.handle_event.get(event)
            player.handle_event(screen)
    room1.draw(screen)
    player.draw(screen, x, y)
    pygame.display.update()
    pygame.display.flip()
    clock.tick(FPS)
main()

I keep getting the same error :

File "C:\Python32\Project3\proj3pt2.py", line 220, in handle_event
self.image = self.image_down.get_rect()
AttributeError: 'pygame.Surface' object has no attribute 'image_down'

I know it's probably an easy fix, but I don't know where to look for it, and how I messed up. If someone could explain that, it would be much appreciated!

Ash
  • 15
  • 4
  • again the same question. where do you create player ? Don't you do `player = player.transform.scale()` or something similar ? It replace `Sprite` with `Surface` and you have problem. BTW: in line in error message `self.image = self.image_down.get_rect()` you replace `Surface` with `Rect` so you make similar mistake. – furas Dec 11 '17 at 07:52

2 Answers2

0

When you have an instance and call one of its methods, the instance gets automatically passed as the first argument, self. So if you have a class MyClass and an instance my_instance and you call its handle_event method, it's the same as calling MyClass.handle_event(my_instance).

In your program you never create an instance of the player class and so you're passing the screen as the self argument directly to the class (the screen is actually a pygame.Surface). That means the self in the handle_event method actually refers to the screen surface and since surfaces don't have an image_down attribute, Python raises an error when the self.image_down.get_rect() part is reached.

To fix this problem, you have to create an instance (also called object) of the player class and must not pass an argument to handle_event (unless you add more parameters to the method):

player_instance = player(x_position, y_position)

Then use the instance inside of the while and event loops:

while True:
    player_instance.handle_event()

You also have to create an instance of the room1 class instead of using the class directly.

Here's a complete example with some comments about other problems:

import pygame

pygame.init()
WINDOWWIDTH = 900
WINDOWHEIGHT = 400
screen = pygame.display.set_mode((WINDOWWIDTH, WINDOWHEIGHT))
FPS = 40
clock = pygame.time.Clock()
# Load images once globally and reuse them in the program.
background = pygame.image.load("bedroom.jpg").convert()
background = pygame.transform.scale(background, (WINDOWWIDTH, WINDOWHEIGHT))
temp_image = pygame.image.load("stand_down.png").convert_alpha()
image_down = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standleft.png").convert_alpha()
image_left = pygame.transform.scale(temp_image, (100, 200))
temp_image = pygame.image.load("standright.png").convert_alpha()
image_right = pygame.transform.scale(temp_image, (100, 200))


class player(pygame.sprite.Sprite):
    def __init__(self, x, y):
        super(player, self).__init__()

        self.image_down = image_down
        self.image_left = image_left
        self.image_right = image_right

        self.image = self.image_down

        # keep position and size in pygame.Rect()
        # to use it in collision checking
        self.rect = self.image.get_rect(x=x, y=y)

    # You don't have to pass x and y, since you already
    # use the `self.rect` as the blit position.
    def draw(self, screen):
        screen.blit(self.image, self.rect)

    def handle_event(self):
        # These two lines don't make sense.
        #self.image = self.image_down.get_rect()
        #self.image = pygame.Surface((x, y))
        # I guess you want to switch back to image_down.
        self.image = self.image_down

        key = pygame.key.get_pressed()
        if key[pygame.K_LEFT]:
            self.rect.x -= 5
            self.image = self.image_left
        if key[pygame.K_RIGHT]:
            self.rect.x += 5
            self.image = self.image_right

class room1():

    def __init__(self):
        self.x, self.y = 16, WINDOWHEIGHT/2
        # Reference to the background image.
        self.background = background

    def draw(self, screen):  # Pass the screen.
        screen.blit(self.background, (0, 0))


def main():
    # Create player and room instances.
    player_instance = player(200, 150)
    room1_instance = room1()

    while True:
        for event in pygame.event.get():
            # Users can press the "X" button to quit.
            if event.type == pygame.QUIT:
                return

        player_instance.handle_event()
        room1_instance.draw(screen)
        player_instance.draw(screen)
        # You don't need both update and flip.
        # pygame.display.update()
        pygame.display.flip()
        clock.tick(FPS)

main()
pygame.quit()

Side note: PEP 8 recommends uppercase names for classes, so Player instead of player. Then you could call the instance player.

skrx
  • 19,980
  • 5
  • 34
  • 48
  • If it's unclear how `self` works, take a look at this [answer](https://stackoverflow.com/a/6990217/6220679). – skrx Dec 11 '17 at 05:32
0

I suspect you do somewhere something like this

 player = player.transform.scale(player.image)

player is Sprite but scale returns Surface - so you replace Sprite with Surface and later you have problems.

(BTW: I saw the same problem in some question few days ago)

If you have to rescale image then do it in __init__ as you already do with some images.

In real game you should create images with correct sizes using any Image Editor so you don't have to use scale()


BTW: in handle_event you do

self.image = self.image_down.get_rect()
self.image = pygame.Surface((x, y))

You assign Rect to Surface (self.image) and later you assing new empty Surface with size x, y. Surface doesn't keep positon, it uses only width, height.

You have self.rect to keep positiona and you already change it with

self.rect.x -= 50

and

self.rect.x += 50

BTW: use UpperCaseNames for classes to make code more readable

class Player(...)

class Room1(...)

Event Stackoverflow knows this rule and it uses light blue color for classes to make code more readable.

More: PEP 8 -- Style Guide for Python Code


BTW: in room1.draw() you read and rescale image again and again - it can slow down program. Do it in room.__init__

furas
  • 134,197
  • 12
  • 106
  • 148