Eu estou pensando sobre como os mecanismos de manipulação do tempo nos jogos são tipicamente projetados. Estou particularmente interessado em reverter o tempo (mais ou menos como no último SSX ou Prince of Persia).
O jogo é um shooter 2D de cima para baixo.
O mecanismo que estou tentando projetar / implementar possui os seguintes requisitos:
1) Ações de entidades além do personagem do jogador são completamente determinísticas.
- A ação que uma entidade realiza é baseada nos quadros progredidos desde o início do nível e / ou na posição do jogador na tela
- As entidades são geradas em um horário definido durante o nível.
2) A reversão do tempo funciona revertendo em tempo real.
- As ações do jogador também são revertidas, repetindo inversamente o que o jogador realizou. O jogador não tem controle durante o tempo inverso.
- Não há limite para o tempo gasto na reversão, podemos reverter todo o caminho até o início do nível, se desejado.
Como um exemplo:
Quadros 0-50: O jogador avança 20 unidades ao longo desse tempo O Inimigo 1 aparece no quadro 20 O Inimigo 1 move-se para a esquerda 10 unidades durante o quadro 30-40 O jogador dispara a bala no quadro 45 Bala viaja 5 na frente (45-50) e mata o Inimigo 1 em quadro 50
A reversão disso seria reproduzida em tempo real: o jogador se move para trás 20 unidades durante esse tempo. O inimigo 1 revive no quadro 50 Bala reaparece no quadro 50 Bala se move para trás 5 e desaparece (50-45) O inimigo se move para a esquerda 10 (40-30) O inimigo é removido quadro 20.
Olhando para o movimento, eu tinha algumas idéias sobre como conseguir isso, pensei em ter uma interface que mudasse o comportamento para quando o tempo estava avançando ou revertendo. Em vez de fazer algo assim:
void update()
{
movement += new Vector(0,5);
}
Eu faria algo assim:
public interface movement()
{
public void move(Vector v, Entity e);
}
public class advance() implements movement
{
public void move(Vector v, Entity e)
{
e.location += v;
}
}
public class reverse() implements movement
{
public void move(Vector v, Entity e)
{
e.location -= v;
}
}
public void update()
{
moveLogic.move(new vector(5,0));
}
No entanto, percebi que isso não seria o desempenho ideal e rapidamente se tornaria complicado para ações mais avançadas (como movimento suave ao longo de caminhos curvos, etc.).