O que é "código de lógica do jogo?"

50

Estou usando C # / XNA e me disseram várias vezes para não misturar código de atualização com código de desenho - e tenho certeza de que não! Mas alguém poderia descrever o que exatamente é 'código lógico'?

Como visto aqui: http://blogs.msdn.com/b/shawnhar/archive/2007/07/25/understanding-gametime.aspx

[...] certifique-se de colocar toda a sua lógica de jogo dentro do método Update (não no Draw!) e tudo funcionará a uma velocidade constante.

Estou perguntando isso, pois a velocidade do meu jogo está flutuando em relação ao FPS. FPS lento é igual a objetos em movimento lento e vice-versa. E sim, estou incluindo o position += speed * (float)gt.ElapsedGameTime.TotalSeconds;código esperado .

Esta é provavelmente uma grande pergunta de novato, mas eu só quero ser absolutamente claro sobre a definição disso.

Shyy Guy
fonte
Eu acho que você quis dizer position = speed * ...TotalSeconds. Observe que =não é +=. Se fosse +=exatamente como você digitou, sua posição sairia da tela quase instantaneamente.
DrZ214
Eu tenho um código que se parece com 'position + = direction * speed * ... TotalSeconds' e que funciona muito bem. Posso ter digitado algo errado, mas position = speed atribuiria a ele todas as atualizações. Seu caminho pode funcionar, mas eu tenho meu código funcionando assim. (Note-se que sentido é normalizado)
Shyy Guy
Eu pensei que gt.ElapsedGameTime.TotalSecondsera o número de segundos decorridos desde o início do programa (jogo). Se você estiver multiplicando sua velocidade por isso, após 5 segundos de jogo, sua velocidade será 5 vezes mais rápida (exceto no caso especial em que a velocidade está definida como 0). Não tenho certeza do que mais você poderia ter que tornaria isso falso, mas estou intrigado.
precisa saber é
11
Ah, é desde a última atualização. gamedev.stackexchange.com/questions/67968/...
Shyy Guy
2
Fascinante, eu nunca teria imaginado isso. Nunca tive essa necessidade em segundos, porque eu pessoalmente uso minha própria variável chamada iiique incremento manualmente cada atualização, porque não a quero em segundos, quero etapas ou quadros. Eu posso ver que o seu caminho é uma maneira válida de codificação suave.
precisa saber é

Respostas:

102

Isso muda o estado do seu mundo de jogo? É um código lógico.

Ele exibe o estado do mundo do jogo? Está renderizando código.

Nils Ole Timm
fonte
Vou dar uma olhada no meu código para ter 100% de certeza. Boa explicação, obrigado.
Cara tímido
38
Ele lida com entrada? Seu código do controlador. Separe o controle da lógica, para que você possa usar a mesma lógica com diferentes tipos de controles. Por exemplo, um FPSInputController + CharacterMotor vs. AIInputController + CharacterMotor vs NetworkInputController (por exemplo, outros jogadores em uma instância multiplayer) + CharacterMotor. O motor (código lógico) não se importa com o modo como recebe as instruções, apenas com o fornecimento (esse tipo de dissociação permite a transição fácil do jogador para o bot de IA (pense em Left 4 Dead e jogadores inativos) e vice-versa, entre outras coisas).
precisa saber é o seguinte
10
Draco traz um bom argumento. Existem muitas divisões diferentes que você pode colocar no código. A divisão de Nils é o que eu consideraria a divisão arquetípica entre lógica e renderização, mas há muitas outras camadas que você verá. O verdadeiro motivo para separá-los em camadas é que cada camada consiste em ações semelhantes que requerem um estilo de código semelhante com requisitos semelhantes. Por exemplo, em muitos jogos, você pode se safar da lógica do jogo, tirando 2 ou 3 quadros para concluir, mas se você não renderizar cada quadro, os olhos do usuário perceberão rapidamente.
Cort Ammon
Mantê-los distintos o ajudará a gerenciar seus requisitos quando eles começarem a se tornar uma fonte de tensão.
Cort Ammon
6
E lembre-se de que, se você lançar muito MVC nele, poderá ficar lento, então sempre procure um equilíbrio entre manutenção e otimização. Mas não otimize muito cedo, a menos que tenha certeza absoluta do que está fazendo. E lembre-se de que você sempre pode refatorar. E ... Uh, faça muitos jogos e aprenda com seus erros.
Maurycy 26/01
24

Sua separação está correta se:

  • Chamar Draw () várias vezes seguidas sem chamadas intercaladas para Update () nunca resultaria em alterações visíveis entre as chamadas.
  • Chamar Update () várias vezes seguidas sem uma chamada intercalada para Draw () seria como jogar o jogo com a tela desligada: tudo se move de maneira perfeita e consistente, você simplesmente não pode vê-lo.
Thomas
fonte
5
Escrita corretamente Draw()pode desenhar figuras diferentes com o passar do tempo. Por exemplo, os quadros de sprites animados podem continuar mudando. Além disso, os objetos podem continuar visualmente avançando se o código de renderização usar um truque comum e aumentar velocity * time since last update / period of updatea posição visível dos objetos (enquanto sua posição real permanecer inalterada).
precisa saber é o seguinte
2
iffsignificando se e somente se?
precisa saber é o seguinte
3
@HolyBlackCat: isso é discutível. E se eu quiser pausar os gráficos? E se os quadros de animação afetarem o jogo (animações de ataque correspondentes a hitboxes etc.)? A interpolação visual ainda implica que o "tempo" (como no tempo delta do jogo) está passando, mas se o tempo está passando e você não Updateestá entendendo, o que mais está saindo de sincronia? Entradas do player perdidas, eventos de rede não sendo processados, etc.? O jogo deve ser acionado por um único relógio, com "ticks" fixos para lógica ou física do jogo derivados desse relógio, e o estado dos gráficos derivados também acionados pelo mesmo relógio.
Sean Middleditch
@SeanMiddleditch Concordo, quase sempre você pode escrever Draw()dessa maneira, para que sempre desenhe a mesma imagem quando chamado várias vezes seguidas. Deve-se fazer isso, se possível. Mas há casos em que você não sabe com que frequência Draw()será chamada. Por exemplo, se você deseja suporte total (120 FPS reais) para novos monitores de 120 hz e ativar o vsync. What if I want to pause graphics?Então você passa 0 em vez do tempo delta real para o Draw().
precisa saber é o seguinte
2
@HolyBlackCat: Nada do que eu estava falando impediria o uso da renderização de 120hz. Eu absolutamente não estava recomendando uma taxa fixa de compra; isso é apenas amador. Deve haver um relógio de jogo global cujo delta é medido em termos de quadros de renderização que alimentam o valor de acumulação para o tick de lógica de jogo de taxa fixa. Esse relógio global gera gráficos, incluindo interpolação. Você pode pausar os gráficos ajustando a escala do relógio para 0. Você pode ter relógios hierárquicos, por exemplo, a interface do usuário ainda é executada e animada, enquanto a interpolação de caracteres é interrompida com muita facilidade.
Sean Middleditch
7

O ponto aqui é a separação das coisas do modelo que não são o modelo.

A lógica do jogo é o modelo conforme mencionado em

Todos esses são padrões de arquitetura de software relacionados e diferentes. Mas, em todos os casos, o Modelo é a mesma coisa: é a lógica real e o estado real.

É o momento em que o software de negócios é chamado de lógica de negócios e codifica algumas das políticas de negócios. Por exemplo, se você está codificando algo para um banco, para calcular faturas de cartão de crédito, a funcionalidade de fazer com que alguém não precise pagar juros se liquidar sua dívida em menos de 30 dias faz parte da lógica de negócios, ela vive no modelo. Por exemplo, ele não fica em uma das camadas exibidas. O código para imprimir uma fatura, por exemplo, não edita o texto com base em suas ações. Este exemplo talvez destaca por que você pode querer organizar seu código dessa maneira.

O mesmo vale para a lógica do jogo.

Imagine que em algum momento seu jogo foi portado para outro console. Pode ajudar a imaginar algo realmente diferente do seu objetivo atual. Por exemplo, se você está alvejando algo com um gamepad / controlador, imagine que seu jogo seja portado para um tablet com tela sensível ao toque. A lógica do jogo é a parte do código que não muda quando você o move.

Se seu jogo era algo parecido com um jogo de estratégia militar, imagine que ele foi convertido no jogo de tabuleiro mais complexo do mundo. A lógica do jogo são as seções do código que correspondem diretamente às linhas do livro de regras. (Nem todas as linhas do livro de regras, nem aquelas sobre peças em movimento, mas algumas.).

A lógica do jogo é o que nunca muda, independentemente da forma.

Lyndon White
fonte