2010-09-01 4 views
2

Quelle est la meilleure façon de traiter quelque chose comme ceci:affaire avec beaucoup d'if-else, l'interrupteur

if(key==Space) 
{ 
    switch(weapon) 
    { 
     case GUN: 
      p->shotGun(); 
      break; 
     case BOW: 
      p->shotBow(); 
      break; 
    } 
} 
else if(key==Enter) 
{ 
    //... 
} 
else if(key==Up) 
{ 
    //... 
} 
+0

pour moi, il semble ok ... quel type est «clé»? –

Répondre

5

J'ai tendance à utiliser une expression de type de carte:

unordered_map<KEY_PRESS,ICommand> myCommands; 
unordered_map<KEY_PRESS,ICommand>::const_iterator currentCommand = myCommands.find(key); 
if(currendCommand != myCommands.end()){ 
    currentCommand->performAction(weapon); 
} 

Là encore, si vous avez fait des armes dans des objets plutôt que de drapeaux que vous pourriez sortir avec un modèle de fonctions surchargées.

+0

+1 pour identifier l'utilisation possible du modèle de commande :) – Wix

1

Comment sur les niveaux des états de commutation imbriqués? Pour une meilleure lisibilité, je refactoriserais également les commutateurs de second niveau pour séparer les fonctions.

10

de Split une dimension en deux:

switch (key) 
{ 
    case Space: 
    ProcessSpaceCmd(); 
    break; 

    case Enter: 
    ProcessEnterCmd(); 
    break; 

    case Up: 
    ProcessUpCmd(); 
    break; 
} 

Voir quelle dimension est plus longue, [key] ou [weapon] et le plus court pour l'interrupteur externe.

+2

Cela peut conduire à un entrepôt de spaghettis si le développeur n'est pas prudent, mais il est judicieux compte tenu des besoins de l'OP. –

+1

C'est bon, Spaghetti Warehouse a de la bonne nourriture. :-) Signalez le commentaire –

2

Ou si vous voulez vraiment vous débarrasser de if-elses, vous pouvez utiliser une forme de correspondance entre les codes clés et les méthodes. Selon si les codes clés sont consécutifs, il pourrait être la carte ou tout simplement un tableau indexé par le code clé comme:

KeyMethods[key]();

+0

Rappelez-moi de revenir dans 11 heures et de mettre ce numéro en doute. :) – sarnold

9

Vous voudrez peut-être penser à utiliser la Command et/ou Strategy motifs. Le motif de commande semble être un bon ajustement pour le si/else externe tandis que le motif de la stratégie semble être un bon ajustement pour le commutateur interne.

cmd = Command->GetCommand(key); 
    cmd->Perform(); 

et pour effectuer la commande associée à l'espace clé

weapon = PlayState->GetCurrentWeapon(); 
    weapon->Fire(); 

Notez ce dernier repose sur une cache globale/état de tenir l'arme actuelle (stratégie).

L'effet de ceci serait de déplacer la logique if/else dans la méthode d'usine où vous déterminez la commande en cours. Choisir quelle commande sélectionne l'une des branches if/else. Stocker l'arme actuelle dans l'état de jeu vous permet de choisir facilement la méthode de tir de l'arme à invoquer, ainsi la "logique" de l'arme à choisir est déplacée dans la logique de sélection d'arme pour l'état et "disparaît" entièrement. Chaque stratégie d'arme sait simplement comment exécuter sa propre logique «feu».

+0

Il pourrait être facilement adapté pour ne pas nécessiter de globalité. –

0

Je suggérerais au moins diviser le contenu de chaque If dans sa propre fonction. Une alternative que j'ai utilisée auparavant est de créer une classe de base qui peut être dérivée par chaque classe qui reçoit une entrée au clavier. Conservez une liste des classes qui en dérivent, puis passez en revue cette liste chaque fois que vous recevez une entrée, en appuyant sur la touche et en la laissant manipuler si elle le souhaite.

3

Puisqu'il est C++, vous pouvez profiter des aspects orientés objet de celui-ci. Faire une interface pour des armes telles que IProjectileWeapon et créer une classe d'arc et de pistolet qui implémente cette interface. Ensuite, lorsque vous appelez la méthode Shoot(), il utilisera le comportement correct. Cela va se débarrasser de l'instruction du commutateur pour l'arme. Il serait probablement préférable d'avoir une classe de personnage ayant une arme en tant que membre et UseWeapon() en tant que méthode. Ainsi, la méthode UseWeapon() appelle la méthode Shoot() de l'arme.Pour déplacer, ajoutez une commande de déplacement à la classe Character et passez dans la direction que le personnage doit déplacer.

2

Une autre possibilité:

class Weapon { 
    public: 
    abstract void shoot(); 
} 

class Gun: public Weapon { 
    public: 
    void shoot(); 
} 

class Bow: public Weapon { 
    public: 
    void shoot(); 
} 

if(key==Space) 
{ 
    weapon.shoot(); 
} 
else if(key==Enter) 
{ 
    //... 
} 
else if(key==Up) 
{ 
    //... 
} 

Quant à la longue suite de déclarations if, qui est très bien. Une instruction switch fonctionnerait également avec IFF avec des entiers. Mais avoir la déclaration break dans chacun peut être gênant, et l'oublier peut être désastreux. C'est plus important si vous avez besoin de vitesse dans une boucle interne pour un code critique. (else if évalue chacun d'eux à tour de rôle, jusqu'à ce que vous ayez trouvé une correspondance switch saute directement à l'option correcte.)

+0

Etes-vous sûr du mot clé "abstract"? Peut-être devrait-il être "virtuel" à la place? Mais votre point est bon. Utiliser le polymorphisme est certainement un meilleur moyen que d'utiliser "switch" ... – ThR37

0

Rendez votre classe d'armes virtuelle.

Questions connexes