[英]Make object traits inheritable
I'm making a natural selection simulator program.我正在制作一个自然选择模拟器程序。 One of the things I want to happen is when two parent objects collide for an offspring object to be created that randomly inherits some of its parents traits.我想要发生的事情之一是,当两个父对象发生碰撞时,将创建一个随机继承其父对象某些特征的后代 object。 In particular, I'm looking to pass on the int values width and height.特别是,我希望传递 int 值宽度和高度。 The problem is, I'm only looking to pass on width and height into the object when it is offspring.问题是,我只想在 object 成为后代时将宽度和高度传递给它。 I want the initial spawn of parent objects to have completely randomized values.我希望父对象的初始生成具有完全随机的值。
My whole code is:我的整个代码是:
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()
Again, specifically, I'm looking to pass on width and height when there are parents with width and height, but in the initial genesis spawn when there have been no parents, I want those values to have been randomly generated.再次,具体来说,当有具有宽度和高度的父母时,我希望传递宽度和高度,但是在没有父母的初始创世纪中,我希望这些值是随机生成的。
Actually, the constructor of the class organism
has a width
and a height
argument and these then set the attributes self.width
and self.height
with them if they are not empty ( None
) and if they are, they are set by random values:实际上,class organism
的构造函数有一个width
和一个height
参数,如果它们不为空( None
),然后用它们设置属性self.width
和self.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) # [...]
Therefore, if you want random values, you must pass None
to these arguments:因此,如果你想要随机值,你必须将None
传递给这些 arguments:
for _ in range(15):
Organism(next(ids), org_list, None, None)
Alternatively, you can pass concrete values, for example, the width and height of the parent:或者,您可以传递具体值,例如父级的宽度和高度:
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.