Sinus&Cosinus: Homing Missiles
-
Hi Th69,
Das scheinen ja die fsin, fcos etc. zu sein, und die sind in <allegro.h> definiert.
Ja, fsin(), fcos() sind in allegro.h.
Aber ich möchte die graphics.h behalten!.Gibt es eine gute Mathelib etc. für C++ die ich für Festkommaarithmetik verwenden kann ? Ich kenne leider nur die cmath für C++ und die verlangt das Bogenmaß!
Aber den Umweg über fixed würde ich nicht mehr gehen - bei heutigen Rechnern (und Grafikkarten) kannst du einfach float-Berechnungen benutzen (außer du benutzt spezielle Umgebungen).
Klar heute sind wir schnell genug!
Viele Grüße und danke für Deine Hilfe,
Merlin
-
Hi,
ich hab darüber nachgedacht. Th69 hat vollkommen recht es macht keinen Sinn an dem fixed-Gedöns festzuhalten weder aus lerntechnischer Hinsicht oder sonstwie!
Ich habe den Code abgeändert aber leider trifft die Rakete ihr Ziel jetzt überhaupt nicht mehr!
Ich hab nicht den leisesten Schimmer wo der Fehler liegt.
void home_in () { // the x, y position of the homing missile int x = SCREEN_W / 2; int y = SCREEN_H / 2; // the angle and length of the missile's velocity vector double angle = 0.0; int length = 1; double angle_stepsize = 1* PI / 180; // determines whether the missile has reached // the target and a new one should be chosen bool new_target = true; // angle to the target double target_angle; // position of the target int target_x; int target_y; while (!GetAsyncKeyState(VK_ESCAPE)) { setbkcolor(0); // Hintergrundfarbe des Ausgabefensters schwarz cleardevice(); // Löschen des Ausgabefensters // choose new target randomly when needed if (new_target == true) { target_x = ((SCREEN_W + rand() % (2 * SCREEN_W)) / 4); target_y = ((SCREEN_H + rand() % (2 * SCREEN_H)) / 4); new_target = false; } // draw a pixel where the target is putpixel ((target_x), (target_y),15); // draw the missile // (actually a circle with a line representing the angle) setcolor(WHITE); circle (x, y, 20); line (x, y, x + (9 * cos (angle)), y + (9 * sin (angle))); // move the missile x = x + length * cos (angle); y = y + length * sin (angle); // if we are very close to the target, set a new target if (abs (x - target_x) + abs (y - target_y) < 10) { new_target = true; } // calculate the angle from the missile to the target target_angle = atan2 (target_y - y, target_x - x); if (fmod(angle - target_angle, 2*PI) < PI) { angle = (angle - angle_stepsize) ; } else { angle = (angle + angle_stepsize) ; } delay (20); } }
Vielen Dank für eure Mühe,
Merlin
-
Dann debugge es oder laß dir die Werte (x, y, angle, ...) in einer Konsole (oder Trace-Fenster oder Logdatei) ausgeben.
-
Atan2 gibt einen Wert zwischen - pi und pi. Was versprichst du dir von dem fmod? Ich denke, du kannst mit
if(target_angle<0) ... else ....
arbeiten
-
Hi Schlangenmensch,
stimmt den fmod hab ich schon entfernt.
Aber es muss heißen:if ((angle - target_angle) < PI) { angle = (angle - angle_stepsize) ; } else { angle = (angle + angle_stepsize) ; }
Wenn ich auf 0 prüfe nimmt die Rakete einen anderen Weg und fliegt sogar etwas näher am Ziel vorbei aber sonst genauso chaotisch!
Grüße und danke für Deine Hilfe,
Merlin
-
So, irgendwie hat mich das jetzt etwas in den Fingern gejuckt.
Mehrere Punkte:
1: Du hast noch Typenunverträglichkeiten durch dein Wechsel auf floatingpoint. Grade bei Divisionen ist das blöd, da da schonmal Kommastellen abegschnitten werden. Auch solltest du von abs() auf fabs() wechseln.2: Wenn du mit einer Länge von 1 arbeitest schießt du schnell am Ziel vorbei, passt aber den Winkel nur sehr langsam an. Ich habe jetzt mal 0.1 als Länge genommen.
3: Dein Winkel Vergleich oszilliert um PI:
if ((angle - target_angle) < 0) { angle = (angle + angle_stepsize); } else { angle = (angle - angle_stepsize); }
funktioniert mit der Länge 0.1.
-
Nur ein kleiner Tip am Rande: Um zu entscheiden ob die Rakete nach links oder rechts drehen soll braucht man keine Winkelfunktionen.
Abstandsvektor Rakete->Ziel, 90° drehen, Flugvektor draufprojizieren (dot product), Vorzeichen prüfen. Fertig.
Da man bloss am Vorzeichen interessiert ist kann man sich auch das Normalisieren sparen.
-
LeftRight(U,V) { return U.x*V.y-U.y*V.x }
-
@Schlangenmensch
Ich habe alles so abgeändert wie Du es gesagt hat aber jetzt fliegt die Rakete auf einer Kreisbahn!Könntest Du Deinen kompletten funktionierenden Code posten?
Ich mach glaub ich einen Kardinalsfehler!#include<windows.h> #include<graphics.h> #include<cmath> #define PI 3.141592654 // circ7 void home_in(); int SCREEN_W = 600; int SCREEN_H = 400; main(int argc, char*argv[]) { // Deklaration und Initialisierung des Grafiktreibers int graphdriver, graphmode; graphdriver = DETECT; initgraph(&graphdriver, &graphmode, "Draw_Sine"); // graphics.h kann keine Windowstitel setzen setbkcolor(0); // Hintergrundfarbe des Ausgabefensters schwarz cleardevice(); // Löschen des Ausgabefensters setcolor(15); // Textfarbe weiss (15) settextstyle(10, HORIZ_DIR, 2); // Fontsyle, Richtung und Größe //outtextxy(20, 120, "Sinuskurve zeichnen: "); // Textausgabe home_in(); // Funktionsaufruf von home_in() return 0; } void home_in() { // the x, y position of the homing missile double x = SCREEN_W / 2; double y = SCREEN_H / 2; // the angle and length of the missile's velocity vector double angle = 0; double length = 0.1; double angle_stepsize = 1 * PI / 180; // determines whether the missile has reached // the target and a new one should be chosen bool new_target = true; // angle to the target double target_angle; // position of the target double target_x; double target_y; while (!GetAsyncKeyState(VK_ESCAPE)) { setbkcolor(0); // Hintergrundfarbe des Ausgabefensters schwarz cleardevice(); // Löschen des Ausgabefensters // choose new target randomly when needed if (new_target == true) { target_x = ((SCREEN_W + rand() % (2 * SCREEN_W)) / 4); target_y = ((SCREEN_H + rand() % (2 * SCREEN_H)) / 4); new_target = false; } // draw a pixel where the target is putpixel ((target_x), (target_y),15); // draw the missile // (actually a circle with a line representing the angle) setcolor(WHITE); circle (x, y, 20); line (x, y, x + (9 * cos (angle)), y + (9 * sin (angle))); // move the missile x = x + length * cos (angle); y = y + length * sin (angle); if (fabs (x - target_x) + abs (y - target_y) < 10) { new_target = true; } // calculate the angle from the missile to the target target_angle = atan2 (target_y - y, target_x - x); if ((angle - target_angle) < 0) { angle = (angle - angle_stepsize) ; } else { angle = (angle + angle_stepsize) ; } delay (1); } }
Danke für Eure Mühe und Hilfe,
Merlin_2
-
Ich poste meinen Code morgen früh, wenn ich wieder am Computer sitze.
Edit: mach mal bei deinem angle stepsize: PI/180.
Also floating point division.
-
@Schlangenmensch
Du wolltest doch Deinen Code posen ;-))Gruß,
Merlin_2
-
Stimmt...hatte gehofft, dass sich das mit der angepassten Winkel Stepgröße ergeben hätte.
Ich habe den Grafikkram auskommentiert und verlasse die Schleife wenn das Ziel getroffen wird. Außerdem sind noch ein paar Debugausgaben drin
#include <iostream> #include <math.h> #define SCREEN_W 800. #define SCREEN_H 600. #define SCREEN_Wi 800 #define SCREEN_Hi 600 #define PI 3.14159265359 void home_in() { // the x, y position of the homing missile double x = SCREEN_W / 2.0; double y = SCREEN_H / 2.0; std::cout << x << std::endl; // the angle and length of the missile's velocity vector double angle = 0.0; double length = 0.1; double angle_stepsize = PI / 180.; // determines whether the missile has reached // the target and a new one should be chosen bool new_target = true; // angle to the target double target_angle; // position of the target double target_x; double target_y; target_x = ((SCREEN_W + rand() % (2 * SCREEN_Wi)) / 4); std::cout << target_x << std::endl; target_y = ((SCREEN_H + rand() % (2 * SCREEN_Hi)) / 4); new_target = false; int count = 0; while (!new_target && count < 10000) { //setbkcolor(0); // Hintergrundfarbe des Ausgabefensters schwarz //cleardevice(); // Löschen des Ausgabefensters // choose new target randomly when needed ++count; /* if (new_target == true) { target_x = ((SCREEN_W + rand() % (2 * SCREEN_W)) / 4); target_y = ((SCREEN_H + rand() % (2 * SCREEN_H)) / 4); new_target = false; } */ // draw a pixel where the target is // putpixel((target_x), (target_y), 15); // draw the missile // (actually a circle with a line representing the angle) //setcolor(WHITE); // circle(x, y, 20); // line(x, y, x + (9 * cos(angle)), y + (9 * sin(angle))); // move the missile x = x + length * cos(angle); y = y + length * sin(angle); // if we are very close to the target, set a new target if (fabs(x - target_x) + fabs(y - target_y) < 10) { new_target = true; } // calculate the angle from the missile to the target target_angle = atan2(target_y-y, target_x-x); if ((angle - target_angle) < 0) { angle = (angle + angle_stepsize); } else { angle = (angle - angle_stepsize); } //delay(20); if ((count % 1000) == 0) { std::cout << target_x << " " << target_y << " " << target_angle << std::endl; std::cout << x << " " << y << " " << angle << std::endl; std::cout << "dif: " << " " << angle - target_angle << std::endl << std::endl; } } if (new_target) std::cout << "hit \n"; else std::cout << "no hit \n"; std::cout << target_x <<" " << target_y << std::endl; std::cout << x << " " << y << std::endl; } int main() { home_in(); std::cin.get(); }
Edit Da ich auf dem Sprung war, habe ich Den Code nicht aufgeräumt, ich bitte das zu verzeihen