Je suis en train de créer un RPG 2D en C ++ 11 avec Allegro 5 et boost.
Mon objectif est de mettre à jour mes paramètres de jeu d'une manière ou d'une autre lorsqu'une option est modifiée dans le menu Options. Je ne veux pas forcer l'utilisateur à redémarrer mon jeu. D'autres jeux ne nécessitent pas de redémarrage lors du changement de résolution ou du passage du mode plein écran au mode fenêtré, donc mon jeu ne devrait pas non plus. Veuillez voir une vue simplifiée du système ci-dessous.
Veuillez noter que je ne souhaite pas nécessairement appeler directement mon objet Game depuis l'écran OptionsScreen. La ligne pointillée sert simplement à illustrer l'effet que j'essaie d'obtenir; pour provoquer en quelque sorte une mise à jour du jeu lorsqu'une option est modifiée dans une autre partie du système.
Explication détaillée
Le ScreenManager contient une liste de tous les GameScreen
objets existants. Ce seront différents écrans du jeu, y compris des popups. Cette conception adhère plus ou moins à l' échantillon de gestion du jeu Etat en C # / XNA .
Le ScreenManager
contient une référence à mon Game
objet. L' Game
objet initialise et modifie les paramètres du jeu. Si je veux changer la résolution, passer en plein écran ou couper le volume, je le ferais en Game
classe.
Cependant, OptionsScreen ne peut actuellement pas accéder à la classe Game. Voir le schéma ci-dessous:
Un GameScreen peut signaler trois événements onFinished
, onTransitionStart
et onTransitionEnd
. Il n'y en a pas onOptionsChanged
parce qu'un seul écran fait ça. ScreenManager ne peut pas configurer la gestion des événements pour cela car il gère tous les écrans en tant que GameScreen
s.
Ma question est, comment puis-je changer ma conception afin qu'une modification dans le menu Options ne nécessite pas un redémarrage, mais est immédiatement modifiée? Je demanderais de préférence que mon Game
objet soit mis à jour une fois que le bouton Appliquer est cliqué.
Réponses:
D'après ce que j'ai vu, l'approche la plus simple est de lire un fichier d'options au démarrage pour déterminer les paramètres d'affichage actuels; puis, lorsque votre écran d'options s'affiche, chargez toutes les options actuelles à partir d'un fichier.
Lorsque les modifications sont finalisées via un bouton
apply
ouok
, elles sont enregistrées dans un fichier. Si des modifications affectent l'affichage, informez l'utilisateur que le jeu doit être redémarré pour qu'il prenne effet.Lorsque le jeu est redémarré, les (désormais nouveaux) paramètres d'affichage sont à nouveau lus à partir du fichier.
--ÉDITER--
Et ... ça aurait aidé si j'avais remarqué cette dernière phrase. Vous ne voulez pas avoir à redémarrer. Rend les choses un peu plus difficiles en fonction de votre implémentation et de votre bibliothèque graphique principale.
IIRC, Allegro dispose d'un appel de fonction qui vous permet de modifier les paramètres d'affichage à la volée. Je ne connais pas encore Allegro 5, mais je sais que vous pourriez le faire en 4.
la source
C'est ce que je fais pour mon jeu. J'ai 2 fonctions distinctes pour initialiser des trucs, 'init' et 'reset'. Init n'est appelé qu'une seule fois au démarrage et fait des choses qui ne dépendent d'aucun paramètre, comme le chargement des ressources principales. La réinitialisation fait des choses comme la présentation de l'interface utilisateur en fonction de la résolution de l'écran, elle est donc appelée à chaque fois que les paramètres changent.
Je ne connais pas Allegro, mais ma réponse est assez générale, donc j'espère que cela vous aidera, vous ou quelqu'un d'autre, avec un problème similaire.
la source
Sans gâcher votre architecture actuelle, je vois deux façons. Tout d'abord, vous pouvez stocker un pointeur vers l'
Game
instance dans laOptionsScreen
classe. Deuxièmement, vous pourriezGame
classe récupère les paramètres actuels dans un intervalle donné, disons toutes les secondes.Pour réellement s'adapter aux nouveaux paramètres, la
Game
classe doit implémenter une sorte de fonctions de réinitialisation qui récupère les paramètres actuels et les réinitialise en fonction de ceux-ci.Pour une solution propre, vous avez besoin d'un gestionnaire global d'une sorte, c'est donc plus d'efforts à mettre en œuvre. Par exemple, un système d'événements ou un système de messagerie. Il est très utile de laisser les classes communiquer sans ces liaisons fortes telles que l'agrégation ou la composition, etc.
Avec un gestionnaire d'événements global, le
OptionsScreen
pourrait simplement déclencher globalement un événement redessiné quiGame
s'est enregistré pour écouter auparavant.En règle générale, vous pouvez implémenter une classe de gestionnaire stockant les événements et les rappels en les écoutant dans une carte de hachage. Vous pouvez ensuite créer une seule instance de ce gestionnaire et lui transmettre des pointeurs à vos composants. L'utilisation de C ++ plus récent est assez simple car vous pouvez l'utiliser
std::unordered_map
comme carte de hachage etstd::function
pour stocker des rappels. Il existe différentes approches que vous pouvez utiliser comme clé. Par exemple, vous pouvez rendre la chaîne du gestionnaire d'événements basée, ce qui rend les composants encore plus indépendants. Dans ce cas, vous utiliseriezstd::string
comme clé dans la carte de hachage. Personnellement, j'aime cela et ce n'est certainement pas un problème de performance, mais la plupart des systèmes d'événements traditionnels fonctionnent avec des événements en tant que classes.la source
Eh bien, c'est un cas spécifique du modèle Observer.
Il existe une solution qui implique des rappels. C'est la meilleure façon de le faire si vous voulez un couplage lâche, et je pense que c'est aussi le plus propre. Cela n'impliquera aucun gestionnaire mondial ou singletons.
Fondamentalement, vous aurez besoin d'une sorte de
SettingsStore
. Là, vous stockez les paramètres. Lorsque vous créez un nouvel écran, ils auront besoin d'un pointeur vers le magasin. Dans le cas du,OptionsScreen
il modifiera lui-même certains des paramètres. Dans le cas duGameScreen
il suffit de les lire. Ainsi, dans votre jeu, vous ne créeriez qu'une seule instance, qui sera transmise sur tous les écrans qui en nécessitent une.Maintenant, cette
SettingsStore
classe aura une liste denotifiables
. Ce sont des classes qui implémentent une certaineISettingChanged
interface. L'interface serait simple et contient la méthode suivante:Ensuite, dans votre écran, vous implémenterez la logique de chaque paramètre qui vous tient à cœur. Ensuite, ajoutez - vous au magasin pour être informé:
store->notifyOnChange(this);
. Lorsqu'un paramètre est modifié, le rappel est appelé avec le nom du paramètre. La nouvelle valeur de réglage peut ensuite être récupérée à partir duSettingsStore
.Maintenant, cela peut être encore augmenté avec les idées suivantes:
SettingsStore
(chaînes const) afin d'empêcher le copier-coller des chaînes.la source
Lisez vos paramètres d'un fichier dans des variables. Demandez à votre gestionnaire d'écran de savoir si l'écran d'où il vient vient de l'écran Options, et si tel est le cas, rechargez vos paramètres à partir des variables. Lorsque l'utilisateur quitte votre jeu, réécrivez les paramètres des variables dans le fichier.
la source