icedgem27
Posts: 5
Joined: Wed Dec 26, 2012 3:53 pm

Attribute error/Import error

Mon Jan 28, 2013 3:45 pm

Hi. Another very noobie question from me but here goes. I'm trying to work through the Raspberry Pi education manual and having a problem I can't work out with the skiing game.

So, I've been using python 2.7 because it used pygame. If I try and run in 3.2 it says "ImportError: No module named pygame"

But when I run in 2.7, I get the error: "AttributeError: 'skiWorld' object has no attribute 'keyEvent'"

In the code, I think this is the root of the problem but I'm not sure why (the last line has no line breaks):

def keyEvent (self, event):
# event should be key event but we only move if the key is pressed down
# but not released up
self.keydir = (0 if event.type == pygame.KEYUP else -1 if event.key == pygame.K_LEFT else +1 if event.key == pygame.K_RIGHT else 0)

And this is the section including the line called in the error message (last line is the one called):

# check external events (key presses, for instance)
for event in pygame.event.get():
if event.type == pygame.QUIT:
world.running = False
elif (hasattr(event, 'key')):
world.keyEvent(event)

Grateful for any suggestions!
Thanks

-rst-
Posts: 1316
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland

Re: Attribute error/Import error

Mon Jan 28, 2013 4:16 pm

There must be some formatting issue in the code - Python is very strict on the indentation...

You should post at least the whole skiWorld class definition (starting with the line 'class skiWordl' and upto the next line where the line starts from the same column as 'class' ...maybe best to post the whole code) and within the code tag (see the button labelled 'Code' above the text-area), so that the code looks something like this:

Code: Select all

class skiWorld:

    ...

    def keyEvent (self, event):
        # event should be key event but we only move if the key is pressed down
        # but not released up
        self.keydir = (0 if event.type == pygame.KEYUP else -1 if event.key == pygame.K_LEFT else +1 if event.key == pygame.K_RIGHT else 0)

...

http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'

icedgem27
Posts: 5
Joined: Wed Dec 26, 2012 3:53 pm

Re: Attribute error/Import error

Tue Jan 29, 2013 1:06 pm

thank you. This is the section of code for the class skiWorld including the def keyEvent section:

Code: Select all

class skiWorld(object):
    running = False
    keydir = 0

    def __init__ (self):
        self.running = True
        self.skier = worldSkier([190, 50], pygame.image.load("skier.png"))

    def updateWorld (self):
        # the skier is part of the world and needs updating
        self.skier.update(self.keydir)

    def drawWorld(self, canvas):
        canvas.fill([255, 250, 250]) # make a snowy white background
        world.skier.draw(canvas) # draw the player on the screen

def keyEvent (self, event):
    # event should be key event but we only move if the key is pressed down
    # but not released up
    self.keydir = (0 if event.type == pygame.KEYUP else -1 if event.key == pygame.K_LEFT else +1 if event.key == pygame.K_RIGHT else 0)
and this is the part that returns the error (I think, when calling the above section):

Code: Select all

# check input, change the game world and display the new game world
while (world.running):

    # check external events (key presses, for instance)
    for event in pygame.event.get():
        if event.type == pygame.QUIT: # stop running the game
            world.running = False
        elif (hasattr(event, 'key')): # process this keyboard input
            world.keyEvent(event)

    # update the game world
    world.updateWorld()

-rst-
Posts: 1316
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland

Re: Attribute error/Import error

Tue Jan 29, 2013 1:09 pm

Once again the indentation bites the leg... your keyEvent() function is now defined in the 'local scope' not within the skiWorld class!

To fix it, indent it to the same indentation as the other skiWorld functions/methods:

Code: Select all

class skiWorld(object):
    running = False
    keydir = 0

    def __init__ (self):
        ...

    ...

    def keyEvent (self, event):
        # event should be key event but we only move if the key is pressed down
        # but not released up
        self.keydir = (0 if event.type == pygame.KEYUP else -1  ...

http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'

icedgem27
Posts: 5
Joined: Wed Dec 26, 2012 3:53 pm

Re: Attribute error/Import error

Tue Jan 29, 2013 1:16 pm

Yay!! thank you... :D

*goes to fix next problem* ;)

DIYKiwi
Posts: 18
Joined: Wed Dec 19, 2012 10:33 pm

Re: Attribute error/Import error

Sun Feb 16, 2014 12:28 am

Hi, I'm another relative noobie to Python & am working through the Raspi Education Manual. I am stuck at the Skiworld game also. It is not at all clear from the manual how to add trees into the class "skiWorld". However, I have done my best. I have also indented the 'def keyEvent' function as per rst's suggestions. When I run the program I get the error message: global name 'worldTreeGroup' is not defined.

I have also tried indenting all of the def keyEvent(self, event): function but this brings up other unfathomable errors located in the OS file library.

Any help greatly appreciated & I post my code here below.

Code: Select all

# pyGameSkier.py
# this versiion has been copied/pasted directly from
# https://github.com/comp-core/code-pi/pull/9/files
# as a trouble-shoot step for my own typed version!

import pygame
# a world sprite is a pygame sprite
class worldSprite(pygame.sprite.Sprite):
    def __init__(self, location, picture):
        pygame.sprite.Sprite.__init__(self)
        self.image = picture
        self.rect = self.image.get_rect()
        self.rect.left, self.rect.top = location
    def draw(self,screen):
        screen.blit(self.image, self.rect)
            # draw this sprite on the screen (BLIT)

# a skier in the world knows how fast it is going
# and it can move horizontally
class worldSkier(worldSprite):
    speed = 5
    def update(self, direction):
        self.rect.left += direction * self.speed
        self.rect.left = max(0, min(380, self.rect.left))
      
class skiWorld(object):
    running = False
    keydir = 0
    
    def __init__(self):
        self.running = True
        self.skier = worldSkier([190, 50], pygame.image.load("skier.png"))
        ## adding trees
        self.trees = worldTreeGroup(pygame.image.load("block.png"))
        
    def updateWorld(self):
        # the skier is part of the world and needs updating
        self.skier.update(self.keydir)
        ## move the tree rows - removing any
        ## line that is off the top of the screen
        self.trees.update()
        ## check if the skier has collided with any 
        ## tree sprite in the tree rows in the tree group
        if pygame.sprite.spritecollide(self.skier, self.trees, False):
            self.running = False
        ## check if the tree group has run out of tree rows – 
        ## skier got to the bottom of the piste
        if len(self.trees)==0:
            self.running = False
                
    def drawWorld(self, canvas):
        canvas.fill([255, 250, 250]) # make a snowy white background
        world.trees.draw(canvas) # draw the trees
        world.skier.draw(canvas) # draw the player on the screen
        
    def keyEvent(self, event): 
        # event should be key event but we only move 
        # if the key is pressed down and not released up
        self.keydir = (0 if event.type == pygame.KEYUP else
    -1 if event.key == pygame.K_LEFT else
    +1 if event.key == pygame.K_RIGHT else 0)

# pygame library wants to do a few things before we can use it
pygame.init()
pygame.display.set_caption("Ski Slalom")
pygame.key.set_repeat(100, 5)

# create something to draw on with a size of 400 wide
canvas = pygame.display.set_mode([400, 500])

# we will need to have a constant time between frames
clock = pygame.time.Clock()

world = skiWorld()

# check input, change the game world and display the new game world
while (world.running):
            
    # check external events (key presses, for instance)
    for event in pygame.event.get():
        if event.type == pygame.QUIT: # stop running the game
            world.running = False
        elif (hasattr(event, 'key')): # process this keyboard input
                world.keyEvent(event)
    # update the game world
    world.updateWorld()
            
    # draw the world on the canvas
    world.drawWorld(canvas)
            
    # important to have a constant time between each display flip.
    # in this case, wait until at least 1/30th second has passed
    clock.tick(30)
    # flip the display to show the newly drawn screen
    pygame.display.flip()

# once the game is not running, need to finish up neatly
pygame.quit()

import random
                             
class worldTreeGroup(pygame.sprite.Group):
    speed = 5

    def __init__(self, picture):
        pygame.sprite.Group.__init__(self)
        treePicture = picture
        treeRow = pygame.sprite.Group()
        
        # in rows with a gap somewhere in the middle
        # only have a line of trees every 5th row or the
        # game is too difficult
        for y in range(0, 400):
            if (y % 5 == 0): # every 5th, add tree row with a gap
                gapsize = 3 + random.randint(0,6) # size of gap
                # starting position of gap
                gapstart = random.randint(0,10 - (gapsize//2))
                
                # create a row of 20 trees but 'gapsize'
                # skip trees in the middle
                for b in range(0,20):
                    if b >= gapstart and gapsize > 0:
                        gapsize-=1
                    else:
                        newtree=worldSprite([b*20, (y+10)*20], treePicture)
                        treeRow.add(newtree)
            
            self.add(treeRow)
    def update(self):
        for treeRow in self:
            treeRow.rect.top-=self.speed
            if treeRow.rect.top <= -20:
                treeRow.kill() # remove this block from ALL groups


User avatar
davef21370
Posts: 897
Joined: Fri Sep 21, 2012 4:13 pm
Location: Earth But Not Grounded

Re: Attribute error/Import error

Sun Feb 16, 2014 8:22 am

Cut your worldTreeGroup class and paste it above the skiWorld class, this way it is defined before skiWorld attempts to use it.

Dave.
Apple say... Monkey do !!

DIYKiwi
Posts: 18
Joined: Wed Dec 19, 2012 10:33 pm

Re: Attribute error/Import error

Sun Feb 16, 2014 8:55 am

Hey, thanks Dave - it worked!! That's such a buzz to get my first Python game running, though I can't yet get to the end of the ski run. I am a secondary school teacher so my raspberrypi co-curricular group will be thrilled to be able to make their own games like this one.

The Raspberrypi Education Manual is a great resource but there are places where the instructions are a bit opaque for newbies.

Thanks again Dave.

PS: I also pasted the 'import random' bit along with the worldTreeGroup class.

Return to “Python”