29/09/2012 - 23:20
Criei um repositório git aqui:
https://github.com/ArthurWulfWhite/Bezier-Distance/
Você pode baixar os arquivos de origem como um zip a partir daí. Ele também inclui uma demonstração que você pode compilar usando o FlashDevelop. Para usar a demonstração, abra o projeto no Flash Develop e clique em 'Test Project'. Durante a execução da demonstração, clique no LMB para selecionar aleatoriamente uma nova curva de Bezier e um novo círculo.
Boa sorte!
É difícil ver o link do zip - basta usar Ctrl + F e digite zip. Essa fonte representa algumas semanas de pesquisa e programação, espero que você goste.
Se você planeja dividir o bezier recursivamente em segmentos e verificar colisões com eles, sugiro fazer uma matriz de 100.100 (grade) e colocar cada segmento nos quatro quadrados mais próximos, para que você só precise verificar colisões com 4 / 10.000 do segmenta cada quadro.
Eu acho que você se beneficiará do box2d tanto como programador quanto como criador de jogos, já que existem muitos pequenos obstáculos ocultos na criação de um mecanismo de física 'simples' que faz o movimento parecer um pouco esburacado e menos fluido do que poderia ser.
Antiga resposta: O caminho puro.
Você pode realmente ver se um círculo está colidindo com uma curva de Bezier, verificando a distância entre a distância entre o centro do círculo e o ponto mais próximo da curva.
A equação para a distância (em geral)
explicado:
Equação de Bezier:
q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))
Isso pode ser resumido em (com alguma álgebra) - vou omitir (x, y) para facilitar a leitura (eles ainda são pontos, não um número)
q(t) = (start -2 * cont + end) t^2 + (-2 * start + 2 * control) + start
A distância do ponto (x, y) é:
sqrt ((q(t).x - point.x)^2 + (q(t).y - point.y)^2)
Para encontrar o ponto mais próximo do bezier da bola, você precisa derivar e encontrar todos os pontos em que a derivada é igual a zero (as raízes). É um polinômio de terceiro grau, portanto, você pode usar uma fórmula fechada, mas pode não ser confiável, pois a precisão das frações representadas pelo ponto flutuante do computador pode não ser suficiente. É muito melhor usar Newton ou algo dessa natureza.
A derivada para a qual você precisa encontrar as raízes é:
Supondo: a = início b = controle c = final d = ponto central do cirlce
A parte complicada é multiplicar esses pontos, você precisa usar o produto com pontos.
Se você preferir, eu tenho o código para isso e posso compartilhá-lo aqui na forma de uma função que simplesmente retorna um booleano se houver uma colisão ou não e um ângulo de colisão. Alguns problemas podem surgir na implementação ingênua de um mecanismo de colisão como este, por exemplo, uma bola em movimento rápido pode ficar presa entre duas curvas.
Eu recomendo evitá-lo por enquanto, basta somar os coeficientes para o eixo xe para o eixo y e adicioná-los.
Use qualquer método confiável que você possa escolher como Newton para encontrar as raízes, verifique a distância dos pontos da raiz no bezier, 0 <= t <= 1 até o centro do círculo e verifique a distância para as duas extremidades do bezier (início e final) até o centro do círculo, o que estiver mais próximo, informará se há uma colisão.
Se o raio for menor que a distância mínima, haverá uma colisão.
O ângulo é aproximadamente aquele entre o centro do círculo e o ponto mais próximo do bezier.
Dito isto, se você realmente deseja fazer um jogo com a física de colisão, sugiro que você repita o processo
q(t) = (1-t) * ((1-t) * start.(x,y) + t * control.(x,y)) + t*(t * control.(x,y) + (1 - t) * end.(x,y))
Divida cada peça no meio recursivamente até que seja pequena o suficiente, digamos 10 pixels ou menos, então construa o bezier aproximadamente a partir de caixas e use o Box2d para a física, pois é possível que escrever todo esse código de detecção de colisão seja ótimo tempo que não melhora muito a jogabilidade. O uso do Box2d provou-se em inúmeros projetos no passado.