146 votes

Conceptuellement, comment fonctionne la relecture dans un jeu ?

J'étais un peu curieux de savoir comment la relecture pouvait être implémentée dans un jeu.

Au départ, je pensais qu'il n'y aurait qu'une liste de commandes de toutes les actions du joueur/de l'IA qui ont été effectuées dans le jeu, et qu'il faudrait ensuite "rejouer" le jeu et laisser le moteur effectuer le rendu comme d'habitude. Cependant, j'ai regardé les replays dans les jeux FPS/RTS, et après une inspection minutieuse, même des choses comme les particules et les glitches graphiques/audibles sont cohérentes (et ces glitches sont en général sur cohérente).

Alors comment cela se produit-il ? Dans les jeux avec un angle de caméra fixe, je pensais qu'il suffisait d'écrire chaque image de la scène entière dans un flux qui est stocké, puis de rejouer le flux, mais cela ne semble pas suffisant pour les jeux qui vous permettent de faire une pause et de déplacer la caméra. Il faudrait stocker l'emplacement de tout ce qui se trouve dans la scène à tout moment (non ?). Donc, pour des choses comme les particules, cela fait beaucoup de données à pousser, ce qui semble être une contrainte importante sur les performances du jeu pendant la lecture.

11 votes

Les Replays originaux de Star Craft n'étaient en fait PAS cohérents. Vous pouviez regarder le même jeu deux fois, et voir des résultats assez différents.

1 votes

@Andres : Intéressant, je n'avais pas remarqué. En particulier, pour le genre RTS, je pensais à Company Of Heroes.

4 votes

Pour clarifier ce que je crois que SnOrfus demande : Certains jeux (Uncharted 2, Halo 3, même Battlefield 2) vous permettent d'enregistrer une partie dans son intégralité. Une fois la partie terminée, vous pouvez la rejouer à une vitesse déterminée et parcourir le niveau au fur et à mesure que l'action se déroule, en la visualisant depuis n'importe quelle position sur la carte. Je suppose donc qu'il s'agit d'enregistrer les mouvements de tous les joueurs/objets et non de quelque chose qui a trait à la mémoire tampon vidéo.

61voto

Peter Ruderman Points 6151

Je pense que votre pensée initiale était correcte. Pour créer une relecture, vous stockez toutes les entrées reçues de l'utilisateur (avec le numéro de l'image à laquelle elles ont été reçues) ainsi que les graines initiales de tous les générateurs de nombres aléatoires. Pour rejouer le jeu, vous réinitialisez vos PRNG en utilisant les graines sauvegardées et vous fournissez au moteur de jeu la même séquence d'entrée (synchronisée avec les numéros d'image). Étant donné que de nombreux jeux mettent à jour l'état du jeu en fonction du temps qui s'écoule entre les images, vous pouvez également avoir besoin de stocker la durée de chaque image.

0 votes

Les nombres d'images peuvent ne pas être une bonne référence, car la rediffusion peut se faire à une fréquence d'images différente de celle du jeu en direct.

6 votes

@Ben : La fréquence d'images ne fait pas de différence, puisque les nombres d'images seront toujours les mêmes. C'est la bonne réponse.

0 votes

Rien ne devrait vraiment s'occuper des cadres. Au lieu de cela, les données devraient être stockées comme : (à 10 sec le joueur A a tiré). De cette façon, le jeu peut être rejoué à n'importe quelle vitesse.

29voto

Bobwise Points 392

Starcraft et Starcraft : Brood War avaient une fonction de relecture. Après avoir terminé un match, vous pouviez choisir d'enregistrer la rediffusion pour la regarder plus tard. Pendant la rediffusion, vous pouviez vous déplacer sur la carte et cliquer sur des unités et des bâtiments, mais pas modifier leur comportement.

Je me souviens avoir regardé une fois la rediffusion d'un match qui avait été joué dans le jeu original, mais la rediffusion était visionnée dans Brood War. Pour ceux qui ne le savent pas, Brood War contient toutes les unités et tous les bâtiments d'origine, ainsi qu'un grand nombre de nouvelles unités. Dans le jeu original, le joueur avait vaincu l'ordinateur en créant des unités que l'ordinateur ne pouvait pas facilement contrer. Lorsque j'ai rejoué à Brood War, l'ordinateur avait accès à différentes unités, qu'il a créées et utilisées pour vaincre le joueur. Ainsi, le même fichier de relecture a donné un vainqueur différent selon la version de Starcraft qui jouait le fichier.

J'ai toujours trouvé ce concept fascinant. Il semblerait que la fonction de relecture fonctionne en enregistrant toutes les entrées du joueur, et suppose que l'ordinateur réagit à ces stimuli exactement de la même manière à chaque fois. Lorsque les entrées du joueur ont été introduites dans le replayer original de Starcraft, le jeu s'est déroulé exactement de la même manière que lors du match original. Lorsque la même entrée exacte a été introduite dans le replayer de Brood War, l'ordinateur a réagi différemment, a créé des unités plus puissantes et a gagné la partie.

C'est une chose à garder à l'esprit si vous écrivez un moteur de lecture.

6 votes

+1 : Très intéressant. Je n'avais jamais entendu parler de ça. Cela donne un bon aperçu de la façon dont ils l'ont développé.

18voto

liori Points 13629

Il existe deux méthodes principales :

  1. Stockage des événements (tels que les actions des joueurs/ai) - comme vous le dites.
  2. Stockage de l'état (état complet du jeu, c'est-à-dire l'emplacement des objets, à des moments consécutifs).

Cela dépend de ce que vous voulez faire. Parfois, il est préférable de stocker les événements, car cela nécessite généralement beaucoup moins de mémoire. D'un autre côté, si vous voulez fournir des rediffusions qui peuvent être jouées à différentes vitesses et à partir de différents points de départ, il est préférable de stocker des états. Lorsque vous stockez des états, vous pouvez également décider de les stocker après chaque événement ou seulement 12 ou 25 fois par seconde, ce qui peut réduire la taille de vos rediffusions et faciliter le retour en arrière ou l'avance rapide.

Notez que le terme "état" ne signifie pas l'état graphique. Il s'agit plutôt de la position des unités, de l'état des ressources, etc. Les choses comme les graphiques, les systèmes de particules et ainsi de suite sont généralement déterministes et peuvent être stockées comme "animation X, temps Y:Z".

Parfois, les reprises sont utilisées comme moyen de lutte contre la discrimination. Dans ce cas, le stockage des événements est probablement la meilleure solution.

10voto

Timothy Baldridge Points 4853

Techniquement, vous devriez écrire votre moteur pour qu'il soit déterministe, c'est-à-dire sans aléa. En supposant qu'un personnage du jeu vise le bras d'un adversaire et tire avec une arme, la même quantité de dégâts devrait être appliquée à l'adversaire dans tous les cas.

En supposant qu'une bombe explose à l'endroit X, les particules produites par cette explosion devraient toujours donner le même résultat visuel. Si vous avez besoin d'aléatoire, créez un ensemble de nombres aléatoires, sélectionnez une valeur de départ lorsque le jeu est joué et enregistrez cette valeur de départ dans le replay.

En général, avoir du hasard dans un jeu est une mauvaise idée. Même pour des choses comme le multijoueur, vous ne pouvez pas avoir la moitié de vos joueurs capables de voir autour d'une explosion alors que les autres ne le peuvent pas simplement parce qu'ils n'ont pas obtenu la bonne valeur aléatoire.

Faites en sorte que tout soit déterministe, et tout devrait bien se passer.

1 votes

Et l'IA ? L'IA n'est-elle pas aléatoire ?

18 votes

Ce n'est vraiment pas nécessaire. Utilisez des nombres pseudo-aléatoires ensemencés pour tous les événements aléatoires et enregistrez l'ensemencement dans le fichier de relecture. De cette façon, les mêmes nombres "aléatoires" seront générés lors de la relecture.

13 votes

-1 pour incompréhension manifeste de la façon dont le "hasard" fonctionne dans les ordinateurs.

10voto

Benoit Points 39210

Compte tenu de la état initial et un série d'actions avec horodatage Pour cela, il suffit de suivre la séquence telle que les actions enregistrées sont censées se produire.

Pour que les événements aléatoires se reproduisent exactement de la même manière, utiliser des nombres pseudo-aléatoires ensemencés et sauvegarder l'ensemencement dans le fichier de relecture.

Tant que vous utilisez le même algorithme pour générer les nombres aléatoires à partir de la graine, vous pouvez recréer tous les événements tels qu'ils se sont produits dans le jeu en direct sans avoir besoin d'instantanés complets de l'état du jeu.

Cela nécessitera que les répétitions soient regardé séquentiellement mais c'est plutôt normal pour les reprises de jeu (voir Starcraft 2). Si vous voulez permettre un accès aléatoire à la ligne de temps, vous pouvez prendre des instantanés complets de l'état à des intervalles définis (disons toutes les minutes), ou de sauter sur la ligne de temps à une granularité définie.

0 votes

Si vous réensemencez toutes les secondes (disons 5 ou 10), il serait assez facile d'enregistrer dans votre flux de relecture et de permettre des sauts en avant ou en arrière (vers des "images clés" PRNG essentiellement).

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X