繁体   English   中英

使 object 特征可继承

[英]Make object traits inheritable

我正在制作一个自然选择模拟器程序。 我想要发生的事情之一是,当两个父对象发生碰撞时,将创建一个随机继承其父对象某些特征的后代 object。 特别是,我希望传递 int 值宽度和高度。 问题是,我只想在 object 成为后代时将宽度和高度传递给它。 我希望父对象的初始生成具有完全随机的值。

我的整个代码是:

import pygame, random

pygame.init()

map_width = 800
map_height = 800
size = [map_width, map_height]
screen = pygame.display.set_mode(size)

# pygame already defines a lot of colors, we we just use them
colors = pygame.color.THECOLORS
pygame.display.set_caption("Natural Selection Game")
done = False
clock = pygame.time.Clock()

# just a simple generator to generate an id for each object 
def id_generator():
    i = 0
    while True:
        i += 1
        yield i

ids = id_generator()

# just a helper function that wraps pygame.sprite.collide_mask
# to prevent a sprite from colliding with itself
def collide(a, b):
    if a.id == b.id:
        return False
    return pygame.sprite.collide_mask(a, b)

class Organism(pygame.sprite.Sprite):

    def __init__(self, id, org_list, width, height, color = None):
        pygame.sprite.Sprite.__init__(self, org_list)
        self.org_list = org_list
        self.id = id
        # Speed and direction
        self.change_x = random.randrange(0,6)
        self.change_y = random.randrange(0,6)

        # Dimensions
        self.width = width or random.randrange(20,60)
        self.height = height or random.randrange(20,60)

        x = random.randrange(0 + width, map_width - width )
        y = random.randrange(0 + height, map_height - height)
        self.rect = pygame.rect.Rect(x, y, width, height)
        self.image = pygame.surface.Surface((width, height))
        self.image.fill(colors['hotpink2'])
        self.image.set_colorkey(colors['hotpink2'])

        # we either pass in the color, or create a random one
        self.color = color or random.choice([colors['red'], colors['green'], colors['blue']])
        pygame.draw.ellipse(self.image, self.color, [0, 0, width, height])
        self.mask = pygame.mask.from_surface(self.image)

        # we keep track of collisions currently happening
        # so we only spawn one children for each collisions  
        self.collisions = set()

        # just something to limit the number of organisms
        self.age = 0
        self.children = 0

    # Initiate movement
    def update(self):
        self.age += 1

        # we move by simply moving the rect
        # the Group's draw function will look that the rect attribute 
        # to determine the position for drawing the image 
        self.rect.move_ip(self.change_x, self.change_y)

        # we can make use of a lot of Rect's attributes to make 
        # this computation simpler
        if self.rect.left < 0 or self.rect.right > map_width:
            self.change_x *= -1

        if self.rect.top < 0 or self.rect.bottom > map_height:
            self.change_y *= -1

        # only reproduce if we are at least 200 ticks old
        # so newly created organisms spwan new ones at the
        # very moment they spawned themself
        if self.age < 200:
            return

        # just an arbitary limit so the screen does not get too full
        if self.age > 500:
            print (self.id, ' died of age')

            # kill() removes the Sprite from all its Groups (which is only org_list at the moment)
            self.kill()
            return

        # just an arbitary limit so the screen does not get too full 
        if self.children > 4:
            print (self.id, ' died of too many children')
            self.kill()
            return

        # check if we collided with another Sprite
        collided = pygame.sprite.spritecollideany(self, self.org_list, collide)

        # also check if this 
        # - is a new collision
        # - the other organism is at least 200 ticks old
        # - there are not too many organisms at the screen at the moment
        if collided and not collided.id in self.collisions and collided.age > 200 and len(self.org_list) < 100:

            # keep track of the current collision, so this code is not triggerd 
            # every frame while the colliding organisms move other each other
            self.collisions.add(collided.id)
            collided.collisions.add(self.id)
            print (self.id, ' collided with ', collided.id)

            # inherit parent dimensions
            width = random.choice(self.width, collided.width)
            height = random.choice(self.height, collided.height)

            # let the dimensions mutate sometimes for fun
            if random.randrange(0, 100) < 5:
                width = random.randrange(5, 100)
                print ('Offspring of', self.id, ' and ', collided.id, ' mutates a dimension change')
            elif random.randrange(0, 100) < 5:
                height = random.randrange(5, 100)    
                print ('Offspring of', self.id, ' and ', collided.id, ' mutates a dimension change')
            elif random.randrange(0, 100) < 5:
                width = random.randrange(5, 100)
                height = random.randrange(5, 100)  
                print ('Offspring of', self.id, ' and ', collided.id, ' mutates a dimension change')

            # let the color mutate sometimes for fun
            if random.randrange(0, 100) < 5:
                color[random.randrange(0, 3)] = random.randrange(0, 256)
                print ('Offspring of', self.id, ' and ', collided.id, ' speciates')

            # create the new child with the new color
            Organism(next(ids), self.org_list, list(map(int, color)))
            self.children += 1
            collided.children += 1
        else:
            # if there are currently no collisions, we clear the collisions set
            # so new collisions can happen
            self.collisions = set()

# we use a Group for all the draw/update/collision magic
org_list = pygame.sprite.Group()

for _ in range(15):
    Organism(next(ids), org_list)

while not done:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            done = True

    # we just call update on the group so update is called
    # an every sprite in the group
    org_list.update()

    screen.fill(colors['white'])

    # same for drawing: just call draw on the group
    org_list.draw(screen)

    clock.tick(60)
    pygame.display.flip()

pygame.quit()

再次,具体来说,当有具有宽度和高度的父母时,我希望传递宽度和高度,但是在没有父母的初始创世纪中,我希望这些值是随机生成的。

实际上,class organism的构造函数有一个width和一个height参数,如果它们不为空( None ),然后用它们设置属性self.widthself.height ,如果它们是,则由随机值设置:

 class Organism(pygame.sprite.Sprite): def __init__(self, id, org_list, width, height, color = None): pygame.sprite.Sprite.__init__(self, org_list) self.width = width or random.randrange(20,60) self.height = height or random.randrange(20,60) # [...]

因此,如果你想要随机值,你必须将None传递给这些 arguments:

for _ in range(15):
    Organism(next(ids), org_list, None, None)

或者,您可以传递具体值,例如父级的宽度和高度:

class Organism(pygame.sprite.Sprite):
    # [...]

    def update(self):
        # [...]

        if collided and not collided.id in self.collisions and collided.age > 200 and len(self.org_list) < 100:
            # [...]

            Organism(next(ids), self.org_list, self.width, self.height, list(map(int, color)))

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM