# Objekt mit cos/sin verschieben



## raven (21. Dez 2006)

Hallo,

Ich sitze nun schon nach einiger Zeit an meinem Problem und rätsle wie ich es lösen kann. In meinen Spiel in dem man einen Panzer fährt, kann man mit den Pfeiltasten die Fahrtrichting(360 Crad) ändern und man kann auch schon in die dem entsprechende Richtung fahren, nur wenn ich die Fahrtgeschwindigkeit gering halte, sieht es flüssig aus, aber die Richung stimmt ganz. Wenn ich die Geschwindigkeit hoch habe, stimmt die Fahrtrichtung aber ist halt nicht so flüssig. Kuckt es euch erst einmal selber an.

So rechne ich die Richtung aus

```
speedX = (int)(Math.cos(Math.toRadians(angle)) * speed);
speedY = (int)(Math.sin(Math.toRadians(angle)) * speed);
```

So steure ich ihn:

```
public void keyPressed (KeyEvent k) {
		int key = k.getKeyCode ();
		switch (key) {
			case KeyEvent.VK_LEFT:
				player.angle = player.angle - 1;
				break;
			case KeyEvent.VK_RIGHT:
				player.angle = player.angle + 1;
				break;
			case KeyEvent.VK_UP:
				player.xPos = player.xPos + (int)player.speedX;
				player.yPos = player.yPos + (int)player.speedY;
				break;
		}
	}
```

und hier könnt ihr euch angucken wie es aussieht, wenn die Richtung nicht so ganz stimmt.

Klickt hier

Hoffe ihr seht was ich mein, fahrt einfach mal nen bissl rum.


----------



## Campino (21. Dez 2006)

Ich gehe mal davon aus, dass du anschließend das x des Panzers um speedX und das y des Panzers um speedY änderst? Ist doch klar das das bei hohen Tempi ruckelt, da macht der Panzer ja große Sprünge statt kleiner Schritte...

Du könntest eventuell mit math.round() echt runden, statt einfach zu casten, vllt. hilft das etwas...aber richtig weg bekommst du es nicht.


----------



## 0xdeadbeef (21. Dez 2006)

Nebenbei bemerkt tabelliert man Winkelfunktionen und dergleichen üblicherweise für Spiele. Das zur Echtzeit zu berechnen ist relativ "teuer" und bringt keinen ernsthaften Vorteil. Wenn man Platz sparen will, braucht man ja eigentlich nur von 0 bis PI/2 zu speichern und kann dann den Rest (inklusive des Kosinus) daraus ableiten.


----------



## raven (22. Dez 2006)

Campino hat gesagt.:
			
		

> Ich gehe mal davon aus, dass du anschließend das x des Panzers um speedX und das y des Panzers um speedY änderst? Ist doch klar das das bei hohen Tempi ruckelt, da macht der Panzer ja große Sprünge statt kleiner Schritte...
> 
> Du könntest eventuell mit math.round() echt runden, statt einfach zu casten, vllt. hilft das etwas...aber richtig weg bekommst du es nicht.



Du hast recht, so mache ich es. Und du glaubst wirklich das das runden was ausmachen würde, da passiert doch genau das gleiche.

// Edit

Hab es gerade mal mit dem round probiert. ändert sich nichts. Wenn ich die Geschwindigkeit auf 5/6 setzte gehts ja, dann stimmt die Richtung ja im groben über ein, aber er macht zu große sprünge, ist ja auch klar, aber bei kleineren Geschwindigkeiten, stimmt die Richtung wieder nicht, was ihr ja oben seht.

Wie realisieren andere sowas in einem Space Invader, ist ja das gleiche Prinzip, wenn man es so nimmt. Da funktioniert es doch auch einmanfrei, hat jemand eine Idee. mfg


----------



## EgonOlsen (22. Dez 2006)

0xdeadbeef hat gesagt.:
			
		

> Nebenbei bemerkt tabelliert man Winkelfunktionen und dergleichen üblicherweise für Spiele. Das zur Echtzeit zu berechnen ist relativ "teuer" und bringt keinen ernsthaften Vorteil. Wenn man Platz sparen will, braucht man ja eigentlich nur von 0 bis PI/2 zu speichern und kann dann den Rest (inklusive des Kosinus) daraus ableiten.


So teuer ist das auf heutigen CPUs auch nicht mehr. Wenn man es nicht für hunderte von Entitäten/Frame durchführt, ist es kein Problem. An der Stelle würde ich wirklich als allerletztes was drehen.


----------



## raven (22. Dez 2006)

Wie machen die das zum Beispiel in diesem Spiel:
http://www.stroehmer.de/games/Java/Arcade/Asteroids-Clones/Asteroids/start-asteroids.htm
ist doch genau das gleiche Prinzip. Und da läuft auch alles flüssig und das Raumschiff fährt auch haar genau in die Richtige Richtung.
mfg


----------



## EgonOlsen (22. Dez 2006)

Das Problem dürfte sein, dass du die Position als int speicherst. Damit verlierst du bei jeder Addition den Nachkommaanteil der Richtung und das summiert sich auf zu einer falschen Richtung.
Speicher die Position entweder als float/double oder von mir aus auch als int, aber dann als Fixedpoint, indem du sie z.B.*256 abspeicherst. Aber ich würde es einfach mit float machen. Dann sollte das passen.

Edit: Gilt natürlich auch für den Speed selber. Also alles als Gleitkomma machen und vor dem Zeichnen erst zu int casten.


----------



## raven (22. Dez 2006)

So hab nun alles auf Float abgeändert und es macht sich schon ein klein bisschen bemerkbar, doch es ist noch nicht so wie in den obrigen Spiel. In meinem Spiel fährt man ja ein Panzer, und bekanntlich sind Panzer ja nicht die schnellsten Fahrzeuge, und sie sollen im Spiel auch nicht so schnell sein.

Hier könnt ihr mein Spiel ncohmal sehen, so schnell sollen sie in etwa sein. Wie kann ich die Richtung noch genau machen und wie mache ich es das die Bewegung nicht ganz so abgehackt ist?

http://toni90.to.funpic.de/TankWar_0_1.jar

mfg


----------



## EgonOlsen (22. Dez 2006)

Aber die Richtung des Panzers stimmt jetzt wenigstens. Vorher hat der ja in Richtung 25Grad gezeigt, um in Richtung 15Grad zu fahren. Um den Rest zu beurteilen, müsste man deinen Code sehen. Guck doch mal hier:www.java-forum.org/de/viewtopic.php?t=41482. Das ist ja so ein ähnliches Thema.


----------



## raven (22. Dez 2006)

Hier hast du den Code meiner Player Klasse, sprich dem Panzer.


```
import java.awt.*;
import javax.swing.*;
import java.awt.geom.*;

public class Player {

	public Background bg;
	public PlayerKey playerKey;

	public Image tank;

	public float xPos;
	public float yPos;
	public float speedX;
	public float speedY;
	public float speed = 3.0F;
	
	public int width = 35;
	public int height = 20;
	public int angle = 45;

	public Player(Background bg, Image tank, int xPos, int yPos) {
		this.bg = bg;
		this.tank = tank;
		this.xPos = xPos;
		this.yPos = yPos;

		playerKey = new PlayerKey(this);
	}

	public void paint(Graphics2D g2D) {
		g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		AffineTransform at = new AffineTransform();
		at.rotate(Math.toRadians(angle), xPos+width/2, yPos+height/2);

		g2D.setTransform(at);

		g2D.setColor(Color.gray);
		g2D.fill(new Rectangle2D.Float(xPos, yPos, width, 5));
		g2D.fill(new Rectangle2D.Float(xPos, yPos+15, width, 5));
		
		g2D.setColor(new Color(92, 65, 35));
		g2D.fill(new Rectangle2D.Float(xPos+3, yPos+2, width-6, height-4));

		g2D.setColor(new Color(128, 103, 59));
		g2D.fill(new Rectangle2D.Float(xPos+12, yPos+5, 13, 10));
		g2D.fill(new Rectangle2D.Float(xPos+25, yPos+9, 15, 2));
	}

	public void calculation() {
		speedX = Math.round((Math.cos(Math.toRadians(angle)) * speed));
		speedY = Math.round((Math.sin(Math.toRadians(angle)) * speed));
	}
}
```

Der Thread den du mir gegeben hast, entspricht nicht ganz meinem Problem.(Ich hab ihn mir durchgelesen) In ihm geht es um die CPU Auslastung, was bei mir kein Problem, oder noch nicht darstellt. Die Richtung ist für mich noch nicht ganz perfekt,man sieht manchmal, wenn man ungefähr im Winkel von 65/70 Crad ist, das es noch leicht schif fährt, um dies auszubessern erhöhe ich die Geschwindigkeit, dann ist die Richtung perfekt, nur leider, wird dabei mein Panzer in großen Scritten gesetzt und es sieht nicht mehr so aus als ich fahren würde.


// edit

Der andere Code ist nicht wichtig für dieses Problem.


----------



## EgonOlsen (22. Dez 2006)

Nimm mal das round() in calculation raus. Das macht da keinen Sinn mehr drin.


----------



## raven (22. Dez 2006)

oh, das habe ich ganz vergessen, aber das wird nichts ändern. oder?

mfg


----------



## EgonOlsen (22. Dez 2006)

Doch sicher. Weil das das ist, was du auf die Position addierst, wenn ich mich recht entsinne. D.h. wenn da 1.4 rauskommt, dann addierst du mit round() nur 1. D.h. nach 100 Durchläufen stehst du bei 100 statt bei 140. Wenn du "speed" erhöhst, wird es übrigens deswegen etwas besser, weil du die verlorene Genauigkeit durch das round() damit prozentual aufs Endergebnis gesehen etwas kompensierst.


----------



## 0xdeadbeef (22. Dez 2006)

EgonOlsen hat gesagt.:
			
		

> So teuer ist das auf heutigen CPUs auch nicht mehr. Wenn man es nicht für hunderte von Entitäten/Frame durchführt, ist es kein Problem. An der Stelle würde ich wirklich als allerletztes was drehen.


Ich sagte "relativ" teuer und das ist es immer noch und wird es auch immer sein im Vergleich zu einem Tabellenzugriff. Außerdem macht er ja sonst nicht viel, also ist es auch bezogen auf die Laufzeit des Algorithmus' teuer.
Wie auch immer, ich komme halt noch aus einer Zeit, in der man keine Ressourcen verschwendet hat und muß auch beruflich noch darauf achten, keine Multiplikation umsonst auszuführen - Fließkommaberechnungen und trigonometrische Funktionen sind da eh außen vor.


----------



## Guest (22. Dez 2006)

0xdeadbeef hat gesagt.:
			
		

> Wie auch immer, ich komme halt noch aus einer Zeit, in der man keine Ressourcen verschwendet hat und muß auch beruflich noch darauf achten, keine Multiplikation umsonst auszuführen - Fließkommaberechnungen und trigonometrische Funktionen sind da eh außen vor.


Ich weiß, ich habe deine Homepage gelesen. Wir sind ein Jahrgang, d.h. ich "komme auch aus dieser Zeit" (C64 in Assembler und so)... :wink: Und ich mache auch noch heute Lookup-Tabellen, aber für diese Anwendung würde ich sie nicht machen. Lookup ist auf einem P4 etwa 4mal schneller. Nur zählt das erst wirklich, wenn man 1000e davon ausführt.


----------



## EgonOlsen (22. Dez 2006)

^^^ Das war ich...


----------



## raven (23. Dez 2006)

EgonOlsen hat gesagt.:
			
		

> Wenn du "speed" erhöhst, wird es übrigens deswegen etwas besser, weil du die verlorene Genauigkeit durch das round() damit prozentual aufs Endergebnis gesehen etwas kompensierst.



Das war mir klar, das wollte ich euch ja die ganze Zeit irgendwie sagen, Aber mein problem ich die Geschwindigkeit nicht so hoch stellen, weil ich das nicht so schön finde.[/quote]



> Ich sagte "relativ" teuer und das ist es immer noch und wird es auch immer sein im Vergleich zu einem Tabellenzugriff. Außerdem macht er ja sonst nicht viel, also ist es auch bezogen auf die Laufzeit des Algorithmus' teuer.
> Wie auch immer, ich komme halt noch aus einer Zeit, in der man keine Ressourcen verschwendet hat und muß auch beruflich noch darauf achten, keine Multiplikation umsonst auszuführen - Fließkommaberechnungen und trigonometrische Funktionen sind da eh außen vor.



Also bist du der Meinung ich kann das Problem nicht ohne enormen Aufwand lösen. Aber ich will es unedingt so haben, sonst hat das ganze Game kein sinn, wenn sich der Panzer nichtrichtig lenken lässt. 

mfg


----------



## LoN_Nemesis (23. Dez 2006)

Nein X_Master, die letzten Beiträge haben sich nur mit der Frage beschäftigt ob man jedesmal den Sinus ausrechnen sollten oder besser eine Tabelle bereithält, in der man alle benötigten Werte dort einträgt und dann nur nachschauen muss.

Das was du vorhast sollte auf jeden Fall gehen, sicher ist irgendwo noch ein kleiner Fehler drin.

Kannst du das .jar File mal so ändern, dass man es mit einem Doppelklick starten kann? Dann schaue ich es mir mal an.


----------



## LoN_Nemesis (23. Dez 2006)

Also ich hab mir deinen Code jetzt nochmal angeschaut und ich würde das anders machen.

Ich würde dem Panzer einen Richtungsvektor geben. Dieser gibt (wie der Name schon sagt) an in welche Richtung der Panzer fährt. Das sollte einfach ein Einheitsvektor sein. Durch die aktuelle Position des Panzers und diesen Richtungsvektor kannst du dann eine Gerade berechnen. Auf dieser Gerade bewegt sich der Panzer dann, wenn du ihn gerade ausfahren lässt; wie weit wird durch den speed bestimmt.

Wenn der Spieler dann die Nach-Rechts oder die Nach-Links Taste drückt, dann rotierst du den Richtungsvektor.

Bin mir ziemlich sicher, dass es so geht und denke auch, dass ist das Standardvorgehen in vielen Spielen.


Edit: Eh ok im Grunde machst du das ja ähnlich, dein Richtungsvektor ist speedX und speedY. Hm..

Habs nun mal ausgeführt, ich sehe das Problem nicht? Wieso soll die Richtung bei langsamer Bewegung nicht stimmen? Mir kommt das richtig vor?


----------



## raven (23. Dez 2006)

Das Problem siehst du besonders gut, wenn du den Panzer in den Winkel von ca. 70 Crad setzt. Die Cradzahl kannst du auf der Konsole sehen. dort wird sie ausgegeben.



> Ich würde dem Panzer einen Richtungsvektor geben. Dieser gibt (wie der Name schon sagt) an in welche Richtung der Panzer fährt. Das sollte einfach ein Einheitsvektor sein. Durch die aktuelle Position des Panzers und diesen Richtungsvektor kannst du dann eine Gerade berechnen. Auf dieser Gerade bewegt sich der Panzer dann, wenn du ihn gerade ausfahren lässt; wie weit wird durch den speed bestimmt.



Ich verstehe dein System nicht ganz so. Extra ein Vector erstellen um die beiden Variablen (xSpeed, ySpeed) zu speichern????

mfg


----------



## EgonOlsen (23. Dez 2006)

Ähhh...was ist nun mit dem round()? Haste das mal entfernt? Dann sollte es doch eigentlich passen, wenn du nicht noch irgendwo anders wild rundest oder abtrennst, wo es nicht sein sollte.


----------



## LoN_Nemesis (23. Dez 2006)

Und was bedeuten die Ausgaben X und Y auf der Konsole? Sind das speedX und speedY? Wenn ja, dann sind es immer noch int Werte und keine Floats.


```
case KeyEvent.VK_UP:
            player.xPos = player.xPos + (int)player.speedX;
            player.yPos = player.yPos + (int)player.speedY;
            break;
```

Hast du das mittlerweile auch korrigiert und den (int) cast weggemacht? Wenn deine Koordinaten alle floats sind, dann solltest du gar nicht mehr runden ausser beim Zeichnen.


----------



## raven (23. Dez 2006)

LoN_Nemesis hat gesagt.:
			
		

> Und was bedeuten die Ausgaben X und Y auf der Konsole? Sind das speedX und speedY? Wenn ja, dann sind es immer noch int Werte und keine Floats.
> 
> 
> ```
> ...



Den hatte ichganz vergessen. Hab ihn jetzt weggemacht. Funktioniert jetzt.
Hier seht ihr die aktuelle version nochmal. http://toni90.to.funpic.de/bin/TankWar_0_1.jar

Ja X und Y Ausgaben sind speedX und speedY.

mfgWeiß auch nicht warum er bei speedX eine Kommastelle und bei SpeedY immer genau eine ganze Zahl ausgibt. HAt mich auch selber schon gewundert.


----------



## Campino (23. Dez 2006)

Du musst in der manifest-datei noch die main-Class eintragen...dann lässt das ganze sich per Doppelklick starten...


----------



## raven (23. Dez 2006)

So hab jetzt wie gewünscht die Manifest Datei abgeändert.

http://toni90.to.funpic.de/TankWar_0_1.jar

Müsste jetzt gehen, Hab auch gleich mal die Steuerung(So wie sich halt nen Panzer/Auto in real steurn lässt) eswas verändert, sagt mal wie ihr sie findet. Funktioniert jetzt alles. Großes DANK an alle die mir geholfen habe. Das einzigste was jetzt noch fehlerhaft ist, seit ich die neue Steuerung habe, das diverse Panzerteile manchmal ein bisschen daneben gezeichnet werden. Aber das Problem denke ich liegt, dann auch an meiner Zeichenmethode.


----------



## raven (23. Dez 2006)

So hab nun noch einiges abgeändert. Die Steuerung liegt jetzt auf den Numernblock. Mit 4, 5, 6, 8 steuert man den Panzer und mit 7 und 9 kann man das Panzerrohr drehen. Als nächstes machen ich die Schüsse und dann werde ich versuchen es Netzwerkfähig zu machen.

Nochmals Danke für eure Hilfe.

mfg X_Master


----------



## LoN_Nemesis (24. Dez 2006)

Sag Bescheid wenns fertig ist, würde es dann gerne mal sehen


----------



## raven (24. Dez 2006)

Werd ich machen. Frohes Weihnachtsfest noch

mfg X_Master


----------

