Reputation: 322
So I'm trying to pass vars from one class to another. I want the Map class to receive the vars from the Game class. When I run it I get an error:
self.width = w*self.multi TypeError: Error when calling the metaclass bases can't multiply sequence by non-int of type 'dict'
How can I fix this, or should I be going about this differently?
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()
Upvotes: 0
Views: 198
Reputation: 4729
You're using Python's syntax for class inheritance. Inheritance is used for 'is a' relationships, hypothetical classes like Sidescroller
or FPS
, because they are types of games.
Map
is not a type of game, it's something in a game, so Game
and Map
have a 'has a' relationship. Your game has a map, like it has sprites and sounds. There is no special syntax for a 'has a' relationship. The parent class just creates an instance of the child class.
Since you want access to Game
's variables, you could pass its original instance to Map
when you declare a map. If you declare Map
within Game
, you can pass the instance of game using self
. Here is an example:
# 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()
Upvotes: 2
Reputation: 208715
To have Map
use Game
as a base class, you should define it using class Map(Game)
instead of class Map(Game())
.
Here is a brief example of what happens when you try to use an instance of Game
as the base class:
>>> 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__'})
So we see that when the class definition for Map
runs, we get two calls to Game.__init__()
. The first is for the Game
instance being created with Game()
, what happens next is a little weird. The instance that was just created is used as the base class for Map
, so its __init__()
method gets called using the same arguments as the three argument version of type()
(the name, base classes, and a dictionary).
This is why you end up with that weird error you see, you end up with a call to Game.__init__()
where w
is the string 'Map'
and multi
is a dictionary, and attempting to multiply a string by a dictionary results in that 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'
Upvotes: 1