# 2D Spiele - Inwiefern Vektorrechnung nötig?



## Jack159 (7. Okt 2012)

Hallo,

Ich habe vor das klassische Spiel "Pong" in Java umzusetzen. Dabei ist es mir wichtig, dass ich das Abprallverhalten des Balls von den Schlägern und Wänden halbwegs physikalisch korrekt hinbekomme.
Lässt sich das nur mithilfe der Vektorrechnung physikalisch korrekt realisieren? Oder geht das auch ohne Vektorrechnung?

Die Mathematischen Kenntnisse der Vektorrechnung habe ich zwar, und eine Vektor-Klasse habe ich mir bereits auch halbwegs schon geschrieben, jedoch wüsste ich nicht, wie ich das ganze nun wirklich grafisch darstellen und damit arbeiten könnte.

Inwiefern braucht man für 2D-Spieleprogrammierung die Vektorrechnung? Würdet ihr für sowas die Vekotrrechnung empfehlen? Oder geht es auch ohne ganz gut?


----------



## Illuvatar (7. Okt 2012)

Die Position des Balls ist ein Vektor, die Geschwindigkeit des Balls ist ein Vektor. Ich weiß nicht, was man da "ohne Vektorrechnung" machen sollte... ???:L


----------



## Dow Jones (7. Okt 2012)

Hallo Jack,

ich bin mir nicht sicher ob ich dich richtig verstehe. Möchtest du die beiden unabhängigen Werte, die man im zweidimensionalen nun einmal hat - nicht in Form von Vektoren sondern in irgendwelchen anderen Datenstrukturen speichern? Oder möchtest du das Ganze auf eine Dimension herunterbrechen (aus dem "Pixel an Position 100,200" wird der "Pixel Nummer 12432")? Geht sicherlich beides, wenn man unbedingt möchte. Allerdings werden die Berechnungen, die du in deinem Spiel durchführen musst, in Kern immer die gleichen bleiben. Die Zusammenfassung zweier Werte zu einem Vektor ist da durchaus angebracht, das macht die Formeln einfach "schöner".



Jack159 hat gesagt.:


> Inwiefern braucht man für 2D-Spieleprogrammierung die Vektorrechnung? Würdet ihr für sowas die Vekotrrechnung empfehlen? Oder geht es auch ohne ganz gut?



Zum Beispiel Pong: Hier würde ich den Ball durch verschiedene Werte charakterisieren (unterstrichene Werte sollen Vektoren sein): Position, Bewegungsrichtung und Geschwindigkeit. Eine Wand könnte man durch Ankerpunkt, Richtung und Länge beschreiben. Und dann kann man relativ einfache Formeln aufstellen, wie etwa:

Ballbewegung: PositionNeu = PositionAlt + Bewegungsrichtung * Geschwindigkeit

Um zu testen ob der Ball dabei gegen eine Wand klatscht müsste man ermitteln ob die Ballbewegung einen Schnittpunkt mit der Mauer hat:

Ankerpunkt + Richtung * l = Position + Bewegungsrichtung * g, mit den Nebenbedingungen 0 < l <= Länge und 0 < g <= Geschwindigkeit

Falls ja bewegt sich der Ball halt nur soweit wie er kann auf die Mauer zu (die obige Lösung für g), dann ändert man die Bewegungsrichtung und anschließend führt man den Rest der Bewegung aus (Geschwindigkeit-g). Ist doch eigentlich recht elegant, oder?


----------



## kaetzacoatl (7. Okt 2012)

Bei sowas reicht es die Bewegung bei
jedem kontakt zu spiegeln.
Die Wände sing ja nur auf der Seite,
also benötigt man eine x-Spiegelung.
Die Richtung wird durch die multiplikation
mit -1 geändert. Die Geschwindigkeit bleibt
dadurch gleicht und muss dann nicht
beachtet werden.

```
if(x == wand.x)vx=-vx;
```


----------



## Jack159 (7. Okt 2012)

Na gut, dann werde ich das mit den Vektoren versuchen. Mein Problem ist aber momentan weiterhin, dass ich einfach nicht weiß, wie ich nun von meinem Vektorobjekt (x,y) auf den konkreten Ball bei "Pong" komme. Klar, die Komponenten des Vektors wären die Koordinaten des Balls. Aber das jetzt praktisch umzusetzen, ist doch schwieriger als ich zunächst dachte. Vorallem im Hinblick auf Schnittpunkt und Winkelberechnung. Was mich am meisten verwirrt ist, dass ein Vektor ja nicht nur 1x genau an einer Stelle existiert, sondern man denselben Vektor beliebig im Raum bzw der Ebene verschieben kann...

Unten habe ich mal meine bisher angefertige Vektorklasse angehangen. Einige Methoden fehlen noch.
Wie genau würde ich jetzt damit den Ballvektor erstellen/zeichnen, wie die Wände, die Schläger?



```
public class Vektor {
	
	public Vektor(double x, double y) {
		this.x=x;
		this.y=y;
	}
	
	
	private double x;
	private double y;
	
	
	public void setX(double x) {
		this.x=x;
	}
	
	public void setY(double y){
		this.y=y;
	}
	
	public double getX() {
		return x;
	}
	
	public double getY() {
		return y;
	}
	
	
	public Vektor addiere(Vektor a, Vektor b) {
		Vektor c = new Vektor(a.getX()+b.getX(), a.getY()+b.getY());
		return c;
	}
	
	public Vektor subtrahiere(Vektor a, Vektor b) {
		Vektor c = new Vektor(a.getX()-b.getX(), a.getY()-b.getY());
		return c;
	}
	
	public Vektor skalarm(Vektor a, double b) {
		Vektor c = new Vektor(a.getX()*b, a.getY()*b);
		return c;
	}
	
	public double norm(Vektor a) {
		double b = Math.sqrt(a.getX()*a.getX() + a.getY()*a.getY() );
		return b;
	}
	
	public double skalarp(Vektor a, Vektor b) {
		double c = (a.getX()*b.getX())+(a.getY()*b.getY());
		return c;
	}
	
	public double winkel(Vektor a, Vektor b) {     							//unfertig    
		double c = Math.acos(skalarp(a,b))/(norm(a)*norm(b));
		return c;
	}
	
}
```


----------



## Dow Jones (7. Okt 2012)

Na, so ganz sattelfest bist du bei der Vektorrechnung aber noch nicht, oder? ;-)



Jack159 hat gesagt.:


> Was mich am meisten verwirrt ist, dass ein Vektor ja nicht nur 1x genau an einer Stelle existiert, sondern man denselben Vektor beliebig im Raum bzw der Ebene verschieben kann...



Das ist richtig. In der Praxis werden Vektoren daher je nach ihrem Zweck unterschiedlich "interpretiert". Soll der Vektor beispielsweise einen Punkt in der 2D-Ebene darstellen (man spricht dann von einem _Ortsvektor_) dann benötigt man einen Bezugspunkt: 
Punkt = Bezugspunkt + Vektor
Ortsvektoren haben nun gewissermaßen einen implizierten Bezugspunkt, d.h. der wird in dem Vektor selber nicht angegeben sondern irgendwo vereinbart. Sofern nichts anderes verlangt ist verwendet man zweckermäßigerweise den Ursprung (0, 0) des Koordinatensystems als Bezug. Damit vereinfacht sich die Gleichung zu
Punkt = (0, 0) + Ortsvektor bzw. Punkt = Ortsvektor
Somit beschreibt ein Ortsvektor (x, y) direkt die Koordinaten x, y.

Wenn man einen Vektor dagegen zur Verschiebung von Punkten einsetzen möchte dann redet man von einem _Verschiebungsvektor_. Verschiebungsvektoren haben keinen vorher definierten Bezugspunkt, man wendet sie vielmehr auf beliebige Punkte (Ortsvektoren) an um immer die gleiche Verschiebung zu erreichen. Um etwa den Punkt (Ortsvektor) (1, 1) um zwei Einheiten nach rechts zu verschieben würde man den Verschiebungsvektor (0, 2) addieren:
(1, 1) + (0, 2) = (1, 3)
(1, 3) ist dabei der neue, verschobene Punkt (Ortsvektor). Mit dem gleichen Verschiebungsvektor kann man freilich auch jeden anderen Ortsvektor um 2 Einheiten nach rechts verschieben.

Eine weitere Art von Vektor ist der sogenannte _Richtungsvektor_. Bei dieser Art von Vektor interessiert uns die Länge eigentlich gar nicht sondern nur die Richtung in die er zeigt (Richtungsvektoren sind aber in aller Regel auf die Länge 1 normiert um das Rechnen mit ihnen zu vereinfachen). 


Naja, jedenfalls sind das alles Vektoren. Es kommt halt nur darauf an wie man sie einsetzt. Im Zweifelsfall hilft's meistens sich das ganze aufzuzeichnen. Bei deinem Pong wäre die aktuelle Ballposition zweckmäßigerweise ein Ortsvektor, also mit Bezug zu Punkt (0, 0). Für einen Bewegungsschritt bräuchte man dann lediglich einen Verschiebungsvektor hinzuaddieren, und schon hat man die neue Ballposition. In meinem vorherigen Post habe ich den Verschiebungsvektor noch aufgeteilt in einen Richtungsvektor und eine Geschwindigkeit (Skalar):
Verschiebungsvektor = Bewegungsrichtung * Geschwindigkeit
und bin dadurch zu der Formel
PositionNeu = PositionAlt  +  Bewegungsrichtung * Geschwindigkeit
gekommen. Eigentlich nicht schwierig. Der Ball wird dabei durch einen Ortsvektor beschrieben, die Bewegungsrichtung durch einen Richtungsvektor und die Geschwindigkeit durch einen Skalar. Dadurch kann man jeden dieser drei Werte unabhängig voreinander verändern.

Den Schläger würde ich durch einen Verschiebungsvektor darstellen, der natürlich noch einen Ortsvektor (die aktuelle Schlägerposition) als Bezugspunkt braucht:
Startpunkt des Schlägers = Ortsvektor und
Endpunkt des Schlägers = Startpunkt des Schlägers + Verschiebungsvektor

Die Mauern würde ich wahrscheinlich in Form von zwei Ortsvektoren (Startpunkt und Endpunkt) speichern und sie gegebenenfalls in die gleiche Form wie den Schläger (Ortsvektor + Verschiebungsvektor) umrechnen lassen:
Verschiebungsvektor = Endpunkt - Startpunkt
Den Verschiebungsvektor kann man dann noch weiter aufteilen in einen Richtungsvektor und eine Länge. Diese Darstellung wird man wahrscheinlich eh brauchen wenn man die Flugbahn des Balls auf einen Schnittpunkt mit der Mauer testen will. Das ist dann einfach ein Test für den Schnittpunkt zweier Geraden.


Übrigens, bei der Klasse Vektor wäre es angebracht die ganzen Rechenmethoden als _static_ zu deklarieren. Die Bewegung des Balles kann man dabei ziemlich direkt so implementieren wie man es auch rechnet:

```
// init
        Vektor ballposition = new Vektor(10, 20);
        Vektor bewegungsrichtung = new Vektor(0.89, 0.45);  // bereits normiert
        double geschwindigkeit = 1.5;
        
        // ball bewegen
        for( int i=0; i<10; i++) {
            System.out.println("Nach "+i+" Schritten ist der Ball bei ("+ballposition.getX()+", "+ballposition.getY()+") " );
            
            if( i == 3 ) {
                System.out.println("Die Geschwindigkeit wird verzehnfacht");
                geschwindigkeit *= 10;
            }
            
            if( i == 5 ) {
                System.out.println("Der Ball läuft Rückwärts");
                bewegungsrichtung = Vektor.skalarm(bewegungsrichtung, -1.0);
            }
            
            Vektor verschiebung = Vektor.skalarm(bewegungsrichtung, geschwindigkeit);
            ballposition = Vektor.addiere( ballposition, verschiebung );
        }
```
Ausgabe:

```
Nach 0 Schritten ist der Ball bei (10.0, 20.0) 
Nach 1 Schritten ist der Ball bei (11.335, 20.675) 
Nach 2 Schritten ist der Ball bei (12.670000000000002, 21.35) 
Nach 3 Schritten ist der Ball bei (14.005000000000003, 22.025000000000002) 
Die Geschwindigkeit wird verzehnfacht
Nach 4 Schritten ist der Ball bei (27.355000000000004, 28.775000000000002) 
Nach 5 Schritten ist der Ball bei (40.705000000000005, 35.525000000000006) 
Der Ball läuft Rückwärts
Nach 6 Schritten ist der Ball bei (27.355000000000004, 28.775000000000006) 
Nach 7 Schritten ist der Ball bei (14.005000000000004, 22.025000000000006) 
Nach 8 Schritten ist der Ball bei (0.6550000000000047, 15.275000000000006) 
Nach 9 Schritten ist der Ball bei (-12.694999999999995, 8.525000000000006)
```


----------



## Jack159 (10. Okt 2012)

@ Dow Jones:
Danke für den ausführlichen Einstieg 

Was ich jetzt aber z.B. noch nicht ganz verstehe, ist die Schnittpunktberechnung bezüglich Vektoren.
Unter "Schnittpunktberechnung" bei der Vektorrechnung fällt mir da nur was mit Geraden/Ebenen ein, aber nichts mit reinen Vektoren...


----------



## Bile Demon (11. Okt 2012)

Schau dir lieber nochmal die Analysis-Grundlagen an, bevor du dich in die 2D- (oder schlimmer: 3D-)Spieleentwicklung wagst. Wenn dir bei solchen Fragen schon die Puste ausgeht, dann wirst du es bei komplexeren Themen wirklich wahnsinnig schwer haben.

Speziell zum Thema Geradengleichung / Schnittpunktberechnung sollte man nach 2 Minuten Googlen schnell darauf kommen, dass sich das prima mit Vektoren berechnen lässt.


----------

