2017-09-15 6 views
2

OK dans mon jeu 2d, j'ai plusieurs instances d'objets 'cellule' (objets sprite) qui ont un attribut self.target = [] vide lors de l'initialisation.Python Comment vérifier si un objet cible n'est plus la même instance ou "valide"

Ils trouveront alors un objet cible "plante" valide à proximité et deviendra le "self.target" des cellules. La 'cellule' naviguera ensuite vers la plante pour finalement entrer en collision avec elle et la manger, et la plante est alors mise à ".kill()" et une autre est réapparue à une nouvelle coordonnée aléatoire. Il existe plusieurs instances d'installation (faisant partie de spr_plant_group) et plusieurs cellules (appartenant à spr_cell_group). Chaque plante "vit" pour X tiques de jeu (200 je crois), et si elle n'est pas mangée d'ici là, elle est "kill() - ed et une nouvelle apparaît à une coordonnée aléatoire. Le problème est le suivant: Si la plante cible d'une cellule arrive à disparaître ou est mangée par quelque chose, les informations de la cellule self.target pointent TOUJOURS sur les anciennes données de l'objet "plant". Cela signifie que la cellule poursuit un objet fantôme, ayant toujours une coordonnée x et y valide. Question: Comment puis-je dire à la cellule que sa cible est morte, partie, invalide? Si je peux le faire, je pense que cela réparerait l'objet cible 'fantôme'.

Pièces de code correspondant:

class Agent(sprite.Sprite): 

def __init__(self, sense_range, size, food, maxspeed): 

    sprite.Sprite.__init__(self) 
    self.x = randint(0,450) 
    self.y = randint(0,450) 
    self.ang = randint(0,359) 
    self.turn_rate = 2 
    self.dx = 0 
    self.dy = 0 
    self.speed = 1 
    self.maxspeed = maxspeed 
    self.food = int(food) 
    self.max_food = food*1.5 
    self.target = [] 
    self.sense_range = sense_range 

# Snip------This part below is supposed to find a new target, but it only 
# works for the first one when the cell spawns, then I can't seem to 
# get it to become 'empty' so that the "if self.target == []" can do its 
# thing.... 

    def seek_food(self): 

    if (self.target == []): 
     #find cell a target within "sense_range" distance (say 200 pixels) 
     dist = self.sense_range 
     targ = [] 
     for t in spr_plant_group: 
      t_dist = abs(self.x - t.x) 
      if t_dist <= dist: 
       targ = t 
       dist = t_dist 

     self.target = targ 
     print ("Found target...",dist, self.target) 

    else: 
     #already have a target, so move cell toward target 
     dx = self.target.x - self.x 
     dy = self.target.y - self.y 
     rads = atan2(dy,dx) 
     rads %= 2*pi 
     degs = degrees(rads) 
     direction = degs - self.ang 
     if direction > 0: 
      self.ang = self.ang + self.turn_rate 
     elif direction < 0: 
      self.ang = self.ang - self.turn_rate 

     # Correct for angle being out of 0-360* range 
     if self.ang > 360: 
      self.ang -= 360 
     elif self.ang < 0: 
      self.ang += 360 

#---This is just a piece of the Plant class for your reference 

class Plant (sprite.Sprite): 
def __init__(self): 

    sprite.Sprite.__init__(self) 

    self.x = randint(0,450) 
    self.y = randint(0,450) 
    self.age = 1 + randint(0,50) 

Pour référence, ci-dessous. Plantes augmente jusqu'à l'âge de 200 tiques, puis ils sont tués, et un nouveau réapparitions ...

def update_plants(): 
for shrub in spr_plant_group: 
    shrub.age += 1 

    # Respawn a new plant in a different place 
    if shrub.age >= 200: 
     shrub.kill() 
     plant.append (Plant()) 

Répondre

1

EDIT: En fait, il est beaucoup plus simple. Pygame's Sprite class supports an alive method, alors faites ceci:

def seek_food(self): 
    if (self.target == [] or not self.target.alive()): 
     # Find a new target that isn't dead... 
    else: 
     # Move to the (alive) target... 

Vous pouvez utiliser une variante de the Observer design pattern. Étendez votre classe Plant avec une propriété supplémentaire qui conserve les instances Cell qui ciblent l'installation. Quand une cellule cible une plante, elle s'ajoute à la liste de la plante. Avant que la plante ne meure, elle notifiera toutes ses cellules.

Nouvelle propriété dans la classe des plantes:

class Plant (sprite.Sprite): 
    def __init__(self): 
     # ... 
     self.followers = [] 
     # ... 

Cellules abonnez-vous à la liste des plantes d'adeptes:

def seek_food(self): 
    if (self.target == []): 
     # ... 
     self.target = targ 
     self.target.followers.append(self) 
     # ... 
    else: 
     # ... 

La classe des plantes emporte sur la classe parente fonction kill si qu'il notifie ses adeptes avant de mourir:

(Ici, la classe cellulaire modifie directement la cible de chaque plante, mais vous pourriez résumer le comportement différemment si vous voulez)

def kill(self): 
    for follower in self.followers: 
     follower.target = [] 
    self.followers = [] 

    super().kill() 
+0

« La classe Cell remplace sa fonction kill classe parente afin qu'elle informe ses disciples avant mourant: " Vouliez-vous dire que la classe" Plant "(non Cell) l'emporte sur sa fonction kill pour effacer ses listes de suiveurs? Cela aurait plus de sens. – PySam

+0

J'ai implémenté votre suggestion et cela fonctionne parfaitement comme j'en avais besoin. Les cellules réapprovisionnent une nouvelle cible végétale si l'ancienne meurt ou est mangée et change de cap pour l'intercepter. Merci beaucoup! On dirait une solution très évidente avec le sprite.alive() que j'ai clairement oublié! – PySam