Estou trabalhando em um jogo em que o jogador pode pegar objetos usando algo como um raio de trator e carregá-los.
Atrair o objeto em direção ao centro do feixe não é difícil. Mas quando o objeto estiver próximo o suficiente do centro, preciso mantê-lo lá enquanto o jogador se move, e é com isso que estou tendo problemas. Posso pensar em duas maneiras de fazer isso, e ambas têm problemas:
Atualize a posição do objeto sempre que a posição do jogador mudar, mantendo-o centralizado no raio.
Atualize a velocidade do objeto para apontar diretamente para o centro do feixe, quanto mais longe, maior a velocidade.
Mover e girar funciona bem com as duas abordagens, mas a física está errada quando o objeto carregado colide com outros objetos:
Com a primeira abordagem, a física é completamente ignorada. O objeto carregado simplesmente empurra qualquer coisa para fora do caminho. Isso ocorre porque as mudanças de posição devem ser feitas apenas como parte da física do mundo, com base na velocidade.
Com a segunda abordagem, a física basicamente se comporta como deveria, mas reage exageradamente. O problema é: Para manter o objeto transportado no centro do feixe, mesmo quando estiver girando e se movendo, preciso usar valores altos de velocidade. Assim, uma vez que o objeto carregado toca outro, fica com velocidade demais da colisão.
Como posso implementar isso corretamente? Meu melhor palpite agora é seguir a segunda abordagem e adicionar um tratamento especial para objetos transportados à física mundial, reduzindo a velocidade a valores sãos para colisões ou quando o jogador parar de carregá-los. Mas isso parece uma solução bastante deselegante.
Edit: Adicionando algum pseudo-código para ilustrar como funciona agora (essa seria a segunda abordagem acima)
void attract_object(object, ticks) {
Vector distance = beam_center - object.center;
// If the object is not close to the beam center, attract it slowly
if (magnitude(distance) > 10) {
object.velocity += distance.normalized() * ticks * 0.1;
return;
}
// Here comes the part we're talking about. That magic 0.5 is just high enough
// that the object isn't lost while moving around. But it's still so high that
// other objects are repelled with way too much force.
object.velocity = distance * ticks * 0.5;
}
Pelo que vejo, isso acontece quando o objeto carregado empurra outro objeto:
- O objeto carregado colide com outro objeto
- As velocidades dos objetos são distribuídas adequadamente, de modo que o objeto carregado é empurrado para longe do centro do feixe no processo
- O código acima faz com que o objeto carregado retorne ao centro do feixe, com tanta velocidade que ele retornará rapidamente
- Quando o objeto transportado se move de volta para o centro do feixe, metade de sua alta velocidade é transferida para o outro objeto, repelindo-o violentamente. Como a velocidade inicial do objeto transportado parece ser sã, posso imaginar que as etapas 2 a 4 são repetidas várias vezes, construindo uma velocidade tão alta.
Essa parece ser a causa. Eu não consigo pensar em uma boa maneira de corrigi-lo :(
Respostas:
Essencialmente, o que você está procurando é fazer com que o objeto 'com vigas' se comporte exatamente como se você o pegasse com as mãos.
Uma opção seria fazê-lo compartilhar as velocidades de aceleração a / o da 'mão' que a segura, em vez de ajustar sua velocidade para preencher a lacuna com o centro do feixe.
Digamos que o centro do feixe seja a mão segurando. se seu personagem girar 90 graus para a esquerda em 1 segundo, a velocidade da mão seria:
If R = length of the arm: which is the radius of the rotation circle
faça o tempo decorrido do quadro para encontrar a velocidade que você deve aplicar ao seu objeto. Encontre o normal horizontal para o feixe para encontrar seu vetor de direção.R^2 *PI /4 would be the distance traveled over a second.
O que quero dizer é que você não precisa resolver problemas se tentar outras implementações que não causam isso em primeiro lugar.
Eu iria brincar com a pistola de gravidade no HL2 para obter alguma inspiração sobre o problema, mas tenho outros planos para hoje.
EDIT: desculpe, eu pensei que era para uma arma 3D, mas é essencialmente a mesma coisa com 2D, exceto que os eixos são diferentes (e não há geometria complexa)
fonte
Que tal adicionar uma conexão de mola, ou seja, forçar o objeto transportado a voltar à posição de transporte com base na distância, mas ainda permitir que ele seja empurrado por objetos sólidos (como paredes).
Ajuste constantemente a velocidade do objeto transportado (alterando a aceleração com base na posição / distância) para apontar para a posição do feixe do trator (ou seja, sua segunda abordagem). Se o objeto for empurrado longe demais, solte a conexão (e o objeto).
Não sei ao certo por que você precisaria de altas velocidades. Especialmente o caso "jogador solta" indica que sua velocidade de rotação pode ser muito alta ou irrealista. Também não se esqueça de coisas como resistência do ar e gravidade.
Edit: Considerando o código atualizado, o problema é bastante trivial para encontrar:
O problema aqui é o caso em que a distância do objeto à sua posição de objetivo é constantemente muito longa (ie
> 10
). Desde que essa condição seja verdadeira, sua velocidade simplesmente aumenta repetidamente (ou seja, indefinidamente).Duas soluções possíveis para isso:
Defina uma velocidade máxima:
Aplique uma velocidade fixa em vez de acelerar:
Acelerar enquanto está muito longe é definitivamente uma abordagem errada aqui. O que é puxar uma mola ou elástico: não importa se você o segura por um segundo ou um minuto. No final, ele acelerará da mesma maneira (considerando que não está em movimento e não há outras forças aplicadas).
fonte