在 python 3.1 中使用 sprite 模块时出错

Error using sprite module in python 3.1

我是一名高中生,正在为我的 HSC 修读软件设计和开发课程,我一直在努力学习 pygame,并且我一直在做一些精灵和房间的工作,因为我完成了把我的代码运行改成若干错误

这里首先是原始代码:

import pygame

BLACK  = (   0,   0,   0)
WHITE  = ( 255, 255, 255)
BLUE   = (   0,   0, 255)
GREEN  = (   0, 255,   0)
RED    = ( 255,   0,   0)
PURPLE = ( 255,   0, 255)


class Wall(pygame.sprite.Sprite):
"""This class represents the bar at the bottom that the player controls """

def __init__(self, x, y, width, height, color):
    """ Constructor function """

    # Call the parent's constructor
    super().__init__()

    # Make a BLUE wall, of the size specified in the parameters
    self.image = pygame.Surface([width, height])
    self.image.fill(color)

    # Make our top-left corner the passed-in location.
    self.rect = self.image.get_rect()
    self.rect.y = y
    self.rect.x = x

class Player(pygame.sprite.Sprite):
""" This class represents the bar at the bottom that the player controls """

# Set speed vector
change_x = 0
change_y = 0

def __init__(self, x, y):
    """ Constructor function """

    # Call the parent's constructor
    super().__init__()

    # Set height, width
    self.image = pygame.Surface([15, 15])
    self.image.fill(WHITE)

    # Make our top-left corner the passed-in location.
    self.rect = self.image.get_rect()
    self.rect.y = y
    self.rect.x = x

def changespeed(self, x, y):
    """ Change the speed of the player. Called with a keypress. """
    self.change_x += x
    self.change_y += y

def move(self, walls):
    """ Find a new position for the player """

    # Move left/right
    self.rect.x += self.change_x

    # Did this update cause us to hit a wall?
    block_hit_list = pygame.sprite.spritecollide(self, walls, False)
    for block in block_hit_list:
        # If we are moving right, set our right side to the left side of
        # the item we hit
        if self.change_x > 0:
            self.rect.right = block.rect.left
        else:
            # Otherwise if we are moving left, do the opposite.
            self.rect.left = block.rect.right

    # Move up/down
    self.rect.y += self.change_y

    # Check and see if we hit anything
    block_hit_list = pygame.sprite.spritecollide(self, walls, False)
    for block in block_hit_list:

        # Reset our position based on the top/bottom of the object.
        if self.change_y > 0:
            self.rect.bottom = block.rect.top
        else:
            self.rect.top = block.rect.bottom

class Room(object):
""" Base class for all rooms. """

""" Each room has a list of walls, and of enemy sprites. """
wall_list = None
enemy_sprites = None

def __init__(self):
    """ Constructor, create our lists. """
    self.wall_list = pygame.sprite.Group()
    self.enemy_sprites = pygame.sprite.Group()

class Room1(Room):
"""This creates all the walls in room 1"""
def __init__(self):
    Room.__init__(self)
    # Make the walls. (x_pos, y_pos, width, height)

    # This is a list of walls. Each is in the form [x, y, width, height]
    walls = [[0, 0, 20, 250, WHITE],
             [0, 350, 20, 250, WHITE],
             [780, 0, 20, 250, WHITE],
             [780, 350, 20, 250, WHITE],
             [20, 0, 760, 20, WHITE],
             [20, 580, 760, 20, WHITE],
             [390, 50, 20, 500, BLUE]
            ]

    # Loop through the list. Create the wall, add it to the list
    for item in walls:
        wall = Wall(item[0], item[1], item[2], item[3], item[4])
        self.wall_list.add(wall)

class Room2(Room):
"""This creates all the walls in room 2"""
def __init__(self):
    Room.__init__(self)

    walls = [[0, 0, 20, 250, RED],
             [0, 350, 20, 250, RED],
             [780, 0, 20, 250, RED],
             [780, 350, 20, 250, RED],
             [20, 0, 760, 20, RED],
             [20, 580, 760, 20, RED],
             [190, 50, 20, 500, GREEN],
             [590, 50, 20, 500, GREEN]
            ]

    for item in walls:
        wall = Wall(item[0], item[1], item[2], item[3], item[4])
        self.wall_list.add(wall)


class Room3(Room):
"""This creates all the walls in room 3"""
def __init__(self):
    Room.__init__(self)

    walls = [[0, 0, 20, 250, PURPLE],
             [0, 350, 20, 250, PURPLE],
             [780, 0, 20, 250, PURPLE],
             [780, 350, 20, 250, PURPLE],
             [20, 0, 760, 20, PURPLE],
             [20, 580, 760, 20, PURPLE]
            ]

    for item in walls:
        wall = Wall(item[0], item[1], item[2], item[3], item[4])
        self.wall_list.add(wall)

    for x in range(100, 800, 100):
        for y in range(50, 451, 300):
            wall = Wall(x, y, 20, 200, RED)
            self.wall_list.add(wall)

    for x in range(150, 700, 100):
        wall = Wall(x, 200, 20, 200, WHITE)
        self.wall_list.add(wall)

def main():
""" Main Program """

# Call this function so the Pygame library can initialize itself
pygame.init()

# Create an 800x600 sized screen
screen = pygame.display.set_mode([800, 600])

# Set the title of the window
pygame.display.set_caption('Maze Runner')

# Create the player paddle object
player = Player(50, 50)
movingsprites = pygame.sprite.Group()
movingsprites.add(player)

rooms = []

room = Room1()
rooms.append(room)

room = Room2()
rooms.append(room)

room = Room3()
rooms.append(room)

current_room_no = 0
current_room = rooms[current_room_no]

clock = pygame.time.Clock()

done = False

while not done:

    # --- Event Processing ---

    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

        if event.type == pygame.KEYDOWN:
            if event.key == pygame.K_LEFT:
                player.changespeed(-5, 0)
            if event.key == pygame.K_RIGHT:
                player.changespeed(5, 0)
            if event.key == pygame.K_UP:
                player.changespeed(0, -5)
            if event.key == pygame.K_DOWN:
                player.changespeed(0, 5)

        if event.type == pygame.KEYUP:
            if event.key == pygame.K_LEFT:
                player.changespeed(5, 0)
            if event.key == pygame.K_RIGHT:
                player.changespeed(-5, 0)
            if event.key == pygame.K_UP:
                player.changespeed(0, 5)
            if event.key == pygame.K_DOWN:
                player.changespeed(0, -5)

    # --- Game Logic ---

    player.move(current_room.wall_list)

    if player.rect.x < -15:
        if current_room_no == 0:
            current_room_no = 2
            current_room = rooms[current_room_no]
            player.rect.x = 790
        elif current_room_no == 2:
            current_room_no = 1
            current_room = rooms[current_room_no]
            player.rect.x = 790
        else:
            current_room_no = 0
            current_room = rooms[current_room_no]
            player.rect.x = 790

    if player.rect.x > 801:
        if current_room_no == 0:
            current_room_no = 1
            current_room = rooms[current_room_no]
            player.rect.x = 0
        elif current_room_no == 1:
            current_room_no = 2
            current_room = rooms[current_room_no]
            player.rect.x = 0
        else:
            current_room_no = 0
            current_room = rooms[current_room_no]
            player.rect.x = 0

    # --- Drawing ---
    screen.fill(BLACK)

    movingsprites.draw(screen)
    current_room.wall_list.draw(screen)

    pygame.display.flip()

    clock.tick(60)

pygame.quit()

if __name__ == "__main__":
main()

当我运行pythonshell中的代码时,出现如下错误:

Traceback (most recent call last):
  File "C:\Users\jack.portegies.KELSO-H.000\Desktop\maze_runner.py", line     273, in <module>
main()
File "C:\Users\jack.portegies.KELSO-H.000\Desktop\maze_runner.py", line 180, in main
movingsprites.add(player)
  File "C:\Python31\lib\site-packages\pygame\sprite.py", line 221, in add
    if not self.has_internal(sprite):
      File "C:\Python31\lib\site-packages\pygame\sprite.py", line 195, in has_internal
     return self.spritedict.has_key(sprite)
AttributeError: 'dict' object has no attribute 'has_key'

虽然有人可能已经更改了它(因为我必须使用共享计算机),但我还是去查看了 sprite 模块本身,这是模块:

class Sprite(object):
"""The base class for your visible game objects.
   The sprite class is meant to be used as a base class
   for the objects in your game. It just provides functions
   to maintain itself in different groups.

   You can initialize a sprite by passing it a group or sequence
   of groups to be contained in.

   When you subclass Sprite, you must call this
   pygame.sprite.Sprite.__init__(self) before you add the sprite
   to any groups, or you will get an error."""

def __init__(self, *groups):
    self.__g = {} # The groups the sprite is in
    if groups: self.add(groups)

def add(self, *groups):
    """add(group or list of of groups, ...)
       add a sprite to container

       Add the sprite to a group or sequence of groups."""
    has = self.__g.has_key
    for group in groups:
        if hasattr(group, '_spritegroup'):
            if not has(group):
                group.add_internal(self)
                self.add_internal(group)
        else: self.add(*group)

def remove(self, *groups):
    """remove(group or list of groups, ...)
       remove a sprite from container

       Remove the sprite from a group or sequence of groups."""
    has = self.__g.has_key
    for group in groups:
        if hasattr(group, '_spritegroup'):
            if has(group):
                group.remove_internal(self)
                self.remove_internal(group)
        else: self.remove(*group)

def add_internal(self, group):
    self.__g[group] = 0

def remove_internal(self, group):
    del self.__g[group]

def update(self, *args):
    pass

def kill(self):
    """kill()
       remove this sprite from all groups

       Removes the sprite from all the groups that contain
       it. The sprite still exists after calling this,
       so you could use it to remove a sprite from all groups,
       and then add it to some other groups."""
    for c in self.__g.keys():
        c.remove_internal(self)
    self.__g.clear()

def groups(self):
    """groups() -> list of groups
       list used sprite containers

       Returns a list of all the groups that contain this
       sprite. These are not returned in any meaningful order."""
    return self.__g.keys()

def alive(self):
    """alive() -> bool
       check to see if the sprite is in any groups

       Returns true if this sprite is a member of any groups."""
    return (len(self.__g) != 0)

def __repr__(self):
    return "<%s sprite(in %d groups)>" % (self.__class__.__name__, len(self.__g))

class AbstractGroup(object):
"""A base for containers for sprites. It does everything
   needed to behave as a normal group. You can easily inherit
   a new group class from this, or the other groups below,
   if you want to add more features.

   Any AbstractGroup-derived sprite groups act like sequences,
   and support iteration, len, and so on."""

# dummy val to identify sprite groups, and avoid infinite recursion.
_spritegroup = True

def __init__(self):
    self.spritedict = {}
    self.lostsprites = []

def sprites(self):
    """sprites()
       get a list of sprites in the group

       Returns an object that can be looped over with a 'for' loop.
       (For now it is always a list, but newer version of Python
       could return different iterators.) You can also iterate directly
       over the sprite group."""
    return self.spritedict.keys()

def add_internal(self, sprite):
    self.spritedict[sprite] = 0

def remove_internal(self, sprite):
    r = self.spritedict[sprite]
    if r is not 0:
        self.lostsprites.append(r)
    del(self.spritedict[sprite])

def has_internal(self, sprite):
    return self.spritedict.has_key(sprite)

def copy(self):
    """copy()
       copy a group with all the same sprites

       Returns a copy of the group that is the same class
       type, and has the same sprites in it."""
    return self.__class__(self.sprites())

def __iter__(self):
    return iter(self.sprites())

def __contains__(self, sprite):
    return self.has(sprite)

def add(self, *sprites):
    """add(sprite, list, or group, ...)
       add sprite to group

       Add a sprite or sequence of sprites to a group."""
    for sprite in sprites:
        # It's possible that some sprite is also an iterator.
        # If this is the case, we should add the sprite itself,
        # and not the objects it iterates over.
        if isinstance(sprite, Sprite):
            if not self.has_internal(sprite):
                self.add_internal(sprite)
                sprite.add_internal(self)
        else:
            try:
                # See if sprite is an iterator, like a list or sprite
                # group.
                for spr in sprite:
                    self.add(spr)
            except (TypeError, AttributeError):
                # Not iterable, this is probably a sprite that happens
                # to not subclass Sprite. Alternately, it could be an
                # old-style sprite group.
                if hasattr(sprite, '_spritegroup'):
                    for spr in sprite.sprites():
                        if not self.has_internal(spr):
                            self.add_internal(spr)
                            spr.add_internal(self)
                elif not self.has_internal(sprite):
                    self.add_internal(sprite)
                    sprite.add_internal(self)

def remove(self, *sprites):
    """remove(sprite, list, or group, ...)
       remove sprite from group

       Remove a sprite or sequence of sprites from a group."""
    # This function behaves essentially the same as Group.add.
    # Check for Spritehood, check for iterability, check for
    # old-style sprite group, and fall back to assuming
    # spritehood.
    for sprite in sprites:
        if isinstance(sprite, Sprite):
            if self.has_internal(sprite):
                self.remove_internal(sprite)
                sprite.remove_internal(self)
        else:
            try:
                for spr in sprite: self.remove(spr)
            except (TypeError, AttributeError):
                if hasattr(sprite, '_spritegroup'):
                    for spr in sprite.sprites():
                        if self.has_internal(spr):
                            self.remove_internal(spr)
                            spr.remove_internal(self)
                elif self.has_internal(sprite):
                    self.remove_internal(sprite)
                    sprite.remove_internal(self)

def has(self, *sprites):
    """has(sprite or group, ...)
       ask if group has a sprite or sprites

       Returns true if the given sprite or sprites are
       contained in the group. You can also use 'sprite in group'
       or 'subgroup in group'."""
    # Again, this follows the basic pattern of Group.add and
    # Group.remove.
    for sprite in sprites:
        if isinstance(sprite, Sprite):
            return self.has_internal(sprite)

        try:
            for spr in sprite:
                if not self.has(sprite):
                    return False
            return True
        except (TypeError, AttributeError):
            if hasattr(sprite, '_spritegroup'):
                for spr in sprite.sprites():
                    if not self.has_internal(spr):
                        return False
                return True
            else:
                return self.has_internal(sprite)

def update(self, *args):
    """update(*args)
       call update for all member sprites

       calls the update method for all sprites in the group.
       Passes all arguments on to the Sprite update function."""
    for s in self.sprites(): s.update(*args)

def draw(self, surface):
    """draw(surface)
       draw all sprites onto the surface

       Draws all the sprites onto the given surface."""
    sprites = self.sprites()
    surface_blit = surface.blit
    for spr in sprites:
        self.spritedict[spr] = surface_blit(spr.image, spr.rect)
    self.lostsprites = []

def clear(self, surface, bgd):
    """clear(surface, bgd)
       erase the previous position of all sprites

       Clears the area of all drawn sprites. the bgd
       argument should be Surface which is the same
       dimensions as the surface. The bgd can also be
       a function which gets called with the passed
       surface and the area to be cleared."""
    if callable(bgd):
        for r in self.lostsprites:
            bgd(surface, r)
        for r in self.spritedict.values():
            if r is not 0: bgd(surface, r)
    else:
        surface_blit = surface.blit
        for r in self.lostsprites:
            surface_blit(bgd, r, r)
        for r in self.spritedict.values():
            if r is not 0: surface_blit(bgd, r, r)

def empty(self):
    """empty()
       remove all sprites

       Removes all the sprites from the group."""
    for s in self.sprites():
        self.remove_internal(s)
        s.remove_internal(self)

def __nonzero__(self):
    return (len(self.sprites()) != 0)

def __len__(self):
    """len(group)
       number of sprites in group

       Returns the number of sprites contained in the group."""
    return len(self.sprites())

def __repr__(self):
    return "<%s(%d sprites)>" % (self.__class__.__name__, len(self))

class Group(AbstractGroup):
"""The basic Group class you will want to use.
   It supports all of the above operations and methods.

   The RenderPlain and RenderClear groups are aliases to Group
   for compatibility."""

def __init__(self, *sprites):
    AbstractGroup.__init__(self)
    self.add(*sprites)

RenderPlain = Group
RenderClear = Group

class RenderUpdates(Group):
"""A sprite group that's more efficient at updating.
   This group supports drawing to the screen, but its draw method
   also returns a list of the Rects updated by the draw (and any
   clears in between the last draw and the current one). You
   can use pygame.display.update(renderupdates_group.draw(screen))
   to minimize the updated part of the screen. This can usually
   make things much faster."""

def draw(self, surface):
   spritedict = self.spritedict
   surface_blit = surface.blit
   dirty = self.lostsprites
   self.lostsprites = []
   dirty_append = dirty.append
   for s in self.sprites():
       r = spritedict[s]
       newrect = surface_blit(s.image, s.rect)
       if r is 0:
           dirty_append(newrect)
       else:
           if newrect.colliderect(r):
               dirty_append(newrect.union(r))
           else:
               dirty_append(newrect)
               dirty_append(r)
       spritedict[s] = newrect
   return dirty

class OrderedUpdates(RenderUpdates):
"""RenderUpdates, but the sprites are drawn in the order they were added.
   More recently added sprites are drawn last (and so, above other
   sprites)."""

def __init__(self, *sprites):
    self._spritelist = []
    RenderUpdates.__init__(self, *sprites)

def sprites(self): return list(self._spritelist)

def add_internal(self, sprite):
    RenderUpdates.add_internal(self, sprite)
    self._spritelist.append(sprite)

def remove_internal(self, sprite):
    RenderUpdates.remove_internal(self, sprite)
    self._spritelist.remove(sprite)

 class GroupSingle(AbstractGroup):
"""A group container that holds a single most recent item.
   This class works just like a regular group, but it only
   keeps a single sprite in the group. Whatever sprite has
   been added to the group last, will be the only sprite in
   the group.

   You can access its one sprite as the .sprite attribute.
   Assigning to this attribute will properly remove the old
   sprite and then add the new one."""

 def __init__(self, sprite = None):
    self.__sprite = None
    if sprite is not None: self.add(sprite)

 def copy(self):
    return GroupSingle(self.__sprite)

 def sprites(self):
    if self.__sprite is not None: return [self.__sprite]
    else: return []

 def add_internal(self, sprite):
    if self.__sprite is not None:
        self.__sprite.remove_internal(self)
    self.__sprite = sprite

 def __nonzero__(self): return (self.__sprite is not None)

 def _get_sprite(self):
    return self.__sprite

 def _set_sprite(self, sprite):
    self.add_internal(sprite)
    sprite.add_internal(self)
    return sprite

 sprite = property(_get_sprite, _set_sprite, None,
                  "The sprite contained in this group")

 def remove_internal(self, sprite):
    if sprite is self.__sprite: self.__sprite = None

 def has_internal(self, sprite):
    return (self.__sprite is sprite)

 # Optimizations...
 def __contains__(self, sprite): return (self.__sprite is sprite)

 def spritecollide(sprite, group, dokill):
 """pygame.sprite.spritecollide(sprite, group, dokill) -> list
   collision detection between sprite and group

   given a sprite and a group of sprites, this will
   return a list of all the sprites that intersect
   the given sprite.
   all sprites must have a "rect" value, which is a
   rectangle of the sprite area. if the dokill argument
   is true, the sprites that do collide will be
   automatically removed from all groups."""
crashed = []
spritecollide = sprite.rect.colliderect
if dokill:
    for s in group.sprites():
        if spritecollide(s.rect):
            s.kill()
            crashed.append(s)
else:
    for s in group:
        if spritecollide(s.rect):
            crashed.append(s)
return crashed

def groupcollide(groupa, groupb, dokilla, dokillb):
"""pygame.sprite.groupcollide(groupa, groupb, dokilla, dokillb) -> dict
   collision detection between group and group

   given two groups, this will find the intersections
   between all sprites in each group. it returns a
   dictionary of all sprites in the first group that
   collide. the value for each item in the dictionary
   is a list of the sprites in the second group it
   collides with. the two dokill arguments control if
   the sprites from either group will be automatically
   removed from all groups."""
crashed = {}
SC = spritecollide
if dokilla:
    for s in groupa.sprites():
        c = SC(s, groupb, dokillb)
        if c:
            crashed[s] = c
            s.kill()
else:
    for s in groupa:
        c = SC(s, groupb, dokillb)
        if c:
            crashed[s] = c
return crashed

def spritecollideany(sprite, group):
"""pygame.sprite.spritecollideany(sprite, group) -> sprite
   finds any sprites that collide

   given a sprite and a group of sprites, this will
   return return any single sprite that collides with
   with the given sprite. If there are no collisions
   this returns None.

   if you don't need all the features of the
   spritecollide function, this function will be a
   bit quicker.

   all sprites must have a "rect" value, which is a
   rectangle of the sprite area."""
spritecollide = sprite.rect.colliderect
for s in group:
    if spritecollide(s.rect):
        return s
return None

如果有人能帮助我解决这个问题,那将是非常棒的,因为我已经问过我的老师并且他指导我访问了这个网站,所以祈祷有人能提供帮助!

has_key 不再用于 python3 只需使用 in:

return sprite in self.spritedict

如果代码最初是为 python2 编写的,则可能存在其他问题,因为 python3 不向后兼容 python2。

我也在学习同样的课程,(我也和你用的是同一台电脑) 把一个同行的 Python 目录复制到你自己的目录似乎已经解决了我的问题。试试看?