Eu tenho alguns programas antigos. Eu peguei um computador Windows do início dos anos 90 e tentei executá-los em um computador relativamente moderno. Curiosamente, eles correram a uma velocidade incrivelmente rápida - não, os 60 quadros por segundo são rápidos, mas sim o tipo oh-meu-deus-o-personagem-está-andando-na-velocidade-do-som velozes. Eu pressionava uma tecla de seta e o sprite do personagem percorria a tela muito mais rápido que o normal. A progressão do tempo no jogo estava acontecendo muito mais rápido do que deveria. Existem até programas feitos para desacelerar sua CPU, para que esses jogos sejam realmente jogáveis.
Ouvi dizer que isso está relacionado ao jogo, dependendo dos ciclos da CPU, ou algo assim. Minhas perguntas são:
- Por que jogos mais antigos fazem isso e como eles se safaram?
- Como os jogos mais recentes não fazem isso e são executados independentemente da frequência da CPU?
FOR F IN 0 TO 1000; NEXT F;
Respostas:
Eu acredito que eles assumiram que o relógio do sistema funcionaria a uma taxa específica e amarraram seus cronômetros internos a essa taxa de relógio. A maioria desses jogos provavelmente rodava no DOS e era de modo real (com acesso completo e direto ao hardware) e supunha que você estivesse executando um sistema iirc 4,77 MHz para PCs e qualquer processador padrão desse modelo executado para outros sistemas como o Amiga.
Eles também adotaram atalhos inteligentes com base nessas suposições, incluindo a economia de um pouquinho de recursos ao não escrever loops de tempo internos dentro do programa. Eles também consumiram o máximo de energia possível do processador - o que era uma idéia decente nos dias de chips lentos, geralmente resfriados passivamente!
Inicialmente, uma maneira de contornar a velocidade diferente do processador era o bom e velho botão Turbo (que tornava o sistema mais lento). Os aplicativos modernos estão no modo protegido e o sistema operacional tende a gerenciar recursos - eles não permitiriam que um aplicativo DOS (que esteja executando o NTVDM em um sistema de 32 bits de qualquer maneira) use todo o processador em muitos casos. Em resumo, os sistemas operacionais tornaram-se mais inteligentes, assim como as APIs.
Muito baseado neste guia no Oldskool PC, onde a lógica e a memória falharam - é uma ótima leitura, e provavelmente vai mais fundo no "porquê".
Coisas como CPUkiller usam o máximo de recursos possível para "desacelerar" o sistema, o que é ineficiente. Seria melhor usar o DOSBox para gerenciar a velocidade do relógio que seu aplicativo vê.
fonte
game loop
. Existem basicamente 2 métodos. 1) Corra o mais rápido possível e aumente a velocidade de movimento, etc, com base na rapidez com que o jogo corre. 2) Se você for rápido demais, aguarde (sleep()
) até estarmos prontos para o próximo 'tick'.Como complemento à resposta do Journeyman Geek (porque minha edição foi rejeitada) para as pessoas interessadas na parte de codificação / perspectiva do desenvolvedor:
Do ponto de vista dos programadores, para os interessados, os tempos do DOS eram momentos em que cada escala de CPU era importante; portanto, os programadores mantinham o código o mais rápido possível.
Um cenário típico em que qualquer programa será executado na velocidade máxima da CPU é simples (pseudo C):
isso vai durar para sempre, agora, vamos transformar esse trecho de código em um jogo pseudo-DOS:
a menos que as
DrawGameOnScreen
funções usem buffer duplo / sincronização V (que era meio cara nos dias em que os jogos do DOS eram criados), o jogo será executado na velocidade máxima da CPU. Nos dias atuais, o i7 móvel seria executado em torno de 1.000.000 a 5.000.000 de vezes por segundo (dependendo da configuração do laptop e do uso atual da CPU).Isso significaria que, se eu pudesse fazer com que qualquer jogo DOS funcionasse na minha CPU moderna em minhas janelas de 64 bits, poderia obter mais de mil (1000!) FPS, o que é muito rápido para qualquer ser humano jogar se o processamento físico "assumir" que ele é executado entre 50-60 fps.
O que os desenvolvedores do dia atual (podem) fazem é:
*** dependendo da configuração da placa gráfica / driver / sistema operacional, pode ser possível.
Para o ponto 1, não há exemplo que mostrarei porque não há realmente nenhuma "programação". É apenas usando os recursos gráficos.
Como nos pontos 2 e 3, mostrarei os trechos de código e explicações correspondentes:
2:
Aqui você pode ver a entrada do usuário e a física levar em consideração a diferença de horário, mas ainda assim você pode obter mais de 1000 FPS na tela porque o loop está sendo executado o mais rápido possível. Como o mecanismo de física sabe quanto tempo passou, ele não precisa depender de "nenhuma suposição" ou "uma certa taxa de quadros" para que o jogo funcione na mesma velocidade em qualquer CPU.
3:
O que os desenvolvedores podem fazer para limitar a taxa de quadros para, por exemplo, 30 FPS não é nada difícil, basta dar uma olhada:
O que acontece aqui é que o programa conta quantos milissegundos se passou, se uma certa quantia for atingida (33 ms) e redesenha a tela do jogo, aplicando efetivamente uma taxa de quadros próxima de ~ 30.
Além disso, dependendo do desenvolvedor, ele / ela pode optar por limitar TODO o processamento a 30 qps com o código acima ligeiramente modificado para isso:
Existem alguns outros métodos, e alguns deles eu realmente odeio.
Por exemplo, usando
sleep(<amount of milliseconds>)
.Sei que esse é um método para limitar a taxa de quadros, mas o que acontece quando o processamento do jogo leva 3 milissegundos ou mais? E então você executa o sono ...
isso resultará em uma taxa de quadros menor do que aquela que somente
sleep()
deveria estar causando.Vamos, por exemplo, dormir 16 ms. isso faria o programa rodar a 60 hz. agora o processamento dos dados, entrada, desenho e todo o material leva 5 milissegundos. agora estamos em 21 milissegundos para um loop, o que resulta em pouco menos de 50 hz, enquanto você ainda pode facilmente estar a 60 hz, mas por causa do sono é impossível.
Uma solução seria fazer um sono adaptativo na forma de medir o tempo de processamento e deduzir o tempo de processamento do sono desejado, resultando na correção de nosso "bug":
fonte
Uma causa principal é o uso de um loop de atraso que é calibrado quando o programa é iniciado. Eles contam quantas vezes um loop é executado em um período conhecido e o dividem para gerar atrasos menores. Isso pode ser usado para implementar uma função sleep () para acelerar a execução do jogo. Os problemas surgem quando esse contador é maximizado devido aos processadores serem muito mais rápidos no loop que o pequeno atraso acaba sendo muito pequeno. Além disso, os processadores modernos alteram a velocidade com base na carga, às vezes até por núcleo, o que diminui ainda mais o atraso.
Para jogos para PC realmente antigos, eles rodavam o mais rápido possível, sem levar em conta o ritmo do jogo. Esse foi mais o caso nos dias do IBM PC XT, no entanto, onde existia um botão turbo que atrasava o sistema para corresponder a um processador de 4,77 mhz por esse motivo.
Jogos modernos e bibliotecas como o DirectX têm acesso a cronômetros de alta precessão, portanto, não é necessário usar loops de atraso com base em código calibrado.
fonte
Todos os primeiros PCs rodavam na mesma velocidade no começo, portanto não havia necessidade de explicar a diferença de velocidades.
Além disso, muitos jogos no começo tinham uma carga de CPU bastante fixa, por isso era improvável que alguns quadros rodassem mais rápido que outros.
Hoje em dia, com seus filhos e seus atiradores sofisticados de FPS, você pode olhar para o chão um segundo e, no Grand Canyon, o próximo, a variação de carga acontece com mais frequência. :)
(E poucos consoles de hardware são rápidos o suficiente para rodar jogos a 60 fps constantemente. Isso se deve principalmente ao fato de os desenvolvedores de console optarem por 30 Hz e tornar os pixels duas vezes mais brilhantes ...)
fonte