Gå til innhold

C#: Vinkel mellom to punkter og rotasjon


Anbefalte innlegg

Holder på med et lite tank 2D spill i C#, og jeg ønsker å kunne vise på skjermen vinkelen jeg må rotere tanksen for å sikte rett på målet.

 

Eksempeldata kan være(posisjoner):

 

Tank: X= 20, Y= -24

Mål: X=18, Y= -25

 

Jeg har googla litt, og ser ut til å måtte bruker Math.Atan2(???)... men jeg får det ikke til og sitter fast.

 

Videre ønsker jeg da å vise hvor mye rotasjon(litt debug tekst) som skal til fra hvilken retning tanksen har til målet.

 

Si at tanksen peker rett nord, 90 grader, så vil jeg da vite hvor mye rotasjon i grader (positiv til venstre, negativ til høyre).

Lenke til kommentar
Videoannonse
Annonse

Vel, problemet er at en vinkel som du får utifra arcus tangens ikke forteller deg ikke nødvendigvis den riktige vinkelen.

Det som kunne gått an, kunne vært å laget en rotasjonsmatrise utifra den normaliserte verdien mellom A og B.

 

Jeg bare tenker litt nå, men her er en 2D roteringsmatrise:

cos(V) -sin(V)
sin(V)  cos(V)

Ta en vektor, la oss kalle den C, som er lik Mål - Start, og normaliser den (altså divider X og Y på lengden)

Deretter danner dy en ny matrise, hvor du bytter ut cos med X og sin med Y fra tabellen vist over. Dette skal his jeg tenker riktig, gi den en roteringsmatrise som roterer hva som helst mot målet.

 

Da slipper du å tenke arcus tangens, som ville ført med seg en del if setninger, og livet blir med ett veldig mye enklere.

 

edit: ops, hvis du vil vise vinkelen i tekst, må du nesten ty til arcus tangens.

Endret av GeirGrusom
Lenke til kommentar
edit: ops, hvis du vil vise vinkelen i tekst, må du nesten ty til arcus tangens.

 

Hmm... ja. var det jeg hadde tenkt meg da. Får prøve igjen. men jeg får feil når jeg regner på det :( me fails

 

           int p1_x = 1;
           int p1_y = 2;

           int p2_x = 2;
           int p2_y = -1;

           double n1 = Math.Sqrt(p1_x * p1_x + p1_y * p1_y);
           double n2 = Math.Sqrt(p2_x * p2_x + p2_y * p2_y);
           double angle = Math.Acos((p1_x * p2_x + p1_y * p2_y) / (n1 * n2)) * 180 / Math.PI;

           MessageBox.Show("Angle: " + angle);

 

På koden ovenfor må jeg fremdeles drive å teste på koordinatene, for den returnerer 90, da den skulle ha returner 270 slik jeg har tenkt det

Endret av South_Bridge
Lenke til kommentar

Problemet ditt kan være at en ikke kan regne ut en vinkel fra tangens til en vinkel alene.

 

Bruk enhetssirkelen for å se for deg hvor problemet er.

 

Cosinus går langs den horisontale linjen, sinus går langs den vertikale, mens tangens går diagonalt. Problemet er at en ikke kan vite hvilken side (positiv eller negativ) en er på ved å bare vite tangens til en vinkel.

 

vector dist = dest - src;
var angle = Math.Atn(dist.Y / dist.X); // Skal gi deg vinkel

Hva hvis en av dem er negative? Denne kan gi riktig svar i to av tilfellene mens det egentlig er fire. For å rette dette, er det enklest å velge for eksempel Y og trekke fra, legge til..180 grader? eller whatever dersom den er negativ.

Jeg er litt sløv i dag :S

Lenke til kommentar

Jeg ser med min formel(copypaste fra en annen), så får jeg alltid den korteste.

 

           int p1_x = 2;
           int p1_y = 2;

           int p2_x = 0;
           int p2_y = -2;

 

Skull jo gi 225 som jeg tenker, men gir meg 135 som er den "andre" veien. Jeg må vel da drive å teste punktene i hvilken kvadrant de ligger i da? hmm... litt tungvint menne.

Endret av South_Bridge
Lenke til kommentar

Nå er ikke jeg noen ekspert på dette i det heletatt, men jeg har lyst til å gjøre et forsøk på å hjelpe.

 

Det første du vil gjøre er å trekke ut vektoren her.

 

Ax = 10

Ay = 20

Bx = 5

By = 15

 

Vx = Ax-Bx = -5

Vy = Ay-By = -5

 

Når Vx er negativ så er målet vest for tanken. Hvis Vx er positiv så er målet øst for tanksen.

 

Når Vy er negativ så er målet sør for tanksen og nord for tanksen når Vy er positiv.

 

Så er det bare å beregne vinkelen mellom de to punktene.

 

Sannsynligvis så har tanksen din også en eller to retningsvektorer. En bevegelsesretning og hastighet og eventuelt også en retning på løpet med høydevinkel (avgjør avstand til nedslagsområdet).

 

Disse må du også ta hensyn til når du beregner hvor målet er i forhold til hvor tanksen peker.

 

 

...egentlig bare åpenbare ting jeg skriver her som du sikkert er kjent med fra før, men man vet jo aldri. :)

Lenke til kommentar
Sannsynligvis så har tanksen din også en eller to retningsvektorer. En bevegelsesretning og hastighet og eventuelt også en retning på løpet med høydevinkel (avgjør avstand til nedslagsområdet).

 

Disse må du også ta hensyn til når du beregner hvor målet er i forhold til hvor tanksen peker.

 

Har ikke tenkt å gjøre det så vanskelig med det første, men er en fremtidig feature :D

 

Koden min ser ut til å funke nå (med tanke på vinkelen til tanken og målet)

 

           int p1_x = 10;
           int p1_y = 20;

           int p2_x = 5;
           int p2_y = 15;

           int vx = p2_x - p1_x;
           int vy = p2_y - p1_y;

           double n1 = Math.Sqrt(p1_x * p1_x + p1_y * p1_y);
           double n2 = Math.Sqrt(p2_x * p2_x + p2_y * p2_y);
           double angle = Math.Acos((p1_x * p2_x + p1_y * p2_y) / (n1 * n2)) * 180 / Math.PI;

           if (vx < 0 && vy > 0)
               angle += 90;
           else if (vx < 0 && vy < 0)
               angle += 180;
           else if (vx > 0 && vy < 0)
               angle += 270;

           MessageBox.Show("Angle: " + angle);

 

Må vel nå trekke fra retningen til tanken(90 grader, altså rett nord) og ta noen if tester igjen da???

Endret av South_Bridge
Lenke til kommentar

Dette ser ut til å funke for meg... Må implementere det i tankspillet men det ser ut til å funke som sagt. MessageBoxene skal seff erstattes med en string jeg kan legge til gui'en.

 

           int p1_x = 10;
           int p1_y = 20;

           int p2_x = 15;
           int p2_y = 15;

           int vx = p2_x - p1_x;
           int vy = p2_y - p1_y;

           double n1 = Math.Sqrt(p1_x * p1_x + p1_y * p1_y);
           double n2 = Math.Sqrt(p2_x * p2_x + p2_y * p2_y);
           double angle = Math.Acos((p1_x * p2_x + p1_y * p2_y) / (n1 * n2)) * 180 / Math.PI;

           if (vx < 0 && vy > 0)
               angle += 90;
           else if (vx < 0 && vy < 0)
               angle += 180;
           else if (vx > 0 && vy < 0)
               angle += 270;

           double tank_retning = 90;

           if (angle > tank_retning && angle < tank_retning+180)
               MessageBox.Show("Turn RIGHT");
           else
               MessageBox.Show("Turn LEFT");

Lenke til kommentar

           //Spiller
           int p1_x = 10;
           int p1_y = 20;

           //Mål
           int p2_x = 15;
           int p2_y = 15;

           //Avstand X og Y
           int vx = p2_x - p1_x;
           int vy = p2_y - p1_y;

 

Nå kjenner vi lengden på katetene i en rettvinklet trekant og det er nå vi må begynne å beregne vinkelen.

 

Hvis vi ser i trigonometrien så vil tangens invers gi oss vinkelen vi er ute etter, men hvilket katet vi bruker som teller og nevner er avhengig av hvilken kvadrant vektoren peker mot.

 

I et rutenett så er kvadrantene definert mot klokken slik:

1. kvadrant = positiv vx og positiv vy

2. kvadrant = negativ vx og positiv vy

3. kvadrant = negativ vx og negativ vy

4. kvadrant = positiv vx og negativ vy

 

Hvis vi er i første kvadrant så vil vy være teller og vx være nevner.

Hvis vi er i andre kvadrant så vil vx være teller og vy være nevner og vi må legge til 90 grader

Hvis vi er i tredje kvadrant så vil vy være teller og vx være nevner og vi må legge til 180 grader.

Hvis vi er i fjerde kvadrant så vil vx være teller og vy være nevner og vi må legge til 270 grader.

 

if (vx >= 0 && vy > 0){
 //første kvadrant
 //Beregne tangens invers av vx/vy
}
else if (vx < 0 && vy >= 0){
 //andre kvadrant
 //Beregne tangens invers av vy/abs(vx) og legge til 90 grader
}
else if (vx <= 0 && vy < 0){
 //tredje kvadrant
 //Beregne tangens invers av abs(vx)/abs(vy) og legge til 180 grader
}
else if (vx > 0 && vy <= 0){
 //fjerde kvadrant
 //Beregne tangens invers av abs(vy)/vx og legge til 270 grader
}
else {
 //Du står rett oppå målet
}

 

Du vil da ha vinkelen mot målet i forhold til en tanks som peker langs X-aksen (mot høyre).

 

Du må justere denne vinkelen i forhold til hvilken vei tanksen peker før du har relativ vinkel i forhold til vinkelen på tanksen. Først da kan du avgjøre om det vil være kortest å svinge mot høyre eller venstre for å sikte rett mot målet.

 

 

Håper dette hjelper.

 

Kilde: http://www.matematikk.net/klassetrinn/klas...rigonometri.php tangens-eksempel 2

 

OBS OBS OBS OBS OBS

Legg merke til at du alltid bruker større/mindre eller lik kun når du sjekker telleren. På den måten unngår du dumme division by zero-feil.

 

Disclaimer: Jeg har ikke forsøkt å kode dette. Dette er kun matematiske beregninger foretatt klokken ett på natten. ;)

 

Edit: La til siste ELSE slik at man ungår å ikke gjore noe som helst hvis man står oppå målet. (vx = 0 && vy=0;)

Endret av BlueEAGLE
Lenke til kommentar

Opprett en konto eller logg inn for å kommentere

Du må være et medlem for å kunne skrive en kommentar

Opprett konto

Det er enkelt å melde seg inn for å starte en ny konto!

Start en konto

Logg inn

Har du allerede en konto? Logg inn her.

Logg inn nå
  • Hvem er aktive   0 medlemmer

    • Ingen innloggede medlemmer aktive
×
×
  • Opprett ny...