Kleines Problem mit Rotation



  • Hallo!

    Ich versuche gerade ein Geschütz auf das Ziel zeigen zu lassen. Den Winkel der Waffe einfach auf den des Ziels zu setzen funktioniert ohne Probleme, allerdings möchte ich dass der Lauf sich in Schritten dem gewünschten Winkel annähern soll.
    Sonst wäre die Bewegung zu sprunghaft.

    Leider gibts bei der Berechnung Probleme...

    xBuf=(targetAimed->x-Position.x);
    	yBuf=(targetAimed->z-Position.z);
    	angleOfFire=atan2f(xBuf,yBuf);
    
    	float grad=(angleOfFire-gFAngle)*180/D3DX_PI;
    
    	float segment=grad/360*2*1*D3DX_PI;
    
    	if(segment>=2*D3DX_PI-segment){
    		turretAimsTargetProcessLeftRight = false;
    	}
    	else
    		turretAimsTargetProcessLeftRight = true;
    

    Wobei gFAngle der Winkel der Waffe ist und anfangs 0 ist.
    Und angleOfFire der Winkel des Ziels aus sicht der Waffe ist.
    Je nach dem was bei turretAimsTargetProcessLeftRight herauskommt wird die Waffe nachher in Schritten nach links oder rechts bewegt.

    if(turretAimsTargetProcessLeftRight)
    				gFAngle+= 1 / 5.0f;
    			else
    				gFAngle-= 1 / 5.0f;
    

    Das Problem ist eben dass die Waffe manchmal in die falsche Richtung läuft und somit fast eine volle Umdrehung macht.

    Dabei muss man aber noch einberechnen dass das ganze um PI/2 rotiert ist.
    Also noch PI/2 zum Winkel der Waffe dazugerechnet werden muss damit die Waffe selbst auch auf die richtige Stelle zeigt.

    Ich sitze da jetzt schon länger dran, hab auch schon einen längeren Tag hinter mir und drehe fast durch, weil es langsam wirklich nervt.



  • ich hatte das problem neulich auch. mathematisch kann man sich da wohl helfen, das soll wohl aber in vielen if-verzweigungen enden... sicher weiß ich das aber nicht, da ich mich nicht auf "viele if-verzweigungen" einlassen wollte.

    ich hab nun den winkel also einmal ausgerechnet, habe mich dann um ein grad (oder eine einheit, wie auch immer) gedreht um dann nochmal den aktuellen winkel zu berechnen. wenn der aktuelle winkel jetzt kleiner als der erste ist, dann wird weitergedreht, ansonsten dreht man die drehrichtung um.
    (die zwischendrehung wird natürlich nur theoretisch gemacht, also nciht wirklich gezeichnet...)
    nicht besonders effektiv, geht aber erstmal 🙂



  • Da Du ja schon ueberpruefst ob weiter als 180 Grad gedreht werden muesste, brauchst Du eigentlich nur noch in Zeile 5 den Absolutwert zu nehmen.



  • iop schrieb:

    ich hatte das problem neulich auch. mathematisch kann man sich da wohl helfen, das soll wohl aber in vielen if-verzweigungen enden... sicher weiß ich das aber nicht, da ich mich nicht auf "viele if-verzweigungen" einlassen wollte.

    ich hab nun den winkel also einmal ausgerechnet, habe mich dann um ein grad (oder eine einheit, wie auch immer) gedreht um dann nochmal den aktuellen winkel zu berechnen. wenn der aktuelle winkel jetzt kleiner als der erste ist, dann wird weitergedreht, ansonsten dreht man die drehrichtung um.
    (die zwischendrehung wird natürlich nur theoretisch gemacht, also nciht wirklich gezeichnet...)
    nicht besonders effektiv, geht aber erstmal 🙂

    Ich weiß nicht ob ich das richtig verstanden habe aber du rechnest dir den Winkel aus, drehst dich dann in eine richtung (wie entscheidest du das?) und dann schaust du ob es größer oder kleiner ist. Verstehe ich nicht ganz.

    hellihjb schrieb:

    Da Du ja schon ueberpruefst ob weiter als 180 Grad gedreht werden muesste, brauchst Du eigentlich nur noch in Zeile 5 den Absolutwert zu nehmen.

    In Zeile 5 rechne ich die differenz von angleOfFire und gFAngle in Grad um...
    also alpha(RAD)*180/PI=alpha(Grad)
    Wenn ich dann den Winkel habe rechne ich den Kreissektor -http://de.wikipedia.org/wiki/Kreissektor - aus und vergleiche dann welcher der beiden größer ist.
    Aber ich denke da ist irgendwo ein großer Fehler drin



  • "angleOfFire" ist der Winkel in den gefeuert werden soll,
    "gFAngle" ist der Winkel entlang dem das Geschuetz momentan ausgerichtet ist.
    Du willst "gFAngle" auf dem kuerzesten Weg zu "angleOfFire" bewegen.
    Dazu musst Du erstens feststellen in welche Richtung es kuerzer ist (Differenz kleiner PI) und den Umbruch bei 2*PI beachten (Differenz kann negativ sein).

    gFAngle < angleOfFire:
    Bewege Dich in positiver Richtung wenn (angleOfFire-gFAngle) < PI

    gFAngle > angleOfFire:
    Bewege Dich in negativer Richtung wenn (gFAngle-angleOfFire) < PI



  • hellihjb schrieb:

    "angleOfFire" ist der Winkel in den gefeuert werden soll,
    "gFAngle" ist der Winkel entlang dem das Geschuetz momentan ausgerichtet ist.
    Du willst "gFAngle" auf dem kuerzesten Weg zu "angleOfFire" bewegen.
    Dazu musst Du erstens feststellen in welche Richtung es kuerzer ist (Differenz kleiner PI) und den Umbruch bei 2*PI beachten (Differenz kann negativ sein).

    gFAngle < angleOfFire:
    Bewege Dich in positiver Richtung wenn (angleOfFire-gFAngle) < PI

    gFAngle > angleOfFire:
    Bewege Dich in negativer Richtung wenn (gFAngle-angleOfFire) < PI

    ok hab das mal so implementiert:

    if(!turretAimsTarget){
    			float xBuf,yBuf;
    			if(!turretAimsTargetProcess){
    
    				xBuf=(targetAimed->x-Position.x);
    				yBuf=(targetAimed->z-Position.z);
    				angleOfFire=atan2f(xBuf,yBuf);
    
    				angleOfFire+=D3DX_PI/2;
    
    				if(gFAngle<angleOfFire){
    					if(angleOfFire-gFAngle<D3DX_PI)
    						turretAimsTargetProcessLeftRight=true;
    				}
    				if(gFAngle>=angleOfFire){
    					if(gFAngle-angleOfFire<D3DX_PI)
    						turretAimsTargetProcessLeftRight=false;			
    				}	
    				turretAimsTargetProcess=true;
    
    			}
    
    			if(turretAimsTargetProcessLeftRight)
    				gFAngle+= 1 / 5.0f;
    			else
    				gFAngle-= 1 / 5.0f;
    
    			if(gFAngle>=D3DX_PI*2)
    				gFAngle-=D3DX_PI*2;
    
    			if(gFAngle<=0)
    				gFAngle+=D3DX_PI*2;
    
    			if(angleOfFire>=D3DX_PI*2)
    				angleOfFire-=D3DX_PI*2;
    
    			if(angleOfFire<=0)
    				angleOfFire+=D3DX_PI*2;
    
    			ma=MAX(gFAngle,angleOfFire);
    			mi=MIN(gFAngle,angleOfFire);
    
    			if((ma-mi)<=0.1f){
    				turretAimsTarget=true;
    				shotStartTime=(unsigned) timeGetTime();
    			}
    
    	}
    

    Der erste Teil soll eben nur einmal aufgerufen werden sobald das ziel in reichweite ist und die richtung des schwenkens bestimmen.
    Der zweite Teil bewegt dann die turret in die richtung.
    Aber das problem besteht immer noch dass sie in manchen situationen in die falsche richtung steuert und somit fast eine volle umdrehung macht.
    😞



  • Ich hatte als selbstverstaendlich vorausgesetzt:

    gFAngle < angleOfFire:
    Bewege Dich in positiver Richtung wenn (angleOfFire-gFAngle) < PI (sonst in negative Richtung)

    Weiterhin brauchst Du eine Abbruchbedingung ("angleOfFire" ist irgendwann erreicht bzw ueberschritten).



  • hellihjb schrieb:

    Ich hatte als selbstverstaendlich vorausgesetzt:

    gFAngle < angleOfFire:
    Bewege Dich in positiver Richtung wenn (angleOfFire-gFAngle) < PI (sonst in negative Richtung)

    Das hatte ich auch schon eingefügt aber es hat nichts gebracht

    if(gFAngle<angleOfFire){
    					if(angleOfFire-gFAngle<D3DX_PI)
    						turretAimsTargetProcessLeftRight=true;
    					else
    						turretAimsTargetProcessLeftRight=false;
    				}
    				if(gFAngle>angleOfFire){
    					if(gFAngle-angleOfFire<D3DX_PI)
    						turretAimsTargetProcessLeftRight=false;	
    					else
    						turretAimsTargetProcessLeftRight=true;
    				}
    

    hellihjb schrieb:

    Weiterhin brauchst Du eine Abbruchbedingung ("angleOfFire" ist irgendwann erreicht bzw ueberschritten).

    Meinst du beim drehen später oder bei der Richtungsberechnung...sorry stehe gerade auf dem schlauch

    Ich dachte auch dass es daran liegen könnte dass die Winkel identisch sein könnten und hab eine Variable zur Absicherung eingebaut:

    if(gFAngle==angleOfFire)
    					hasToTurn=false;
    				else
    					hasToTurn=true;
    

    und frage dann vor dem drehen ab ob diese true ist.



  • Angenommen "gFAngle" ist 0.0 und "angleOfFire" ist 1.1, dann bewegst Du "gFAngle" jedes mal um +0.2 (1/5) weiter:
    0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, ...
    Wieso sollte Dein Geschuetz jemals aufhoeren sich zu drehen?



  • hellihjb schrieb:

    Angenommen "gFAngle" ist 0.0 und "angleOfFire" ist 1.1, dann bewegst Du "gFAngle" jedes mal um +0.2 (1/5) weiter:
    0.0, 0.2, 0.4, 0.6, 0.8, 1.0, 1.2, 1.4, ...
    Wieso sollte Dein Geschuetz jemals aufhoeren sich zu drehen?

    Danke...jetzt funktionierts bzw nach 5 Minuten testen ist es nicht mehr aufgetreten...
    hab die rotationsgeschwindigkeit angepasst...
    🤡


Anmelden zum Antworten