Je pense qu'une solution solide consisterait à adopter une approche orientée objet.
Selon le type de réalisation que vous souhaitez soutenir, vous avez besoin d’un moyen d’interroger l’état actuel de votre jeu et / ou l’historique des actions / événements créés par les objets du jeu (comme le joueur).
Supposons que vous ayez une classe de réussite de base telle que:
class AbstractAchievement
{
GameState& gameState;
virtual bool IsEarned() = 0;
virtual string GetName() = 0;
};
AbstractAchievement
détient une référence à l'état du jeu. Il est utilisé pour interroger les choses qui se passent.
Ensuite, vous faites des implémentations concrètes. Utilisons vos exemples:
class MasterSlicerAchievement : public AbstractAchievement
{
string GetName() { return "Master Slicer"; }
bool IsEarned()
{
Action lastAction = gameState.GetPlayerActionHistory().GetAction(0);
Action previousAction = gameState.GetPlayerActionHistory().GetAction(1);
if (lastAction.GetType() == ActionType::Slice &&
previousAction.GetType() == ActionType::Slice &&
lastAction.GetObjectType() == ObjectType::Watermelon &&
previousAction.GetObjectType() == ObjectType::Strawberry)
return true;
return false;
}
};
class InvinciblePipeRiderAchievement : public AbstractAchievement
{
string GetName() { return "Invincible Pipe Rider"; }
bool IsEarned()
{
if (gameState.GetLocationType(gameState.GetPlayerPosition()) == LocationType::OVER_PIPE &&
gameState.GetPlayerState() == EntityState::INVINCIBLE)
return true;
return false;
}
};
Ensuite, c’est à vous de décider quand vérifier avec cette IsEarned()
méthode. Vous pouvez vérifier à chaque mise à jour du jeu.
Un moyen plus efficace serait, par exemple, d’avoir une sorte de gestionnaire d’événements. Et puis enregistrez les événements (tels que PlayerHasSlicedSomethingEvent
ou PlayerGotInvicibleEvent
ou simplement PlayerStateChanged
) à une méthode qui prendrait la réalisation en paramètre. Exemple:
class Game
{
void Initialize()
{
eventManager.RegisterAchievementCheckByActionType(ActionType::Slice, masterSlicerAchievement);
// Each time an action of type Slice happens,
// the CheckAchievement() method is invoked with masterSlicerAchievement as parameter.
eventManager.RegisterAchievementCheckByPlayerState(EntityState::INVINCIBLE, invinciblePiperAchievement);
// Each time the player gets the INVINCIBLE state,
// the CheckAchievement() method is invoked with invinciblePipeRiderAchievement as parameter.
}
void CheckAchievement(const AbstractAchievement& achievement)
{
if (!HasAchievement(player, achievement) && achievement.IsEarned())
{
AddAchievement(player, achievement);
}
}
};
if(...) return true; else return false;
c'est pareil quereturn (...)
En bref, les réalisations sont déverrouillées lorsqu'une certaine condition est remplie. Vous devez donc pouvoir produire des déclarations if pour vérifier la condition souhaitée.
Par exemple, si vous voulez savoir qu'un niveau est terminé ou qu'un boss est vaincu, vous devez activer le drapeau booléen lorsque ces événements se produisent.
Ensuite:
Vous pouvez rendre cela aussi complexe ou simpliste que nécessaire pour répondre à la condition souhaitée.
Vous trouverez quelques informations sur les réalisations de la Xbox 360 ici .
la source
Que se passe-t-il si chaque action du joueur envoie un message à
AchievementManager
? Ensuite, le responsable peut vérifier en interne si certaines conditions sont remplies. Les premiers objets postent des messages:Et puis les
AchievementManager
vérifications s’il faut faire quelque chose:Vous voudrez probablement faire cela avec des énumérations au lieu de chaînes. ;)
la source
AchievementManager
chaque fois. classe (qui est ce que OP demandait comment éviter en premier lieu). Et utilisez une énumération ou des classes séparées pour vos messages, et non des chaînes de caractères. L'utilisation de chaînes de chaînes pour transmettre l'état est toujours une mauvaise idée.La dernière conception que j'ai utilisée reposait sur le fait de disposer d'un ensemble de compteurs persistants par utilisateur, puis de permettre à des réalisations de désactiver un certain compteur atteignant une certaine valeur. La plupart étaient une seule paire réalisation / compteur où le compteur ne serait jamais que 0 ou 1 (et la réalisation déclenchée sur> = 1), mais vous pouvez également l'utiliser pour "mecs X tués" ou "coffres X trouvés" aussi. Cela signifie également que vous pouvez configurer des compteurs pour quelque chose qui n'a pas de succès et qu'il sera toujours suivi pour une utilisation future.
la source
Lorsque j'ai mis en œuvre des réalisations dans mon dernier jeu, j'ai tout basé sur des statistiques. Les réalisations sont débloquées lorsque nos statistiques atteignent une certaine valeur. Considérez Modern Warfare 2: le jeu contient des tonnes de statistiques! Combien de coups avez-vous pris avec le SCAR-H? Combien de miles avez-vous sprinté en utilisant le bonus Lightweight?
Ainsi, dans mon implémentation, j'ai simplement créé un moteur de statistiques, puis un gestionnaire de réalisations qui exécute des requêtes très simples pour vérifier l'état des réalisations tout au long du jeu.
Bien que ma mise en œuvre soit assez simpliste, elle fait le travail. J'ai écrit à ce sujet et partagé mes questions ici .
la source
Utilisez le calcul d'événement . Ensuite, établissez des conditions préalables et des actions à appliquer une fois les conditions préalables remplies:
Utilisez-le comme (non optimisé pour la vitesse!):
Si vous voulez faire vite:
Remarque
Il est difficile de donner les meilleurs conseils car toutes les choses ont des avantages et des inconvénients.
la source
Quel est le problème avec un contrôle IF après l'événement de réalisation?
la source