Como criar um tipo muito específico de junção em Farseer?

7

Editar

Problema resolvido (consulte a resposta de Drackir). Aqui está uma demonstração do que eu estava tentando alcançar com essa articulação. Mais informações sobre o cenário nesta outra questão .


Problema

Estou tentando criar um tipo muito específico de junta no Farseer que se comporta assim:

  • Objectos deve sempre manter a mesma distância entre eles em ambos os eixos X e Y.
  • Tradução - Uma colisão com um dos objetos deve mover o grupo inteiro, mas o grupo não deve girar - apenas os objetos individuais podem girar em torno de seus centros como resultado do torque.
  • Rotação - Os objetos devem sempre ter a mesma rotação. Uma colisão com um dos objetos deve fazer com que todos os outros giram exatamente a mesma quantidade.

Aqui está uma foto:

insira a descrição da imagem aqui

Se não há como conseguir isso com o Farseer pronto para uso, como eu o estenderia para criar um novo tipo de junção que funciona assim? Basicamente, quero que cada corpo se comporte como um "clone" dos outros, mas com um deslocamento fixo entre eles.

David Gouveia
fonte
Não tenho certeza sobre esse sistema específico, mas você não pode simplesmente desligar a cinemática do "fantasma" e movê-lo / girá-lo manualmente?
Tetrad
Isso também não desabilitaria colisões no fantasma? Talvez o fantasma não fosse a melhor analogia para ele - talvez um clone.
David Gouveia
Ou seja, colisões com o clone também devem afetar o corpo principal (da mesma maneira). Sua sugestão funcionaria nesse caso?
David Gouveia
Bate-me, provavelmente não.
Tetrad

Respostas:

6

Ok, depois de duas horas de conserto, consegui fazer isso, mas é preciso adicionar alguns corpos extras. Você provavelmente desejará extrair essas coisas em um método / classe, mas a idéia básica é a seguinte:

  1. Crie o que chamo de corpos "detentores" para seus objetos. Esses corpos compartilham o tamanho e a posição dos seus "objetos", mas não participam de colisões. Essencialmente, eles são clones.

    //Create "Main" (center) body
    _bodyMain = BodyFactory.CreateRectangle(World, 5f, 5f, 1f);
    _bodyMain.BodyType = BodyType.Dynamic;
    _bodyMain.Position = new Vector2(2, 2);
    //Create "MainHolder"
    _bodyMainHolder = BodyFactory.CreateRectangle(World, 5f, 5f, 1f);
    _bodyMainHolder.BodyType = BodyType.Dynamic;
    _bodyMainHolder.CollisionCategories = Category.None; //Prevents collisions
    _bodyMainHolder.Position = new Vector2(2, 2);
    _bodyMainHolder.IsSensor = true;
    //See http://farseerphysics.codeplex.com/discussions/222524 for why they're sensors
    _bodyMainHolder.FixedRotation = true;
    //Note: Only add FixedRotation for the main one, leave it off of the other
    //      holders. I'll explain later.
  2. Anexe cada suporte ao "mainHolder" usando a WeldJoint. Isso impedirá que eles se afastem um do outro. O FixedRotationno suporte principal impede que eles girem. Não sei se há um bug no clarividente, mas se você adicionar um WeldJointe os dois corpos tiverem FixedRotation == true, a articulação não funcionará corretamente. É por isso que apenas o titular principal possui .FixedRotation = true.

    //Weld the holders together so they don't move. Assumes another holder is defined
    //  for the object on the right side (bodyRightHolder).
    JointFactory.CreateWeldJoint(World, _bodyMainHolder, _bodyRightHolder,
    _bodyRightHolder.Position - _bodyMainHolder.Position, Vector2.Zero);
  3. Anexe seus corpos de "objetos" aos respectivos proprietários usando RevoluteJoints. Isso bloqueia seus objetos nos suportes, mas permite que eles girem livremente.

    //Lock the actual bodies to the holders
    JointFactory.CreateRevoluteJoint(World, _bodyMainHolder, _bodyMain, Vector2.Zero);
    JointFactory.CreateRevoluteJoint(World, _bodyRightHolder, _bodyRight, Vector2.Zero);
  4. Faça as rotações dos seus objetos reais se encaixarem, anexando uma junta angular. Nota: você não precisa anexar uma junta angular a cada par de objetos. Basta adicionar uma junta angular ao corpo principal e ao outro corpo e as rotações serão traduzidas em todos os objetos.

    //Make them rotate the same as each other
    JointFactory.CreateAngleJoint(World, _bodyMain, _bodyRight);

É isso aí! Basta adicionar o código extra para o outro objeto / suporte de objeto que você deseja e ele cuidará do resto. Aqui está uma imagem para ilustrar meu teste:Imagem de exemplo de corpos de teste.

Aqui você verá que os corpos verdes são os detentores. Eles não giram ou colidem e são soldados juntos. Os corpos amarelo e vermelho são seus "objetos" (o amarelo é o principal). Você pode ver que eles são girados na mesma quantidade e estão girando em torno de seus respectivos suportes. Além disso, apenas os corpos vermelho e amarelo participam de colisões. Acredito que isso atenda às três condições acima.

Exemplo de trabalho

Se você carregar a solução Farseer "Samples XNA" e encontrar o SimpleDemo1.cs (projeto "Samples XNA"> pasta "Samples"), eu o reescrevi ( código aqui ) para testar.

Espero que isto ajude. Deixe-me saber se você tiver alguma dúvida.

Richard Marskell - Drackir
fonte
Parece que ainda falta uma peça do quebra-cabeça. Como realocar instantaneamente todo o sistema para outra posição no mundo. Eu preciso disso para "quebrar" os objetos nas bordas da tela. Apenas definir a posição no suporte principal não está funcionando.
David Gouveia
Não se preocupe com a pergunta anterior, parece funcionar se realocar todos os titulares e órgãos principais ao mesmo tempo.
David Gouveia
Fico feliz em ajudar e, sim, você precisaria realocar todos os corpos. Você pode transformá-lo em uma classe e armazenar as posições relativas ao corpo principal ( Vector2diferença entre a posição do corpo e o corpo principal). Em seguida, reposicione a principal e apenas atualize suas posições em relação à principal.
Richard Marskell - Drackir
Foi praticamente o que eu fiz. :)
David Gouveia
0

Infelizmente, não posso verificar esta resposta, pois estou em um telefone agora, então peço desculpas se não funcionar como eu esperava.

Eu acho que você poderia usar várias articulações existentes para conseguir o que deseja. Crie um corpo sem geometria de colisão no canto do triângulo e, em seguida, use três juntas de distância para obter a tradução desejada. Então, se você conectar os dois corpos colidíveis com uma junta de ângulo fixo, eles girarão juntos.

Martin
fonte
Também estou com pouco tempo no momento e tentarei hoje à noite. Mas, embora meu exemplo tenha apenas dois corpos, na verdade vou precisar de algo mais complexo que isso, com nove corpos conectados . Sua ideia ainda se aplica?
David Gouveia
@ David: Isso parece ... interessante. Você pode dizer mais sobre o que você está tentando alcançar com esta configuração? Gostaria de saber se pode não haver alguma maneira alternativa de conseguir o que deseja.
Ilmari Karonen
@IlmariKaronen Há um link no final da minha pergunta para outra pergunta que descreve exatamente o que estou tentando alcançar. Basicamente, estou tentando lidar com a física corretamente em um ambiente 2D, onde os corpos podem "envolver" as bordas e aparecer em vários lados da tela simultaneamente.
David Gouveia
@ Martin Ainda não tenho tempo para testar isso hoje, então irei retornar amanhã.
David Gouveia
Ok, eu tentei isso agora, mas não consegui fazer o trabalho. O problema é que eu quero impedir que todo o sistema gire. As 3 juntas de distância (que também podem ser substituídas por 2 juntas de solda) mantêm o sistema rígido, mas não o impedem de girar.
David Gouveia