Python TypeError传递类变量?

时间:2012-12-20 22:32:53

标签: python class pygame

所以我试图将vars从一个类传递到另一个类。我希望Map类从Game类接收变量。当我运行它时,我收到一个错误:

self.width      = w*self.multi 
TypeError: Error when calling the metaclass bases
can't multiply sequence by non-int of type 'dict'

我该如何解决这个问题,或者我应该以不同的方式解决这个问题?

import pygame, os
from pygame.locals import *
from pygame import Color
from time import time
from datetime import datetime




class Game():
    """ Lets try to get this going by simple steps
    One by one. First step, lets figure how to make a class
    that can do the display stuff. NOTE TO SELF: Remember, these
    are only called ONCE at the start. Lord have mercy on my soul"""
    def __init__(self, w=256, h=224, multi=3):
        """Initialization"""
        pygame.init()
        self.multi      = multi
        self.runGame    = True
        self.width      = w*self.multi
        self.height     = h*self.multi
        self.sprSz      = 16*self.multi
        self.clock      = pygame.time.Clock()
        self.screen     = pygame.display.set_mode((self.width, self.height))
        self.kl         = []
        self.walk       = [0, 0]
        self.speed      = self.multi*1.5
        self.x,self.y   = (self.width/2-(self.sprSz/2)), (self.height/2-(self.sprSz/2))
        self.music      = self.sndLoad('relent.ogg')
        self.playerSpr  = self.imgLoad('link1.png', self.multi, 0, 0)
        self.playerRec  = Rect(self.x,self.y,self.sprSz,self.sprSz)
        self.aSprite    = self.imgLoad('greenwall_01.png', self.multi, 0, 0)
        self.aSpriteRec = Rect(self.aSprite.get_rect())


    def imgLoad(self, image, size, flipx, flipy):
        try:
            self.img=pygame.image.load('images/'+image).convert_alpha()
        except pygame.error, message:
            print "Unable to load image: " + image
            raise SystemExit, message               
        if size>1:
            self.img=pygame.transform.scale(self.img, (self.img.get_width()*size, self.img.get_height()*size))
        if flipx==1:
            self.img=pygame.transform.flip(self.img, True, False)
        if flipy==1:
            self.img=pygame.transform.flip(self.img, False, True)
        if flipy>1 or flipy<0:
            self.img=pygame.transform.rotate(self.img, flipy)        
        return self.img


    def sndLoad(self, sound):
        try:
            self.sound = pygame.mixer.Sound('sounds/'+sound)
        except pygame.error, message:
            print "Cannot load sound: " + sound
            raise SystemExit, message
        return self.sound    


    def mainLoop(self):
        """Loop through the main game routines
        1. Drawing  2. Input handling  3. Updating
        Then loop through it until user quits"""
        self.music.play()
        self.music.set_volume(0.01)
        while self.runGame:
            self.clock.tick(160)
            self.events()
            self.draw()


    def events(self):
        """Time to handle some events"""
        for e in pygame.event.get():
            if (e.type == pygame.QUIT) or (e.type == KEYDOWN and e.key == K_ESCAPE):
                self.runGame = False
                break
            if e.type == KEYDOWN and e.key == K_PRINT:
                self.screenShot()
            if e.type==KEYDOWN:    
                if e.key==pygame.K_a: self.kl.append(1)
                if e.key==pygame.K_d: self.kl.append(2)
                if e.key==pygame.K_w: self.kl.append(3)
                if e.key==pygame.K_s: self.kl.append(4)             
            if e.type==pygame.KEYUP:
                if e.key==pygame.K_a: self.kl.remove(1)            
                if e.key==pygame.K_d: self.kl.remove(2)
                if e.key==pygame.K_w: self.kl.remove(3)             
                if e.key==pygame.K_s: self.kl.remove(4)

            if   self.kl[-1:]==[1]: self.walk=[-self.speed, 0]
            elif self.kl[-1:]==[2]: self.walk=[ self.speed, 0]
            elif self.kl[-1:]==[3]: self.walk=[0,-self.speed]
            elif self.kl[-1:]==[4]: self.walk=[0, self.speed]
            else:                   self.walk=[0, 0]

        self.playerRec.move_ip(*self.walk)              # instead of self.x+=self.walk[0] / self.y+=self.walk[1]
        self.playerRec.clamp_ip(self.screen.get_rect()) # probably do this right after 'move_ip'


    def screenShot(self):
        """Lets make a folder if it doesnt exist for screenshots
        Then lets name teh screenshot something useful and unique"""
        if not os.path.exists('screenshots'):
            os.makedirs('screenshots')
        t = datetime.now()
        pygame.image.save(self.screen, ('screenshots/'+str(t.strftime("%a-%d-%b-%Y-%H.%M.%S_%f"))+'.png'))


    def idk(self):
        pygame.sprite.collide_rect(left, right)

    def draw(self):
        """Draw and update the main screen. Sacrifice virgins to the
        unholy prankster god of programming and cross fingers"""
        pygame.display.set_caption('Grid2. FPS: '+str(round(self.clock.get_fps(), 1)))
        back = self.screen.fill(Color('darkblue'))
        map.drawMapArray(map.readMap('kk.txt'))             
        link = self.screen.blit(self.playerSpr, self.playerRec) # 'blit' accepts a 'Rect' as second parameter
        bush = self.screen.blit(self.aSprite, self.aSpriteRec)
        d = link.colliderect(bush)
        print d  
        pygame.display.update()



class Map(Game()):
    """What we need to do here is go out and open a map file. 
    Read the file, and for each charactor load it onto the surface 
    in the right x/y coords. Should be easy. lulz"""
    def __init__(self, md='maps/'):
        self.md     = md
        self.tiles  = []
        #self.sprSz  = game.sprSz
        #self.multi  = game.multi
        #self.screen = game.screen

    def readMap(self, mapfile):
        """Lets open that map file up in a semi elegant way. Let
        us code cleanly and improve on simple things. """
        try:
            self.mpath  = os.path.join(self.md, mapfile)
            self.map    = open(self.mpath, 'r')
        except IOError, message:
            print "Unable to Map: " + self.md+mapfile
            raise SystemExit, message

        self.lines  = self.map.readlines()        
        self.Ty     = len(self.lines)
        self.Tx     = len(self.lines[0])-1
        self.map.close()

        for c in range(self.Ty):
            self.tiles.append([])
            for r in range(self.Tx):
                self.tiles[c].append(self.lines[c][r])                        
        return self.tiles


    def drawMapArray(self, map):
        for x in range(0, self.Tx):
            for y in range(0, self.Ty):
                #Determines tile type.
                curTile=tile_d[map[y][x]][3]
                #print x,y
                #print map
                #print curTile
                #if  tile_d[self.readMap[y][x]][2]>-1:
                    #game.screen.blit(curTile, (x*game.sprSz, y*game.sprSz+game.multi*56), (tile_d[self.readMap[y][x]][2]*resmulti*16, 0, 16*resmulti, 16*resmulti))
                #else:
                e = self.screen.blit(curTile, (x*self.sprSz, y*self.sprSz+self.multi*56))
                #print e


if __name__ == "__main__":
    game = Game()
    map = Map()   
    tile_d={
'#' : ('Link', True, 0, game.imgLoad("link1.png", game.multi, 0, 0)),
' ' : ('Link', True, 0, game.imgLoad("empty.png", game.multi, 0, 0)),
'Q' : ('Link', True, 0, game.imgLoad("link1.png", game.multi, 0, 0)),
'R' : ('Link', True, 0, game.imgLoad("empty.png", game.multi, 0, 0)),
'W' : ('Link', True, 0, game.imgLoad("link1.png", game.multi, 0, 0)),
'E' : ('Link', True, 0, game.imgLoad("empty.png", game.multi, 0, 0)),
'R' : ('Link', True, 0, game.imgLoad("link1.png", game.multi, 0, 0)),
'B' : ('Link', True, 0, game.imgLoad("empty.png", game.multi, 0, 0)),
'T' : ('Link', True, 0, game.imgLoad("link1.png", game.multi, 0, 0)),
'Y' : ('Link', True, 0, game.imgLoad("empty.png", game.multi, 0, 0)),
}
    game.mainLoop()

2 个答案:

答案 0 :(得分:2)

您正在使用Python的语法进行类继承。继承用于'是'关系,假设类如SidescrollerFPS,因为它们是游戏类型。

Map不是一种游戏,它是游戏中的某种东西,因此GameMap'具有'关系。你的游戏有一张地图,就像有精灵和声音一样。 '具有'关系没有特殊语法。父类只是创建子类的实例。

由于您希望访问Game的变量,因此在声明地图时可以将其原始实例传递给Map。如果您在Map内声明Game,则可以使用self传递游戏实例。这是一个例子:

# print the game's title via the Map class

class Game:

    def __init__(self):
        self.title = "Robot Ninja Spaceman: Lazer Quest"
        self.map = Map(self)

class Map:

    def __init__(self, game):
        print game.title

if __name__ == "__main__":
    game = Game()

答案 1 :(得分:1)

要让Map使用Game作为基类,您应该使用class Map(Game)而不是class Map(Game())来定义它。

以下是尝试使用Game实例作为基类时会发生什么的简短示例:

>>> class Game():
...     def __init__(*args):
...         print args
... 
>>> class Map(Game()):
...     pass
... 
(<__main__.Game instance at 0x7fa41d06f320>,)
(<__main__.Game instance at 0x7fa41d0549e0>, 'Map', (<__main__.Game instance at 0x7fa41d06f320>,), {'__module__': '__main__'})

因此,我们看到当Map的类定义运行时,我们会调用Game.__init__()两次。第一个是用Game创建的Game()实例,接下来发生的事情有点奇怪。刚刚创建的实例用作Map的基类,因此使用与{{3}的三个参数版本相同的参数调用 __init__()方法(名称,基类和字典)。

这就是为什么你最终会遇到这个奇怪的错误,最后打电话给Game.__init__(),其中w是字符串'Map'multi是字典,并尝试将字符串乘以字典会导致TypeError:

>>> self.multi = 'Map' * {}
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
TypeError: can't multiply sequence by non-int of type 'dict'