How do I create many precise instances of a class

2019-07-06 22:53发布

I'm trying to make an atari breakout style game using pygame, and I want the breakable blocks to be objects with certain attributes that I can change as the game progresses. As such I created a "Block" class and a subsequent function that loops through this class several times assigning the instances to a list. The problem that I encountered is that I didn't have a distinct "name" for each object so that made it sort of tough to access their individual attributes.

Here is an example:

class Block:
    def __init__(self):
        self.brick = pygame.sprite.Sprite()
        pygame.sprite.Sprite.__init__(self.brick)
        self.brick.image = pygame.Surface([width, height])
        self.brick.image.fill(RED)
        self.brick.rect = self.brick.image.get_rect()
    def blockType (self, hardness):
        self.hardness = hardness  

def lay ():
    layoutm = []
    for x in range (0, 5):
        layoutl = []
        for y in range (0, 12):
            layoutl.append (Block())
        layoutm.append (layoutl)
    return layoutm  

layoutm=lay()

horIndex = -1
for x in range(20, 195, 35):
    horIndex += 1
    verIndex = -1
    for y in range (20, 660, 55):
        verIndex += 1
        #set_trace ()
        brick = (layoutm[horIndex][verIndex]).brick
        brick.rect.topleft = (y,x)
        block_list.add(brick)
        list_of_sprites.add(brick)

Some of you might point out that I can just simply inherit from the pygame.sprite.Sprite() parent class and that might be a solution (too many attributes or something maybe) but for some reason that wasn't working for me.

Everything after the layoutm=lay() is the positional code for the respective Blocks and the only reason I included it is to show how I was planning to access the position attributes of each respective self.brick. Probably not the best way to do this, but all the methods coming after the constructer are necessary for the features I intend to add to the game (which is why I left in the blockType () to simplify the problem).

My question is basically if I always have to use the code that comes after the set_trace() (which is the command to run the debugger pudb) to access these individual instances or not.

Just for information: The reason I go through all this stuff is because I plan to have some lists such as

level_1 = [  
[1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1]] 

level_2 = [
[0,1,1,2,2,3,3,2,2,1,1,0],
[1,1,2,2,3,3,3,3,2,2,1,1],
[1,2,2,3,3,4,4,3,3,2,2,1],
[1,1,2,2,3,3,3,3,2,2,1,1],
[0,1,1,2,2,3,3,2,2,1,1,0]]

representing the level layout to say which type of block goes were (the code will be modified to work of course.

ALSO my terminology may be wrong sometimes (I'm taking this class in French) such as confusing instances vs objects (I call them the same but they probably aren't) so feel free to ask me if something isn't clear.

1条回答
别忘想泡老子
2楼-- · 2019-07-06 23:24

Your example seems to have a lot going on, so I will show you how I would have organized it. I have little experience with PyGame, so I will leave the tips for your Brick class to others, but I will try to help with your storage of Bricks.

This is how I would have defined lay:

def lay():
    return [[Brick() for y in range(12)] for x in range(5)]
layoutm = lay()

This construct is called a list comprehension. It is faster than using "for" and "append" and I think it looks clearer. It will create a list containing 5 lists, which will represent the rows. Each of the rows will contain 12 Bricks.

Now to deal with editing the attributes of the bricks after they have been created:

for (row, y) in zip(layoutm, range(20, 195, 35)):
    for (brick, x) in zip(row, range(20, 660, 55)):
        brickSprite = brick.brick
        brickSprite.rect.topleft = (y, x)

This one is a little more involved. Firstly, Python allows you to iterate over objects in any iterable object, like so:

for num in [0, 1, 2]:
    print(num)

This will print out the values 0, 1 and 2. Now, zip is a function which takes two iterable objects, and returns an iterable containing pairs of the objects. For instance:

for num_name in zip([0, 1, 2], ["zero", "one", "two"]:
    print(num_name)

This will print the values (0, "zero"), (1, "one"), and (2, "two"). Now back to my snippet: first, the outer loop will iterate over each row and its y coordinate. Then, the inner loop will iterate over each brick in that row and its x coordinate. After that, we can perform operations on the bricks.

Notice I did not build the block_list and list_of_sprites in the for loops. I would do that using another list comprehension:

block_list      = [brick       for row in layoutm for brick in row]
list_of_sprites = [brick.brick for brick in block_list]

block_list should now contain every Brick in the layoutm list and list_of_sprites should contain the Sprites corresponding to each Brick. If you decide to make Brick subclass the Sprite class, then your can change this accordingly.

查看更多
登录 后发表回答