Como posso implementar atualizações independentes da taxa de quadros?

7

Edit: Eu corrigi o problema, tornando a jumpvelocity aquela que é modificada e adicionada e a yvelocity é igual à jumpvelocity * t. Isto é o que eu tenho agora:

if (GUI->Space && grounded){
    jumpvelocity = -185.f * 2  / gravity;
    grounded = false;

}

if(!grounded ){
    if(jumpvelocity < terminaly){
        jumpvelocity += 185.f * t * 4  / gravity;
        yvelocity = jumpvelocity * t;
    }
    else{
        jumpvelocity = terminaly;
        yvelocity = jumpvelocity * t / gravity;
    }
}
else{
    yvelocity = 0.f;
    jumpvelocity = 0.f;
}

Obrigado pela ajuda.

Estou tentando fazer minha gravidade funcionar. O código que eu tenho até agora é

if (jumpvelocity < 0){
   yvelocity = jumpvelocity * t *2/gravity;
    jumpvelocity += 185.f*t * 2 / gravity;
}

else if(!grounded ){
    if(yvelocity < terminaly)
        yvelocity += t / gravity;
    else
        yvelocity = terminaly;
}

A gravidade aumenta para cima, fazendo com que a queda e o salto sejam mais lentos. Seu valor padrão é 1. Jumpvelocity é definido como 185 quando o jogador deseja pular. Meu problema é que você cai mais devagar em uma taxa de quadros mais lenta, mas salta na mesma velocidade como se fosse uma taxa de quadros mais alta. Como eu faria com que o quadro fosse independente? T é tempo delta.

user975989
fonte
Você pode mostrar o código em que o Velocity é usado para modificar a posição?
Jordaan Mylonas
Então, re seu comentário ... qual é o problema? Funciona exatamente da mesma maneira para x e y.
Engenheiro de
Estou usando o SFML, então é só você. Move (xvelocty, yvelocity).
User975989 18/10/11
Seu código atualizado ainda tem absolutamente todos os problemas que eu apontei. Você não está calculando jumpvelocitya média com o valor anterior ao atualizar yvelocity, fornecendo um erro de precisão que piorará com menor taxa de quadros. O que você chama de yvelocityfato deve ser, ymovementpois é uma velocidade multiplicada pelo tempo. Você está atualizando jumpvelocityquando o personagem não toca mais o chão, o que não tem significado físico. Sua verificação terminalyé feita antes da atualização, causando jumpvelocityum terminalyaumento maior e piorando nas taxas de quadros inferiores.
21711 Sam

Respostas:

13

Em cada iteração do loop principal:

  1. Verifique o temporizador do sistema e armazene como currentTime(por exemplo, SDL_GetTicks ())
  2. timeDelta = currentTime - lastTime
  3. Converta timeDeltapara segundos (geralmente em ms ou ns), armazene comotimeDeltaSeconds
  4. For each entity in entities: entity.position = velocityInUnitsPerSecond * timeDeltaSeconds
  5. lastTime = currentTime (também pode ser feito antes da etapa 1 em vez de aqui)

... Você precisará ajustar seus números atuais para que estejam em unidades por segundo, ou seja, para que eles façam sentido a 1FPS. Por exemplo, se você esperava que a velocidade horizontal do seu personagem fosse 2 pixels por décimo de segundo, agora você precisa defini-la como 20 pixels por segundo. Dessa forma, o acima irá funcionar corretamente.

Para alguns aplicativos, é melhor fixar seu timestep em um determinado valor. Nesse caso timestep != timeDelta,. O último é a quantidade de tempo do sistema que realmente passou; o primeiro é um valor quantizado que você deseja consumir do seu acumulador de tempo cada vez que aplica atualizações lógicas no seu jogo. Isso ajuda na integração quando você está usando solucionadores iterativos, como os encontrados nos conhecidos mecanismos de física, porque os intervalos de tempo devem ser iguais ao fazer o cálculo. Nesse caso, como você não está gastando todo o tempo restante em cada tick, você terá frações de tempo restantes e precisará acumulá-las para usá-las em ticks posteriores. Para saber mais sobre isso, leia Fix Your Timestep, de Glenn Fiedler.

Engenheiro
fonte
Op aqui, desculpe, não tenho certeza de como responder a uma resposta, mas já tenho um intervalo de tempo definido em 1/60 de segundo ou menos, dependendo do valor retornado. Minha xvelocidade funciona bem e é independente de quadro (200.f * t), mas minha yvelocidade não.
user975989
Você não deseja, velocityInUnitsPerSecondmas a velocidade média durante o período decorrido. Se a velocidade é constante, seu código está correto. Se a velocidade varia linearmente, como é o caso da gravidade, esse valor é 0.5 * (OldVelocity + NewVelocity). Caso contrário, pode ser necessário integrar-se em um intervalo de tempo menor para evitar problemas de precisão.
18711 Sam
0

Parece que não jumpvelocityé necessário. Saltar significa ajustar instantaneamente a velocidade para um determinado valor: uma vez que os pés não tocam mais o chão, a única coisa que pode mudar de velocidade é a gravidade (e a resistência do ar, que você implementa usando a velocidade terminal).

Outra observação: as divisões de ponto flutuante são extremamente lentas. Eu sugiro que você armazene em 1.0f / gravityvez de gravity.

Finalmente, existe a possibilidade de que, para um quadro, yvelocityseja maior que terminaly.

Minha sugestão:

if (GUI->Space && grounded) {
    yvelocity = 185.f;
    grounded = false;
} else if (!grounded ) {
    yvelocity += t * inv_gravity;
    if (yvelocity > terminaly)
        yvelocity = terminaly;
}

E lembre-se de que o seguinte não é preciso:

ypos += t * yvelocity;

Você precisa fazer:

ypos += t * 0.5f * (old_yvelocity + yvelocity);
sam hocevar
fonte