I am sorry if this is simple but I can't find an answer. I am trying to get random enemies in pygame (they should be same but spawn random).
So I have class:
class Enemy(object):
def __init__(self, ...):
...
self.visible = True
#and then I wanna make a list of this object
E1 = []
#in my while loop
while True:
...
if event.type == USEREVENT+2:
EN1.append(Enemy(10, 20, 64, 64, 259))
if len(enemy_bullets) < 1:
rocks.append(ro((round(EN1.x + EN1.width//2) - 30), (round(EN1.y + EN1.height//2) - 50), 23, 23))
I imported * from pygame.locals and in the beginning I set
pygame.time.set_timer(USEREVENT+2, random.randint(1000, 5000))
My error is 'list' object has no attribute 'x' and if I comment this I got another error in if E1.visible == True: ... it says: 'list' object has no attribute 'visible'.
Why?
Like #dcg said in the comments, EN1 is a list. You are appending to that list and then within that list you have your object of class Enemy. If you want to access a property in one of your enemy you need to index into that list (i.e. EN1[index of your enemy]) then access the variable inside, for example:
EN1[index].x
Related
tl;dr at the bottom. Most of this post is to give context to my problem. If that isn't needed, my main question is down below.
I am currently working on a pygame project (action adventure game) and I currently am working on stuff relating to object persistence and room transitioning. Basically, I want to create a system where I have a dictionary that contains all of the information about a particular room including the images it uses and the objects that are in that room.
My game has a dictionary that contains lists of the current objects that are updating and doing stuff in my game. Let's call this instances. Anytime I add an object to instances, it will appear in game. With that in mind, lets consider how loading the objects in a particular room actually works.
The way my system works is that I have a variable that is called room which contains a string that represents what room I am currently in. I have another dictionary that contains all of the objects within a room. Lets call this room_dict. room_dict would have the keys "objects":[obj1,obj2]. So based on the current value of room, it can access certain objects (i.e,room_dict[room]["objects"] would return a list of all of the objects in the current room).
Now that I've explained the basics of how it works, I have a method that actually knows when I have triggered a room transition (or rather, when the value of room is changed). When this happens, all of the objects existing in the room (that I was just in) are cleared from the instances dictionary. All of the objects from room_dict[room]["objects"] are added to instances so that they now appear in the game. Makes sense so far, right?
The main problem with this is that when objects in the instances dictionary (objects that are currently loaded) are updating, the objects that are in room_dict[room]["objects"] are also updated as well. This means that if I change the position of an enemy in one room and then leave the room and return, the object will be created at that position instead of the original position. So I tried doing instances[list_of_enemies].append(copy.copy(enemy_object)) to add a copy of the object as well. This still didn't work though, and when I tried doing a copy.deepcopy(), the interpreter said that it was unable to serialize the object because one of its attibutes was a pygame.Surface object.
So in other words my main issue is that I want to make a copy of an object that contains a pygame.Surface as its attribute that doesn't reference the original object at all. How would I go about making a deepcopy with an object that has a pygame.Surface type attribute?
tl;dr: I want to make a copy of an object that has an attribute that is a pygame.Surface object but copy.deepcopy() doesn't work. Is there any other way to copy without referencing the original object?
EDIT: Forgot to mention that the project is rather hefty, so it would be quite difficult to give code for context. I personally don't think it is needed, but I thought I'd put this out anyways. Thanks everyone!
One way to solve this is to create your objects from your json file everytime you need a new copy instead of creating the objects beforehand.
Or you could change your copy method: implement __deepcopy__ and/or __copy__ and copy the attributes of your objects without the image attribute, maybe just create a new instance.
Simple example:
import pygame
from copy import deepcopy
from itertools import cycle
# an implementation of something in our game
class Cloud(pygame.sprite.Sprite):
def __init__(self, pos, speed):
super().__init__()
self.pos = pos
self.speed = speed
self.image = pygame.Surface((50, 20))
self.image.set_colorkey((11, 12, 13))
self.image.fill((11, 12, 13))
pygame.draw.ellipse(self.image, 'white', self.image.get_rect())
self.rect = self.image.get_rect(topleft=self.pos)
def update(self):
super().update()
self.rect.move_ip(self.speed, 0)
if not pygame.display.get_surface().get_rect().colliderect(self.rect):
self.rect.right = 0
def __deepcopy__(self, memo):
# just create a new instance
return Cloud(self.pos, self.speed)
# the definition of our game world
game_data = {
'WORLD_A': {
'color': 'lightblue',
'objects': pygame.sprite.Group(Cloud((50, 50), 1))
},
'WORLD_B': {
'color': 'red',
'objects': pygame.sprite.Group(Cloud((100, 100), 2), Cloud((80, 30), 3))
},
}
screen = pygame.display.set_mode((300, 300))
clock = pygame.time.Clock()
keys = cycle(game_data.keys())
# happy deepcopying
current = deepcopy(game_data[next(keys)])
while True:
for e in pygame.event.get():
if e.type == pygame.QUIT:
quit()
if e.type == pygame.KEYDOWN:
# happy deepcopying
current = deepcopy(game_data[next(keys)])
screen.fill(current['color'])
current['objects'].update()
current['objects'].draw(screen)
pygame.display.flip()
clock.tick(30)
Another solution is to lazy load the images and look them up only when needed so you don't need to copy them. Here's a simple example:
... see example above ...
# load/create all images once and store them in a dict
def create_cloud_image():
image = pygame.Surface((50, 20))
image.set_colorkey((11, 12, 13))
image.fill((11, 12, 13))
pygame.draw.ellipse(image, 'white', image.get_rect())
return image
images = {
'cloud': create_cloud_image()
}
# a simple sprite that lazy loads its image
class CopyableActor(pygame.sprite.Sprite):
def __init__(self, image_key, pos):
super().__init__()
self.pos = pos
self.image_key = image_key
def init_image(self):
self.image = images['cloud']
self.rect = self.image.get_rect(topleft=self.pos)
def update(self):
if not hasattr(self, 'image'):
self.init_image()
# an implementation of something in our game
class Cloud(CopyableActor):
def __init__(self, pos, speed):
super().__init__('cloud', pos)
self.speed = speed
def update(self):
super().update()
self.rect.move_ip(self.speed, 0)
if not pygame.display.get_surface().get_rect().colliderect(self.rect):
self.rect.right = 0
... see example above ...
I'm new to python and doing some practice for uni,
I'm familiar with java so I am trying to create a class in python and then create an instance of the class to be used as an object from another file in the same directory.
so here's how I'm trying to do it:
within main.py -
import player
p1 = player.Player(300, 300, 64, 64)
here's my Player class located in player.py
import main
class Player:
def __init__(self, x, y, width, height):
self.x = x
self.y = y
self.width = width
self.height = height
self.vel = 15
self.left = False
self.right = False
self.walkCount = 0
this results in:
AttributeError: module 'player' has no attribute 'Player'
After some research I have also tried:
from player import Player
p1 = Player(300, 300, 64, 64)
which results in: ImportError: cannot import name 'Player' from 'player' (C:\Users\Alex\PycharmProjects\BunkerGame\player.py)
quite simply and ignoring some other code this should create an instance of the Player class in player.py to be used within the main.py file
As you noted in the comment, you import main into player - which means you have a circular import: Python can't resolve this so raises an attribute error.
You shouldn't need to do that. There shouldn't be anything in main that is needed by player. If there is, move it to player itself or a third module.
From the error you mentioned you most likely have a module already installed called player, which Python is importing as opposed to your local file player.py. Try renaming the file player.py to something else, or going on console and doing pip uninstall player.
Notice how the error says cannot import name 'Player' from 'player', which means Python is accessing a module called player, but is unable to access the class Player.
As #Daniel Roseman pointed out, I had 'import main' within player.py which python doesn't like apparently, removing this and any related code fixed the issue!
You just should write the import just like this:
import Player
p1 = Player(300, 300, 64, 64)
You can also write something like:
import Player as p
p1 = p(300, 300, 64, 64)
You need to remove the player. You are passing a class through as an attribute by using . which is the reason for the first error and the second is that your importing main on your player page and importing player on your main page. Just get rid of import main on your player page.
The first error:
import player
p1 = player.Player(300, 300, 64, 64)
This should just be:
import player
p1 = Player(300, 300, 64, 64)
Here is an example of whats happened:
class Player:
def __init__(self, name, age):
self.name = name
self.age = age
player = Player # setting the class to variable
player.name = 'Johnny' # .name is the attribute of the Player class
print(player.name)
Output:
'Johnny'
You have done this:
player.Player.name = 'Johnny'
print(player.name)
Which returns your error:
Traceback (most recent call last): File "main.py",
line 8, in <module>
player.Player.name = 'Johnny'AttributeError: type object 'Player' has no attribute 'Player'
I'm getting this error:
[...], line 28, in <module>
PlayerDamage = Dice * int(set_p_w.player_damage)
AttributeError: 'NoneType' object has no attribute 'player_damage'
When I run this code:
import player
Dice = random.randrange(1, 7)
set_p_w = player.set_player_weapon()
PlayerDamage = Dice * set_p_w.player_damage
This is how player.set_player_weapon() looks like:
def set_player_weapon():
import items
player_weapon = items.WBrokenSword
player_damage = player_weapon.damage
I searched everywhere and tried a bunch of different solutions, but nothing helped me. What is wrong with my code?
From the code you posted, player.set_player_weapon() doesn’t return anything. So set_p_w is nothing. You are interacting with set_p_w as if it is an object, but set_player_weapon() doesn’t create an object, it just sets two local variables (player_weapon and player_damage) and then discards them when the function ends.
The simplest way to get this to work is to have your player.set_player_weapon() method return a tuple with that information so it can be stored in the a variable outside the function: (player_weapon, player_damage).
Tuple Method
def set_player_weapon():
import items
player_weapon = items.WBrokenSword
player_damage = player_weapon.damage
return (player_weapon, player_damage)
player_weapon_damage = player.set_player_weapon()
PlayerDamage = Dice * player_weapon_damage[0]
A better way would be to make an class for Player which has the attributes player_weapon and player_damage as well as methods like def set_player_weapon() that set and change its attributes.
This question already has answers here:
Changing a string to variable [duplicate]
(2 answers)
Closed 4 years ago.
I am trying to create a function that calls an attribute determined by what argument is passed.
class room:
def __init__(self, length, bredth, depth):
self.length = length
self.bredth = bredth
self.depth = depth
def displaymeasurement(self, side):
print(self.side)
kitchen = room(10, 20, 15)
room.displaymeasurement("depth")
This is an abstraction of the code I'm using as that's too convoluted. I have striven to match it to the code in question, and it does produce the same error message.
Traceback (most recent call last):
File "/home/townsend/Documents/PycharmProjects/untitled2/Test/inplicitreference.py", line 13, in <module>
room.displaymeasurement("depth")
File "/home/townsend/Documents/PycharmProjects/untitled2/Test/inplicitreference.py", line 8, in displaymeasurement
print(self.side)
AttributeError: 'shape' object has no attribute 'side'
What syntax am I missing to communicate to the computer to replace side with the entered argument depth and process from there.
I have spent a couple of days searching but I can't seem to find an attempt at a similar construction. Perhaps it's because I'm using incorrect terminology. I am very new to this.
I don't expect this method to work but I thought it was the best way to illustrate. I have tried several different methods.
I am aware of a series of if checks as a solution but I'm convinced there's an simpler and more expandable solution.
def displaymeasurement(self, side):
if side == "length":
print(self.length)
if side == "bredth":
print(self.bredth)
if side == "depth":
print(self.depth)
You need to use the getattr builtin method. This allows you to search for an attribute of a class with a string.
class Room:
def __init__(self, length, bredth, depth):
self.length = length
self.bredth = bredth
self.depth = depth
def displaymeasurement(self, side):
print(getattr(self, side))
kitchen = Room(10, 20, 15)
kitchen.displaymeasurement("depth")
This is a fragile way to search for member's in an object's look up table. getattr() is intended for just this use case. Example below:
class MyClass(object):
def __init__(self):
self.x = 'foo'
self.y = 'bar'
myClass = MyClass()
try:
print(getattr(myClass, 'x'))
print(getattr(myClass, 'y'))
print(getattr(myClass, 'z'))
except AttributeError:
print 'Attribute not found.'
Sample Output:
foo
bar
Attribute not found.
So I have an exercise on python - building a BlackJack game.
I have started with defining how every phrase of the game would go.
Now when I run this code below, In case the input is '0' - which means you don't want cards anymore, it runs perfectly. But when the input is '1' - which means you want to pick card, I get an error:
Traceback (most recent call last):
File "C:/Users/Maymon/PycharmProjects/untitled4/BlackJack.py", line 1, in <module>
class blackjack(object):
File "C:/Users/Maymon/PycharmProjects/untitled4/BlackJack.py", line 34, in blackjack
player(1)
File "C:/Users/Maymon/PycharmProjects/untitled4/BlackJack.py", line 25, in player
PickCard(1)
File "C:/Users/Maymon/PycharmProjects/untitled4/BlackJack.py", line 18, in PickCard
self.hand+= random.randrange(1, 13)
AttributeError: 'int' object has no attribute 'hand'
The code:
class blackjack(object):
#this func defines how player should react
def player(self):
#this func defines what case of technical loosing
def loser():
print("You have reached", hand , ". Which is beyond 21. Therefor, you have lost the game. Better luck next time!")
#this func is responsible for picking card issue.
def PickCard(self):
import random
x=1
while x == 1:
pick = int(raw_input("Enter 1 if you want another card, else Enter 0"))
if pick == 1:
self.hand = self.hand + random.randrange(1, 13)
else:
x=0
import random
print "Now your first card will automatically be given to you:"
hand=random.randrange(1,13)
print "hand: ", hand
PickCard(1)
print hand
if hand>21:
loser()
elif hand==21:
pass
else:
pass
player(1)
Thanks in advance.
You are making the function call as player(1) where the player function expects the argument as of self type .i.e. instance of the class blackjack. Hence, while doing self.hand = self.hand + random.randrange(1, 13) it is throwing the above mentioned error.
I think you do not want to make a call to player() function from within the class, Is it? Move that part to outside the class. Firstly create the object of class blackjack (Note: In Python, class names should be defined as CamelCase variables like: BlackJack). For example:
blackjack_obj = blackjack()
Then call the player() function as:
blackjack_obj.player()