# Spritebewegung rotiert zum Mausklick



## Eichelhäer (30. Jun 2015)

Hallo zusammen,

seit längerem beschäftige ich mich mit der Sprite-Bewegung eines Strategiespiels wie beispielsweise C&C.

Hierfür habe ich den Mittelpunkt des Sprites (hier ein Panzer) berechnet und möchte diesen möglichst linear auf die aktuell geklickte Mausposition zubewegen. Zuerst habe ich den Winkel zwischen Sprite und Maus berechnet mittels atan2 und schließlich die Geschwindigkeit xspeed bzw. yspeed mit Kosinus bzw. Sinus. Wenn ich nun den jeweiligen Speed zur Position hinzuaddiere pro Frame sollte sich das Sprite auch zum Mauszeiger hinbewegen, nur tut es das keineswegs. Stattdessen schwebt das Sprite nach Klick völlig unkoordiniert über das JLabel.

Hier meine Frage:

Wie kann ich erreichen, dass sich das Sprite linear zum Mauszeiger hinbewegt, dort stehenbleibt und keine seltsamen Drehungen mehr macht, sondern in der richtigen Richtung ausgerichtet bleibt?

Darüber hinaus würde mich interessieren wie man es realisiert, dass sich das Sprite zuerst um sein Zentrum dreht bis es die Bewegungsrichtung gefunden hat und dann erst losfährt?

Hier mein etwas rudimentärer Code:


```
[B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]public
[/COLOR][/SIZE][/COLOR][/SIZE][/B][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]void[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2] update([/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]int[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]xm[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2],[/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]int[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]ym[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2],[/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]long[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]delta[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]){[/SIZE]
[SIZE=2]        
            
[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]bounding[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]x[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = ([/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]int[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2])[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]centerx[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2];[/SIZE]
[SIZE=2]            
[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]bounding[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]y[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = ([/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]int[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2])[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]centery[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]; [/SIZE]
[SIZE=2]            
            
[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]winkel[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = Math.[I]toDegrees[/I]((Math.[I]atan2[/I]([/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]ym[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]-[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]centerx[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2],[/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]xm[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]-[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]centerx[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2])));[/SIZE]
[SIZE=2]            
            
[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]xspeed[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = Math.[I]cos[/I]([/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]winkel[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]);[/SIZE]
[SIZE=2]            
[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]yspeed[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = Math.[I]sin[/I]([/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]winkel[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]);[/SIZE]
[SIZE=2]            
            
[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]centerx[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] += [/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]xspeed[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2];[/SIZE]
[SIZE=2]            
[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]centery[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] += [/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]yspeed[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2];[/SIZE]
[SIZE=2]            
            System.
[/SIZE][B][I][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]out[/COLOR][/SIZE][/COLOR][/SIZE][/I][/B][SIZE=2].println([/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]winkel[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]);[/SIZE]
[SIZE=2]    }
    
    
[/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]public[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2] BufferedImage rotate([/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]double[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]winkel[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]){[/SIZE]
[SIZE=2]        AffineTransform 
[/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]at[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = AffineTransform.[I]getRotateInstance[/I](Math.[I]toRadians[/I]([/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]winkel[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]),[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]pic[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].getWidth()/2,[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]pic[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].getHeight()/2);[/SIZE]
[SIZE=2]        BufferedImage 
[/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]rotateImage[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = [/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]new[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2] BufferedImage([/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]pic[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].getWidth(),[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]pic[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].getHeight(),[/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]pic[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].getType());[/SIZE]
[SIZE=2]        Graphics2D 
[/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]g2[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2] = (Graphics2D) [/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]rotateImage[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].getGraphics();[/SIZE]
[SIZE=2]        
[/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]g2[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].setTransform([/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]at[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2]);[/SIZE]
[SIZE=2]        
[/SIZE][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]g2[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2].drawImage([/SIZE][SIZE=2][COLOR=#0000c0][SIZE=2][COLOR=#0000c0]pic[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2],0,0,[/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]null[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2]);[/SIZE]
[SIZE=2]        
[/SIZE][B][SIZE=2][COLOR=#7f0055][SIZE=2][COLOR=#7f0055]return[/COLOR][/SIZE][/COLOR][/SIZE][/B][SIZE=2][COLOR=#6a3e3e][SIZE=2][COLOR=#6a3e3e]rotateImage[/COLOR][/SIZE][/COLOR][/SIZE][SIZE=2];[/SIZE]
[SIZE=2]    }
[/SIZE]
```


Würde mich über Hilfe sehr freuen.



Eichelhäer


----------



## Major_Sauce (30. Jun 2015)

Das da oben ist für mich alles andere als Java code...

Naja, mal die Theorie:

Ich gehe mal aus wir sind im 2-Dimensionalen Raum, da wirst du dann eben die Zielkoordinaten haben, und die Koordinaten des Panzers. Das eine vom anderen mal abziehen, dann noch mal die Differenz der y-Koordinaten durch die der x-Koordinaten teilen, schon hast du eine Steigung, welche dir angibt um wie viel Längeneinheiten das ding sich in der y-Koordinate bewegt, wenn du das ding um eine Flächeneinheit in x-Richtung bewegst, wenn du in Mathe ein wenig aufgepasst hast dann dürftest du wissen wovon ich rede.

Das könnte vielleicht helfen:
Steigung berechnen | Lineare Funktionen - Mathebibel.de

Dann sollte man sich noch gedanken um die Geschwindigkeit machen, da du aber nun ein Rechtwinkliges Dreieck  bilden kannst, bei dem eine Seite parallel zur x-Achse verläuft, die andere zur y-Achse, und die Hypotenuse dürfte wohl auf der Strecke von Panzer zum Zielpunkt liegen, dann musst du den Betrag der Länge der Hypotenuse so festlegen dass er der Geschwindigkeit des Panzers entspricht. In dem Dreieck am bessten auch noch mal die Winkel ausrechnen, werden zur Rotation des Sprites benötigt. 
Wenn du die Hypotenuse und nen Winkel im Dreieck hast, kannst du die entsprechende x und y verschiebung über den Pythagoras berechnen, dann weißt du um wie viele Längeneinheiten der Panzer in x- und y-Richtung verschoben werden müssen.

Um wie viel grad du den Panzer drehen musst sollte dann auch klar sein, das ist der Winkel welcher von Hypotenuse und x-Achse eingeschlossen wird.

Wenn du es etwas "einfacher" erklärt haben willst, dann solltest du beim nächsten mal vielleicht noch ein paar infos hinzufügen, vll mal nen kleinen Screenshot oder ähnliches, da ich mir nicht wirklich vorstellen kann wie es bei dir im mom aussieht und wie der Panzer zum Bleistift gedreht wird (Vogelperspektive ?)

mfg Major


----------



## Eichelhäer (30. Jun 2015)

Hallo,

erstmal danke für die schnelle Antwort. Zunächst einmal hier nochmal der Java Code der Drehung sowie die update-Methode der Klasse Tank.

*public
* *void* update(*int* xm,*int* ym,*long* delta){
 

bounding.x = (*int*)centerx;
 
bounding.y = (*int*)centery; 
 

winkel = Math._toDegrees_((Math._atan2_(ym-centerx,xm-centerx)));
 

xspeed = Math._cos_(winkel);
 
yspeed = Math._sin_(winkel);
 

centerx += xspeed;
 
centery += yspeed;
 
	        System.
*out*.println(winkel);
	}


*public* BufferedImage rotate(*double* winkel){
        AffineTransform 
at = AffineTransform._getRotateInstance_(Math._toRadians_(winkel),pic.getWidth()/2,pic.getHeight()/2);
        BufferedImage 
rotateImage = *new* BufferedImage(pic.getWidth(),pic.getHeight(),pic.getType());
        Graphics2D 
g2 = (Graphics2D) rotateImage.getGraphics();
 
g2.setTransform(at);
 
g2.drawImage(pic,0,0,*null*);
 
*return* rotateImage;
    }

Nochmal als Vorstellungstütze:

In einem simplen Fenster (400 auf 400) wird ein 20 auf 20 großer Panzer angezeigt aus der Vogelperspektive der sich je nach Mausklick zu diesem hin ausrichtet. Also sehr einfach gehalten.

Das ganze ist im Übrigen nicht ganz so trivial, dass nur ein bisschen Mathe dafür ausreicht. Denn zum einen habe ich ja bereits ein Problem mit dem Winkel der wenn man von der Mathematik ausgeht vom Panzer aus vom vierten Quadranten 0 bis zum dritten +180 ausgibt und für den 2ten und 1sten Quadranten von -180 bis 1 ausgibt. Ich glaube nämlich ich müsste das von den Quadranten in welchem ich mich befinde abhängig machen (nach auffrischen auf Wikipedia mit Sinus und Kosinus) wie sich der Panzer bewegen soll oder nicht. Kann mich aber auch irren.

Also Pythagoras ist mir geläufig.

Grüße Eichelhäer


----------



## Major_Sauce (30. Jun 2015)

So, erstmal: Java Code bitte immer mit Java-Tags versehen, so wie in deinem ersten Post.


```
bounding.y = (int)centery;


winkel
```

Finde ich mal wieder genial, Winkel heißt "angle", Leo.org kann helfen  (Man sollte normalerweise versuchen entweder deutsche oder englische Bezeichungen zu nehmen, nicht mischen... Nurn kleiner Tipp)

So, nun zum Problem Selbst:

Du hast im endeffekt einer lineare Funktion, wenn ich mich nicht irre ? Die Steigung bekommst du dann ja auch noch hin, denke ich mal, ist ja immer nur (y2 - y1) / (x2 - x1)

Bei dem Winkel bin ich mir nicht sicher, in Mathe sitzt bei mir die Theorie, praktisch bin ich ne Niete...
Schlimmsten Falls mal Google fragen wie man den Schnittwinkel zweier Geraden berechnet, dann ein mal die Gerade nehmen, die durch die aktuelle Position des Panzers und durch den Zielpunkt führt, als zweite gerade y = 0 benutzen (Also die x-Achse) und dann den Schnittwinkel berechnen. Das Problem mit den Quadranten kannst du ganz einfach über die Steigung lösen: Fährt der Panzer nach links und die Steigung is negativ, dann fährt der nach unten links, ist die Steigung pos, dann oben links, analog das selbe für rechts, blos invertiert...


----------



## Eichelhäer (30. Jun 2015)

Hallo nochmal,

und wenn die Steigung 0 ist dann einfach die Ordinatenachsen nehmen, wenn ich dich richtig verstanden habe?


----------



## Major_Sauce (30. Jun 2015)

Wenn die Steigung 0 ist, dann fährt der Panzer waagrecht, also nur noch herausfinden in welche richtung, links oder rechts und dann um den Betrag der geschwindigkeit verschieben


----------



## Eichelhäer (30. Jun 2015)

Hallo mal wieder,

hab nun Hypothenuse und Steigungswinkel. Wie bekomme ich nun den Speed nochmal heraus, sodass der Panzer weiss wieviele Pixel er in y- bzw. in x-Richtung fahren soll. Ist mir noch nicht ganz klar?

Gruß Eichelhäer


----------



## Eichelhäer (30. Jun 2015)

Hallo,

es funktioniert teilweise. Der Panzer fährt zwar zuckelt aber im Endpunkt ständig herum. Wieso?

Pseudo-Code:

angle = Math.toDegrees(Math.atan(m));

xspeed = Math.cos(angle);
yspeed = Math.sin(angle);

centerx += xspeed;
centery += yspeed;

Gruß Eichelhäer...

PS : Bin schon längere Zeit aus der Schule heraus und programmiere nur als Hobby weils Spass macht!


----------



## Major_Sauce (30. Jun 2015)

Nun ist das ganze relativ simpel.

Du hast den winkel der von x-Achse und Hypotenuse eingeschlossen ist.
Geh einfach mal davon aus, dass die Länge der Hypotenuse gleich der Geschwindigkeit deines Panzers ist, gib ihr also einen beliebigen Wert.
Wenn ich micht nicht irre, dann reicht es in einem rechtwinkligem Dreieck aus, eine Länge und einen Winkel zu haben um die anderen Seitenlängen auszurechnen.
Wenn du nun also die Seitenlänge der beiden Katheten berechnest, ergeben diese deine x- und y-Werte

mfg Major


----------



## Major_Sauce (30. Jun 2015)

Joa, dass der ein wenig rumzuckelt glaube ich dir.

Das liegt einfach da dran dass er nicht merkt dass er schon am Ziel ist, dann schießt er vorbei und muss wieder zurück, schießt wieder dran vorbei und so weiter...

Da musst du dir noch ne Zielerkennung einbauen, zum beispiel kannst du die Länge der Streck speichern, die er reisen soll und dann ziehst du bei jedem update einfach die "bei diesem Update gefahrene Strecke" ab. Wenn das ganze unter 0 Fällt dann ist er mehr oder weniger da, vielleicht auch schon ein bisschen zu weit, musst dir da einfach ne schöne variante raussuchen.

mfg Major


----------



## Eichelhäer (30. Jun 2015)

Hallo, 

also ich hab die Hypotenuse so berechnet:Pseudo-Code:
 h = Math._sqrt_(((ym-centery)*(ym-centery))+((xm-centerx)*(xm-centerx)));

Wenn ich die nun die Seitenlänge berechne Math.sin(angle)*h ist das zwar der xspeed, aber es findet keine lineare Bewegung statt, sondern konfuses kreisen über das Label.  Und wenn ich eben nen konstanten Wert für diese nehm bleibt der Panzer auf halber Strecke hängen.

Erstmal noch Danke für Deine Geduld mit mir, aber denkst du nicht auch, dass man da dann sehr viel Rumdoktorn muss bis es funktioniert? Versteh mich nicht falsch, ich bin Dir sehr dankbar für deine kluge Hilfe, aber ich bin wenn es ums Programmieren geht eher minimalistisch eingestellt und es müsste doch auch einfacher gehen mit gutem Ergebnis. Das Problem ist glaub ich, nicht die Theorie, die ist richtig, sondern JAVA als solches also wie sich die, vor allem grafische Programme verhalten usw..

Gruss Eichelhäer


----------



## Major_Sauce (30. Jun 2015)

Klar, gibt auch einfachere Lösungen, dann solltest du dir vielleicht mal Vektoren anschauen, wenn dir das was sagt. Damit kann man das wohl wesentlich einfacher Lösen, du musst nur einen Weg finden, einen Vektor auf einen Bestimmten Betrag zu bringen.

mfg Major


----------



## Eichelhäer (30. Jun 2015)

Ok ich les mich da mal ein. Ich melde mich dann noch mal hier allerdings nicht mehr heute, sondern im Laufe der nächsten Tage.

Vielen vielen herzlichen Dank nochmal für deine Geduld wäre schön wenn Du hier ab und zu mal draufschauen würdest falls Du Dich mit Vektoren auskennen solltest, wenn nicht könnten wir vielleicht zusammen ne Lösung finden.


Gruß Eichelhäer


----------



## Major_Sauce (30. Jun 2015)

Mit den Verktoren sollte es gehen, habe da auch ein wenig "Ahnung" von, mal sehen ob ich helfen kann.

mfg Major


----------



## Eichelhäer (4. Jul 2015)

Hallo ein letztes Mal,

also man kann dieses Thema zum Teil als geschlossen betrachten, denn die Bewegung funktioniert jetzt glatt und sauber.

Hier der Code:


deltax
= (MouseInput._mousx_-tank.getWidth()/2) - centerX;
 
deltay = (MouseInput._mousy_-tank.getHeight()/2) - centerY;
 

directionradian = Math._atan_(deltay/deltax);
 

*double* distance = Math._sqrt_(((deltax)*(deltax))+((deltay)*(deltay)));
 

*if*(deltax>0 && distance>speed){
 
centerX += Math._cos_(directionradian)*speed;
 
centerY += Math._sin_(directionradian)*speed;
 
		}

*else* *if*(deltax<=0 && distance>speed){
 
centerX -= Math._cos_(directionradian)*speed;
 
centerY -= Math._sin_(directionradian)*speed;
		}

Danke nochmal Major für seine Geduld.


Mfg Eichelhäer


----------

