2010-03-11 9 views

Répondre

2

Java fournit un javax.swing.undo.UndoManager qui est essentiellement une pile de UndoableEdit (c'est-à-dire des commandes). Si vous sauvegardez l'état avant et après dans un UndoableEdit, chaque fois que vous exécutez une annulation, ou un rétablissement, il s'agit simplement de restaurer cet état sur annuler ou rétablir.

Si vous ne pouvez pas utiliser la classe Swing ci-dessus, vous pouvez utiliser une pile ou une liste de base tant que vous vous assurez d'effectuer les opérations correctes lorsque différentes éditions/commandes sont effectuées. Par exemple, si vous annulez quelques opérations et effectuez une modification différente, les commandes précédemment annulées seront perdues.

2

La suggestion de Kaleb est géniale (+1) mais ne donne pas de détails. Je ne peux pas donner suffisamment de détails dans un commentaire, et je n'ai pas vu une bonne explication simple sur la façon de l'utiliser. Une modification annulable se compose de 3 parties importantes: le constructeur, la méthode d'annulation et la méthode de refaire. L'astuce consiste à garder chaque "edit" TRES simple. Selon la complexité de votre jeu, il peut y avoir des centaines de modifications entre les "mouvements". Imaginons que dans une simulation au tour par tour, vous déplacez une armée - c'est une modification - alors l'ordinateur déplace toutes ses armées (chacune étant une édition). Une condition météorologique aléatoire - une autre édition, une ville construit un nouveau réservoir - une autre édition, ...

Chaque type d'édition est un type d'objet différent. Disons que vous déplacez une unité de (35,150) à (35, 151). Faire votre déménagement peut ressembler à ceci:

undoManager.addEdit(new MoveOne(map, new Point(35,150), new Point(35,151))); 

et défaisant cette édition serait simplement:

undoManager.undo(); 

qui UNDOS automatiquement tout jusqu'à la dernière modification « significative » (le dernier le joueur humain a)

Voici ce que le "mouvement" classe ressemblerait à ceci:

MoveOne extends AbstractUndoableEdit { 
    private final Point start; 
    private final Point finish; 
    private final Map map; 

    public MoveOne(Map pMap, Point pStart, Point pFinish) { 
     start=pStart; 
     finish=pFinish; 
     map=pMap; 
     redo(); 
    } 

    public redo() { 
     MapObject piece=map.getObjectAt(start); 
     map.moveObject(piece, finish); 
    } 

    public undo() { 
     MapObject piece=map.getObjectAt(finish); 
     map.moveObject(piece, start); 
    } 
} 

A tas de mouvements minuscules comme celui-ci pourraient s'accumuler en un mouvement "humain". Ces "humains" pourraient être marqués par l'étiquette "isSignificant" - de cette façon, vous pourriez facilement défaire le dernier événement "significatif" .Tout le reste dans votre jeu devient une simple manipulation de ces petits objets triviaux

J'aime ce modèle et des accessoires pour @Kaleb de remarquer que java il prend en charge maintenant dans le JDK!

3

programmation du jeu n'a pas grand-chose à voir avec « l'application entreprise » programmation ni avec la « programmation webapp ».

il Cela dépend du type de jeu sur lequel vous travaillez, mais votre approche et celle de Gaven ont absolument rien à voir avec la façon dont les états de jeu sont sauvegardés dans les "vrais" jeux. Les performances vont être horriblement mauvaises et vous finirez par utiliser un lot de mémoire et d'espace disque.

grands jeux comme, par exemple, Warcraft III par Blizzard ou Age of Empires Microsoft ne jamais stocker les entrées utilisateur nécessaires pour reproduire tout état de jeu.

C'est ainsi qu'ils réalisent une transmission réseau très efficace même lorsque les joueurs ont des centaines ou des milliers d'objets et qu'ils réalisent de petits fichiers de sauvegarde (qui peuvent être utilisés pour continuer le jeu ou faire une relecture) facile, il suffit d'envoyer par UDP les frappes et les coups de souris des joueurs et l'heure à laquelle ces entrées se sont produites.

Comment cela est-il lié à une annulation/rétablissement? Imaginez que vous avez reçu 200 entrées d'utilisateurs depuis le début de votre partie et que vous souhaitez annuler la dernière étape: vous démarrez le jeu à partir de rien et vous alimentez les 199 premières entrées. C'est tout. Parfait défaire.

Bien sûr, vous n'avez besoin de rejouer la logique que lors de la lecture de ces 199 étapes, sans avoir besoin de mettre à jour votre vue. Pour la plupart des jeux, la logique est une infime partie du temps total passé (la plupart du temps étant passé dans la vue). Donc, rejouer ces entrées est très rapide.

Been there, done that :)

Maintenant, si vous voulez une autre façon de faire illimité défont/redo alors quelque chose doit être dit au sujet de « OO sur des objets immuables »: J'ai des outils de jeu éditeurs écrit (comme un éditeur de carte) avec un nombre illimité d'annulations et de reprises. L'astuce consiste à seulement jamais utiliser des objets immuables. Ensuite, les états précédents persistants sont faciles: simplement l'objet en haut de la hiérarchie ('gamemap239'). Parce que vous n'utilisez que des objets immuables, un "nouveau" plan de jeu partage 99,9% de ses objets avec le précédent plan de jeu et donc l'utilisation de la mémoire est ridiculement faible, permettant de conserver un grand nombre d'états.

J'ai appliqué avec succès ce "OO sur des objets immuables pour une annulation/restauration efficace" dans des logiciels commerciaux qui ne sont pas des jeux et c'est vraiment une technique incroyable. Maintenant, cela dépend du jeu que vous faites: bien sûr, pour un jeu de dragueur de mines, vous pouvez utiliser Swing et les techniques de programmation Java régulières. Mais pour les jeux plus avancés, les collections et API Java ordinaires et les techniques de programmation régulières entreprise/webapp/fatclient ne le coupent pas.