Related
I am making a small game using pygame.
I have defined a function called draw_Objects() but Name Error occurs as if I didn't define the function. What should I do?
The code is part of the module
I have tried to change the draw_Objects() function but I couldn't solve it.
import pygame
from const import *
class item(pygame.sprite.Sprite):
def __init__(self,game):
super().__init__()
self.game=game
#self.screen=screen
self.width=WIDTH
self.height=HEIGHT
#potion 사진 불러옴
self.image=pygame.image.load("tile/red-potion.png")
self.rect = self.image.get_rect()
self.red_potion=pygame.image.load("tile/red-potion.png")
self.blue_potion=pygame.image.load("tile/blue-potion.png")
self.mask=pygame.mask.from_surface(self.image)
self.rect = self.image.get_rect()
redItem=[50,530,300,50,850,100,600,280,800,400]
def __call__(self):
print (" ")
def item_display(self,screen):
#아이템 화면에 표시
screen.blit(self.red_potion,(50,530)) #red1
screen.blit(self.blue_potion,(30,530))
screen.blit(self.blue_potion,(30,460))
screen.blit(self.red_potion,(300,50)) #red2
screen.blit(self.blue_potion,(400,150))
screen.blit(self.image,(850,100)) #red3
screen.blit(self.red_potion,(600,280)) #red4
screen.blit(self.red_potion,(800,400)) #red5
screen.blit(self.blue_potion,(600,370))
def draw_Objects(myList=[]):
for i in myList:
x=myList[i]
y=myList[i+1]
screen.blit(self.red_potion,(x,y))
i+=1
def item_eat(self,screen):
item__=item(self)
#red2 item
self.rect.x=300
self.rect.y=50
#item과 player 충돌 검사
hits_item=pygame.sprite.spritecollide(self,self.game.player_group,False,pygame.sprite.collide_mask)
if hits_item :
screen.blit(self.red_potion,(50,530)) #red1
screen.blit(self.blue_potion,(30,530))
screen.blit(self.blue_potion,(30,460))
screen.blit(self.blue_potion,(400,150))
screen.blit(self.red_potion,(850,100)) #red3
screen.blit(self.red_potion,(600,280)) #red4
screen.blit(self.red_potion,(800,400)) #red5
screen.blit(self.blue_potion,(600,370))
else:
#item__.item_display(self.screen)
draw_Objects(redItem)
this line
draw_Objects(redItem)
is looking for a global function named draw_Objects which does not exist. you need to call
self.draw_Objects(redItem)
However, you would also need to include self as a parameter in the function definition like so
def draw_Objects(self, myList=[]):
draw_Objects is not a global function, it is an attribute of the class and can be called with self.
def item_eat(self,screen):
item__=item(self)
#red2 item
self.rect.x=300
self.rect.y=50
#item과 player 충돌 검사
hits_item=pygame.sprite.spritecollide(self,self.game.player_group,False,pygame.sprite.collide_mask)
if hits_item :
screen.blit(self.red_potion,(50,530)) #red1
screen.blit(self.blue_potion,(30,530))
screen.blit(self.blue_potion,(30,460))
screen.blit(self.blue_potion,(400,150))
screen.blit(self.red_potion,(850,100)) #red3
screen.blit(self.red_potion,(600,280)) #red4
screen.blit(self.red_potion,(800,400)) #red5
screen.blit(self.blue_potion,(600,370))
else:
#item__.item_display(self.screen)
self.draw_Objects(redItem) # Change this line to reference draw_Objects
It's rather simple.
def draw_Objects(self):
myList=[]
for i in myList:
x=myList[i]
y=myList[i+1]
screen.blit(self.red_potion,(x,y))
i+=1
Then call it like:
self.draw_Objects()
Currently I am exploring the possibilities of Pygame and have created a simple game and am now trying to neaten it up. I am trying to define new objects by using a class I have made in a function.
This is what I tried:
def CreateEnemy():
enemy1 = Enemies()
enemy2 = Enemies()
enemy3 = Enemies()
enemy1.getInstructions()
enemy2.getInstructions()
enemy3.getInstructions()
However when I try to use the object enemy1 it says it is not defined. From what I know the objects may be only local in the function. Does this mean that I have to somehow use the return function?
I am assuming you have a class called Enemies something like below
class Enemies:
def getInstructions():
return "instructions"
now want a method to create a bunch of enemies instances
def create_enemies(num_of_enemies):
enemies = []
for i in range(num_of_enemies):
enemies.append(enemy)
return enemies
and then use the above method to create enemies like this:
enemy1, enemy2 , enemy3 = create_enemies(3)
class Ins_Normal():
def getInstructions(self, *args):
return "GetInstructions_Normal"
class Ins_Agressive():
def getInstructions(self, *args):
return "GetInstructions_Agressive"
class Enemies(object):
def __init__(self, behaivor = 'Ins_Normal', mode = True, *args):
self.behaivor = behaivor
self.mode = mode
def getInstructions(self, *args):
#create instance based on behaivor
try:
ins = globals()[self.behaivor]() # same like ins = Ins_Agressive()
except KeyError as e:
raise NotImplementedError(e)
# return getInstructions() init value behaivor
return ins.getInstructions()
def xyz(self, *args):
# if True return worldspace position (eg)
if self.mode:
return "xyz"
return 'com_xyz'
def CreateEnemy(enemy = 0, behaivor = 'Ins_Normal', mode =True):
# wrapper function to collect Enemies
# create dict, so no hardcoded variabels, scalable....
data = dict((_id, Enemies(behaivor, mode)) for _id in range(enemy))
return data
# create groups of enemies
enemies_com_normal = CreateEnemy(3, 'Ins_Normal') #com
enemies_user_normal = CreateEnemy(3, 'Ins_Normal', True) #interactive
enemies_com_agressive = CreateEnemy(5, 'Ins_Agressive', True) #interactive
print enemies_com_normal
# we get dict of Enemy instances with id(int) as key
#>>> {0: <Enemies object at 0x7f2d8cfe5b10>, 1: <Enemies object at 0x7f2d8cfe5b50>, 2: <Enemies object at 0x7f2d8cfe5b90>}
#lets print some infos of the agents
print enemies_com_normal[0].xyz()
#>>>xyz
print enemies_com_normal[0].getInstructions()
#>>>GetInstructions_Normal
print enemies_com_agressive[2].getInstructions()
#>>>GetInstructions_Agressive
enemies_com_hgd = CreateEnemy(5, 'Ins_HGD', True) #interactive
print enemies_com_hgd[0].getInstructions()
#Traceback (most recent call last):
# File "python", line 56, in <module>
# File "python", line 21, in getInstructions
#NotImplementedError: 'Ins_HGD' <<<<< no Instruction Implemented for Ins_HGD
please include some code so that you can get better answer but no you don't require to write return function as you can see in my example.
class Enemies:
def getInstructions(self):
print("Instructions")
def createEnemy():
global allEnemy
allEnemy.append(Enemies())
allEnemy = []
createEnemy()
createEnemy()
for enemy in allEnemy :
enemy.getInstructions()
Been trying to get a dictionary working for some sprites.
class Player(Digimon):
def __init__(self):
super(Player, self).__init__(0,2,0,0,0,0) # age, weight, str, def, speed, intelligence
self.image_dict = {(0,2,0,0,0,0): itertools.cycle([pygame.image.load("images/egg_sprite_1.png"),
pygame.image.load("images/egg_sprite_2.png"),
pygame.image.load("images/egg_sprite_3.png")]),
(2,4,0,0,2,5): itertools.cycle([pygame.image.load("images/leaf_1.png"),
pygame.image.load("images/leaf_2.png"),
pygame.image.load("images/leaf_3.png"),
pygame.image.load("images/leaf_4.png")])}
and then in the main loop
Player.images = Player.image_dict[(Player.age, Player.weight, Player.strength, Player.defence, Player.speed, Player.intelligence)]
Player.image = next(Player.images)
I get the error stated in the title. I've looked at similar questions, but they don't seem to help. As far as I can see, it should work. Player.image_dict is created in the Player(digimon) subclass, so I don't know how there is no attribute.
Well, you actually need to create an instance of the Player class as follows:
player = Player()
Then you can call:
player.images = player.image_dict[(player.age, player.weight, player.strength, player.defence, player.speed, player.intelligence)]
player.image = next(player.images)
Note these are player the object, not Player the class
Player.image_dict
this way you can only access ststic members of class Player. If you dont want to do that you need to create a object of the class player. like this
Player player = Player(<arguments>)
player.image_dict(...)
I am working on a game, in which you can create mazes. You place blocks on a 16x16 grid, while choosing from a variety of block to make the level with. Whenever you create a block, it adds this class:
class Block(object):
def __init__(self,x,y,spr):
self.x=x
self.y=y
self.sprite=spr
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
to a list called instances.
I tried shelving it to a .bin file, but it returns some error dealing with surfaces. How can I go about saving and loading levels?
Any help is appreciated! :)
Here is the whole code for reference:
import pygame
from pygame.locals import *
#initstuff
pygame.init()
screen=pygame.display.set_mode((640,480))
pygame.display.set_caption('PiMaze')
instances=[]
#loadsprites
menuspr=pygame.image.load('images/menu.png').convert()
b1spr=pygame.image.load('images/b1.png').convert()
b2spr=pygame.image.load('images/b2.png').convert()
currentbspr=b1spr
curspr=pygame.image.load('images/curs.png').convert()
curspr.set_colorkey((0,255,0))
#menu
menuspr.set_alpha(185)
menurect=menuspr.get_rect(x=-260,y=4)
class MenuItem(object):
def __init__(self,pos,spr):
self.x=pos[0]
self.y=pos[1]
self.sprite=spr
self.pos=(self.x,self.y)
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
class Block(object):
def __init__(self,x,y,spr):
self.x=x
self.y=y
self.sprite=spr
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
while True:
#menu items
b1menu=b1spr.get_rect(x=menurect.left+32,y=48)
b2menu=b2spr.get_rect(x=menurect.left+64,y=48)
menuitems=[MenuItem(b1menu,b1spr),MenuItem(b2menu,b2spr)]
screen.fill((20,30,85))
mse=pygame.mouse.get_pos()
key=pygame.key.get_pressed()
placepos=((mse[0]/16)*16,(mse[1]/16)*16)
if key[K_q]:
if mse[0]<260:
if menurect.right<255:
menurect.right+=1
else:
if menurect.left>-260:
menurect.left-=1
else:
if menurect.left>-260:
menurect.left-=1
for e in pygame.event.get():
if e.type==QUIT:
exit()
if menurect.right<100:
if e.type==MOUSEBUTTONUP:
if e.button==1:
to_remove = [i for i in instances if i.rect.collidepoint(placepos)]
for i in to_remove:
instances.remove(i)
if not to_remove:
instances.append(Block(placepos[0],placepos[1],currentbspr))
for i in instances:
screen.blit(i.sprite,i.rect)
if not key[K_q]:
screen.blit(curspr,placepos)
screen.blit(menuspr,menurect)
for item in menuitems:
screen.blit(item.sprite,item.pos)
if item.rect.collidepoint(mse):
if pygame.mouse.get_pressed()==(1,0,0):
currentbspr=item.sprite
pygame.draw.rect(screen, ((255,0,0)), item, 1)
pygame.display.flip()
You can't serialize/pickle/shelve pygame's Surface objects (at least not without a lot of effort). So the answer to your question is: just don't try to serialize your surfaces (it will just waste disk space anyway).
You could for example create a simple dict to store your surfaces, and let your classes just store the key, for example:
menuspr=pygame.image.load('images/menu.png').convert()
b1spr=pygame.image.load('images/b1.png').convert()
b2spr=pygame.image.load('images/b2.png').convert()
currentbspr=b1spr
curspr=pygame.image.load('images/curs.png').convert()
curspr.set_colorkey((0,255,0))
# create a dict to store all surfaces
surf_dict = {'b1spr': b1spr,
'b2spr': b2spr,
'currentbspr': currentbspr,
'curspr': curspr}
...
class Block(object):
def __init__(self,x,y,spr):
self.x=x
self.y=y
self.sprite=spr
# self.sprite is no longer a Surface, but a str
self.rect=surf_dict[self.sprite].get_rect(x=self.x,y=self.y)
...
...
# don't pass the surface to the Block, just the key
instances.append(Block(placepos[0],placepos[1], 'currentbspr'))
...
for i in instances:
# get the Surface from the dict, not from the instance itself
screen.blit(surf_dict[i.sprite],i.rect)
Now you can savely try to pickle/shelve all Block-instances (I see you have asked a related question here).
I found a way around it myself. I used python's built in open(fname,mode) to create a level file.
Whenever a block is created, it takes the sprite-name and coordinates of the block, and adds it to the save file in a .bin format:
f.write('Block('+str(placepos[0])+','+str(placepos[1])+',b1spr).')
Then I created a function to read this, and create the level accordingly:
def CreateLevel(levelname):
f=open(levelname,'r')
obj=f.read()
f.close()
obj=obj.split('.')
for b in obj:
instances.append(eval(b))
And it worked with flying colors!
Here is the whole code, and thank you guys for the help.
import pygame
from pygame.locals import *
#initstuff
pygame.init()
screen=pygame.display.set_mode((640,480))
pygame.display.set_caption('PiMaze')
instances=[]
level='save.bin'
#loadsprites
menuspr=pygame.image.load('images/menu.png').convert()
b1spr=pygame.image.load('images/b1.png').convert()
b2spr=pygame.image.load('images/b2.png').convert()
b3spr=pygame.image.load('images/b3.png').convert()
currentbspr=b1spr
curspr=pygame.image.load('images/curs.png').convert()
curspr.set_colorkey((0,255,0))
#menu
menuspr.set_alpha(185)
menurect=menuspr.get_rect(x=-260,y=4)
class MenuItem(object):
def __init__(self,pos,spr):
self.x=pos[0]
self.y=pos[1]
self.sprite=spr
self.pos=(self.x,self.y)
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
class Block(object):
def __init__(self,x,y,spr):
self.x=x
self.y=y
self.sprite=spr
self.rect=self.sprite.get_rect(x=self.x,y=self.y)
def CreateLevel(levelname):
f=open(levelname,'r')
obj=f.read()
f.close()
obj=obj.split('.')
for b in obj:
instances.append(eval(b))
try:
CreateLevel(level)
except:
pass
f=open(level,'a+')
while True:
#menu items
b1menu=b1spr.get_rect(x=menurect.left+32,y=48)
b2menu=b2spr.get_rect(x=menurect.left+64,y=48)
b3menu=b3spr.get_rect(x=menurect.left+96,y=48)
menuitems=[MenuItem(b1menu,b1spr),MenuItem(b2menu,b2spr),MenuItem(b3menu,b3spr)]
screen.fill((20,30,85))
mse=pygame.mouse.get_pos()
key=pygame.key.get_pressed()
placepos=((mse[0]/16)*16,(mse[1]/16)*16)
if key[K_q]:
if mse[0]<260:
if menurect.right<255:
menurect.right+=1
else:
if menurect.left>-260:
menurect.left-=1
else:
if menurect.left>-260:
menurect.left-=1
for e in pygame.event.get():
if e.type==QUIT:
f.close()
exit()
if menurect.right<100:
if key[K_LSHIFT]:
if pygame.mouse.get_pressed()==(1,0,0):
to_remove = [i for i in instances if i.rect.collidepoint(placepos)]
if not to_remove:
instances.append(Block(placepos[0],placepos[1],currentbspr))
f.write('Block('+str(placepos[0])+','+str(placepos[1])+',b1spr).')
to_remove = []
if not key[K_LSHIFT] or key[K_RSHIFT]:
if e.type==MOUSEBUTTONUP:
if e.button==1:
to_remove = [i for i in instances if i.rect.collidepoint(placepos)]
for i in to_remove:
instances.remove(i)
if not to_remove:
instances.append(Block(placepos[0],placepos[1],currentbspr))
f.write('Block('+str(placepos[0])+','+str(placepos[1])+',b1spr).')
if key[K_RSHIFT]:
if pygame.mouse.get_pressed()==(1,0,0):
to_remove = [i for i in instances if i.rect.collidepoint(placepos)]
for i in to_remove:
instances.remove(i)
to_remove=[]
for i in instances:
screen.blit(i.sprite,i.rect)
if not key[K_q]:
screen.blit(curspr,placepos)
screen.blit(menuspr,menurect)
for item in menuitems:
screen.blit(item.sprite,item.pos)
if item.rect.collidepoint(mse):
if pygame.mouse.get_pressed()==(1,0,0):
currentbspr=item.sprite
pygame.draw.rect(screen, ((255,0,0)), item, 1)
pygame.display.flip()
I was attempting to place certain class variables within a list. Each class has a method known as update and considering they each do the exact same thing I though it would be allot more convenient to simply place them in a list and call the method that way.
The method I am trying to call is known as update and this is the error that I get:
Traceback (most recent call last):
File "C:\Users\GoodPie\Desktop\New Game Dev\main.py", line 177, in <module>
initialize_game()
File "C:\Users\GoodPie\Desktop\New Game Dev\main.py", line 61, in initialize_game
start_menu(debugging, screen, clock, image_cache)
File "C:\Users\GoodPie\Desktop\New Game Dev\main.py", line 88, in __init__
self.init_start_screen()
File "C:\Users\GoodPie\Desktop\New Game Dev\main.py", line 115, in init_start_screen
self.update_group.append[New_Game_Button, Load_Game_Button, Quit_Game_Button, Settings_Button]
TypeError: 'builtin_function_or_method' object is not subscriptable
Here is the code I am trying to use
Entities.py:
class Quit_Game_Button(Entity):
def __init__(self, x, y, image_cache):
Entity.__init__(self)
self.image_cache = image_cache
self.image = function.get_image("images/Quit_Game.png", self.image_cache)
self.image.convert()
self.rect = Rect(x, y, 150, 30)
def update(self, mouse_position):
if self.rect.collidepoint(mouse_position):
self.image = function.get_image("images/Quit_Game_Hover.png", self.image_cache)
else:
self.image = function.get_image("images/Quit_Game.png", self.image_cache)
def check_click(self, clicked, mouse_position):
quit = False
if self.rect.collidepoint(mouse_position):
if clicked:
quit = True
return quit
class Settings_Button(Entity):
def __init__(self, x, y, image_cache):
Entity.__init__(self)
self.image_cache = image_cache
self.image = function.get_image("images/Settings_Button.png", self.image_cache)
self.image.convert()
self.rect = Rect(x, y, 50, 50)
def update(self, mouse_position):
if self.rect.collidepoint(mouse_position):
self.image = function.get_image("images/Settings_Button_Hover.png", self.image_cache)
else:
self.image = function.get_image("images/Settings_Button.png", self.image_cache)
main.py
self.update_group.append[New_Game_Button, Load_Game_Button, Quit_Game_Button, Settings_Button]
mouse_position = pygame.mouse.get_pos()
#Updating Entities on the screen
for entity in self.update_group:
entity.update(mouse_position)
Just so it's clear, the functions do exist. I was just wondering if I was going about calling methods the write way through a list/array? If not could someone please point me in the right direction? :)
You are trying to assign one to one(1) and two to two(), that results in a referenced before assignment error So change the class Names to something more suitable like One and Two
Also It is strictly recommended(for CapWords convention see pg4 here) to always start a python class name with a uppercase character
Corrected code would look like: (I've implemented the str method)
class One:
def __init__(self, x):
self.x = x
def update(self):
self.x += 1
def __str__(self):
return str(self.x)
class Two:
def __init__(self, x):
self.x = x
def update(self):
self.x += 1
def __str__(self):
return str(self.x)
def test():
one = One(1)
two = Two(2)
update_list = [one, two]
for i in update_list:
i.update()
print i
test()
Output:
2
3
This is a simple error.
self.update_group.append[New_Game_Button, Load_Game_Button, Quit_Game_Button, Settings_Button]
should be
self.update_group.extend([New_Game_Button, Load_Game_Button, Quit_Game_Button, Settings_Button])
You're trying to index append where you should call it. Second point is, that append takes only one parameter, so you should use extend.
But you're still operating on the classes, not instances of the classes.
The issue did not lie within the actual for loop for calling the update function within the class, it occurred through the appending off the class instances to the list. Therefore to solve this problem I tried:
self.update_group = [New_Game_Button, Load_Game_Button, Quit_Game_Button, Settings_Button]
and it worked perfectly. I don't know what the issue is with the appending to the array, but having a fixed list/array seems to work just fine for me. Credits to #Matthias for actually making me look at the method for adding the instances to the array.