Conceitualmente, como a reprodução funciona em um jogo?

145

Eu estava meio curioso sobre como a repetição pode ser implementada em um jogo.

Inicialmente, pensei que haveria apenas uma lista de comandos de todas as ações de jogador / ai que foram executadas no jogo e, em seguida, 'reproduz' o jogo e deixa o mecanismo renderizar como de costume. No entanto, eu olhei para replays em FPS / RTS jogos, e após uma inspeção cuidadosa até mesmo coisas como as partículas e / falhas audíveis gráficas são consistentes (e as falhas são geralmente em consistente).

Então, como isso acontece? Nos jogos com ângulo fixo da câmera, acho que ele pode gravar todos os quadros da cena inteira em um fluxo que é armazenado e depois apenas repassa o fluxo de volta, mas isso não parece suficiente para jogos que permitem pausar e mover a câmera por aí. Você teria que armazenar os locais de tudo na cena em todos os momentos (não?). Então, para coisas como partículas, são muitos os dados a serem enviados, o que parece ser um atrativo significativo no desempenho do jogo durante o jogo.

Steven Evers
fonte
10
As replays originais do Star Craft não eram de fato consistentes. Você pode assistir ao mesmo jogo duas vezes e ver alguns resultados bastante diferentes.
Andres
1
@ André: Interessante, eu não tinha notado. Em particular, para o gênero RTS, eu estava pensando em Company Of Heroes.
Steven Evers
4
Para esclarecer o que eu acho que o SnOrfus está perguntando: Alguns jogos (Uncharted 2, Halo 3 e até Battlefield 2) permitem gravar um jogo na íntegra. Depois que o jogo terminar, você poderá reproduzi-lo em uma velocidade designada e voar pelo nível enquanto a ação está ocorrendo, visualizando-o de qualquer posição no mapa. Então, suponho que se trata de gravar os movimentos de todos os players / objetos e não algo a ver com o buffer de vídeo.
Sean
1
@ Sean O'Hollaren: Sim, está correto.
Steven Evers
1
Depois, adicionarei também aos jogos de corrida de carros em que os replays são quase o padrão. Tenho certeza de que a localização dos modelos é gravada e tudo é executado através do mecanismo.
precisa

Respostas:

61

Eu acho que seu pensamento inicial estava correto. Para criar uma reprodução, você armazena toda a entrada recebida do usuário (junto com o número do quadro no qual foi recebida) junto com as sementes iniciais de qualquer gerador de números aleatórios. Para reproduzir o jogo, você redefine seus PRNGs usando as sementes salvas e alimenta o mecanismo de jogo com a mesma sequência de entrada (sincronizada com os números de quadro). Como muitos jogos atualizam o estado do jogo com base na quantidade de tempo que passa entre os quadros, também pode ser necessário armazenar a duração de cada quadro.

Peter Ruderman
fonte
Os números de quadros podem não ser uma boa referência, pois a reprodução pode ser executada em uma taxa de quadros diferente do jogo ao vivo.
Ben S
5
@ Ben: Framerate não faz diferença, já que os números dos quadros ainda serão os mesmos. Essa é a resposta correta.
BlueRaja - Danny Pflughoeft
14
Os quadros gráficos e os 'quadros' do mecanismo (ou iterações) não são necessariamente os mesmos. Em muitos jogos mais antigos, o mecanismo era atualizado na mesma proporção que os gráficos, em um loop principal. Com os mecanismos modernos, os gráficos geralmente podem ser atualizados o mais rápido que a GPU permite, com o mecanismo avançando no nível necessário para uma resolução boa e consistente da dinâmica do jogo (geralmente um mecanismo de física).
Dan Bryant
3
@iamgopal: se você conhece o estado do gerador de números pseudo-aleatórios, esse problema já está resolvido. Outro método pode ser o de tratar números aleatórios como outra forma de entrada e salvá-los ao lado de pressionamentos de tecla e similares.
Kylotan
1
Gostaria de anunciar que essa abordagem exige que seu mecanismo de jogo seja determinístico e que funcione com uma etapa de tempo fixo. Acredito que todos os jogos RTS da Blizzard foram construídos dessa maneira. Jogos não determinísticos incluiriam dados adicionais de sincronização para garantir consistência a longo prazo.
John Leidegren
28

Starcraft e Starcraft: Brood War tiveram um recurso de repetição. Após a conclusão de uma partida, você pode salvar a reprodução para visualizá-la mais tarde. Durante a reprodução, você pode rolar pelo mapa e clicar em unidades e edifícios, mas não alterar seus comportamentos.

Lembro-me de uma vez assistindo a uma repetição de uma partida que havia sido disputada no jogo original, mas a repetição estava sendo vista em Brood War. Para quem não conhece, Brood War contém todas as unidades e edifícios originais, bem como uma variedade de novos. No jogo original, o jogador havia derrotado o computador, criando unidades que o computador não poderia facilmente combater. Quando reproduzi o jogo em Brood War, o computador tinha acesso a diferentes unidades, criadas e usadas para derrotar o jogador. Portanto, o mesmo arquivo de reprodução resultou em um vencedor diferente, dependendo de qual versão do Starcraft estava sendo reproduzida.

Eu sempre achei o conceito fascinante. Parece que o recurso de reprodução funcionou gravando todas as entradas do player e assumiu que o computador responderia a esses estímulos exatamente da mesma maneira a cada vez. Quando as entradas do jogador foram inseridas no replayer original de Starcraft, o jogo se desenrolou exatamente como na partida original. Quando a mesma informação exata foi inserida no replayer da Guerra da Ninhada, o computador reagiu de maneira diferente, criou unidades mais fortes e venceu o jogo.

Algo a ter em mente se você estiver escrevendo um mecanismo de repetição.

Bobwise
fonte
6
+1: muito interessante. Eu nunca tinha ouvido falar sobre isso. Fornece uma boa visão de como eles o desenvolveram.
Steven Evers
18

Existem dois métodos principais:

  1. Armazenando eventos (como ações player / ai) - exatamente como você diz.
  2. Estado de armazenamento (estado do jogo completo, localizações dos objetos, em momentos consecutivos).

Depende do que você quer fazer. Às vezes, armazenar eventos é melhor, porque geralmente é necessário muito menos memória. Por outro lado, se você deseja fornecer replays que podem ser reproduzidos em velocidades diferentes e em diferentes pontos de partida, é melhor armazenar os estados. Ao armazenar estados, você também pode decidir se os armazena após cada evento ou por apenas 12 ou 25 vezes por segundo - isso pode reduzir o tamanho da sua reprodução e facilitar o retrocesso / avanço rápido.

Observe que "estado" não significa estado gráfico. Mais algo como posições de unidade, estado de recursos e assim por diante. Coisas como gráficos, sistemas de partículas e assim por diante geralmente são determinísticas e podem ser armazenadas como "animação X, tempo Y: Z".

Às vezes, os replays são usados ​​como esquema de anti-aquecimento. Então, armazenar eventos é provavelmente o melhor aqui.

liori
fonte
10

Tecnicamente, você deve escrever seu mecanismo para ser determinístico, isso não é aleatório. Assumindo que um personagem no jogo está mirando o braço de um oponente e dispara uma arma, a mesma quantidade de dano deve ser aplicada ao oponente em todos os casos.

Assumindo que uma bomba detona no local X, as partículas produzidas por essa explosão sempre devem resultar no mesmo resultado visual. Se você precisar de aleatoriedade, crie um conjunto de números aleatórios, selecione um valor inicial quando o jogo for jogado e salve esse valor inicial na repetição.

Em geral, ter aleatoriedade em um jogo é uma má ideia. Mesmo para coisas como multiplayer, você não pode ter metade dos seus jogadores capazes de ver em torno de uma explosão, enquanto os outros não podem simplesmente porque não obtiveram o valor aleatório certo.

Faça tudo determinístico, e você deve ficar bem.

Timothy Baldridge
fonte
1
E quanto à IA? A IA não é aleatória?
perfil completo de Jesse Jashinsky
18
Isso realmente não é necessário. Use números pseudo-aleatórios semeados para todos os eventos aleatórios e salve a semente no arquivo de repetição. Dessa forma, os mesmos números "aleatórios" serão gerados durante a reprodução.
Ben S
13
-1 para entender claramente como a "aleatoriedade" funciona em computadores #
BlueRaja # Danny Pflughoeft
10
hum .... não .... Estou perfeitamente ciente de que não existe algo aleatório "verdadeiro". No entanto, a maioria das pessoas tenta contornar isso definindo sua semente aleatória para algo como a hora do sistema. No entanto, o que estou dizendo é que isso não deve ser feito. Não me importo se ele usa a API do sistema ou uma tabela predefinida de números aleatórios. O que eu disse originalmente estava correto. Toda função em seu mecanismo deve produzir o mesmo resultado com base em suas entradas. O tempo nunca deve ser um fator.
Timothy Baldridge
2
Se as partículas não interagem com a mecânica do jogo de maneira significativa, não importa se os RNGs são diferentes para elas. Isso ajudaria no caso de uma simulação sincronizada em rede (como na maioria dos jogos RTS e em muitos outros gêneros de jogos), pois é um pouco menos que a simulação precisa sincronizar todos os quadros (os efeitos das partículas são atualizado individualmente).
RCIX 18/06/10
10

Dado o estado inicial e uma série de ações com registro de data e hora , basta percorrer a sequência, pois as ações gravadas devem ter uma repetição.

Para que eventos aleatórios ocorram exatamente da mesma forma, use números pseudo-aleatórios semeados e salve a semente no arquivo de reprodução.

Contanto que você use o mesmo algoritmo para gerar os números aleatórios a partir da semente, poderá recriar todos os eventos da mesma forma que ocorreram no jogo ao vivo, sem a necessidade de capturas instantâneas completas do estado do jogo.

Isso exigirá que os replays sejam assistidos sequencialmente , mas isso é bastante normal para replays de jogos (consulte Starcraft 2). Se você deseja permitir acesso aleatório à linha do tempo, pode tirar instantâneos de estado completo em intervalos definidos (digamos a cada minuto), para pular a linha do tempo com uma granularidade definida.

Ben S
fonte
Se você reinventar cada número de segundos (digamos 5 ou 10), seria fácil gravar no seu fluxo de reprodução e também permitir avançar ou recuar (para PRNG "quadros-chave" essencialmente).
Wedge
7

O NVidia PhysX (um mecanismo de simulação física frequentemente usado em jogos) é capaz de gravar o estado completo da cena física ao longo do tempo. Isso incorpora quaisquer informações de direção do mecanismo de jogo, o que significa que você não precisa rastrear sementes de números aleatórios, como sugeriram outros. Se você fizer esse despejo de cena, poderá reproduzi-lo em uma ferramenta externa (fornecida pela NVidia), que é muito útil para rastrear problemas com seus modelos físicos. No entanto, você também pode usar o mesmo fluxo físico para acionar seu mecanismo gráfico, o que permitiria um controle normal da câmera, uma vez que apenas a física que conduz os gráficos foi gravada. Em muitos jogos, isso inclui os efeitos das partículas (o PhysX inclui alguns sistemas de partículas muito sofisticados.) Quanto ao som, suponho que isso seja gravado literalmente (como um fluxo de som), mas eu '

Dan Bryant
fonte
4

Sua idéia original está certa e, para os efeitos realmente complexos, eles não são lembrados exclusivamente. Por exemplo, o sistema de repetição do Warcraft 3 não armazena o estado das animações ou efeitos de partículas no caso de efeitos aleatórios, etc. Além disso, a MAIORIA das coisas pode ser computada computacionalmente a partir de um ponto de partida de maneira determinística, assim como na maioria dos sistemas que usam variáveis ​​aleatórias (uma explosão de partículas que fornece um deslocamento aleatório, por exemplo), tudo o que você precisa é o tempo do efeito e a semente aleatória. Em seguida, você poderá gerar novamente o efeito sem realmente saber como ele será .. sabendo que ele está passando por um caminho de código determinístico.

Pensando nisso de maneira conceitual, para reproduzir uma linha do tempo de eventos, tudo o que você precisa são as ações do usuário. O programa reagirá exatamente da mesma maneira, exceto no caso de variáveis ​​aleatórias. Nesse cenário, você pode ignorar a aleatoriedade (isso realmente importa se os efeitos parecem EXATAMENTE iguais, ou podem ser gerados aleatoriamente), ou armazenar o valor da semente e falsificar a aleatoriedade.

Stefan Valianu
fonte
3

Jogue minhas duas moedas.

Depende do que você deseja, a reprodução pode ser realizada via

  1. Gravar buffer de vídeo e reproduzir mais tarde,
  2. Capturando o estado do objeto em todos os quadros e reproduzindo posteriormente,

Na maioria das vezes, as pessoas querem um replay interativo, então 2. é o caminho a percorrer. Então, dependendo de suas restrições, existem várias maneiras de otimizar esse processo

  • garantir que o sistema seja uma simulação determinística *, de modo que cada entrada gere uma saída consistente e esperada
  • se for necessária aleatoriedade, verifique se os números aleatórios podem ser reproduzidos exatamente mais tarde [veja a propagação com o PRNG dos Geradores de Números Aleatórios Pseudo-Aleatórios ou use conjuntos aleatórios fixos]
  • divida os elementos do jogo em elementos "mecânicos" e "estéticos". elementos mecânicos afetam o resultado [por exemplo, queda de coluna e caminho de bloqueio], elementos estéticos são mostrados e não influenciam nenhum processo de tomada de decisão no sistema [por exemplo, efeitos de partículas visuais como faíscas].

É realmente um tópico fascinante. Lembro que um título de lançamento do Xbox Wreckless original tinha um bom recurso de reprodução. Infelizmente, em mais de uma ocasião, o replay estragou tudo;)

oh sim, como alguém poderia esquecer o Blinx Time Sweeper ! ótimo replay interativo que foi incorporado à mecânica do jogo!


* = parece que existem alguns comentários sobre o intervalo de tempo. Eu estou usando "simulação" aqui para capturar esse recurso. No núcleo, seu mecanismo precisa ser capaz de produzir períodos discretos de tempo. mesmo que um quadro de reprodução demore mais ou menos para ser processado do que o original, o sistema deve perceber que o mesmo delta já passou. isso significa gravar o intervalo de tempo do quadro com cada entrada gravada e fornecer esse delta ao relógio do seu motor.

johnny g
fonte
2

Talvez você possa simplesmente salvar uma pilha de comandos enviados por cada jogador. Então, em vez de salvar que uma bomba detonar em um determinado ponto e tempo, ou que um determinado carro seja destruído, basta salvar as teclas pressionadas por cada jogador. Então, no replay, você simplesmente simula o jogo como teria acontecido com essas impressoras. Sinto que isso tem potencial para ocupar menos espaço, mas nunca trabalhei em um sistema de repetição como esse.

Pergunta interessante, no entanto. Eu estaria interessado em como isso é feito em jogos profissionais.

ThirdD3gree
fonte
2

Dan Bryant

Além disso, o registro de sementes aleatórias não seria suficiente para retroceder o suporte, pois a progressão aleatória não é um procedimento reversível sem suporte especial em toda a lógica que depende da aleatoriedade. É mais flexível registrar os resultados das operações aleatórias como parte do fluxo de eventos.

Foi exatamente o que pensei no começo, quando estava tentando descobrir como eles conseguiam, para que o jogo fosse sempre sempre o mesmo. Com Doom, pensei em quão aleatórios eram os tiros: D. Armazenar qualquer número aleatório se acostumou, eu descobri que poderia ser uma solução. Isso foi antes de me deparar com um documento em PDF sobre a tecnologia Crysis. Algumas texturas barulham lá e a disposição da grama ou da árvore, parecia estar usando a pseudo-randomização com sementes reversíveis fixas para torná-lo assim que você não via disposição alterada de ruído, árvores e grama sempre que olhava!

Evitando, ao mesmo tempo, armazenar milhões de árvores e posição das árvores. Aparentemente, a sequência pseudo-aleatória pode repetir o mesmo a qualquer momento, conforme a lógica é fixa, para criar uma sequência estatisticamente aleatória falsa de números.

Antonymous
fonte
Se você deseja chamar a atenção de Dan para isso, adicione um comentário sob a contribuição dele - caso contrário, ele provavelmente não o verá.
halter
Poderia ser porque eu sou apenas um convidado, mas não consegui ver nenhuma função "adicionar comentário" no post principal, respondeu Dan, muito menos a resposta de Dan. Vi que há uma função de edição-melhoria, mesmo para postagens que não são minhas, mas como isso funciona?
Antonymous
Ah, boa pergunta! Ele parece aqui que você precisa de 50 pontos de rep a comentar sobre perguntas ou respostas diferentes da sua - as minhas desculpas. Porém, é muito fácil obter 50 - apenas algumas contribuições úteis geralmente conseguem isso. Sim, você pode editar as perguntas e respostas de outras pessoas, embora suas edições sejam revisadas por outras pessoas até chegar a 2000. Veja aqui o seu gráfico de privilégios .
halfer
1

O problema de ter um replay consistente é o mesmo (bem, mais fácil) do que ter um jogo multiplayer consistente.

Como mencionado anteriormente, os replays nos jogos RTS são armazenados gravando todas as entradas (isso tem um efeito. A rolagem não tem efeito.) O multiplayer também transmite todas as entradas

A gravação de todas as entradas e não apenas um palpite - há uma biblioteca para ler replays do Warcraft3 com isso.

A entrada inclui registros de data e hora para esta resposta.

Franky
fonte
Não, não é o mesmo (ou mais fácil) que um jogo de MP consistente. Quando você está jogando MP, os jogos geralmente exigem que todos tenham a mesma versão do jogo, o que não é necessariamente o caso das sessões armazenadas (pois podem ter sido armazenadas com uma versão mais antiga do jogo). Isso é especialmente crítico se um dos jogadores for um oponente da IA. Imagine que você reproduz um jogo no qual uma unidade possui apenas mais um ponto de ataque em uma versão mais recente do que na versão em que foi gravada. Isso pode levar a um resultado completamente diferente.
Drakon 19/04
-1

Eu acreditaria que em certos incrementos o jogo tiraria um instantâneo do estado de tudo (TUDO). Então, quando a reprodução estiver ocorrendo, o uso simples de interpolação linear pode ser usado para preencher os "buracos". Pelo menos é assim que eu acho que seria feito.

Você está certo de que gravar as entradas não seria confiável / não garantiria a mesma saída. O jogo definitivamente precisa acompanhar o estado de todos os objetos (ou pelo menos os importantes)

Bob Fincheimer
fonte
2
Não, alimentar as mesmas entradas resultará exatamente no mesmo resultado da primeira vez. Você só precisa garantir o tempo correto, alimentando a entrada entre os mesmos quadros em que foi originalmente recebida. Salvar o estado inteiro do jogo periodicamente pode exigir uma quantidade colossal de memória e produzir resultados inconsistentes também.
Peter Ruderman
@ Peter, "alimentar as mesmas entradas resultará exatamente no mesmo resultado": não. Há um elemento aleatório em muitos jogos, que pode ser diferente cada vez que a reprodução é reproduzida. Você precisa acompanhar mais do que as entradas.
houbysoft
Isso é verdade. Você também precisa armazenar as sementes de seus PRNGs (veja minha resposta a esta pergunta).
precisa
1
Eu sei que isso consome desempenho e memória, mas se você perder uma coisinha no que diz respeito à entrada ou aos geradores aleatórios ... ou realmente qualquer coisa, a repetição ocorrerá em uma tangente horrível!
Bob Fincheimer
@BlueRaja, a ideia de instantâneo de memória de Bob não é necessariamente tão absurda, embora um bom mecanismo possa gravar 'deltas' de estado em vez de codificar toda a memória para cada iteração. Provavelmente, é mais fácil oferecer suporte no nível do mecanismo. Além disso, o registro de sementes aleatórias não seria suficiente para retroceder o suporte, pois a progressão aleatória não é um procedimento reversível sem suporte especial em toda a lógica que depende da aleatoriedade. É mais flexível registrar os resultados das operações aleatórias como parte do fluxo de eventos.
Dan Bryant