# Flugbahnberechnung (Quaxlis Tutorial)



## manuche (18. Mrz 2008)

Hallo,
ich programmiere grad TankWar und habe ine Problem mit der Flugbahnberechnung! Das ganze basiert teilweise auf Quaxlis Tutorial für die Spieleprogrammierung. Hier die Klasse für die Kugel:


```
import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;

import meta.Evaluation;


public class Canonball extends Rectangle2D.Double implements Movable, Drawable{
	int					size;
	double				angle;
	double				weight;
	double				cW;
	GamePanel			gamePanel;

	protected double	dx;
	protected double	dy;

	public Canonball(double x, double y, int size, int angle, double speed, double weight, double cW, GamePanel gamePanel) {
		this.x = x;
		this.y = y;
		this.angle = angle;
		this.weight = weight;
		this.cW = cW;
		this.computeStartSpeedX (angle, speed);
		this.computeStartSpeedY (angle, speed);
		this.size = size;
		this.gamePanel = gamePanel;
	}

	private void computeStartSpeedX (int angle, double speed){
		this.setHorizontalSpeed (speed * Math.cos (angle));
	}

	private void computeStartSpeedY (int angle, double speed){
		this.setVerticalSpeed (speed * Math.sin (angle));
	}

	public void doLogic (long delta){
		double friction = Evaluation.computeFriction (cW, size, dx, dy);
		angle = Math.atan (dy / dx);
		this.setHorizontalSpeed (Evaluation.computeSpeedX (dx, angle, friction, weight, delta));
		this.setVerticalSpeed (Evaluation.computeSpeedY (dy, angle, friction, weight, delta));
	}

	public void move (long delta){
		if (dx != 0){
			x += dx * (delta / 1e9);
		}
		if (dy != 0){
			y += dy * (delta / 1e9);
		}
	}

	public void drawObjects (Graphics g){
		g.setColor (Color.RED.darker ());
		g.fillOval (((int) x) - 1, ((int) y) - 1, size / 10, size / 10);
	}

	public void setVerticalSpeed (double d){
		dy = -d;
	}

	public double getVerticalSpeed (){
		return dy;
	}

	public void setHorizontalSpeed (double d){
		dx = d;
	}

	public double getHorizontalSpeed (){
		return dx;
	}
}
```

und die Berechnungen...

```
public static double computeFriction (double cW, double area, double vX, double vY){
		return (0.5 * PLUFT * cW * area * ((vX * vX) + (vY * vY)) / 10000);
	}

	public static double computeSpeedX (double vX, double angle, double friction, double weight, double delta){
		return (vX + (-Math.cos (angle) * friction / weight) * (delta / 1e9));
	}

	public static double computeSpeedY (double vY, double angle, double friction, double weight, double delta){
		return (vY + (-G - Math.sin (angle) * friction / weight) * (delta / 1e9));
	}
```

Bei jedem Thread durchlauf wird die Position der Kugel neu bestimmt. Alles in Abhängigkeit der für den Schleifendurchlauf benötigten Zeit natürlich...
Das Problem ist, dass die Kugel nicht wirklich in einer Kurve "fliegt" sondern eher in einer horizontalen Schlangenlinie...
Das ganze basiert auf den Formeln für eine ballistische Kurve mit Luftwiderstand: Flugbahnberechnung
Ich hab mir schon die Augen aus dem Kopf gesucht bzw. alles was mir logisch vorkam ausprobiert allerdings kann ich nicht feststellen, woran es jetzt liegt...
Ich hoffe einer von euch Klugen köpfen weiss weiter oder hat ein Auge für sowas!
Gruß manuche


----------



## 0x7F800000 (18. Mrz 2008)

:shock: 
1) du hast es irgendwie übertrieben kompliziert geschrieben... aber so richtig voll übertrieben... Mach erstmal diese 7-8 (oder wieviele das auch sind) Methoden weg, und ersetze die jeweil durch einen einzeiler in der move() methode und in der shot() methode [ also, bitte eine methode, die die anfangsgeschwindigkeit ausrechnet, drei sind da echt fehl am platz, vor allem weil du vielles doppelt ausrechnest ]

2) schreib dir eine vernünftige R²-Vektorklasse, um mit den ganzen punkten, positionen, geschwindigkeiten und kräften vernünftig rechnen zu können ( in der klasse muss du die vektoren zumindest mal addieren und mit skalaren multiplizieren können) 
Diese ganzen siebzighundertzweiundneunzigtausendhundertzweiundzwanzig methode um jede geschwindigkeitskomponente einzeln zu setten ist totaler murks...
"dy dx usw" sind merkwürdige bezeichnungen...

3) so berechnest du die bahn näherungsweise: (x[vektor] bezeichne die position, v[vektor] die geschwindigkeit, F[vektor] die kraft, m[skalar] die masse, a[vektor] die beschleunigung, dt[skalar] die vergangene zeit [die zeit zwischen den aufrufen der move()-methode]. Also:

in jedem move() aufruf berechnest du:

```
F=F_reibung+F_gravitation=(-v*|v|*cw*area*luftdichte*dieGanzenAnderenKonstanten)+F_gravitation
//privat final static MyVector F_gravitation = new MyVector(0,-Gravitationskonstante); gravitationskonstante halt...

//Newtonsches gesetz: F=a*m => a=F/m
a=F/m

//geschwindigkeit ein bisschen ändern
v=v+a*dt

//position ein bisschen ändern
x=x+v*dt
```

das ist der allertrivialste weg so irgendwas näherungsweise zu berechnen. Wenn es eine explizite formel mit luftreibung gibt, müsstest du für diese lange rumhocken und wirres zeug integrieren, und am ende würdest du etwas exaktes rausbekommen, was 100 mal langsamer ist. Da es keine wissenschaftliche simulation, sondern nur ein spiel ist, sollte diese einfache methode völlig aureichen.


4) achso: die anfangsgeschwindigkeit und position kriegst du schon irgendwie hin, steht ja exakt in wikipedia


----------



## Marco13 (18. Mrz 2008)

"int angle" und nirgendwo ein "toRadians" - meine Kristallkugel sagt mir, dass du Winkel, die in GRAD angegeben sind, an Math.cos etc. übergibst - die Wollen die Winkel aber in Radians...


----------



## 0x7F800000 (19. Mrz 2008)

überlasse mal das rechnen mit grad den alten griechen, im gewöhnlichen code für computerspiele hat dieses merkwürdige hexagesimale artefakt nichts verloren.


----------



## Quaxli (19. Mrz 2008)

Wenn Du schon die Klassen des Tutorials verwendest, warum läßt Du Cannonball nicht von Sprite erben? 
Du müßtest dann prinzipiell nur die move-Methode überschreiben und da die physikalische Formel vom schiefen Wurf reinfrickeln (und ein paar Anpassungen im Konstruktor).
Ich habe da vor einiger Zeit mal was gebastelt, allerdings war das, bevor ich für's Tutorial nochmal über die Klassen gegangen bin und dran rumgebastelt habe. Die folgende Klasse wird mit den Klassen des Tutorials nicht 100% zusammen passen (delta wird z. B. noch in Millisekunden berechnet). Sie ist auch schon ein bißchen älter und ich würde einiges so nicht mehr machen (Berechnung von t² zum Beispiel), aber als Beispiel ist sie noch gut.


```
public class RealisticShot extends Sprite {

	double shotangle;
	double velo = 1000;
	double start;
  double shottime;
	double ynull;
	double xnull;
	
	public RealisticShot(Image i, double x, double y, int d, int a, GamePanel gp) {
		super(i, x, y, d, gp);
		shotangle = a;
		if(shotangle>=0){
	    shotangle = Math.toRadians(angle);
		}else{
	    shotangle = Math.toRadians((90-angle)*-1);
		}
    start = System.currentTimeMillis();
    ynull = y;
    xnull = x;
	}
	
	public RealisticShot(Image[] i, double x, double y, int d, int a, GamePanel gp) {
		super(i, x, y, d, gp);
		shotangle = a;
		if(shotangle>=0){
	    shotangle = Math.toRadians(angle);
		}else{
	    shotangle = Math.toRadians((90-angle)*-1);
		}
    start = System.currentTimeMillis();
    ynull = y;
    xnull = x;
	}

	@Override
	public void move(long delta) {
		
		shottime = (System.currentTimeMillis() - start)/1000;

		if(shotangle>=0){
			x = xnull + (velo*shottime * (Math.cos(shotangle)));
			y = ynull - (velo*shottime*(Math.sin(shotangle))) + (0.5 * 981 * shottime * shottime);
			
		}else{
			x = xnull + (velo*shottime * (Math.sin(shotangle)));
			y = ynull - (velo*shottime*(Math.cos(shotangle))) + (0.5 * 981 * shottime * shottime);
			
		}	}

	
	
}
```


----------



## manuche (19. Mrz 2008)

Danke erstmal für eure Hilfe...

@Andrey: Die ganzen Methoden waren ja schon "vorgefertigt" da, weil die Klasse von Movable und Drawable erbt... Ich musste mir also nur noch die horizontale und vertikale Geschwindigkeit ausrechnen lassen. Das geschieht in der Klasse Evaluation, welche ich für stumpfe Berechnungen angelegt hab.

@Marco13: Is mir auch schon aufgefallen... Seither fliegt die Kugel in einer Kurve, wenn auch sehr unrealistisch 

@quaxli: Es hatte einen Grund, dass ich die Klasse nicht von Sprite hab erben lassen, allerdings weiss ich grad nicht mehr genau welchen! ^^ Spontan würde ich sagen wegen dem BufferedImage... War auch erstmal garnich so schlimm. Da es eh maximal einen Schuss gibt, brauchte ich ihn nicht der Collection hinzufügen... Ich bin allerdings dabei meinen Code generell ein wenig aufzuräumen und hatte vor das nachträglich noch zu ändern!

Ich werde jetzt mal auf quaxlis Code aufbauen und ihn testen! Trotzdem Danke an euch alle...


----------

