[Resolvido] calculando colisões: entre duas linhas e dois circulo
Calcular colisões é importante, principalmente para jogos.
Então vamos calcular colisões entre dois circulos e também de duas linhas.
circulo-circulo
Para calcular é bem fácil.
Basta saber a distância dos centros dos dois circulos e o raio dos dois.
Se a distância dos dois circulos for menor que a soma dos dois raios há interseção.
Para saber a distância use o teronema de pitágoras.
"O quadrado da hipotenusa é igual a soma do quadrado dos catetos."
Hipotenusa ² = cateto_adjascente ² + cateto_oposto ²
Então é só elevar ao quadrado os dois catetos e somar eles. Depois tirar a raiz quadrada.
Fiz um exemplo:
http://megaswf.com/serve/2311190
import flash.events.MouseEvent;
import flash.display.Sprite;
import flash.display.Shape;
var format:TextFormat = new TextFormat();
format.size = 17 ;
var ins = new TextField() ;
addChild(ins);
ins.x = 72;
ins.y = 332;
ins.width = 401;
ins.height = 25;
ins.defaultTextFormat = format;
//texto interseção
var intersection = new TextField() ;
addChild(intersection);
intersection.x = 72;
intersection.y = 365;
intersection.width = 401;
intersection.height = 25;
intersection.defaultTextFormat = format;
stage.addEventListener(MouseEvent.CLICK , mclick);
var cirtemp:Shape = new Shape();
var lintemp:Shape = new Shape();
addChild(lintemp);
addChild(cirtemp);
var circ1:Shape = new Shape();
var circ2:Shape = new Shape();
addChild(circ1);
addChild(circ2);
var p_r:Array = new Array();
var px:Number ;
var py:Number ;
var clicks:Number = 0;
ins.text = "defina o ponto do meio do circulo 1" ;
function mclick(e:MouseEvent):void{
if(clicks == 0){
px = e.localX;
py = e.localY;
stage.addEventListener(MouseEvent.MOUSE_MOVE, mm);
trace('down');
ins.text = "defina o raio do circulo 1" ;
clicks = 1;
p_r['x1'] = e.localX;
p_r['y1'] = e.localY;
}else if(clicks == 1){
circ1.graphics.lineStyle(1,0x000000,1);
circ1.graphics.drawCircle(px,py, teronema_de_pitagoras(e.localX - px, e.localY - py));
lintemp.graphics.clear();
clicks = 2 ;
ins.text = "defina o ponto do meio do circulo 2" ;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mm);
p_r['r1'] = teronema_de_pitagoras(e.localX - px, e.localY - py);
}else if(clicks == 2){
px = e.localX;
py = e.localY;
stage.addEventListener(MouseEvent.MOUSE_MOVE, mm);
trace('down');
clicks = 3;
ins.text = "defina o raio do circulo 2" ;
p_r['x2'] = e.localX;
p_r['y2'] = e.localY;
}else if(clicks == 3){
circ2.graphics.lineStyle(1,0x000000,1);
circ2.graphics.drawCircle(px,py, teronema_de_pitagoras(e.localX - px, e.localY - py));
lintemp.graphics.clear();
clicks = 4 ;
ins.text = "clique em algum lugar para apagar" ;
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mm);
p_r['r2'] = teronema_de_pitagoras(e.localX - px, e.localY - py);
if(teronema_de_pitagoras(p_r['x1'] - p_r['x2'] ,p_r['y1'] - p_r['y2'] ) < p_r['r1'] + p_r['r2']){
intersection.text = "há interseção";
}else intersection.text = "não há interseção";
}else if(clicks == 4){
circ2.graphics.clear();
circ1.graphics.clear();
cirtemp.graphics.clear();
clicks = 0;
ins.text = "defina o ponto do meio do circulo 1" ;
intersection.text = "";
}
}
function mm(e:MouseEvent):void{
cirtemp.graphics.clear();
cirtemp.graphics.lineStyle(1,0xFF0000,1);
cirtemp.graphics.drawCircle(px,py, teronema_de_pitagoras(mouseX - px, mouseY - py));
lintemp.graphics.clear();
lintemp.graphics.lineStyle(1,0xFF0000,1);
lintemp.graphics.moveTo(px,py);
lintemp.graphics.lineTo(mouseX,mouseY);
trace('mm');
}
function teronema_de_pitagoras(ca:Number , co:Number):Number{
//soma dos quadrados dos catetos
var s_d_q_d_c:Number = Math.pow(Math.abs(ca),2) + Math.pow(Math.abs(co),2)
var hipotenusa:Number = Math.sqrt(s_d_q_d_c);
return hipotenusa;
trace('tdp');
}
para testar o exemplo é só criar o fla com 550x400 px e colar o script no frame 1
A função teronema_de_pitagoras funciona assim:
ca é o cateto adsjascente, e co o oposto
ca é a diferença da posição x dos dois pontos(ponto1.x - ponto2.y)
e co é a diferença da posição y.
linha-linha
Eu estava querendo calcular a interseção de duas linhas,
Fiz vários calculos com seno e cosseno, só que não achava uma fórmula,
Até achar no wikipedia.
http://en.wikipedia....ne_intersection
Aqui está a formula:
/applications/core/interface/imageproxy/imageproxy.php?img=http://upload.wikimedia.org/wikipedia/en/math/a/c/d/acd2938d1c482f5247654e6822ec06ad.png&key=92207dcacdb2b01f4945ae572abebd3b04eae3044a9d93182df94e631aceca62" alt="acd2938d1c482f5247654e6822ec06ad.png" />
Imagem do wikipedia.
Para saber se é paralelo:
/applications/core/interface/imageproxy/imageproxy.php?img=http://upload.wikimedia.org/wikipedia/en/math/6/c/8/6c88e10b6c07b86c33deac72ba33cf6f.png&key=469f0cf09dfeaa2cfe7a77b9fe814513d053847676bc086a20f02dd95c2d0a19" alt="6c88e10b6c07b86c33deac72ba33cf6f.png" />
Então fiz um exemplo:
http://megaswf.com/serve/2311190
É só clicar para definir os 4 pontos das 2 linhas.
E vai aparecer duas linhas vermelhas indicando a interseção.
Só que tem o seguinte:
Essa formula calcula a interseção das linhas como se fossem infinitas, então entre duas linhas que não sejam paralelas, sempre haverá uma interseção em algum lugar.
Então é só ver se essa interseção está na "área" das duas linhas, se estiver fora vai aparecer no textfield "fora da linha:true".
Se for paralelo vai aparecer: "paralelo:false"
import flash.events.MouseEvent;
import flash.display.Sprite;
//cria todos os textsfields
var format:TextFormat = new TextFormat();
format.size = 17 ;
var instr:TextField = new TextField();
instr.x = 26;
instr.y = 49;
instr.defaultTextFormat = format;
instr.width = 367;
instr.height = 45;
instr.selectable = false;
//
var line1p1:TextField = new TextField();
line1p1.x = 15;
line1p1.y = 226.6;
line1p1.defaultTextFormat = format;
line1p1.width = 200;
line1p1.height = 65;
line1p1.selectable = false;
//cria outro textfield
var line1p2:TextField = new TextField();
line1p2.x = 15;
line1p2.y = 295;
line1p2.width = 200;
line1p2.height = 65;
line1p2.defaultTextFormat = format ;
line1p2.selectable = false;
//mais um
var line2p1:TextField = new TextField();
line2p1.x = 12;
line2p1.y = 363;
line2p1.width = 200;
line2p1.height = 65;
line2p1.defaultTextFormat = format ;
line2p1.selectable = false;
//outro
var line2p2:TextField = new TextField();
line2p2.x = 12;
line2p2.y = 430;
line2p2.width = 200;
line2p2.height = 65;
line2p2.defaultTextFormat = format ;
line2p2.selectable = false;
//o ultimo
var inter:TextField = new TextField();
inter.x = 363;
inter.y = 219;
inter.width = 209;
inter.height = 203;
inter.defaultTextFormat = format ;
inter.selectable = false;
//agora addChild em tudo
addChild(inter);
addChild(line1p1);
addChild(line1p2);
addChild(line2p1);
addChild(line2p2);
addChild(instr);
var ponto_atual:int = 0;
var pontos = new Array();
stage.addEventListener(MouseEvent.CLICK , mclick);
var ln1:Shape = new Shape();
var ln2:Shape = new Shape();
var lnx:Shape = new Shape();
var lny:Shape = new Shape();
addChild(ln2);
addChild(ln1);
addChild(lnx);
addChild(lny);
instr.text = "clique em lugar para definir o ponto 1(linha 1)";
function mclick(e:MouseEvent):void{
if(ponto_atual == 0){
pontos['x1'] = mouseX;
pontos['y1'] = mouseY;
ponto_atual = 1;
//ja definiu o ponto 1
line1p1.text = "linha 1(ponto1(x1 e y2)) \n x1 = " + pontos["x1"] + "\ny1 = " + pontos["y1"] ;
instr.text = "clique em lugar para definir o ponto 2(linha 1)";
}else
if(ponto_atual == 1){
pontos['x2'] = mouseX;
pontos['y2'] = mouseY;
ln1.graphics.lineStyle(2, 0x000000, 1);
ln1.graphics.moveTo(pontos['x1'], pontos['y1']);
ln1.graphics.lineTo(pontos['x2'], pontos['y2']);
ponto_atual = 2;
line1p2.text = "linha 1(ponto2(x2 e y2)) \n x2 = " + pontos["x2"] + "\ny2 = " + pontos["y2"] ;
//ja definiu o ponto 2
instr.text = "clique em lugar para definir o ponto 3(linha 2)";
}else
if(ponto_atual == 2){
pontos['x3'] = mouseX;
pontos['y3'] = mouseY;
ponto_atual = 3;
line2p1.text = "linha 2(ponto1(x3 e y3)) \n x3 = " + pontos["x3"] + "\ny3 = " + pontos["y3"] ;
//ja definiu o 3
instr.text = "clique em lugar para definir o ponto 4(linha 2)";
}else
if(ponto_atual == 3){
pontos['x4'] = mouseX;
pontos['y4'] = mouseY;
ln2.graphics.lineStyle(2, 0x000000, 1);
ln2.graphics.moveTo(pontos['x3'], pontos['y3']);
ln2.graphics.lineTo(pontos['x4'], pontos['y4']);
ponto_atual = 4;
line2p2.text = "linha 2(ponto2(x4 e y4)) \n x4 = " + pontos["x4"] + "\ny4 = " + pontos["y4"] ;
//ja definiu o 4
instr.text = "Para zerar tudo clique em qualquer lugar";
var a_intc = line_intersection(pontos);
//desenha a linha do ponto de interseção x
lnx.graphics.lineStyle(1, 0xFF0000, 1);
lnx.graphics.moveTo(a_intc['x'], 0);
lnx.graphics.lineTo(a_intc['x'], stage.stageHeight);
//aqui é do y
lny.graphics.lineStyle(1, 0xFF0000, 1);
lny.graphics.moveTo(0, a_intc['y']);
lny.graphics.lineTo(stage.stageWidth,a_intc['y']);
inter.text= "interseção:\nx: " + a_intc["x"] + "\ny: " + a_intc["y"] + "\nfora da linha: " + a_intc['f'] + "\nparalelo: " + a_intc['p'];
}else
if(ponto_atual == 4){
ponto_atual = 0 ;
ln1.graphics.clear();
ln2.graphics.clear();
lnx.graphics.clear();
lny.graphics.clear();
pontos["x1"] = null ;
pontos["x2"] = null ;
pontos["x3"] = null ;
pontos["x4"] = null ;
pontos["y1"] = null ;
pontos["y2"] = null ;
pontos["y3"] = null ;
pontos["y4"] = null ;
//ja apagou tudo
instr.text = "clique em lugar para definir o ponto 1(linha 1)";
}
}
function line_intersection(pontos_array:Array):Array{
var array = new Array();
var x1 = pontos_array['x1'];
var x2 = pontos_array['x2'];
var x3 = pontos_array['x3'];
var x4 = pontos_array['x4'];
var y1 = pontos_array['y1'];
var y2 = pontos_array['y2'];
var y3 = pontos_array['y3'];
var y4 = pontos_array['y4'];
var conta1 = (x1 * y2 - y1* x2) * (x3 - x4) - (x1 - x2) * (x3 * y4 - y3*x4);
var conta2 = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3-x4);
array["x"] = conta1/conta2;
var conta3 = (x1*y2 - y1* x2) * (y3 - y4) - (y1-y2)*(x3*y4 - y3 * x4) ;
var conta4 = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3-x4);
array["y"] = conta3/conta4;//agora verifica se é está fora da linha
if(en(x1,x2,array['x']) && en(y1,y2,array['y']) && en(x3,x4,array['x']) && en(y3,y4,array['y'])){
array["f"] = false;
}else array["f"] = true;
var conta5:Number = (x1 - x2) * (y3 - y4) - (y1 - y2) * (x3 - x4);
if(conta5 ==0){
array['p'] = true;
}else array['p'] = false;
return array ;
}
function en(a:Number , b :Number,c:Number):Boolean{
var maior:Number ;
var menor:Number ;
if(a>B){
maior = a;
menor = b;
}else{
maior = b;
menor = a;
}
if(c >= menor && maior >= c){
return true;
}else return false
}
Para testar esse exemplo:
Crie um fla com 600x500 px e coloque o script no frame 1.
Se quizer pode colocar um static text com "interseção de duas linhas retas" como coloquei.
A função line_intersection recebe um array com os 4 pontos das duas linhas(x1,y1,x2,y2,x3,y3,x4 e y4), e retorna um array com o ponto da interseção(x e y) e se está fora da linha(f) e se é paralelo(p)
Acredito que esse algoritmo possa servir para qualquer liguagem.
Se tiverem algum problema por favor postem.
Discussão (0)
Carregando comentários...