Como codificar Time Stop ou Bullet Time em um jogo?

11

Estou desenvolvendo um jogo de plataforma RPG para um jogador no XNA 4.0. Eu gostaria de adicionar uma habilidade que faria o tempo "parar" ou desacelerar, e fazer com que apenas o personagem do jogador se movesse na velocidade original (semelhante ao feitiço Time Stop da série Baldur's Gate). Não estou procurando uma implementação exata, mas algumas idéias gerais e padrões de design.

EDIT: Obrigado a todos pela excelente contribuição. Eu vim com a seguinte solução

    public void Update(GameTime gameTime)
        {

            GameTime newGameTime = new GameTime(gameTime.TotalGameTime,
 new TimeSpan(gameTime.ElapsedGameTime.Ticks / DESIRED_TIME_MODIFIER));
            gameTime = newGameTime;

ou algo nesse sentido. Dessa forma, posso definir um horário diferente para o componente player e diferente para o restante. Certamente não é universal o suficiente para trabalhar em um jogo em que um tempo de distorção como esse seria um elemento central, mas espero que funcione nesse caso. Eu meio que não gosto do fato de ele ninhar o loop principal de atualização, mas certamente é a maneira mais fácil de implementá-lo. Eu acho que é essencialmente o mesmo que o tesselode sugeriu, então eu vou dar a ele o sinal verde :)

David Miler
fonte

Respostas:

8

Esta pode ser uma solução ruim, mas não necessariamente. Se você estiver usando o tempo delta, poderá alterar isso para alterar a velocidade de certas coisas.

Por exemplo:

player.update(dt)
dt = dt * .5 --half speed
enemy.update(dt)

Obviamente, isso só funciona se você souber quando está atualizando o inimigo e não com outra coisa. Você também pode dar a tudo um valor de velocidade e fazer algo como:

x = x + xspeed * dt * speed
tesselode
fonte
A primeira parte faz todo o sentido, a segunda parte não está claro
AturSams
2
Apenas dê a cada objeto que move uma variável de velocidade que você pode alterar e, quando tiver uma transformação (de x, por exemplo), multiplique a magnitude pela variável de velocidade.
Tesselode 30/09/12
Faz sentido agora. :)
AturSams
A segunda ideia parece ... desligada. Apenas escalar o movimento pelo fator "velocidade" pode funcionar para objetos movidos pela física, mas a IA seria capaz de reagir na velocidade normal, apenas com o movimento lento / prejudicado.
Como assim, a IA seria capaz de reagir na velocidade normal? Que código teria a IA que não poderia ter uma variável de velocidade aplicada?
Tesselode 1/10/12
3

Usar o tempo delta (milissegundos que passaram desde o último quadro) pode não ser suficiente para diminuir a velocidade dos inimigos. Coisas como a taxa de ataque podem ser implementadas com base no último horário do ataque. Embora ele desacelere o movimento se for baseado no tempo, negligenciará a taxa de ataque lenta, o lançamento de feitiços e outros efeitos (regeneração de vida, duração dos efeitos do feitiço).

Se você quiser desacelerar um grande grupo de elementos do jogo em um jogo para um jogador, poderá criar um segundo relógio interno para cada criatura, o relógio inicia no horário atual em que a criatura aparece. Quando um feitiço lento é lançado, a cada quadro, o relógio é incrementado em x% do tempo que realmente passou. Todo o comportamento dos monstros é então determinado pelo seu relógio interno. Se vários monstros têm resistência a desacelerar, eles podem usar seu próprio relógio, é basicamente um número inteiro que não requer muito espaço ou computação.

Quando o efeito lento é interrompido, os relógios ainda estão sendo usados ​​e são incrementados em 100% do tempo que realmente passou.

Isso também pode funcionar para acelerar os feitiços.

@Sidar: vejo duas opções,

  1. Relógio interno por criatura. Para descobrir se a criatura está pronta para atacar novamente: salve a última vez que cada ataque foi usado + tempo de recarga e verifique se o relógio interno já passou desse tempo.

  2. Um cronômetro por ataque: você sabe quanto tempo leva para recarregar o ataque e simplesmente define um cronômetro e subtrai o tempo que passou * (1% de desaceleração) a cada turno.

Pessoalmente, prefiro evitar subtrair vários cronômetros individuais e usar um relógio interno para economizar tempo e complexidade de processamento.

É realmente de preferência (não afeta tanto o desempenho).

AturSams
fonte
A necessidade de relógios internos não é necessária. Simplesmente se resume a um multiplicador que você pode (de alguma forma) vincular ao seu objeto que aumenta ou diminui o produto do seu dt (tempo delta). Você pode gerenciar os objetos por grupos ou por qualquer meio. Eu acho que seu caminho pode ser um pouco excessivo. Mas ei, se funcionar ... então funciona.
Sidar
@Sidar Se você evitar isso, provavelmente precisará de um relógio por ataque apenas para recarregar o tempo, duração do feitiço e outras coisas. Pelo menos dessa maneira, você só precisa atualizar um relógio e simplesmente manter o tempo da 'última ativação' para redefinir as propriedades.
AturSams
Sua pergunta, no entanto, é sobre desacelerar o ambiente, exceto o jogador. Para mim, isso parece a forma mais simples de multiplicar o dt por um número menor que 1. Mantendo-o como está para o jogador.
Sidar
Bem, diminuir a velocidade do ambiente inclui diminuir a taxa de ataque e outras habilidades (já que é um rpg), pode haver várias habilidades da máfia que dependem do tempo de recarga. Cura, buffs, debuffs, feitiços e etc. Sem mencionar o tempo de ativação.
AturSams 30/09/12
2

Você pode começar com uma solução simples como a exposta pelo tesselode ou pelo Sr. Beast. Mas se você começar a misturar coisas complexas, como um tempo de bala enquanto um feitiço de desaceleração for lançado, você ficará preso.

Sugiro que você implemente uma hierarquia de relógio :

.
├── Main clock
│   └── UI clock
│   └── 3D clock
│       ├── GFX clock
│       └── Gameplay clock
│           └── Slowdown spell clock 01
│           └── Slowdown spell clock 02

Tudo no seu jogo deve usar tempos delta em um relógio: efeitos gráficos executados no relógio GFX, IA e animação no relógio Gameplay, criaturas afetadas por um feitiço de desaceleração executado em um relógio temporário de feitiço de desaceleração, etc. afeta diferentes partes da sua hierarquia: um feitiço de desaceleração cria e afeta um relógio personalizado, enquanto um tempo de marcador afeta toda a hierarquia do relógio 3D.

Laurent Couvidou
fonte
Obrigado, este é um insight importante. No entanto, acho que manterei o pensamento simples, pois não faz sentido no meu caso particular que vários efeitos de desaceleração ocorram ao mesmo tempo.
David Miler
1

Você só precisa de dois relógios diferentes em vez de um, um para o tempo relevante para a jogabilidade e um para o "verdadeiro".

currentGameTime = 0;
gameSpeed = 1.0f;
[...]
currentApplicationTime = GetTime():
timeDelta = (currentApplicationTime - lastApplicationTime)*gameSpeed;
currentGameTime += timeDelta;
lastApplicationTime = currentApplicationTime;

Em seguida, você pode simplesmente mudar a velocidade do jogo para acelerar (> 1) ou diminuir o tempo (<1). Para o jogador se mover em velocidade diferente, verifique se o tempo está mais lento ou não.

API-Beast
fonte