Projet : étape 3.3
Fin de vie
Buts:
Faire perdre l'immortalité aux entités qui peuplent le monde
(si vous éprouvez un sentiment de puissance à l'énoncé de cet objectif, il est peut-être temps d'adopter un vrai lézard et de vous y attacher).
Pour avoir un modèle prédateur-proie plus réaliste et éviter une surpopulation incontrôlée lorsque nos animaux auront le moyen de se reproduire, il s'agit maintenant de les rendre mortels.
Plus largement, toute entité vivante du monde peut passer de vie à trépas pour les raison suivantes:
- elle est trop âgée;
- elle a un niveau d'énergie trop bas (ce qui arrive si elle ne mange pas assez par exemple);
- elle se fait dévorer par une autre entité.
Il s'agit concrètement de mettre en oeuvre le fait :
- que chaque type d'entité organique a une longévité maximale qui ne peut être dépassée;
- qu'un animal perd de l'énergie en se déplaçant, et que s'il se déplace trop de fois sans trouver de nourriture, il meurt d'inanition (:-/ );
- qu'un animal se nourrit (ce qui peut correspondre à la fin d'un autre!).
Mort de vieillesse
Pour mettre en oeuvre le premier point, une idée simple consiste à :
- doter les entités organiques d'une «horloge» associée à l'âge (de type sf::Time). L'initialisation à zéro de cette horloge à la naissance de l'entité se fait au moyen de la valeur sf::Time::Zero;
- faire en sorte qu'à chaque pas de simulation cette horloge augmente de dt;
- et doter les entités organiques d'une méthode permettant de tester si elles sont mortes ou non : niveau d'énergie inférieur à un certain seuil (paramétrable via getAppConfig().animal_min_energy (mais pour simplifier, identique pour toutes les entités) ou âge dépassant la longévité possible.
[Question Q3.7] Comment proposez-vous de procéder pour faire en sorte que les sous-classes d'entités organiques existantes vieillissent et puissent avoir soit la longévité par défaut soit une longévité spécifique? Répondez à cette question dans votre fichier REPONSES.
[Question Q3.8] Comment proposez-vous de procéder pour qu'une entité morte disparaisse de l'environnement ? Quelle précaution doit alors être prise pour une gestion correcte de la mémoire ? Répondez à ces questions dans votre fichier REPONSES.
Test 17 : mort de vieillesse
Pour tester vos nouveaux développements vous utiliserez à nouveau la cible ppsTest.
Reprenez pour cela votre fichier .json et dotez les scorpions et les lézards d'une longévité réduite, par exemple 3 (pour ne pas faire durer trop longtemps le supplice).
Ensuite:
- lancez la cible ppsTest et mettez la simulation en pause (barre d'espace).
- créez un scorpion avec la touche 'S'
- relancez la simulation (barre espace);
[Video : disparition des animaux trop âgés (ici le mode «debugging» est désactivé)] |
Refaites le même test avec un lézard (vous pouvez "nettoyer" l'environnement avec la touche 'R').
Mort d'inanition
La méthode update est codée pour le moment selon l'algorithme suivant:
- mise à jour de l'état;
- calcul de la force f régissant le déplacement, en fonction de l'état;
- mise à jour du déplacement, compte tenu de f ;
- "viellissement" de l'animal.
(il n'est pas précisé ici où sont codées ces différentes facettes du traitement, à vous de voir ... ).
Il convient maintenant de la compléter de sorte à ce qu'au terme de ces traitements, l'animal perde de l'énergie (il perd de l'énergie à chaque pas de temps de la simulation).
La perte d'énergie est fonction du pas de temps écoulé (en secondes) et de la norme de la vitesse (plus l'animal va vite et plus il se fatigue) selon la formule suivante:
perte_energie = depense_energetique_de_base + norme_vitesse * facteur_perte_energie() * dt
depense_energetique_de_base est paramétrable (getAppConfig().animal_base_energy_consumption). Le facteur de perte d'énergie se calcule de façon différente pour chaque type d'animaux (getAppConfig().scorpion_energy_loss_factor pour les scorpions par exemple).
[Question Q3.9] Comment proposez-vous de modifier la méthode getMaxSpeed de sorte à ce qu'en dessous d'un seuil critique d'énergie l'animal se déplace plus lentement ? répondez à cette question dans votre fichier REPONSES et mettez en oeuvre cette fonctionnalité conformément à votre réponse (vous pouvez pour simplifier considérer que ce seuil est le même pour toute entité vivante).
Test 18 : mort d'inanition
On utilisera le même fichier de test que précédemment.
Commencez par configurer votre simulation comme suit:
- Dotez les scorpions et les lézards d'une très grande longévité (1E9 par exemple, pour bien faire la distinction entre les deux causes de mortalité)
- Dans le fichier .json, augmenter le facteur de perte d'énergie des animaux (par exemple ["scorpion"]["energy"]["loss factor"] valant 0.2)
Ensuite:
- lancez la cible ppsTest et mettez la simulation en pause (barre d'espace).
- créez un scorpion avec la touche 'S'
- relancez la simulation (barre espace);
← le scorpion perd de l'énergie au cours du temps et se déplace plus lentement s'il est trop faible | |
[Video : un animal s'affaiblit au cours du temps] |
Consommation de nourriture/prédation
Vos animaux perdent de l'énergie en se déplaçant, il faut qu'ils puissent en recouvrer lorsqu'ils consomment de la nourriture. Sans cela, ils seraient amenés à mourir beaucoup trop vite.
Il devient nécessaire pour cela de s'intéresser aux «rencontres» qu'un animal peut faire en cours de déplacement (un lézard croise t-elle de la nourriture ? un scorpion croise t-il un lézard ? etc.)
La classe Collider a été introduite lors de la première étape du projet afin de permettre de tester la collision entre deux corps circulaires. Il est temps de l'utiliser.
Modifiez votre méthode updateState de sorte à ce que :
- l'animal se mette à se nourrir (passe en mode FEEDING) s'il est collision avec la source de nourriture la plus proche. Dans ce cas son niveau d'énergie doit augmenter de getAppConfig().animal_meal_retention;
- la nourriture avec laquelle il entre en collision perde de l'énergie selon des modalités qui sont spécifiques à son type: les lézards meurent s'il se font manger (énergie réduite à zéro) alors que les cactus perdent getAppConfig().animal_meal_retention de leur énergie;
- et que si l'animal est déjà en mode FEEDING il observe un temps de pause (donné par getAppConfig().animal_eating_pause_time) avant de repasser à l'état WANDERING
[Question Q3.10] Comment proposez-vous de mettre en oeuvre le fait que la prédation n'a pas le même effet selon le type de proie, sans faire de tests de type ? répondez à cette question dans votre fichier REPONSES.
Perfectionnisme (bonus)
Temps de pause durant la marche aléatoire
Pour que les animaux ne soient pas perpetuellement en déplacement lorsqu'il sont dans l'état WANDERING, vous pouvez faire en sorte que l'animal observe aussi des temps de pauses aléatoires lorsqu'il se déplace sans but. Vous disposez de deux paramètres configurables si vous souhaitez mettre en oeuvre ce bonus (getAppConfig().animal_idle_probability et getAppConfig().animal_walking_idle_time).
Ralentissement aux abords d'une cible
Lorsque l'animal est en mode FOOD_IN_SIGHT sa cible est la position de la source de nourriture et la force régissant son déplacement est calculée en conséquence.
Il peut cependant y avoir une distance relativement importante entre le bord de la source de nourriture et son centre. Une fois que l'animal a touché le bord (collision détectée), il serait préférable qu'il ralentisse (au lieu de continuer à se précipiter vers le centre de la source).
La méthode update peut donc calculer différemment la force régissant le déplacement, lorsque l'animal est passé en mode FEEDING.
Pour mettre en oeuvre le ralentissement, on peut calculer la force régissant le déplacement comme une force d'attraction exercée par une cible négative dans le repère local de l'animal, par exemple {-1,0}. Faites ralentir l'animal jusqu'à ce que sa vitesse devienne proche de zéro (test avec isEqual !). La force devient nulle à partir de ce moment. Il peut être judicieux de faire une méthode de ce calcul de force particulier.
Test 19 : consommation de nourriture
Comme pour les tests de l'étape précédente créez des situation où vous pouvez observer la consommation de nourriture.
L'exécution devrait ressembler à celle montrée par ces petites vidéo :
|
||
(redémarrez la vidéo au besoin) |
(redémarrez la vidéo au besoin) |
|
|
|
[Question Q3.11] : Pour réaliser les tests de collision, notre conception «voit» les entités organiques qui peuplent le monde simulé comme étant aussi des Collider. Quelle autre conception est-il possible de mettre en place pour réaliser ces traitements ? Quel avantage/inconvénient y voyez-vous ? Répondez à ces questions dans votre fichier REPONSES.
Retour à l'énoncé du projet (partie 3) Module suivant (partie 3.4)