Projet : étape 3.5
Courage .. fuyons !

Buts: Les lézards apprennent à fuir leurs prédateurs.

Jusqu'ici un animal analyse les entités dans son champs de vision pour déceler des sources de nourriture ou des partenaires potentiels.

Pour avoir un comportement de fuite, il doit évaluer également lesquelles parmi ces entités organiques peuvent être des prédateurs pour lui (par lesquelles il peut être mangé!). S'il existe au moins un prédateur dans son champ de vision, il doit en fait entrer dans l'état «en fuite» ( RUNNING_AWAY).

Le passage à l'état RUNNING_AWAY aura la précédence sur le passage aux autres états possibles : la présence d'un prédateur conditionne l'état avant la présence de nourriture ou de partenaire.

L'animal doit fuir devant tout prédateur de son champ de vision et ne doit pas repasser à l'état WANDERING tant qu'il y a un prédateur à proximité.

Pour la distance à partir de laquelle l'animal se sent suffisamment en sécurité pour ne pas fuir, vous pouvez la configurer selon votre choix (en prenant par exemple un ratio sur la taille du monde).

Force gérant le déplacement

La force gérant le déplacement doit être adaptée à l'état de fuite.

Soit la différence entre la position du prédateur i et celle de l'animal :

La force gérant le déplacement de l'animal en présence de prédateurs se calculera selon la formule suivante 

k est le nombre de prédateurs, δ1 un coefficient d'amplification de la fuite (par exemple 500) et δ2 un coefficient supérieur à 1 (par exemple, 1.2) permettant de tenir compte de l'impact de la distance (plus le prédateur est loin et moins la "répulsion" qu'il entraîne est forte).

[Question Q3.16] Vous semble t-il utile d'avoir un attribut pour mémoriser les prédateurs potentiels d'un animal. Répondez à cette question dans votre fichier REPONSES en justifiant votre réponse.

Test 22  : Fuite

Pour tester le comportement de fuite, vous utiliserez toujours PPSTest.cpp

Vous procéderez comme pour les tests précédents, en configurant votre simulation pour faciliter l'observation.

Créez des configurations entraînant normalement un phénomène de fuite:

Les lézards fuient puis reprennent un comportement de type WANDERING une fois le scorpion suffisamment éloigné. La fuite n'a pas lieu lorsque le prédateur est hors du champ de vision.

Vous disposez à ce stade d'un outil relativement complet pour simuler un modèle prédateurs-proies. Bravo!

Vous pouvez, si vous le souhaitez, jouer avec vos fichiers de configuration (paramètres liés à la reproduction, à la longévité etc.) pour voir si vous parvenez à dégager des situations où les populations des deux types restent stables pendant assez longtemps. Par exemple, avec le fichier de configuration fourni appPPS.json, Vous devriez pouvoir observer des phènomènes cycliques: avec suffisamment de cactus (10) et d'humidité (pluie activée), une population raisonnable de lézards (~20) va proliférer puis ensuite décliner (plus assez de nourriture pour tous) puis à nouveau proliférer si vous remettez des cactus etc. L'évolution des populations n'est toutefois pas toujours facile à observer du point de vue quantitatif. Nous allons y remédier en toute fin de projet en ajoutant l'affichage de courbes d'évolution.


Améliorations du graphisme

Notez enfin que si vous êtes dérangés par le fait que les animaux se dessinent parfois sous le cactus, la classe Drawable offre une méthode getDepth() qui permet de définir l'ordre de priorité du dessin et donc de résoudre ce souci.

Pour tirer profit de cela, les animaux en tant qu'objets dessinables devrait avoir une redéfinition de getDepth qui retourne leur niveau de priorité dans le dessin (DrawingPriority::ANIMAL_PRIORITY) et les cactus de même (avec la valeur DrawingPriority::CACTUS_PRIORITY). Quand la méthode de dessin de l'environnement dessine les OrganicEntity, elle peut désormais le faire en dessinant les objets dans l'ordre de priorité voulu:

    // entities est le vector des OrganicEntity de l'encironnement,on en crée une copie dans une liste:
      list<Entity*> sorted( entities.begin(), entities.end());
     // on définit une relation d'ordre sur la base de getDepth(): 
    auto comp([](Entity* a, Entity* b)->bool{ return int(a->getDepth()) < int(b->getDepth()); }); 
   // on trie l'ensemble sur cette base
    sorted.sort (comp); 
   // il faut ensuite dessiner l'ensemble trié sorted et non plus entities
    
Retour à l'énoncé du projet (partie 3)