Como crio um objeto arrastável que se encaixa nos obstáculos no caminho?

8

Trago mais uma pergunta de arrastar com o mouse (estou usando o Unity com C #), mas com um detalhe particular menos comum: a existência de obstáculos no meio do caminho através do qual o arrastamento ocorre (espaço 3D, não 2D) .

Deixe-me explicar. Suponha que eu tenha um plano sobre o qual desejo arrastar um cubo chamado "obj". Isso é fácil. Aqui está minha implementação simples para isso:

void Update () {
  Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition);
  RaycastHit hit;
  if(Physics.Raycast(ray, out hit, 1000000))
  obj.transform.position = new Vector3(hit.point.x,0.25F,hit.point.z);
}

Funciona. No entanto, suponha que eu também tenha alguns outros cubos sobre o avião, que são os obstáculos. Obviamente, quando o jogador move "obj" sobre o avião, esse movimento deve ser bloqueado pelos obstáculos. E então, ao colidir com os obstáculos, "obj" deve se mover apenas cortada para os lados desse obstáculo. Se o mouse for movido e "obj" parar de colidir com obstáculos, o movimento livre de arrastar será retomado novamente.

objeto sendo arrastado em direção a um obstáculo e parando em sua borda, e depois retomado quando o arrasto passa pelo obstáculo

Para dificultar o desafio, estou tentando conseguir isso sem o uso dos componentes RigidBody nos obstáculos (o objeto arrastado pode tê-lo). Alguma idéia sobre qual é a maneira mais eficiente de conseguir isso? Muito Obrigado!

EDIT: Os comentaristas trouxeram à minha atenção que eu deveria mencionar que os objetos podem girar durante o snap.

EDIT 2: Considerando a dificuldade da formulação original, mudei a questão permitindo o uso de componentes do corpo rígido nos objetos arrastados. A solução simplesmente não pode usar os componentes do corpo rígido nos obstáculos.

MAnd
fonte
Você está movendo formas convexas arbitrárias - elas sempre são de quatro lados? Eles são sempre 2D?
6165 Steven
Posso saber o motivo pelo qual você não usará Rigidbodies? Eles são a maneira mais fácil de fazer o que você deseja, sem precisar reimplementar o código já disponível no Unity.
EvilTak
@EvilTak Prefiro aprender a lidar com a geometria envolvida na tarefa e, por razões de desempenho, não gosto de usar Rigidbodies, a menos que seja realmente inevitável. Nesse caso em particular, terei muitos milhares de objetos se comportando como obstáculos
MAnd
Btw, obrigado a @Anko (ou a quem o fez) por incluir essa imagem animada para ilustrar o problema! Eu ainda estava pensando na melhor maneira de fazer isso.
May
11
@ Steven e EvilTak: o objeto pode girar, os obstáculos não. Maneiras habituais de detectar colisões parecem não ser suficientes: o objeto principal continua entrando nos objetos.
Mand

Respostas:

2

É difícil detectar colisões sem a presença de corpos rígidos, mas, como você está usando cubos, pode usar o Bounds.Intersects . A cada atualização, verifique se os limites do objeto arrastado se cruzam com os limites de qualquer obstáculo. Se isso acontecer, você pode tentar o seguinte:

  1. Desative o Renderizador de malha do objeto arrastado para torná-lo invisível (mas continue a arrastá-lo).
  2. Solte um objeto de espaço reservado, idêntico ao arrastado na última posição antes da interseção dos limites (agora parece que o objeto foi parado, mas na verdade você ainda está arrastando o original).
  3. A cada atualização, verifique se os limites do objeto que você ainda está arrastando se cruzam com os limites de um obstáculo.
  4. Quando os limites do objeto arrastado não se cruzam mais com os obstáculos, exclua / desative o objeto de espaço reservado e reative o Renderizador de malha do objeto arrastado para torná-lo visível novamente.

Você nunca para de arrastar o bloco; simplesmente parece ao usuário que o bloco parou de arrastar enquanto cruzava com um obstáculo.

Evan
fonte
Com base nos comentários anteriores e na sua resposta, editei a pergunta para facilitar sua realização: digamos agora que o Rigidbody poderia ser usado para o objeto arrastável ou seus espaços reservados. O corpo rígido não podia ser usado para os obstáculos.
Mand
1

Sem ter feito isso sozinho, eis o que eu tentaria:

  1. Decida a que altura deve haver algum obstáculo no avião para bloquear seu objeto arrastado (onde "alto" significa removido ao longo do eixo que for apropriado - eu suporia o que aponta para a câmera).
  2. A cada atualização, salve a posição do seu hit do raycast.
  3. Cada atualização, antes de salvar a posição do hit atual do raycast, verifique a posição do hit atual do raycast contra a posição do hit anterior do raycast.
  4. Se a diferença> = altura de bloqueio, pare o objeto em movimento na posição anterior do golpe de raio.

Parece-me que, se você deseja que seu objeto se arraste ao longo de um plano inclinado de um obstáculo, você deve simplesmente fazer com que sua transformação continue seguindo a posição do último hit do raycast.

Evan
fonte
Obrigado pela sua resposta, @Evan. No entanto, essa solução não seria precisa. Suponha que o RayCast seja disparado do centro da caixa delimitadora do objeto arrastável. E se o obstáculo no caminho bloquear apenas uma parte do objeto arrastável que está à esquerda ou à direita do raio lançado? Mesmo se aumentarmos o número de raios lançados (o que pode ficar exponencialmente alto se o objeto arrastável puder ser arrastado em direções de 360º nas dimensões X, Z), dependendo de quão pequeno o obstáculo seja em relação ao objeto arrastável, ele ainda poderá ser lançada entre os raios - e, portanto, não seria detectada
MA 14/10/2015
Tudo bem, acho que entendi o que você quer dizer.
Evan