Mouais, peut être qu'ils gagneront en clarté, ça serait pas mal
Quoiqu'avec les UDE on peut rajouter des scripts à l'IA de base sans risquer de la perturber.
Bref, j'ai réussi à créer une IA mimétique de PNJ très (très) basique, donc je vais vous en faire part
- Comportement souhaité
Ici le but était qu'un PNJ fasse 2 choses très simples :
- la plupart du temps, se balader sur une petite zone (RandomWalk);
- de temps en temps, se déplacer sur de longues distances
(pour faire une ville un petit peu plus réaliste, enfin personnellement je vois pas souvent des gens dans la rues qui tournent en rond toute la journée, généralement chaque personne va a un endroit précis)
- Memes
Logiquement, on devra créer 2 memes sur chaque citoyen, un par actions souhaitées. A noter que l'action "de grand déplacement" se déclenchera périodiquement, mais j'ai choisi de la créer dès le début et de lui donner une priorité nulle (ajustable par la suite).
- Générateurs
Y'en a pas encore
- Events
On va avoir besoin d'un event, fourni avec le package DR 5 : e_prioritize. Celui-ci permet de changer la priorité d'un meme au cours du jeu, ce qui nous permettra de faire se déplacer le PNJ à un moment voulu.
-- Scripts --
Là on entre dans le vif du sujet
J'ai eu besoin de créer 3 scripts : le OnSpawn du PNJ, et les scripts du meme "i_deplac" (grand déplacement).
Bien sûr, pour que les objets mimétiques inclus au DR 5 fonctionnent, il faut initialiser les libraires sur le module etc. mais je détaille pas, c'est pas vraiment un tutorial
Alors, le OnSpawn du PNJ :
s_citoyen
//::///////////////////////////////////////////////
//:: s_citoyen
//:: Copyright (c) 2001 Bioware Corp.
//:://////////////////////////////////////////////
/*
Initialisation des memes, generateurs
et events des PNJs citoyens
(Mimetic AI)
*/
//:://////////////////////////////////////////////
//:: Created By: Taern
//:://////////////////////////////////////////////
#include "h_ai"
void main()
{
object oMeme, oEvent, oSeq, oGen;
float fDelai = IntToFloat(Random(20)+40); // Delai précédant la première activation de l'event e_prioritize
// 1er meme : balade (action de fond)
MeCreateMeme("i_wander", // Nom du meme (celui-la est inclus au DR 5)
PRIO_LOW, // Priorite (de PRIO_NONE à PRIO_HIGH)
0, // Modificateur a l'interieur de la priorite
MEME_RESUME|MEME_REPEAT); // Flags (ici le meme boucle a l'infini
// et recommence apres une interruption)
// 2e meme : grand deplacement (action en attente)
oMeme = MeCreateMeme("i_deplac", // J'ai du creer ce meme
PRIO_NONE, // Le meme reste "en attente", aucune priorite
0, // idem
MEME_RESUME); // Le meme reprendra si il est arrete, mais ne boucle pas
// 1er event : grand deplacement
oEvent = MeCreateEvent("e_prioritize", // Cet event est inclus au DR 5
EVENT_PERSISTANT); // Flags, mais la on a pas le choix, c'est le seul existant
MeAddTriggerTime(oEvent, fDelai); // On declare un trigger, càd une condition pour que l'evenement se lance.
// Il y a 2 types de triggers : triggers temporels et triggers signaux
// Le 2e type est utilise pour les emitters, donc ici on s'en fout :P
// Parametres de l'event (connus a partir de la description de l'event dans le script lib_events)
MeAddFloatRef(oEvent, 120.0, "Delay"); // Delai entre chaque nouveau changement de priorite
// en fait cet event va tourner en boucle, remettant
// a chaque fois la priorite du meme a la meme valeur
MeAddObjectRef(oEvent, oMeme, "Meme"); // Meme qui doit etre modifie (on peut en entrer plusieurs)
MeAddIntRef(oEvent, PRIO_MEDIUM, "Priority"); // Nouvelle priorite voulue
MeAddIntRef(oEvent, 50, "Modifier"); // Nouveau modificateur voulu
MeAddIntRef(oEvent, 20, "DelayJitter"); // Composante aleatoire sur le delai defini plus haut
MeStartEvent(oEvent); // Et hop on lance l'event : )
MeUpdateActions(); // Cette commande assigne le meme adequat au PNJ
// Elle doit toujours etre appelee lorsqu'on modifie les memes d'un PNJ
// a noter qu'elle n'est souvent utilisee que dans le onspawn, mais qu'elle l'est
// aussi bien sur dans l'event e_prioritize
}
Voilà, rien de bien méchant en fait, l'important étant d'être rigoureux et méthodique. La plupart du temps rien de marchait chez moi parce que j'oubliais soit de lancer l'event, soit de définir un trigger, etc.
Bon ensuite le premier script du meme de grand déplacement, i_deplac_go.
i_deplac_go
/* Meme : i_deplac_go (grand deplacement)
Choix d'une destination, enregistrement de celle-ci
Ordre de mouvement
*/
#include "pnj_inc"
#include "h_ai"
void main()
{
object oDest = GetLocalObject(OBJECT_SELF, "destination"); // Ceci permet de verifier si une destination
// avait deja ete assignee au PNJ mais n'avait
// pas ete atteinte
if(!GetIsObjectValid(oDest)) // Si effectivement aucune destination n'etait assignee...
{
oDest = ChoixObjetZone(GetArea(OBJECT_SELF), "pnj_interet"); // Alors on en choisit une
// (fonction perso que j'ai faite pour mes PNJs,
// secret defense ; ) )
SetLocalObject(OBJECT_SELF, "destination", oDest); // On assigne cette destination
// (au cas ou le meme serait interrompu)
}
MoveToLocationDecalee(OBJECT_SELF, GetLocation(oDest)); // On va vers cette destination
// (autre fonction perso :P a noter que ces fonctions
// sont dans pnj_inc)
}
En fait les memes ressemblent à de simples scripts d'action. Mais il est possible de faire plus compliqué en rajoutant des paramètres, des valeurs renvoyées par le meme etc. Enfin là c'est ma première IA (oui bon je sais, ça a rien d'intelligent
) donc on reste dans le basique.
Enfin, dernier script créé : i_deplac_end (la fin du grand déplacement).
i_deplac_end
/* Meme : i_deplac_end (grand deplacement)
Suppression de la destination enregistree
*/
#include "h_ai"
void main()
{
DeleteLocalObject(OBJECT_SELF, "destination"); // On supprime la destination precedemment assignee au PNJ
// puisque celle-ci a ett atteinte
MeSetPriority(MEME_SELF, PRIO_NONE, 0); // Ici on doit absolument remettre la priorite du meme a zero
// si on veut que le PNJ se remette a se balader aleatoirement
// sans ca, ledit PNJ resterait betement sur place
// jusqu'a la fin de ses jours, cruel non ? ; )
MeUpdateActions(); // Encore elle, je ne suis pas sr de sa necessite, mais on est jamais trop prudent
// de toutes facons, cette fonctions ne perturbera jamais
// le comportement d'une creature, elle ne fait que de le "rafraichir"
}
Voilà ! J'espère que ça vous aura un peu aidé
Ces scripts sont tout de même très basiques, mais je trouve ça très formateur
Prochaine leçon : les emitters ! pourvu que j'arrive à les faire marcher