Mudança Média De Fps


Você precisa de uma média lisa, a maneira mais fácil é tomar a resposta atual (o tempo para desenhar a última moldura) e combiná-la com a resposta anterior. Ao ajustar a proporção de 0,9 0,1, você pode alterar a constante de tempo - é a rapidez com que o número responde às mudanças. Uma fração maior a favor da resposta antiga dá uma mudança mais lenta e suave, uma grande fração a favor da nova resposta dá um valor de mudança mais rápido. Obviamente, os dois fatores devem ser adicionados a um respondido 17 de setembro 08 às 20:33 Mas, como você ressalta, há muita variação no tempo necessário para renderizar um único quadro e, a partir de uma perspectiva de UI, atualizando o valor do fps no A taxa de quadros não é utilizável (a menos que o número seja muito estável). O que você quer é provavelmente uma média móvel ou algum tipo de contador de reposição binning. Por exemplo, você poderia manter uma estrutura de dados da fila que continha os tempos de renderização para cada um dos últimos 30, 60, 100 ou quais-que-você-frames (você poderia projetá-lo para que o limite fosse ajustável em tempo de execução). Para determinar uma aproximação decente de fps, você pode determinar a média de fps de todos os tempos de renderização na fila: quando você acabou de renderizar um novo quadro, encaue um novo tempo de renderização e desanexa um tempo de renderização antigo. Alternativamente, você pode desativar somente quando o total dos tempos de renderização excedeu algum valor predefinido (por exemplo, 1 segundo). Você pode manter o último valor de fps e um último carimbo de data e hora atualizado para que você possa ativar quando atualizar a figura do fps, se desejar. Embora com uma média móvel se você tiver formatação consistente, a impressão de fps média instantânea em cada quadro provavelmente seria ok. Outro método seria ter um contador de reposição. Mantenha um timestamp preciso (milissegundo), um contador de quadros e um valor de fps. Quando você terminar de renderizar um quadro, incremente o contador. Quando o contador atinge um limite pré-definido (por exemplo, 100 quadros) ou quando o tempo transcorrido pelo timestamp tiver passado algum valor pré-definido (por exemplo, 1 segundo), calcule o fps: então, reinicie o contador em 0 e defina o timestamp para o hora atual. Respondeu 17 de setembro 08 às 20:48 Há pelo menos duas maneiras de fazê-lo: o primeiro é o que outros já mencionaram antes de mim. Eu acho que é o caminho mais simples e preferido. Você apenas para acompanhar cn: contador de quantos quadros você selecionou timestart: o tempo desde que você começou a contar timenow: a hora atual Calculando o fps neste caso é tão simples como avaliar esta fórmula: FPS cn (timenow - timestart). Então, há a melhor maneira que você gostaria de usar algum dia: digamos que você tenha quadros a serem considerados. Eu uso esta notação: f0, f1. Fi-1 para descrever o tempo que demorou para renderizar frame 0, frame 1. frame (i-1), respectivamente. Então, a definição matemática de fps após i frames seria E a mesma fórmula, mas apenas considerando i-1 frames. Agora, o truque aqui é modificar o lado direito da fórmula (1) de forma a conter o lado direito da fórmula (2) e substituí-lo pelo lado esquerdo. Assim como (você deve vê-lo mais claramente se você escrevê-lo em um papel): Então, de acordo com esta fórmula (minha habilidade derivada de matemática é um pouco enferrujada embora), para calcular o novo fps, você precisa saber o fps do quadro anterior , A duração que demorou para renderizar o último quadro e o número de quadros que você renderizou. Isso pode ser um exagero para a maioria das pessoas, por isso não o postei quando o implementei. Mas é muito robusto e flexível. Ele armazena uma fila com os últimos tempos de quadros, para que ele possa calcular com precisão um valor médio de FPS muito melhor do que apenas levar em consideração o último quadro. Ele também permite que você ignore um quadro, se você está fazendo algo que você sabe que irá destruir artificialmente esse tempo de quadros. Ele também permite que você altere o número de quadros para armazenar na fila à medida que ele é executado, para que você possa testá-lo sobre o que é o melhor valor para você. Respondeu 23 de maio 13 às 19:41 boas respostas aqui. O modo como o implementa é dependente do que você precisa. Eu prefiro a média de corrida um tempo de tempo 0.9 lastframe 0.1 pelo cara acima. No entanto, eu pessoalmente gosto de aumentar a minha média mais fortemente em relação aos dados mais recentes, porque em um jogo são SPIKES que são os mais difíceis de espreitar e, portanto, de maior interesse para mim. Então, eu usaria algo mais como uma divisão .7 .3 fará com que um espetáculo apareça muito mais rápido (embora seu efeito caia fora da tela mais rápido também. Veja abaixo) Se o seu foco estiver em tempo de RENDER, então a divisão .9.1 Funciona muito bem e geralmente tende a ser mais suave. Por favor, para pontos de jogo, os pontos da Áfísica são muito mais uma preocupação, pois normalmente o que faz o seu jogo parecer molhado (o que muitas vezes é pior do que uma baixa taxa de quadros, supondo que não estivesse mergulhando abaixo de 20 fps). Então, o que eu faria também é adicionar algo assim : (Preencha 3.0f com qualquer magnitude que você ache para ser um pico inaceitável) Isso permitirá que você encontre e, assim, resolva os problemas do FPS no final do quadro, eles acontecem. Respondeu 13 de novembro 08 às 22:56 Eu gosto do tempo 0.9 lastframe 0.1 cálculo médio que faz a exibição mudar suavemente. Ndash Fabien Quatravaux 27 de setembro 12 às 13:00 Você poderia manter um contador, incrementá-lo depois que cada quadro é renderizado e, em seguida, redefinir o contador quando estiver em um novo segundo (armazenando o valor anterior como os últimos segundos de quadros renderizados) Em ( C como) pseudocódigo estes dois são o que eu usei em aplicações industriais de processamento de imagens que tiveram que processar imagens de um conjunto de câmeras desencadeadas externamente. As variações na taxa de quadros tiveram uma fonte diferente (produção mais lenta ou mais rápida na correia), mas o problema é o mesmo. (Eu suponho que você tenha uma chamada simples timer. peek () que lhe dá algo como o nr de msec (nsec) desde o início do aplicativo ou a última chamada) Solução 1: rápido, mas não atualizado a cada quadro Solução 2: atualizado cada quadro, Requer mais memória e CPU respondeu 17 de setembro 08 às 22:03 respondeu 6 de janeiro 13 às 0:42 Heres como eu faço isso (em Java): respondeu 18 de maio 13 às 17:41 Um sistema muito melhor do que usar uma grande variedade de antigos Framerates é apenas fazer algo como isto: este método usa muito menos memória, requer muito menos código e coloca mais importância em framerates recentes do que os framerates antigos, enquanto ainda suaviza os efeitos de mudanças repentinas de framerate. Respondido 16 de novembro às 21:20 Sua resposta 2017 Stack Exchange, IncA Explicação detalhada dos jogos de JavaScript e do tempo O loop principal é uma parte central de qualquer aplicação em que o estado muda ao longo do tempo. Nos jogos, o loop principal geralmente é chamado de loop do jogo. E normalmente é responsável pela computação de física e AI, além de desenhar o resultado na tela. Infelizmente, a grande maioria dos loops principais encontrados on-line - especialmente aqueles em JavaScript - estão escritos incorretamente devido a problemas de tempo. Eu deveria saber que escrevi minha parte justa dos maus. Esta publicação pretende mostrar-lhe por que muitos loops principais precisam ser corrigidos e como escrever um loop principal corretamente. Se você preferiu ignorar a explicação e apenas obter o código para fazê-lo direito. Você pode usar o meu projeto MainLoop. js de código aberto. Uma primeira tentativa, vamos escrever um jogo. Por simplicidade, basta desenhar uma caixa oscilante: vamos fazer aparecer: Ok, isso não foi tão ruim. Agora, vamos implementar o aplicativo JavaScript. Primeiro, nossa caixa precisará de algumas propriedades para determinar sua posição e velocidade. Permite também lançar uma função, desenhar (). Para exibir as novas posições da caixa: agora a lógica dos jogos. Queremos que a caixa se mova para frente e para trás, tão bem, apenas adicione a velocidade à posição. É aí que as coisas começam a dar errado, como você verá em um momento. E agora vamos fazê-lo funcionar. Para fazer isso, precisamos de um loop que apenas continue executando a função update () para fazer a caixa se mover e, em seguida, a função draw () para atualizar sua visualização na tela. Como devemos fazer isso Se você já escreveu jogos em outro idioma, você pode pensar em um loop de tempo: No entanto, o JavaScript é de um único thread, o que significa que essa abordagem impedirá o navegador fazer quase qualquer outra coisa nessa página. Como resultado, o navegador irá bloquear e, após alguns segundos, ele mostrará ao usuário um erro perguntando se eles querem encerrar seu script. Você quer que seu jogo seja executado por mais de alguns segundos, então isso não é bom. Precisamos de uma maneira de renderizar o controle do loop do jogo de volta ao navegador por algum tempo, até que o navegador esteja pronto para fazer algum trabalho novamente. Se você estiver familiarizado com o JavaScript, você pode pensar em setTimeout () ou setInterval () - funções que permitem a execução do código após uma determinada quantidade de tempo. Esta é uma ideia bastante razoável, mas nos navegadores há uma maneira melhor: requestAnimationFrame (). É uma função bastante nova com um forte suporte do navegador (no momento da escrita, todos os navegadores, exceto o IE9 e abaixo, o suportam). Você passa um retorno de chamada para esta função e executa esse retorno de chamada na próxima vez que o navegador estiver pronto para alterar a aparência da página. Em um monitor de 60 Hz, isso significa que um aplicativo otimizado pode desenhar as atualizações (chamadas quadros de pintura) 60 vezes por segundo. Então, seu loop principal tem 1 60 16.667 milésimos de segundo para fazer a coisa toda vez que corre se você quiser atingir esse ideal de 60 quadros por segundo. Bem, cubra um polyfill para node. jsio. js e navegadores menores mais tarde. Tenha em mente que a maioria dos monitores não pode exibir mais de 60 quadros por segundo (FPS). Se os seres humanos podem distinguir as altas taxas de quadros depende da aplicação, mas para referência, o filme geralmente é exibido em 24 FPS, outros vídeos em 30 FPS, a maioria dos jogos é aceitável acima de 30 FPS e a realidade virtual pode exigir 75 FPS para sentir natural. Alguns monitores de jogos vão até 144 FPS. Tudo bem, vamos usar requestAnimationFrame () para escrever esse loop principal. É importante que draw () seja chamado após a atualização () porque queremos que a tela reflita um estado do aplicativo que seja tão atualizado quanto possível. (Observe que as aplicações baseadas em tela podem precisar cuidar para desenhar o primeiro quadro no estado inicial dos aplicativos, antes de qualquer atualização ter ocorrido. Uma abordagem para fazer isso é discutida mais adiante neste artigo.) Algumas postagens na internet especulam que A renderização mais cedo no pedidoAnimationFrame callback pode fazer com que a tela seja pintada mais rapidamente, isso na maioria não é verdade, e mesmo quando é, geralmente é apenas um trade-off entre renderizar o quadro atual mais cedo e renderizar o próximo quadro mais tarde. Isso realmente não importa quando requestAnimationFrame é chamado de novo porque apenas um quadro pode ser executado de uma só vez, mas acho que ele faz o sentido mais lógico para solicitar outro quadro quando o atual for concluído. Problemas de sincronização Até agora, nossa função de atualização () sofre do problema que depende da taxa de quadros. Em outras palavras, se o seu jogo estiver sendo executado lentamente (ou seja, menos quadros por segundo), seu objeto também aparecerá para mover-se lentamente, enquanto que se seu aplicativo estiver sendo executado rapidamente (ou seja, mais quadros por segundo), seu objeto aparecerá Para se mover rapidamente. Ter experiências de jogabilidade tão imprevisíveis é indesejável, especialmente em jogos para vários jogadores. Ninguém quer que seu personagem seja um slowpoke apenas porque seu computador não é tão poderoso. Mesmo nos jogos de um jogador, a velocidade afeta significativamente a dificuldade: os jogos que exigem reações rápidas serão mais fáceis em velocidades lentas e pouco úteis em situações rápidas. Para ver isso por nós mesmos, vamos adicionar a capacidade de acelerar o FPS. Bem, aproveite o fato de que requestAnimationFrame () passa um timestamp para o retorno de chamada. Toda vez que o circuito é executado, bem, verifique se um período mínimo de tempo passou, se bem, renderize o quadro e, se ele não tiver, bem, apenas aguarde a próxima moldura. Você pode ver o quanto mais dolorosamente é lento: precisamos fazer melhor. O problema é que nossa aplicação não está ligada ao tempo real. Como corrigimos isso. Como uma primeira passagem, tentemos multiplicar a velocidade pela quantidade de tempo que passou entre os quadros de renderização, que bem chamam de delta. Então, ao invés de rodar boxPos boxVelocity, em vez disso, execute boxPos boxVelocity delta. Bem, precisa ajustar nossa função de atualização para receber o delta como um parâmetro do loop principal: bons resultados Nossa caixa agora parece mover uma distância constante ao longo do tempo, independentemente da taxa de quadros. Se não se comportar do jeito que você espera. Bem, continue lendo. Problemas de física Tente colocar a velocidade para um valor como 0.8. Dentro de apenas alguns segundos, você notará que a caixa começará a se comportar de forma errática, possivelmente indo para fora da janela visível. Isso não deve acontecer O que deu errado O que está acontecendo é aquele, enquanto que antes que a caixa movesse uma distância constante de cada quadro, agora a caixa está movendo distâncias variadas em cada quadro - e algumas dessas distâncias são bastante grandes. Nos jogos, esse fenômeno pode permitir que os jogadores atravessem paredes, ou impedi-los de saltar sobre os obstáculos. Um segundo problema é que, porque a caixa está movendo uma distância variável em cada quadro, pequenos erros de arredondamento de multiplicar a velocidade com o delta da moldura resultarão na posição das caixas com o tempo. Ninguém poderá jogar exatamente o mesmo jogo porque suas taxas de quadros serão diferentes e isso causará diferentes erros de arredondamento. Isso pode parecer inconsequente, mas, na prática, pode ser visível depois de apenas alguns segundos, mesmo em taxas de quadros normais. Isso não é apenas ruim para os jogadores - também é ruim para o teste, porque se casaram como o nosso programa para produzir exatamente o mesmo resultado, se nós o damos Mesma entrada. Ou seja, queremos que nosso programa seja determinista. Uma solução A visão chave para corrigir nossos problemas de física é que queremos o melhor dos dois mundos: queremos simular uma quantidade constante de tempo no jogo toda vez que executamos nossas atualizações, e ainda assim precisamos simular o tempo decorrido. quadro, armação. Acontece que podemos fazer os dois, apenas executando nossas atualizações várias vezes com um delta de tamanho fixo até que nós simulássemos o tempo todo o tempo que precisamos. Permite ajustar nosso loop principal: tudo o que fizemos foi que separamos a quantidade de tempo simulado em cada atualização () da quantidade de tempo entre os quadros. Nossa função de atualização () não precisa mudar, só precisamos mudar o delta que passamos para que cada atualização () simule uma quantidade fixa de tempo. A função update () agora será executada várias vezes por quadro, se necessário, para simular o tempo total passado desde o último quadro. (Se o tempo transcorrido desde a última moldura for inferior ao tempo de simulação fixo, simplesmente não executaremos uma atualização () até o próximo quadro. Se houver tempo não imitado, isso é menor do que o nosso timestep, então basta sair Para ser simulado durante o próximo quadro. É por isso que precisamos adicionar ao delta em vez de atribuí-lo - porque precisamos manter o tempo restante do último quadro.) Esta abordagem evita erros de arredondamento inconsistentes e garante que não há Saltos gigantes através das paredes entre os quadros. Vamos ver isso em ação: se você ajustar o boxVelocity, verá que nossa caixa agora corre corretamente onde deveria ser. Nice One note: a escolha do valor para nosso timestep não era arbitrária. O denominador efetivamente encapsula os quadros por segundo que os usuários poderão perceber (a menos que o desenho seja interpolado, conforme discutido abaixo). Diminuir o timestep aumenta o FPS máximo percebido ao custo de executar a atualização () mais vezes por quadro quando o FPS real é menor do que o máximo. Uma vez que a execução da atualização (), mais vezes leva mais tempo para processar, isso pode diminuir a taxa de quadros. Se retardar demais, isso poderia levar a uma espiral de morte. Panic Spiral of death Infelizmente, mais uma vez, introduzimos um novo problema. Em nossa primeira tentativa, se os quadros demorassem muito para atualizar e renderizar, a taxa de quadros apenas diminuiu até que cada quadro durasse o suficiente para que as atualizações ocorressem. No entanto, nossas atualizações dependem do tempo agora. Se um quadro leva muito tempo para simular, o próximo precisará simular uma quantidade de tempo ainda maior. Isso significa que é preciso executar a atualização () mais vezes, o que significa que nosso novo quadro demorará ainda mais para simular, e assim por diante. Até o aplicativo congelar e falhar. Isso é chamado de espiral da morte. Não é bom. Geralmente, estavam bem desde que nosso timestep esteja configurado para um valor que seja alto o suficiente para que as chamadas de atualização geralmente levem menos tempo do que a quantidade de tempo que eles estão simulando. No entanto, isso será diferente para hardware e carga de trabalho diferentes. Além disso, o JavaScript está falando sobre isso: temos muito pouco controle sobre o ambiente de execução. Se o usuário mudar para outra guia, o navegador irá parar de pintar quadros, e bem acabar com muito tempo para simular quando o usuário voltar. Se for muito tempo, o navegador irá pendurar. Verificação de sanidade Precisamos de uma rota de fuga. Permite adicionar uma verificação de sanidade ao nosso loop de atualização: o que devemos fazer em nossa função de pânico Bem, isso depende. Os jogos multiplayer baseados em turnos usam uma técnica de rede chamada lockstep que garante que todos os jogadores estejam experimentando o mesmo ritmo. Isso significa que todos os jogadores experimentam o jogo no ritmo do mais lento. Se um jogador se atrasar por muito tempo, esse jogador cai para que os outros jogadores não sejam arrastados para baixo também. Então, nos jogos de lockstep, o jogador acabará por se deixar cair. Nos jogos multiplayer que não usam o Lockstep, como atiradores de primeira pessoa, geralmente existe um servidor com um estado autoritário do jogo. Ou seja, o servidor recebe todos os insumos dos jogadores e calcula o que o mundo deveria ter para impedir que os jogadores trapaceiam. Se um jogador se afastar muito longe do estado autoritário, como seria o caso em um pânico, então o jogador precisa ser encaminhado para o estado autoritário. (Na prática, isso é desorientador, de modo que o jogador pode recuar em uma função de atualização alternativa temporária que irá facilitar o mundo do cliente de volta ao mundo do servidor mais facilmente). Uma vez que encaixamos o usuário em seu novo estado, não queremos que eles Ainda há um monte de tempo para simular, porque nós efetivamente encaminhamos rapidamente através dele. Então, podemos livrar-se disso: se o servidor fizer isso, ele apresentaria comportamento não determinista, mas apenas o servidor precisa que o jogo prossiga de forma determinista para que seja bom no cliente em um jogo em rede. Em jogos de jogador único, pode ser aceitável permitir que o aplicativo continue funcionando por algum tempo para ver se ele irá recuperar o atraso. No entanto, isso também pode fazer com que o aplicativo pareça estar executando muito rapidamente para alguns quadros à medida que transita pelos estados intermediários. Uma alternativa que pode ser aceitável é simplesmente ignorar o tempo transcorrido não simulado como fizemos acima no caso de rede não lockstep em rede. Mais uma vez, isso introduz um comportamento não determinista, mas você pode decidir que um pânico é uma circunstância extraordinária e todas as apostas estão desativadas. Em todos os casos, se o aplicativo entrar em pânico com freqüência e não por estar em uma guia de fundo, isso provavelmente é uma indicação de que o loop principal está sendo executado muito devagar. Você pode querer aumentar seu timestep. Controle de FPS Uma maneira complementar de evitar espirais de morte (e baixas taxas de quadros em geral) é monitorar a taxa de quadros e ajustar as atividades que estão ocorrendo no loop principal se a taxa de quadros for muito baixa. Muitas vezes, uma queda na taxa de quadros provavelmente será notável antes de um pânico ocorrer, para que possamos prevenir o pânico ao estar preparado. Há muitas maneiras de rastrear a taxa de quadros. Uma maneira é manter o controle de quantos quadros foram renderizados em cada segundo por algum período de tempo (digamos, os últimos 10 segundos) e a média deles. No entanto, isso é um pouco mais intensivo em desempenho do que o wed, e seria bom pesar a média em relação a segundos mais recentes. Uma abordagem mais fácil que essa ponderação é usar um FPS médio exponencial em nosso loop principal: o 0.25 é um parâmetro de decaimento - é essencialmente como os pesos mais recentes são ponderados. A variável fps agora contém nossos quadros estimados por segundo. Ótimo. Agora, o que devemos fazer com isso. Bem, o que é óbvio é exibi-lo: podemos usar o FPS de maneiras mais úteis. Se for muito baixo, podemos sair do jogo, diminuir a qualidade visual, parar ou reduzir atividades fora do loop principal, como manipuladores de eventos ou reprodução de áudio, realizar atualizações não críticas menos freqüentemente ou aumentar o timestep. (Observe que esta última opção resulta em mais tempo sendo simulado por chamada de atualização (), o que faz com que o aplicativo se comporte de forma não determinística, portanto, ele deve ser usado com moderação, se for o caso.) Se o FPS voltar, podemos reverter esses ações. Começos e finais Pode ser útil ter funções que o seu loop principal chama no início e no final do loop (vamos chamá-los begin () e end (). Respectivamente) para fazer a instalação e limpeza. Geralmente, begin () é útil para processar a entrada antes que as atualizações sejam executadas (por exemplo, projéteis de desova quando o jogador pressiona a chave da arma de fogo). Se houver ações de longa duração que precisam ser tomadas em resposta à entrada do usuário, processá-las em pedaços no loop principal em vez de todas as vezes nos manipuladores de eventos podem ser úteis para evitar atrasos nos quadros. A função final () também é útil para executar incrementalmente atualizações de longa duração que são sensíveis ao tempo, bem como para ajustar as mudanças no FPS. Escolhendo um timestep Geralmente, 1000 60 é uma boa escolha para a maioria dos casos porque a maioria dos monitores corre a 60 Hz. Se você está achando que seu aplicativo é muito intensivo em desempenho, você pode querer configurá-lo para, por exemplo, 1000 30. Isso efetivamente encapsula sua taxa de quadros perceptível em 30 FPS (a menos que o desenho seja interpolado conforme discutido abaixo). Observe que os quadros podem ser acelerados dependendo do seu monitor e driver de gráficos, então o máximo que você definiu pode não ser o máximo que você obtém na prática. Se o seu jogo for executado rapidamente e você quiser simulações mais precisas, você poderia considerar os valores máximos de FPS das telas de jogos high-end: 75, 90, 120 e 144. Muito além disso e você acabará desacelerando. Considerações de desempenho Se o seu desempenho não é tão bom quanto você gostaria, a interpolação de desenho e o uso de web workers são duas mudanças estruturais que você pode fazer, que podem ter um impacto sólido. Interpolar desenho Depois que nossas atualizações terminarem, geralmente haverá algum tempo no delta que é menor que um timestep completo. Passar a porcentagem de um timestep que ainda não foi simulado até a função draw () permite interpolar entre os quadros. Este alisamento visual ajuda a reduzir a gagueira mesmo em altas taxas de quadros. A gagueira aparece porque o tempo simulado pela atualização () eo tempo entre as chamadas draw () geralmente são diferentes. Para ilustrar, se update () avançar a simulação em cada barra vertical na primeira linha abaixo, e as chamadas draw () acontecem em cada barra vertical na segunda linha abaixo, então alguns quadros terão tempo restante que ainda não foram simulados por Update () quando a renderização ocorre no draw (): Para desenhar () para interpolar o movimento para fins de renderização, o estado dos objetos após a última atualização () deve ser retido e usado para calcular um estado intermediário. Observe que isso significa que renders será até uma atualização () por trás. Isso ainda é melhor do que a extrapolação (estado de projeto de objetos após uma atualização futura) que pode produzir resultados bizarros. Armazenar vários estados pode ser difícil de configurar, e tenha em mente que executar esse processo leva tempo que pode empurrar a taxa de quadros para baixo, por isso pode não valer a pena, a menos que a gagueira seja visível. Heres como podemos implementar a interpolação para nossa caixa: Use o Web Workers para atualizações Como em tudo no loop principal, o tempo de execução da atualização () afeta diretamente a taxa de quadros. Se a atualização () demorar o tempo suficiente para que a taxa de quadros caia abaixo da taxa de quadros de destino (orçada), partes da função de atualização () que não precisam ser executadas entre cada quadro podem ser movidas para os Trabalhadores da Web. (Diversas fontes na internet, por vezes, sugerem outros padrões de agendamento usando setTimeout () ou setInterval (). Essas abordagens às vezes oferecem melhorias modestas com mudanças mínimas no código existente, mas porque o JavaScript é de um único thread, as atualizações ainda bloquearão a renderização e arrastam para baixo A taxa de quadros. O uso dos Trabalhadores da Web é mais trabalho, mas eles são executados em segmentos separados, então liberam mais tempo no loop principal.) Uma lista não exaustiva de coisas para pensar quando você está considerando usar os Trabalhadores da Web: Perfil do seu código Antes de fazer o trabalho para movê-lo para Web Workers. Pode ser a renderização que é o gargalo, caso em que a primeira solução deve ser diminuir a complexidade visual da cena. Não faz sentido mover todo o conteúdo da atualização () para os trabalhadores, a menos que sua função draw () possa interpolar entre os quadros conforme discutido acima. A fruta mais baixa para sair da atualização () é atualizações de fundo (como calcular a felicidade dos cidadãos em um jogo de construção de cidades), a física que não afeta a cena (como bandeiras ondulando no vento) e qualquer coisa que esteja ocluída ou acontecendo Longe da tela. Se draw () precisa interpolar a física com base na atividade que ocorre em um trabalhador, o trabalhador precisa passar o valor de interpolação para o segmento principal, de modo que está disponível para desenhar (). Os Trabalhadores da Web não podem acessar o estado do segmento principal, então eles não podem modificar objetos diretamente em sua cena. Mover dados de e para os Trabalhadores da Web é uma dor. A maneira mais rápida de fazê-lo é com objetos transferíveis: basicamente, você pode passar um ArrayBuffer para um trabalhador, destruindo a referência original no processo. Você pode ler mais sobre Trabalhadores da Web e objetos transferíveis em HTML5 Rocks. Começando e parando Até agora, uma vez que o nosso jogo começou o loop principal, não tivemos uma maneira de detê-lo. Permite introduzir as funções start () e stop () para gerenciar se o aplicativo está em execução. A primeira coisa que precisamos fazer é descobrir como parar de solicitar quadros. Uma maneira seria manter uma variável booleana em execução que controle se o loop principal chama requestAnimationFrame () novamente. Isso normalmente está bem, mas se o jogo é iniciado e parado rapidamente, um quadro será solicitado sem nenhuma maneira de cancelá-lo. Então, em vez disso, o que precisamos é uma maneira de cancelar quadros. Por sorte, há uma função para isso: cancelAnimationFrame (). Solicitar um quadro realmente retorna um ID de quadro que podemos passar para a função de cancelamento: Certifique-se de fazer isso também na condição de aceleração do FPS, se você o manteve ao redor. Agora, vamos implementar stop (): Além dessa implementação, o tratamento de eventos e outras tarefas em segundo plano (como aquelas que ocorrem por setInterval () ou em web workers) também devem ser pausadas quando o loop principal está em pausa. Isso geralmente não é um grande negócio, porque eles só podem verificar a variável em execução para ver se eles devem executar ou não. Observe também que a pausa em jogos para vários jogadores fará com que o cliente dos jogadores fique fora de sincronia, de modo geral, o jogo deve sair ou encaixar o jogador em sua posição atualizada quando o loop principal é iniciado novamente (depois de confirmar com o jogador que eles realmente querem pausa). Começar o loop é mais complicado. Precisamos prestar atenção a quatro coisas. Em primeiro lugar, não devemos permitir o início do loop principal se já iniciou, já que isso exigiria vários quadros ao mesmo tempo e nos atrasaria. Em segundo lugar, precisamos ter certeza de que trocar entre iniciar e parar rapidamente não causa problemas. Terceiro, talvez devêssemos renderizar o estado inicial do jogo antes que ocorram quaisquer atualizações, já que nosso loop principal é desenhado após a atualização. Finalmente, precisamos repor algumas variáveis ​​para evitar simular o tempo que passou enquanto o jogo estava em pausa. Além disso, os manipuladores de eventos e as tarefas em segundo plano devem ser retomadas assim que o jogo começar novamente. Aqui vamos: Node. jsIO. js e suporte ao IE9 O principal problema com o nosso código agora que está segurando o suporte para node. jsIO. js, bem como IE9 e versões anteriores, se você se preocupa com esses navegadores, é a falta de solicitaçãoAnimationFrame () E cancelAnimationFrame (). Nós podemos compensá-lo com os polifrenos com base em temporizadores: reduzimos o problema de compatibilidade para suporte para Date. now (), que não está disponível no IE8. Se você realmente precisa do suporte ao IE8, você pode usar o novo Date () em vez disso, mas você estará gerando muitos novos objetos e isso criará uma grande quantidade de coleta de lixo que fará seu jogo gaguejar. E o IE8 é lento o suficiente para começar com que dificilmente faz sentido fazer qualquer coisa que seja intensiva em JavaScript. Embrulho Isso foi muito para pensar. Se você quiser o seu loop principal da maneira mais fácil, você pode usar meu projeto open-source do MainLoop. js. Então você não terá que se preocupar com todos esses problemas. Se estiver rodando o seu, há uma limpeza geral que poderia ser feita. Por exemplo, a caixa deve ser embrulhada em sua própria classe. Todo o script deve ser envolvido em um IIFE com uma interface exportada para evitar a poluição do espaço de nomes global em navegadores ou embalados como um módulo CommonJS ou AMD. MainLoop. js faz isso (e mais) para você, mas, no geral, foi bastante bem. Finalmente, gostaria de agradecer a Glenn Fiedler por ter escrito o clássico Fix your timestep, que foi o ponto de partida para muitos trabalhos aqui. Graças a Ian Langworth também por revisar uma versão mais curta deste artigo que incluí no meu livro sobre fazer jogos de navegador 3D e algumas dicas sobre os trabalhadores da web. Se, depois de tudo isso, você ainda está procurando por mais recursos sobre o assunto, você também pode considerar verificar os livros de padrões de programação do jogo ou a tomada menos minuciosa no MDN. Anormalidades globais médias de temperatura do ano passado de 1881 a 2006 Créditos de visualização Alex Kekesi (GST): animador principal Lori Perkins (NASAGSFC): animador James Hansen Ph. D. (NASAGSFC GISS): cientista Makiko Sato Ph. D. (NASAGSFC GISS): cientista Reto A. Ruedy Ph. D. (NASAGSFC GISS): cientista Ken Lo Ph. D. (NASAGSFC GISS): cientista David Lea Ph. D. (Universidade da Califórnia, Santa Bárbara): cientista Martin Medina-Elizade (Universidade da Califórnia, Santa Bárbara): cientista Dê crédito para este item para: NASAGoddard Space Flight Center Scientific Visualization Studio Dados fornecidos por Robert B. Schmunk (NASAGSFC GISS) URL curto para compartilhar esta página: svs. gsfc. nasa. gov3375 As palavras-chave GCMD podem ser encontradas na Internet com a seguinte citação: Olsen, LMG Major, K. Shein, J. Scialdone, S. Ritz, T. Stevens, M. Morahan, A. Aleman, R. Vogel, S. Leicester, H. Weir, M. Meaux, S. Grebas, C. Solomon, M. Holland, T. Northcutt, RA Restrepo, R. Bilodeau, 2013. NASAGlobal Change Master Diretório (GCMD) Palavras-chave Ciência da Terra. Versão 8.0.0.0.0 Lugares que você pode ter visto: a Associated Press, ABC, Albuquerque Tribune, BBC, CBC, CBS, Cleveland Plain Dealer, CTV, Detroit Free Press, Discovery Channel, Fox News, Houston Chronicle, Indianapolis Star, KIRO-TV (Seattle), KMBC-TV (Kansas City), KUTV-TV (Salt Lake City), MSNBC, New Scientist, Newsday, The New York Times, Salão, San Francisco Chronicle, San Jose Mercury News, Toronto Star, The Wall Street Journal, The Washington Post, WNBC-TV (Nova York), WPXI-TV (Pittsburgh) e WSMV-TV (Nashville). International coverage: Australia, Canada, China, Cuba, Denmark, France, Germany, India, Ireland, Japan, Norway, Philippines, Qatar, Russia, South Africa, Spain, Turkey, United Arab Emirates, United Kingdom. Browse Stories

Comments

Popular Posts