Voir la version complète : Gérer les factions.
Bonsoir, messieurs, mesdames, mesdemoiselles et autres trucs pas bien définis ...
Je viens demander de l'aide pour un problème qui me taraude actuellement : voilà, pour mon projet, j'ai décidé de gérer les relations entre les différentes créatures à l'aide de factions.
Par exemple, la faction des Innocents pour les gentils petits lapins tout blancs, celle des agents de l'ordre, celle des voleurs, celle des paladins, celle du joueur ...
Ensuite, attaquer un personnage d'une faction modifie légèrement les relations entre sa faction et celle de l'attaquant. Ça, j'y arrive. Maintenant, le problème restant, c'est comment faire la mise à jour pour que, en attaquant un personnage d'une faction, non seulement les relations avec cette faction se dégradent, mais également celles avec les factions amies de cette faction, pendant que les relations avec les factions ennemies de cette faction s'améliorent ?
Et, mettons que j'y arrive : pensez-vous que cette méthode soit efficace ?
Mettons 5 factions A, B, C, D, E
A amie avec B, ennemie avec C et neutre avec D et E
B amie avec A, neutre avec C et E et ennemie avec D
C ennemie avec A, neutre avec B et E et amie avec D
D neutre avec A et E, ennemie avec B et amie avec C
E neutre avec tout le monde
Si un membre de A attaque un membre de D :
- les relations A <-> D se dégradent
- les relations A <-> C se dégradent
- les relations A <-> B s'améliorent un peu
- les relations A <-> E ne changent pas.
ZeBlueCow
22/11/2005, 21h40
comment faire
ça me semble plutôt simple au niveau de la mise à jour elle-même. par contre pour la structure de donnée... le pb est que tu risques de te retrouver avec des informations redondante (relation de A avec B et relation de B avec A). à priori, je ne vois pas de solution élégante à ce pb (mais ce n'est pas très important).
cette méthode soit efficace ?
yop. simple et efficace. ce n'est pas forcément très subtile (mais ça dépends bcp du contexte aussi) mais la méthode est claire et facilement prévisible pour le joueur (il sait ce qu'il risque en attaquant la faction B et n'a pas de "mauvaise" surprise comme pourrait en provoquer un système plus complexe).
Bon, en fait, j'ai opté pour une solution moins "brutale" : en attaquant un membre d'une autre faction, par exemple, on appelle la fonction other->degradeRelationWith( get_shared_ptr_from_this() )
Ça modifie un peu les relations (sur une échelle de 0 à 100, de 5). Quand le 100 ou le 0 est atteint, la modification change de niveau : on passe par exemple de "neutre" à "ennemi".
Voici le code : si quelque chose vous paraît aberrant, ça m'intéresse ;)
PS : je ne mets pas le code de degradeRelationWith, c'est sensiblement similaire à improveRelationWith.
class Faction
{
public:
enum RelationShip
{
FRIEND, // A cup of tea ?
NEUTRAL, // I've nothing against you.
ENEMY // Die. DIE !
};
/* Return the identifiant of the faction */
const string& getID() const;
/* Return the human readable name of the faction */
const string& getName() const;
/* Return the relationship of this faction with another faction, whose identifiant is _factionID */
RelationShip getRelationWith( const string& _factionID ) const;
/* Set the relation with another faction, and also modify relation of its friends with the relation.
For example, if A and B are friends factions, and are neutral with C : if A->setRelationWith( "C", ENEMY ) is called,
A and C will be enemies, so will be B ( A will call B->setRelationWith( "C", ENEMY ) )*/
void setRelationWith( const string& _factionID, RelationShip _rel = NEUTRAL );
/* Make the relationship with another faction a bit better. */
void improveRelationWith( const string& _factionID );
/* Make the relationship with another faction a bit worse. */
void degradeRelationWith( const string& _factionID );
private:
/* Unique identifiant of the faction (e.g, "animals", "bad_guies" ...) */
const string mID;
/* Human readable name of the faction (e.g, "Animals", "Bad guies" ...) */
const string mName;
/* Map each faction identifiant with a type of relation : for example, "paladins"
will be mapped with ENEMY, if this faction is the one of the bad guies */
map< const string, RelationShip > mRelations;
/* Keep trace of the evolution of current relationship, with a number between 0 and 100 :
for example, NEUTRAL with 1 is really close to ENEMY : the newt degradation of the
relations will make the two factions enemies. */
map< const string, unsigned short int > mRelationsEvolution;
/* Constructor : can only be called by FactionManager */
Faction( const string& _id, const string& _name );
friend class FactionManager;
};
void Faction::setRelationWith( const string& _factionID, RelationShip _rel )
{
if( !FactionManager::getSingleton().getFaction( _factionID ) )
{
// This faction doesn't exist
return;
}
mRelationsEvolution[ _factionID ] = 50;
if( mRelations[ _factionID ] == _rel )
{
return;
}
else if( mRelations[ _factionID ] == ENEMY || ( mRelations[ _factionID ] == NEUTRAL && _rel == FRIEND ) )
{
// Things are better
mRelations[ _factionID ] = _rel;
FactionManager::getSingleton().getFaction( _factionID )->improveRelationWith( mID );
}
else if( mRelations[ _factionID ] == FRIEND || ( mRelations[ _factionID ] == NEUTRAL && _rel == ENEMY ) )
{
// Things are worst
mRelations[ _factionID ] = _rel;
FactionManager::getSingleton().getFaction( _factionID )->degradeRelationWith( mID );
}
}
void Faction::improveRelationWith( const string& _factionID )
{
if( !FactionManager::getSingleton().getFaction( _factionID ) )
{
// This faction doesn't exist
return;
}
map< const string, RelationShip >::iterator it = mRelations.find( _factionID );
if( it == mRelations.end() )
{
mRelations[ _factionID ] = NEUTRAL;
mRelationsEvolution[ _factionID ] = 50 + BASE_MODIFICATION; // Begins with a slight bonus, as we are in improveRelationWith()
}
else
{
if( mRelationsEvolution[ _factionID ] + BASE_MODIFICATION >= 100 )
{
/* The relationship is *really* changing */
RelationShip oldRS = getRelationWith( _factionID );
if( oldRS == ENEMY )
{
setRelationWith( _factionID, NEUTRAL );
mRelationsEvolution[ _factionID ] = BASE_MODIFICATION;
}
else if( oldRS == NEUTRAL )
{
setRelationWith( _factionID, FRIEND );
mRelationsEvolution[ _factionID ] = BASE_MODIFICATION;
}
else
{
mRelationsEvolution[ _factionID ] = 100;
// Do nothing else, things cannot be better.
}
}
else
{
mRelationsEvolution[ _factionID ] += BASE_MODIFICATION;
}
}
}
Vu le nombre de fois que tu utilises FactionManager::getSingleton().getFaction( _factionID ) dans la première méthode, tu devrais garder un pointeur dessus au début du bloc.
Ça augmenterait la lisibilité et, des fois que tu ais à debugguer, tu te remercieras à ce moment là (permettre au debuggueur d'afficher les étapes intermédiaires aide).
Pareil pour mRelationsEvolution[ _factionID ] dans la deuxième méthode.
Quand je lis ces deux blocs répété, je suis obligé d'aller vérifier que _factionID est bien const et que chaque répétition n'est pas une forme un peu altérée de la précédente. Avec un pointeur (ou une référence ou ce que tu veux :) ) en début de méthode, je n'ai pas à vérifier ça lors de la lecture. Je n'ai à vérifier que si le pointeur est modifié, et ça facilite grandement la relecture.
vBulletin® v.3.6.5, Copyright ©2000-2009, Jelsoft Enterprises Ltd. Tous droits réservés - Version française vbulletin-fr.org