Plataformas 2D: por que tornar a física dependente da taxa de quadros?


12

"Super Meat Boy" é um jogo de plataformas difícil lançado recentemente para PC, exigindo controle excepcional e salto perfeito em pixels. O código de física no jogo depende da taxa de quadros, que está bloqueada para 60fps; isso significa que se o seu computador não puder rodar o jogo a toda velocidade, a física ficará louca, causando (entre outras coisas) seu personagem correr mais devagar e cair no chão. Além disso, se o vsync estiver desativado, o jogo corre extremamente rápido.

Os experientes em programação de jogos 2D poderiam ajudar a explicar por que o jogo foi codificado dessa maneira? Não seria um loop físico funcionando a uma taxa constante uma solução melhor? (Na verdade, acho que um loop de física é usado para partes do jogo, já que algumas das entidades continuam a se mover normalmente, independentemente da taxa de quadros. Seu personagem, por outro lado, roda exatamente [fps / 60] o mais rápido.)

O que me incomoda nessa implementação é a perda de abstração entre o mecanismo do jogo e a renderização gráfica, que depende de coisas específicas do sistema, como monitor, placa gráfica e CPU. Se, por qualquer motivo, seu computador não suportar o vsync ou o jogo a exatamente 60fps, ele será quebrado de maneira espetacular. Por que a etapa de renderização influencia de alguma forma os cálculos da física? (Atualmente, a maioria dos jogos atualmente diminui a velocidade do jogo ou ignora os quadros.) Por outro lado, entendo que os criadores de plataformas da velha escola do NES e do SNES dependiam de uma taxa de quadros fixa para grande parte de seu controle e física. Por que isso é possível e seria possível criar um modificador nesse sentido sem a dependência da taxa de quadros? Existe necessariamente uma perda de precisão se você separar a renderização gráfica do restante do mecanismo?

Obrigado e desculpe se a pergunta foi confusa.


Tangencial para sua pergunta. Aqui está um ótimo artigo que aborda exatamente os problemas que você está descrevendo e a maneira "correta" de lidar com timesteps e taxas de quadros. gafferongames.com/game-physics/fix-your-timestep
num1

Realmente me surpreendeu que eles fizessem dessa maneira. Suponho que deve ser porque foi construído principalmente para console, onde a taxa de quadros pode ser confiável. Desapontante!
Iain

Respostas:


7

Por quê?

Um punhado de razões, faça a sua escolha: eles não sabiam melhor. .É mais rápido e fácil de implementar. Eles estavam mais focados na jogabilidade e menos nos casos extremos que podem não surgir na maioria dos casos.

Você fez um bom trabalho ao explicar por que não. Tenho certeza que você notou que existem muitos tópicos que abordam o assunto . Não sei se você encontrará uma resposta satisfatória além das que listei.


"Eles não sabiam nada melhor" descreve por que eu adotei essa abordagem com "Jack is a Fool". Mas - confiei bastante em chamar o dt desde o último quadro com toda a minha lógica. Mas - com coordenadas de ponto flutuante, pode levar a algum estranho, difícil de erros replicar
lochok

4

O SMB era originalmente um jogo de console, onde é seguro assumir que é capaz de rodar a 60fps em todos os Xbox 360 (bem, talvez 50 para alguns jogadores PAL). Supondo que um timestep fixo simplifique bastante o código.

Embora seja fácil dimensionar muitas coisas com um timestep variável - 'pos + = speed * timestep', fica bastante complicado fazê-lo corretamente quando você está lidando com acelerações e taxas de mudança de aceleração, e assim por diante.

A dissociação entre jogabilidade e renderização é uma boa solução em teoria , mas implementá-la bem (com boa interpolação) é bastante complicada e as coisas podem facilmente ficar confusas. É bastante incomum que essa técnica seja usada em jogos reais (embora alguns grandes jogos o façam, principalmente jogos RTS, mas mais para sincronização de jogos em rede).

Ao projetar também para uma resolução de tela fixa e uma taxa de quadros fixa, há outra coisa que você pode fazer para tornar a rolagem ainda mais suave. Você pode garantir que o jogo role em um número inteiro de pixels por quadro - evitando qualquer 'subpixel oscilação' que você possa obter rolando um número fracionário de pixels por quadro.


1

A solução óbvia é ter 2 loops em paralelo - a renderização a cada 1/60 de segundo e o jogo em loop a cada 1/60 de segundo.

Mas com minha experiência em Flash (AS3, no qual tenho certeza de que o Super Meat Boy foi criado), o agendador nem sempre é muito preciso. A precisão também depende muito do ambiente. No flash player independente, ele pode ter resolução abaixo de milissegundos. Mas quando executado em alguns navegadores da Web, sua precisão se torna a da taxa de quadros.

Portanto, a maneira mais próxima de desacoplar os loops de renderização e lógica do jogo é basear todos os movimentos no tempo (e executar cada quadro com base no tempo decorrido desde o último quadro). Isso pode introduzir um pouco de matemática mais complicada (como aplicar a gravidade continuamente, em vez de aumentar a velocidade de um objeto em intervalos definidos). Como o jogo pode demorar um segundo e, em seguida, seu jogador mover 200 pixels em uma única etapa, a detecção e a resposta a colisões podem se tornar ainda mais complicadas. Se o programador estivesse realizando uma detecção de colisão baseada em quadros (verificando uma colisão a cada passo), ele também teria que mudar para a detecção de colisão baseada no tempo. E se eles quisessem que parecesse natural, teriam que usar o método da gravidade descrito acima, que faz com que o movimento do objeto seja uma curva (em oposição a uma linha),


2
O Meat Boy original era um jogo em Flash. Super Meat Boy é um jogo de C ++.
Archagon

0

Eu não acho muito pedir jogos 2D para PC para jogar a 60fps. Até a maioria dos jogos 2D são acelerados por hardware agora, então, pessoalmente, não me preocuparia com o requisito de fps.

A verdadeira questão é por que você não usaria um pixel, os jogos estão cheios de truques e atalhos.

Se você está fazendo um jogo baseado em física (talvez jogar pássaros?), A resposta é óbvia, mas um super mario clone? movimento baseado no tempo pode ser um pouco demais.


Não é difícil reproduzi-los a 60fps, mas os displays com taxas de atualização nativas de 50Hz, 70-85Hz e 120Hz ainda são facilmente encontrados.

0

Para evitar comportamentos estranhos na 2ª física que eles estão usando?

Honestamente, eu posso apenas adivinhar. Vou tentar uma explicação:

No coração do jogo está o loop principal do jogo. Que basicamente se parece com isso:

while(gameRunning)
{
  updateGame(timestep);
  renderGame(timestep);
}

updateGame atualiza o gameState: verifica a entrada do jogador, aplica a entrada do jogador ao mundo do jogo e executa a simulação de física etc.

O renderGame desenha e anima o jogo.

Isso combina a atualização física com a renderização. Se você quiser dissociá-lo, precisará usar threads e sincronizar adequadamente cada acesso a dados da renderização e do thread gameUpdate com dados compartilhados, por exemplo, posição do jogador. Isto pode ser feito.

Outro problema pode ser que a simulação física exija um passo constante no tempo para ser estável. Isso depende de como o supermeatboy calcula o movimento (novamente, podemos adivinhar como eles fizeram isso;)).

Uma abordagem ingênua seria (que eu estou usando no meu jogo * suspiro *):

position=position+speed*timestep;
speed=speed+acceleration*timestep;

Isso se chama Integração Euler e geralmente é considerado uma má ideia. Se o timestep não for constante, ocorrerão erros de cálculo, o que tornará a simulação menos estável. O objeto pode se mover em velocidades excessivas ou não todas ou voar através das paredes da tela. Mesmo que o timestep seja constante, a Integração Euler causa pequenos erros de cálculo. Melhor usar outro método de integração como o RK4 ou usar um mecanismo de física.

Além disso, pode haver problemas na detecção de colisão se o timestep ficar muito grande. Como as colisões não são verificadas entre duas atualizações do jogo, os objetos podem passar por obstáculos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.