Você quer desenhar e girar os triângulos na mão usando vetores, é isso?
- Crie uma classe para representar o seu vetor2d;
- Associe um vetor de direção ao seu triângulo;
- Associe um vetor de posição ao seu triângulo;
O vetor da seta pode ser facilmente desenhado a partir do vetor direção e do vetor posição. Basta:
- Desenhar a flecha;
- Rotaciona-la no mesmo ângulo do vetor direção;
- Soma-la ao vetor posição + offset para que ela caia no meio do triângulo.
Trabalhe para que todos os seus desenhos sejam feitos “de pé” e todas as rotações e translações sejam feitas posteriormente, através de objetos como o affineTransform (alguns métodos fazem isso automaticamente).
Eu fiz algo similar para o meu engine de ia, mas usando C++ e OpenGL:
Nossa…Isso é que é domínio da API…
Se não me engano vi uma explanação a respeito dessas transformações afins em um material de Java2d que você indicou em um dos tópicos deste fórum…Tentarei encontrar esse material e entender esse processo, qualquer coisa volto a falar com você…
Agradeço desde já…
Só mais uma coisa…Como você segure que eu define a estrutura do meu objeto Triangulo2D?
Extendo um Polygon? Além dos vetores associados, relaciono também os pontos que definem seus vértices?
Como você faria isso?
Eu não me incomodaria em criar um filho de Shape.
Na verdade, além da classe Vector2D já mencionada, eu criaria uma classe propria, chamada Triangle. Aí sim, nela usaria um Polygon2D para fazer o desenho do centro. Também criaria um objeto “Arrow” que desenha a seta. Por fim, criaria uma classe “Agent” que encapsularia a lógica do agente, teria sua posição e usaria as duas classes anteriores para desenha-los, aplicando as devidas transformações.
Por isso que eu gosto de usar OpenGL para esse tipo de simulação, já que por lá os triângulos são uma primitiva e as rotações são feitas por um simples comando (glRotate).
A API do Java 2D está aqui:
http://java.sun.com/j2se/1.5.0/docs/guide/2d/spec/j2d-bookTOC.html
Ok… agora que vimos a maneira mais “vetorialmente correta”, vamos ver a mais fácil:
O jeito mais trivial de fazer o desenho dos agentes seria criar uma imagem bitmap e rotaciona-la. O java já tem diversos comandos prontos para isso, e são bastante rápidos, embora não seja possível usar isso com milhares de agentes. Foi o que utilizei no caça à bandeira, que você pode baixar em http://vinigodoy.wordpress.com/meus-jogos, para fazer a flechinha que fica embaixo das peças. Talvez essa técnica (que é realmente trivial) já seja suficiente para o seu caso.
O seu comportamento emergente é baseado em Steering Behaviors?
Nos fontes do Caça a Bandeira, você também vai encontrar a classe Vector2D implementada. Se precisar, também escrevi um artigo falando sobre como funciona uma classe de vetores bidimensionais e posso passar para você. Ë em C++ e está aqui em Anexo. O artigo é mais focado em programadores, que não gostam muito daquela “matematicagem” toda de um livro de matemática (se gostassem, já teriam lido o livro). E também tenta mostrar algumas aplicações práticas do uso de vetores em jogos de computadores.
Putz, agora que vi o número exacerbado de erros no meu post anterior, hehe…Foi mal, tinha acabado de voltar do bar
A classe que você referencia como Vector2D seria realmente a representação de um vetor em um plano bidimencional? Ou seja, uma dupla de valores que definem direção, sentido e intensidade? Se for o caso, já utilizo uma na minha simulação atual. O mesmo ocorre com a classe Agent…
Pois é…Não havia pensado em utilizar uma bitmap. De fato, tornaria as coisas mais simples, do ponto de vista da programação. Todavia, creio que a performance ficaria prejudicada em relação à utilização da abordagem baseada em desenhos de polígonos 2D…O que você acha?
Até agora o máximo que consegui na minha simulação foi rodar dois ambientes multiagentes (implementados inteiramente por mim, por isso otimizados para a tarefa específica) com 200 agentes cada, em uma mesma máquina. Agora estou, ao mesmo tempo que cuidando da estética, buscando reduzir a complexidade de certos algoritmos…
O comportamento dos meus agentes é baseado em Steering Behaviors sim. Todavia, por enquanto implementei um comportamento de forma intuitiva, para teste. Mas pretendo estudar mais esses comportamentos e analisar qual seria o mais adequado ao meu ambiente, ou ainda pensar em uma forma de instanciar um comportamento específico para os agentes na simulação, dinamicamente…Entrei em um link que você passou ontem (acho que é seu blog) e vi que você explicou alguns deles. Este material vai me ajudar bastante no futuro…Você poderia me passar a referência de onde obteve aquelas informações?
Eu até gosto bastante de matemática e meu impulso inicial, para desenhar os tais triângulos, foi fazer toda aquela geringonça matemática que eu falei no início do tópico, hehehe…Não tinha me tocado que poderia usar transformações afins e todas essas facilidades da API. Você expandiu consideravelmente minhas possibilidades
Bem, vou meter a mão na massa agora. Assim que eu tiver resultados (que podem demorar, visto que estou trabalhando em muitos projetos ao mesmo tempo) volto aqui para comentar…
Valeu pela força. Muito sucesso.
Ah, acabo de ver que no PDF que você anexou ao último post você coloca a referência dos comportamentos…Valeu.
Eu me baseei no livro Programming Game AI By Example, do Mat Buckland. O autor também mantém o site:
http://www.ai-junkie.com
E também no próprio trabalho do Reynolds, de onde retirei algumas figuras:
http://www.red3d.com/cwr/steer/
O Buckland implementou esse interessante simulador de cardumes, no anexo (tive de fazer um idêntico para a minha disciplina de IA).
Uma outra maneira de você desenhar um triângulo é calcular os três pontos, sendo cada um um deslocamento em relação a um ponto central. Ou seja, você calcula 3 vetores em relação ao centro do triângulo, um para cada ponta do triângulo, representando a distância e a direção do ponto em relação ao centro. Aí, para girar o triângulo, basta girar os três vetores juntos. É mais intuitivo do que partir para matrizes de transformação… e mais lento também.
E aquela minha forma de já calcular os pontos diretamente em função do vetor (já rotacionados). O que você acha dela? Implementei desta forma porque parti do pressuposto de que, de qualquer forma eu teria que calcular os três pontos para plotar o triângulo. Assim, pensei, porque já não calcular os pontos nas coordenadas finais? Intuitivamente pensei que seria a forma menos custosa…Só que, como disse, acho que errei uma parte do raciocínio, porque não consegui triângulos, hehe…
Vou dar uma olhada com mais profundidade nesse material todo que você me passou. Gosto bastante da programação gráfica, apensar de estar ainda angatinhando nela, hehe
Na verdade, não tenho tempo de parar e ler a calculeira aqui no meu trabalho. O raciocínio, pelo que vc descreveu, me parece fazer sentido. Mas tenho que parar e olhar as contas.
Olá, tudo bem…
Estou testando a possibilidade de carregar uma imagem PNG de um triângulo e plotá-la na tela, para cada um dos meus agentes, rotacionando-a em função do vetor direção de cada agente e transladando-a em função da posição de cada agente. Para tanto, bolei um método que desenha um único agente que é chamado para desenhar cada um deles. Segue o método abaixo. Detalhe: TRIANGULO é uma static BufferedImage carregada na inicialização do programa.
private void desenhaSer(Graphics g, Ser ser)
{
Graphics2D g2D = (Graphics2D)g;
AffineTransform tranformacaoAfim = new AffineTransform();;
tranformacaoAfim.setToRotation( (double)ser.getXDirecao(), (double)ser.getYDirecao(), 1.0, 0.0 );
tranformacaoAfim.concatenate( AT.getTranslateInstance( (double)ser.getXPosicao(), (double)ser.getYPosicao() ));
g2D.drawImage(TRIANGULO,tranformacaoAfim,null);
}
Todavia, aparece um único triângulo na tela (quando deveriam aparecer N), rotacionado, mas não em função da direção em que se desloca. Você saberia qual poderia ser o problema? Eu utilizei direito o AffineTransform?
O ideal seria ter um AffineTransform para cada Agente (sendo um atributo do Triangulo2D que, por sua vez, é atributo do Agente)?
Esqueci de mencionar…Chamo este método dentro do método paintComponent(Graphics g) de um JPanel. Dentro de um laço, onde o chamo para desenhar cada um dos meus agentes.
Geralmente eu faço assim:
[code]AffineTransform base = new AffineTransform(); //Não faz transformação de coordenadas
//getAngle() retorna o ângulo do ser em relação a x, equivalente ao teta,
//que a função recebe de entrada
AffineTransform rotation = base.getRotateInstance(ser.getAngle());
//Agora, posicionamos o ser no local desejado.
AffineTransform translation =
rotation.getTranslatedInstance(ser.getX(), ser.getY());
g2D.drawImage(TRIANGULO,translation,null); [/code]
Se isso não der certo, tente primeiro inverter a ordem da translação e da rotação. Não me lembro ao certo a ordem no java 2D. Esse artigo do meu blog explica o fenômeno do que ocorre quando a ordem das matrizes é invertida (basicamente, ao invés do objeto girar no próprio eixo, ele vai “orbitar” em torno da posição dele já deslocada):
http://vinigodoy.wordpress.com/2008/02/17/transformacoes/
Mas ele é para o OpenGL, a ordem é inversa no DirectX e pode ser que seja aqui também.
Certo…Vou tentar a sua solução hoje a noite quando chegar em casa.
Você recomenda que esses objetos AffineTranform sejam instanciados assim mesmo, toda vez que chamo o método? Será que não seria consideravelmente menos custoso já criar esses dois AffineTransform para cada Agente/Ser e só setar seus parâmetros cada vez que vou desenhá-los…
Desculpe qualquer coisa, sei que talvez essas perguntas sejam bem básicas, hehe…
É que eles são combinados. Você pode fazer o teste, mas geralmente não me preocupo com o custo deles. Multiplicações de matrizes costumam a ser bem rápidas.
É bem provável que vai haver outros gargalos na sua simulação, como o próprio cálculo do comportamento dos agentes. O ideal mesmo é depois de pronto rodar um profiler.
Só lembrando que a próprio BufferedImage tem o método getRotatedInstance e existe uma versão do draw que aceita a posição da imagem. Seria uma forma de fazer sem usar o affine transform. O Sun recomenda usar as transformações. Creio que elas possam ser aceleradas por hardware.
Pois é, não tinha percebido esse método da própria BufferedImage…Vou testar tudo isso e ver qual a solução que mais se adequa às minhas restrições…Depois eu posto aqui qual usei.
Obrigado pela orientações, foram fundamentais
De nada. É um assunto que eu curto muito. Se você se empolgar, tente ver depois como fazer isso com o JOGL… depois de aprender o básico, você vai ver que é muito fácil.
Bah, não sei se estou viajando, mas não encontrei o método getRotatedInstance da BufferedImage, hehe
Talvez eu tenha confundido, então.