# spielgeschwindigkeit an rechenzeit anpassen



## stevewilson (14. Nov 2006)

Hallo,

gerade bin ich mit 2 Kollegen im Rahmen eiens Netzwerkprogrammieren-Praktikums dabei, ein Multiuser-game im Peer-To-Peer-Netzwerk zu realisieren. Wir haben uns für ein einfaches 2D-Schießspiel entschieden, wo sich bis zu n Spieler mit Raumschiffen abscheißen können.

Jetzt ist gerade ein Raumschiff fertig, aber es tut sich ein Problem mit der Synchronisation auf. Je nach eingesetztem Betriebssystem und je nach Rechnerleistung fliegt das Raumschiff unterschiedlich schnell.

Jetzt habe ich versucht, die sleep-Zeit an die rechenleistung anzupassen(siehe Code), indem ich eine for-schleife durchlaufen lasse und proprtional abhängig von der Zeit, die der Rechner dafür benötigt hat eine sleep-time ausrechne. Das Problem ist, dass das Schiff auf verschiedenen Systemen immernoch unterschiedlich schnell fliegt, was alleine ja schon nicht sein kann, da man die sleep-Zeit in Millisekunden angibt. Dauert das Zeichnen etwa so lange? Wenn doch, dann sage mir bitte irgendwer, wie ich die sleep-Zeit dynamisch an die Rechenleitsung anpassen kann.

Hier mein bisheriger Code:



```
package spaceships;

import java.awt.*;

public class MoveShip extends Thread {

    public static final Color ownShipColor = Color.green;
	public static final Color otherShipColor = Color.red;
	private Color shipColor;
	private int shipWidth;
	private int shipHeight;
	private int x;
	private int y;
	private int direction = 0;
	private Graphics g;
	private int maxX;
	private int maxY;
	private long sleepTime;
	
    //Test-Methode
	public void setXY(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	//Funktion, die ein bisschen wartet
	public void pause() {
		try {
			Thread.sleep(sleepTime);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public MoveShip(Graphics g, Color shipColor) {
		x = 100;
		y = 100;
		long l = System.currentTimeMillis();
		System.out.println(System.currentTimeMillis());
		int a;
		for (int i = 0; i < 50000000 ; i ++)
		{ 
		}
	    l = System.currentTimeMillis() - l;
 	    System.out.println(System.currentTimeMillis());
	    System.out.println(l);
	    sleepTime = l / 200;
	    System.out.println(sleepTime);
	    this.g = g;	
	    this.shipColor = shipColor;
	    //Bildschirmauflösung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		maxX = d.getSize().width;
		maxY = d.getSize().height;
	    //Schiff an Bildschirmauflösung anpassen
	    shipWidth = Math.round(maxX / 32); 
	    shipHeight = Math.round(maxY / 16);
	}
	
	public void moveDown(Graphics g) {
		//Schiff-Koordinaten
		int[] xPol = { x, x - Math.round(shipWidth / 2), x,
				x + Math.round(shipWidth / 2), x };
		int[] yPol = { y, y - shipHeight, y - 2 * Math.round(shipHeight / 3),
				y - shipHeight, y };
		g.setColor(shipColor);
		//Schiff zeichnen
		g.drawPolygon(xPol, yPol, 5); 
		g.fillPolygon(xPol, yPol, 5); 
        pause(); //Das Schiff soll nicht rasen!
		g.setColor(Color.black);
        //Schiff überzeichnen
		g.drawPolygon(xPol, yPol, 5);
		g.fillPolygon(xPol, yPol, 5);
		//Schiff nach unten bewegen
		y = y + 1;
		yPol[0] = y;
		yPol[1] = y - shipHeight;
		yPol[2] = y - 2 * Math.round(shipHeight / 3);
		yPol[3] = y - shipHeight;
		yPol[4] = y;
	}

	public void moveUp(Graphics g) {
		//Schiff-Koordinaten
		int[] xPol = { x, x - Math.round(shipWidth / 2), x,
				x + Math.round(shipWidth / 2), x };
		int[] yPol = { y, y + shipHeight, y + 2 * Math.round(shipHeight / 3),
				y + shipHeight, y };
		g.setColor(shipColor);
		//Schiff zeichnen
		g.drawPolygon(xPol, yPol, 5); 
		g.fillPolygon(xPol, yPol, 5); 
        pause(); //Das Schiff soll nicht rasen!
		g.setColor(Color.black);
        //Schiff überzeichnen
		g.drawPolygon(xPol, yPol, 5);
		g.fillPolygon(xPol, yPol, 5);
		//Schiff nach oben bewegen
		y = y - 1;
		yPol[0] = y;
		yPol[1] = y + shipHeight;
		yPol[2] = y + 2 * Math.round(shipHeight / 3);
		yPol[3] = y + shipHeight;
		yPol[4] = y;
	}

	public void moveLeft(Graphics g) {
		//Schiff-Koordinaten
		int[] xPol = { x, x + shipHeight, x + 2 * Math.round(shipHeight / 3),
				x + shipHeight, x };
		int[] yPol = { y, y - Math.round(shipWidth / 2), y,
				y + Math.round(shipWidth / 2), y };
		g.setColor(shipColor);
		//Schiff zeichnen
		g.drawPolygon(xPol, yPol, 5); 
		g.fillPolygon(xPol, yPol, 5); 
        pause(); //Das Schiff soll nicht rasen!
		g.setColor(Color.black);
        //Schiff überzeichnen
		g.drawPolygon(xPol, yPol, 5);
		g.fillPolygon(xPol, yPol, 5);
		//Schiff nach links bewegen
		x = x - 1;
		xPol[0] = x;
		xPol[1] = x + shipHeight;
		xPol[2] = x + 2 * Math.round(shipHeight / 3);
		xPol[3] = x + shipHeight;
		xPol[4] = x;
	}

	public void moveRight(Graphics g) {
		//Schiff-Koordinaten
		int[] xPol = { x, x - shipHeight, x - 2 * Math.round(shipHeight / 3),
				x - shipHeight, x };
		int[] yPol = { y, y - Math.round(shipWidth / 2), y,
				y + Math.round(shipWidth / 2), y };
		g.setColor(shipColor);
		//Schiff zeichnen
		g.drawPolygon(xPol, yPol, 5); 
		g.fillPolygon(xPol, yPol, 5); 
        pause(); //Das Schiff soll nicht rasen!
		g.setColor(Color.black);
        //Schiff überzeichnen
		g.drawPolygon(xPol, yPol, 5);
		g.fillPolygon(xPol, yPol, 5);
		//Schiff nach rechts bewegen
		x = x + 1;
		xPol[0] = x;
		xPol[1] = x - shipHeight;
		xPol[2] = x - 2 * Math.round(shipHeight / 3);
		xPol[3] = x - shipHeight;
		xPol[4] = x;
	}
	
	public void setDirection(int direction) {
      this.direction = direction;
	}
	
	public void run() {
		while (true) {
			//Schiff auf der anderen Seite wieder erscheinen lassen, wenn
			//es über den Bildschirmrand hinausgeht 
			if (x < 0)
				x = maxX;
			else if (x > maxX)
				x = 0;
			if (y < 0)
				y = maxY;
			else if (y > maxY)
				y = 0;
			//Das Schiff kann in 4 unterschiedliche Richtungen fliegen
			switch (direction) {
				case 0 : moveLeft(g);
						 break;
				case 1 : moveRight(g);
						 break;
				case 2 : moveUp(g);
						 break;
				case 3 : moveDown(g);
						 break;
			}
		}
	}
}
```
[/code]


----------



## Wildcard (14. Nov 2006)

Die Berechnung deiner sleep-Time ist total daneben.
Ausserdem ist der Code ziemlicher foobar.
Warum benutzt du keine Objekte die sich selbst zeichnen? So kann das ja kein Mensch lesen.
Ausserdem wage ich zu bezweifeln das du für ein kleines 2D Spiel schon active-rendering brauchst.


----------



## stevewilson (14. Nov 2006)

Na toll, danke für die überaus tolle Info.

Hab ich irgendwas von active rendering erzählt? Was ist das überhaupt?

Wie soll ich bitte Objekte verwenden, die sich selber zeichnen?

Das mit dem Zeichnen habe ich in Pascal damals auch so gemacht, nur dass es damals einen schönen XOR-Mode gab, das man das alles nicht mit schwarz überschreiben musste und somit kein Flackern aufkam.

Das ist aber nicht mein Problem, sondern das mit der Sleeptime.
Und wie kriege ich das bitte hin, wenn du so superschlau bist und weißt, dass
mein Code unfug ist?

Warum wird man in Foren eigentlich immer angekackt?


----------



## Wildcard (14. Nov 2006)

> Hab ich irgendwas von active rendering erzählt? Was ist das überhaupt?


In Java zeichnet man passiv. Nur für Aufwendige Grafische Anwendung (komplexere Spiele) kann man Active Rendering verwenden.
Da du nicht weißt was ich damit meine solltest du so zeichnen wie es das Swing(oder AWT)-Toolkit vorsieht.



> Wie soll ich bitte Objekte verwenden, die sich selber zeichnen?


Wenn du ein Netzwerk basiertes Spiel in Java schreiben willst, solltest du das eigentlich wissen. 
Sieh dich mal auf http://www.javalinkbase.de/ nach Tutorials um.



> Das mit dem Zeichnen habe ich in Pascal damals auch so gemacht, nur dass es damals einen schönen XOR-Mode gab, das man das alles nicht mit schwarz überschreiben musste und somit kein Flackern aufkam.


Das ist nicht Pascal. Man verwendet DoubleBuffering um flackern zu vermeiden (in Swing passiert das automatisch)



> Das ist aber nicht mein Problem, sondern das mit der Sleeptime.


Dein Problem mit der Sleeptime löst sich von alleine sobald du verstanden hast wie man in Java zeichnet und Darstellung sauber von Logik und Bewegung getrennt hast.



> Warum wird man in Foren eigentlich immer angekackt?


Ich habe dich nicht 'angekackt' sondern nur versucht dir mit deutlichen Worten klar zu machen das dein bisher eingeschlagener Weg nicht zu einem vernünftigen Ergebnis führen wird.
Ich kann eben einfach nicht verstehen warum jeder immer meint er könne schon alles und sich einfach nicht die Zeit nimmt mal ein Tutorial zu machen oder ein passendes Buch zu lesen.
Schon die Tatsache das du eine Instanzvariable von Graphics hast und diese auch noch in einem *Thread* zeigt mir das du nicht weißt was du tust.
Und nein, auch das war nicht 'angekackt'


----------



## SlaterB (14. Nov 2006)

noch ein paar allgemeine Tipps:

```
g.setColor(shipColor);
      //Schiff zeichnen
      g.drawPolygon(xPol, yPol, 5);
      g.fillPolygon(xPol, yPol, 5);
        pause(); //Das Schiff soll nicht rasen!
      g.setColor(Color.black);
        //Schiff überzeichnen
      g.drawPolygon(xPol, yPol, 5);
      g.fillPolygon(xPol, yPol, 5);
```

sollte in deinem Programm genau einmal vorkommen,
z.B. in einer Operation
zeicheSchiff(g,xPol,yPol), die dann eben an 4 Stellen aufgerufen wird,

eine solche Code-Wiederholung ist eine böse Sache

-------

```
2 * Math.round(shipHeight / 3)
```
könnte genauso in eine Operation,
aber hier ist es schon verwerflich, das überhaupt ständig auszurechen,
dann ist dann eine zweite Exemplarvariablen

```
double shipHeight23 = 2 * Math.round(shipHeight / 3);
```
besser

---------

am Ende der 4 move-Operation hast du Code wie

```
xPol[0] = x;
      xPol[1] = x - shipHeight;
      xPol[2] = x - 2 * Math.round(shipHeight / 3);
      xPol[3] = x - shipHeight;
      xPol[4] = x;
```
aber wozu hier die nicht mehr benutzten lokalen Objekte noch mal ändern, kann weg!

-----------

zu deiner Ursprungsfrage:
die Wartezeit sollte nicht einmalig fest ausgerechnet werden sondern auf Zeitpunkte in der Systemzeit warten

wenn sich das Schiff beispielsweise nur 10x pro Sekunde bewegen darf,
dann messe am Anfang die Systemzeit, übergib diese an pause() und pause() wartet solange, bis (messbar genau) 100ms vergangen sind

das sollte natürlich nicht in der Mitte einer Zeichenoperation geschehen, sondern davor oder danach


----------



## Wildcard (14. Nov 2006)

Die Tipps sind zwar schön und gut, aber das nützt ja alles nichts solange nicht die eigentlichen Probleme gelöst sind (wie zum Beispiel das busy-waiting, zeichnen aus einem Thread raus, usw.)
Den Code wird stevewilson eh neu schreiben müssen.


----------



## stevewilson (15. Nov 2006)

Was die Berechnungen angeht, habt ihr natürlich recht. Einem wie mir, dem das in Numerik in Militärton 
reingeprügelt wurde, sollte das eigentlich nicht passieren...

Jetzt hab ich das Ding ein Bisschen umgebaut. Jedes Schiff ist nun Teil eines Containers, der das repainting übernimmt.

Jetzt habe ich also 3 Klassen:

Den Controller, der auch zugleich Frame ist(ich weiß, ein MVC-Pattern wär wahrscheinlich besser)


```
package spaceships;

import java.awt.*;
import java.awt.event.*;

public class Controller extends Frame {

	private MoveShip ownShip;
	private MoveShip ownShip2;
	private ShipContainer shipContainer;

	public Controller() {
	    //Bildschirmauflösung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        //Fenster soll ganz oben links beginnen  
	    setLocation(0, 0);
	    //Vollbild
		setSize(d.getSize().width, d.getSize().height);
		setVisible(true);
		setResizable(false);
		setBackground(Color.BLACK); //Schwarze Farbe, damit 
		                            //Spielatmosphäre aufkommt
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		ownShip = new MoveShip(MoveShip.ownShipColor);
        shipContainer = new ShipContainer();
        shipContainer.addShip(ownShip);
        add(shipContainer);
		//Testobjekt
		ownShip2 = new MoveShip(MoveShip.otherShipColor);
		ownShip.setXY(300, 300);
        //Testobjekt
		addKeyListener(new KeyAdapter() {
	        public void keyPressed( KeyEvent k )
	        {
	            if(k.getKeyCode() == KeyEvent.VK_LEFT) { 
	            	ownShip.setDirection(MoveShip.LEFT);
	            	shipContainer.repaint();
	            }
	            else if(k.getKeyCode() == KeyEvent.VK_RIGHT) 
	            	ownShip.setDirection(MoveShip.RIGHT);
	            else if(k.getKeyCode() == KeyEvent.VK_UP) 
	            	ownShip.setDirection(MoveShip.UP);
	            else if(k.getKeyCode() == KeyEvent.VK_DOWN) 
	            	ownShip.setDirection(MoveShip.DOWN);
	            if(k.getKeyCode() == KeyEvent.VK_SPACE)
	            	System.out.println("space");
	            else if(k.getKeyCode() == KeyEvent.VK_ESCAPE)
	            	System.exit(0);
	        }
		});
	}
	
	public static void main(String[] args) {
		new Controller();
		//Client2.runClient();
	}
}
```

Den Container:


```
package spaceships;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Toolkit;

public class ShipContainer extends Container {
	
	private int maxX;
	private int maxY;
	
	public ShipContainer() {
		//Bildschirmauflösung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		maxX = d.getSize().width;
		maxY = d.getSize().height;
	}
	
	public int getMaxX() {
		return maxX;
	}
	
	public int getMaxY() {
		return maxY;
	}
	
	public void addShip(MoveShip ship) {
		this.add(ship);
	    ship.setShipContainer(this);
	}

}
```

Das Schiff:


```
package spaceships;

import java.awt.*;

public class MoveShip extends Component implements Runnable {

    public static final Color ownShipColor = Color.green;
	public static final Color otherShipColor = Color.red;
	public static final int LEFT = 0;
	public static final int RIGHT = 1;
	public static final int UP = 2;
	public static final int DOWN = 3;
	private Color shipColor;
	private int shipWidth;
	private int shipHeight;
	private int x;
	private int y;
	private int direction = 0;
	
	//Variablen, um Anzahl Berechnungen zu minimieren
	private int shipHeight23;
	private int shipHalfWidth;
	
	private ShipContainer shipContainer;

	private long sleepTime;
	
    //Test-Methode
	public void setXY(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	//Funktion, die ein bisschen wartet
	public void pause() {
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public MoveShip(Color shipColor) {
		x = 100;
		y = 100;
		Thread t = new Thread(this);
		t.start();
	    //Schiff an Bildschirmauflösung anpassen
	    shipWidth = Math.round(shipContainer.getMaxX() / 32); 
	    shipHeight = Math.round(shipContainer.getMaxY() / 16);
		shipHeight23 = 2 * Math.round(shipHeight / 3);
		shipHalfWidth = Math.round(shipWidth / 2);
	    this.shipColor = shipColor;

	}
	
	public void setDirection(int direction) {
      this.direction = direction;
	}
	
	public void paint(Graphics g) {
		int[] xPol = null;
		int[] yPol = null;
		// Schiff-Koordinaten für die vier unterschiedlichen Richtungen
		switch (direction) {
		case LEFT:
			xPol[0] = x;
			xPol[1] = x + shipHeight;
			xPol[2] = x + shipHeight23;
			xPol[3] = xPol[1];
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHalfWidth;
			yPol[2] = y;
			yPol[3] = y + shipHalfWidth;
			yPol[4] = y;
			x = x - 1;
			break;
		case RIGHT:
			xPol[0] = x;
			xPol[1] = x - shipHeight;
			xPol[2] = x - shipHeight23;
			xPol[3] = xPol[1];
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHalfWidth;
			yPol[2] = y;
			yPol[3] = y + shipHalfWidth;
			yPol[4] = y;
			break;
		case UP:
			xPol[0] = x;
			xPol[1] = x - shipHalfWidth;
			xPol[2] = x;
			xPol[3] = x + shipHalfWidth;
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y + shipHeight;
			yPol[2] = y + shipHeight23;
			yPol[3] = yPol[1];
			yPol[4] = y;
			break;
		case DOWN:
			xPol[0] = x;
			xPol[1] = x - shipHalfWidth;
			xPol[2] = x;
			xPol[3] = x + shipHalfWidth;
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHeight;
			yPol[2] = y - shipHeight23;
			yPol[3] = yPol[1];
			yPol[4] = y;
			break;
		}
		// Schiff auf der anderen Seite wieder erscheinen lassen, wenn
		// es über den Bildschirmrand hinausgeht
		if (x < 0)
			x = shipContainer.getMaxX();
		else if (x > shipContainer.getMaxX())
			x = 0;
		if (y < 0)
			y = shipContainer.getMaxY();
		else if (y > shipContainer.getMaxY())
			y = 0;
		g.setColor(shipColor);
		// Schiff zeichnen
		g.drawPolygon(xPol, yPol, 5);
		g.fillPolygon(xPol, yPol, 5);
	}
	
	public void run() {
		while (true) {
			//System.exit(0);
		   pause();
           shipContainer.repaint();
		}
	}

	public void setShipContainer(ShipContainer container) {
		// TODO Auto-generated method stub
		shipContainer = container; 
	}

}
```

Kann mir jetzt mal jemand sagen, warum meine Events gar nicht mehr funktionieren?


----------



## SlaterB (15. Nov 2006)

zunächst mal läuft das Programm doch gar nicht an:

java.lang.NullPointerException
	at spaceships.MoveShip.<init>(MoveShip.java:49)
	at spaceships.Controller.<init>(Controller.java:29)
	at spaceships.Controller.main(Controller.java:59)
java.lang.NullPointerException
	at spaceships.MoveShip.run(MoveShip.java:136)
	at java.lang.Thread.run(Unknown Source)
Exception in thread "main" 

shipContainer ist eine null-Variable,
die muss erstmal gefüllt werden


----------



## stevewilson (15. Nov 2006)

Doch es läuft, du musst den Controller ausfühern.

Und shipContainer wird initialisiert. Die Methode shipContainer.addship wird im Controller aufgerufen ruft diese Methode im MoveShip auf:

public void setShipContainer(ShipContainer container) {
		shipContainer = container; 
	}


----------



## SlaterB (15. Nov 2006)

da ist doch schon eine main mit new Controller(),
meinst du ich habe erst 10 Änderungen gemacht statt diese aufzurufen?

und die Fehlermeldung gibt den Weg des Fehlers doch eindeutig vor:

das Schiff wird mit
ownShip = new MoveShip(MoveShip.ownShipColor);
erzeugt,
im KONSTRUKTOR MoveShip wird bereits auf den container zugegriffen,
der zu diesem Zeitpunkt noch null ist, 
er ist in der Variablen in MoveShip noch nicht gespeichert, in diesem Fall noch nichtmal im Controller erzeugt worden,
das passiert erst eine Zeile später im Contorller,

die Operation setShipContainer wird erst viel später ausgeführt,
zu spät,

aber warum erzähle ich das, bei dir sollte doch die gleiche Exception kommen,
schaue in die Konsole!,
die GUI wird dennoch angezeigt, das stimmt


----------



## stevewilson (15. Nov 2006)

Seltsamerweise erscheint bei mir nix in der Konsole, ganz komisch. Naja, jetzt hab ich ne init-Methode gebastelt und die shipContainer-Zugriffe aus dem Konstruktor von Moveship entfernt. Im Container hab ich auch 2 kleine Fehler entfernt.

Hier die neuen Codes:

Ship:


```
package spaceships;

import java.awt.*;

public class MoveShip extends Component implements Runnable {

    public static final Color ownShipColor = Color.green;
	public static final Color otherShipColor = Color.red;
	public static final int LEFT = 0;
	public static final int RIGHT = 1;
	public static final int UP = 2;
	public static final int DOWN = 3;
	private Color shipColor;
	private int shipWidth;
	private int shipHeight;
	private int x;
	private int y;
	private int direction = 0;
	
	//Variablen, um Anzahl Berechnungen zu minimieren
	private int shipHeight23;
	private int shipHalfWidth;
	
	private ShipContainer shipContainer;

	private long sleepTime;
	
    //Test-Methode
	public void setXY(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	//Funktion, die ein bisschen wartet
	public void pause() {
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public MoveShip(Color shipColor) {
		x = 100;
		y = 100;
		Thread t = new Thread(this);
		t.start();


	}
	
	public void setDirection(int direction) {
      this.direction = direction;
	}
	
	public void paint(Graphics g) {
		int[] xPol = null;
		int[] yPol = null;
		// Schiff-Koordinaten für die vier unterschiedlichen Richtungen
		switch (direction) {
		case LEFT:
			xPol[0] = x;
			xPol[1] = x + shipHeight;
			xPol[2] = x + shipHeight23;
			xPol[3] = xPol[1];
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHalfWidth;
			yPol[2] = y;
			yPol[3] = y + shipHalfWidth;
			yPol[4] = y;
			x = x - 1;
			break;
		case RIGHT:
			xPol[0] = x;
			xPol[1] = x - shipHeight;
			xPol[2] = x - shipHeight23;
			xPol[3] = xPol[1];
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHalfWidth;
			yPol[2] = y;
			yPol[3] = y + shipHalfWidth;
			yPol[4] = y;
			break;
		case UP:
			xPol[0] = x;
			xPol[1] = x - shipHalfWidth;
			xPol[2] = x;
			xPol[3] = x + shipHalfWidth;
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y + shipHeight;
			yPol[2] = y + shipHeight23;
			yPol[3] = yPol[1];
			yPol[4] = y;
			break;
		case DOWN:
			xPol[0] = x;
			xPol[1] = x - shipHalfWidth;
			xPol[2] = x;
			xPol[3] = x + shipHalfWidth;
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHeight;
			yPol[2] = y - shipHeight23;
			yPol[3] = yPol[1];
			yPol[4] = y;
			break;
		}
		// Schiff auf der anderen Seite wieder erscheinen lassen, wenn
		// es über den Bildschirmrand hinausgeht
		if (x < 0)
			x = shipContainer.getMaxX();
		else if (x > shipContainer.getMaxX())
			x = 0;
		if (y < 0)
			y = shipContainer.getMaxY();
		else if (y > shipContainer.getMaxY())
			y = 0;
		g.setColor(shipColor);
		// Schiff zeichnen
		g.drawPolygon(xPol, yPol, 5);
		g.fillPolygon(xPol, yPol, 5);
	}
	
	public void run() {
		while (true) {
		   pause();
           shipContainer.repaint();
		}
	}

	public void setShipContainer(ShipContainer container) {
		shipContainer = container; 
	}

	public void init() {
	    //Schiff an Bildschirmauflösung anpassen
	    shipWidth = Math.round(shipContainer.getMaxX() / 32); 
	    shipHeight = Math.round(shipContainer.getMaxY() / 16);
		shipHeight23 = 2 * Math.round(shipHeight / 3);
		shipHalfWidth = Math.round(shipWidth / 2);
	    this.shipColor = shipColor;
	}
}
```

Container:


```
package spaceships;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Toolkit;


public class ShipContainer extends Container {
	
	private int maxX;
	private int maxY;
	
	public ShipContainer() {
		//Bildschirmauflösung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		maxX = d.getSize().width;
		maxY = d.getSize().height;
	}
	
	public int getMaxX() {
		return maxX;
	}
	
	public int getMaxY() {
		return maxY;
	}
	
	public void addShip(MoveShip ship) {
		this.add(ship);
	    ship.setShipContainer(this);
	    ship.init();
	}
}
```

Controller:


```
package spaceships;

import java.awt.*;
import java.awt.event.*;

public class Controller extends Frame {

	private MoveShip ownShip;
	private MoveShip ownShip2;
	private ShipContainer shipContainer;

	public Controller() {
	    //Bildschirmauflösung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        //Fenster soll ganz oben links beginnen  
	    setLocation(0, 0);
	    //Vollbild
		setSize(d.getSize().width, d.getSize().height);
		setVisible(true);
		setResizable(false);
		setBackground(Color.BLACK); //Schwarze Farbe, damit 
		                            //Spielatmosphäre aufkommt
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
        shipContainer = new ShipContainer();
        ownShip = new MoveShip(MoveShip.ownShipColor);
        shipContainer.addShip(ownShip);
        add(shipContainer);
		//Testobjekt
		ownShip2 = new MoveShip(MoveShip.otherShipColor);
		ownShip.setXY(300, 300);
        //Testobjekt
		addKeyListener(new KeyAdapter() {
	        public void keyPressed( KeyEvent k )
	        {
	            if(k.getKeyCode() == KeyEvent.VK_LEFT) { 
	            	ownShip.setDirection(MoveShip.LEFT);
	            	shipContainer.repaint();
	            }
	            else if(k.getKeyCode() == KeyEvent.VK_RIGHT) 
	            	ownShip.setDirection(MoveShip.RIGHT);
	            else if(k.getKeyCode() == KeyEvent.VK_UP) 
	            	ownShip.setDirection(MoveShip.UP);
	            else if(k.getKeyCode() == KeyEvent.VK_DOWN) 
	            	ownShip.setDirection(MoveShip.DOWN);
	            else if(k.getKeyCode() == KeyEvent.VK_SPACE)
	            	System.out.println("space");
	            else if(k.getKeyCode() == KeyEvent.VK_ESCAPE)
	            	System.exit(0);
	        }
		});
	}
	
	public static void main(String[] args) {
		new Controller();
		//Client2.runClient();
	}
}package spaceships;

import java.awt.*;
import java.awt.event.*;

public class Controller extends Frame {

	private MoveShip ownShip;
	private MoveShip ownShip2;
	private ShipContainer shipContainer;

	public Controller() {
	    //Bildschirmauflösung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        //Fenster soll ganz oben links beginnen  
	    setLocation(0, 0);
	    //Vollbild
		setSize(d.getSize().width, d.getSize().height);
		setVisible(true);
		setResizable(false);
		setBackground(Color.BLACK); //Schwarze Farbe, damit 
		                            //Spielatmosphäre aufkommt
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
        shipContainer = new ShipContainer();
        ownShip = new MoveShip(MoveShip.ownShipColor);
        shipContainer.addShip(ownShip);
        add(shipContainer);
		//Testobjekt
		ownShip2 = new MoveShip(MoveShip.otherShipColor);
		ownShip.setXY(300, 300);
        //Testobjekt
		addKeyListener(new KeyAdapter() {
	        public void keyPressed( KeyEvent k )
	        {
	            if(k.getKeyCode() == KeyEvent.VK_LEFT) { 
	            	ownShip.setDirection(MoveShip.LEFT);
	            	shipContainer.repaint();
	            }
	            else if(k.getKeyCode() == KeyEvent.VK_RIGHT) 
	            	ownShip.setDirection(MoveShip.RIGHT);
	            else if(k.getKeyCode() == KeyEvent.VK_UP) 
	            	ownShip.setDirection(MoveShip.UP);
	            else if(k.getKeyCode() == KeyEvent.VK_DOWN) 
	            	ownShip.setDirection(MoveShip.DOWN);
	            else if(k.getKeyCode() == KeyEvent.VK_SPACE)
	            	System.out.println("space");
	            else if(k.getKeyCode() == KeyEvent.VK_ESCAPE)
	            	System.exit(0);
	        }
		});
	}
	
	public static void main(String[] args) {
		new Controller();
		//Client2.runClient();
	}
}
```

Jetzt läuft zwar mein escape, aber ich kriege immernoch kein Schiff angezeigt...


----------



## SlaterB (15. Nov 2006)

also ohne Konsole, ohne Anzeige der Fehler kannst du nicht weitermachen,
oder willst du das jetzt hier jemand im Forum alle deine Fehler aufzählt?

es gibt immer noch eine Exception

java.lang.NullPointerException
	at spaceships.MoveShip.run(MoveShip.java:131)
	at java.lang.Thread.run(Unknown Source)
(shipContainer nicht gesetzt)

am besten startest du den Thread erst in der init()-Operation, wenn dann der shipContainer da ist

-----------

ich habe gleich mal ein wenig weiter geschaut:
der Befehl setVisible(true) muss ans Ende des Frame-Konstruktors, 
ansonsten werden die später eingefügten Elemene (wie der shipContainer) nicht angezeigt,

in der MoveShip-paint-Operation ist
int[] xPol = null;
und wird nirgendwo erzeugt (z.b. new int[5])

usw.

da gibts bestimmt noch viele Sachen die im Argen liegen,
ohne die Exceptions zu erkennen, in diesem Fall

java.lang.NullPointerException
	at spaceships.MoveShip.paint(MoveShip.java:61)
	at java.awt.GraphicsCallback$PaintCallback.run(Unknown Source)
	at sun.awt.SunGraphicsCallback.runOneComponent(Unknown Source)
	at sun.awt.SunGraphicsCallback.runComponents(Unknown Source)
	at java.awt.Container.paint(Unknown Source)

wird das nicht gehen


----------



## stevewilson (15. Nov 2006)

Ja, ich weiß, das ist total dämlich ohne Konsole. Aber ich weiß nicht, warum ich da nix angezeigt kriege...Keine Ahnung...Sonst geht das immer ohne Probleme...


----------



## stevewilson (15. Nov 2006)

okay, ein neustart von eclipse bewirkt wunder.....

Schiff:


```
package spaceships;

import java.awt.*;

public class MoveShip extends Component implements Runnable {

    public static final Color ownShipColor = Color.green;
	public static final Color otherShipColor = Color.red;
	public static final int LEFT = 0;
	public static final int RIGHT = 1;
	public static final int UP = 2;
	public static final int DOWN = 3;
	private Color shipColor;
	private int shipWidth;
	private int shipHeight;
	private int x;
	private int y;
	private int direction = 0;
	
	//Variablen, um Anzahl Berechnungen zu minimieren
	private int shipHeight23;
	private int shipHalfWidth;
	
	private ShipContainer shipContainer;

	private long sleepTime;
	
    //Test-Methode
	public void setXY(int x, int y) {
		this.x = x;
		this.y = y;
	}
	
	//Funktion, die ein bisschen wartet
	public void pause() {
		try {
			Thread.sleep(1);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
	public MoveShip(Color shipColor) {
		x = 100;
		y = 100;
	}
	
	public void setDirection(int direction) {
      this.direction = direction;
	}
	
	public void paint(Graphics g) {
		int[] xPol = new int[5];
		int[] yPol = new int[5];
		// Schiff-Koordinaten für die vier unterschiedlichen Richtungen
		switch (direction) {
		case LEFT:
			xPol[0] = x;
			xPol[1] = x + shipHeight;
			xPol[2] = x + shipHeight23;
			xPol[3] = xPol[1];
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHalfWidth;
			yPol[2] = y;
			yPol[3] = y + shipHalfWidth;
			yPol[4] = y;
			x = x - 1;
			break;
		case RIGHT:
			xPol[0] = x;
			xPol[1] = x - shipHeight;
			xPol[2] = x - shipHeight23;
			xPol[3] = xPol[1];
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHalfWidth;
			yPol[2] = y;
			yPol[3] = y + shipHalfWidth;
			yPol[4] = y;
			break;
		case UP:
			xPol[0] = x;
			xPol[1] = x - shipHalfWidth;
			xPol[2] = x;
			xPol[3] = x + shipHalfWidth;
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y + shipHeight;
			yPol[2] = y + shipHeight23;
			yPol[3] = yPol[1];
			yPol[4] = y;
			break;
		case DOWN:
			xPol[0] = x;
			xPol[1] = x - shipHalfWidth;
			xPol[2] = x;
			xPol[3] = x + shipHalfWidth;
			xPol[4] = x;
			yPol[0] = y;
			yPol[1] = y - shipHeight;
			yPol[2] = y - shipHeight23;
			yPol[3] = yPol[1];
			yPol[4] = y;
			break;
		}
		// Schiff auf der anderen Seite wieder erscheinen lassen, wenn
		// es über den Bildschirmrand hinausgeht
		if (x < 0)
			x = shipContainer.getMaxX();
		else if (x > shipContainer.getMaxX())
			x = 0;
		if (y < 0)
			y = shipContainer.getMaxY();
		else if (y > shipContainer.getMaxY())
			y = 0;
		g.setColor(shipColor);
		// Schiff zeichnen
		g.drawPolygon(xPol, yPol, 5);
		g.fillPolygon(xPol, yPol, 5);
	}
	
	public void run() {
		while (true) {
		   pause();
           shipContainer.paint();
		}
	}

	public void setShipContainer(ShipContainer container) {
		shipContainer = container; 
	}

	public void init() {
	    //Schiff an Bildschirmauflösung anpassen
	    shipWidth = Math.round(shipContainer.getMaxX() / 32); 
	    shipHeight = Math.round(shipContainer.getMaxY() / 16);
		shipHeight23 = 2 * Math.round(shipHeight / 3);
		shipHalfWidth = Math.round(shipWidth / 2);
	    this.shipColor = shipColor;
		Thread t = new Thread(this);
		t.start();
	}
}
```

Controller:


```
package spaceships;

import java.awt.*;
import java.awt.event.*;

public class Controller extends Frame {

	private MoveShip ownShip;
	private MoveShip ownShip2;
	private ShipContainer shipContainer;

	public Controller() {
	    //Bildschirmauflösung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
        //Fenster soll ganz oben links beginnen  
	    setLocation(0, 0);
	    //Vollbild
		setSize(d.getSize().width, d.getSize().height);
		setResizable(false);
		setBackground(Color.BLACK); //Schwarze Farbe, damit 
		                            //Spielatmosphäre aufkommt
		addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
        shipContainer = new ShipContainer();
        try {
        ownShip = new MoveShip(MoveShip.ownShipColor);
        shipContainer.addShip(ownShip);
        add(shipContainer);
        }
        catch (Exception e)
        {
        	e.printStackTrace();
        }
		//Testobjekt
		ownShip2 = new MoveShip(MoveShip.otherShipColor);
		ownShip.setXY(300, 300);
        //Testobjekt
		addKeyListener(new KeyAdapter() {
	        public void keyPressed( KeyEvent k )
	        {
	            if(k.getKeyCode() == KeyEvent.VK_LEFT) { 
	            	ownShip.setDirection(MoveShip.LEFT);
	            	//shipContainer.repaint();
	            }
	            else if(k.getKeyCode() == KeyEvent.VK_RIGHT) 
	            	ownShip.setDirection(MoveShip.RIGHT);
	            else if(k.getKeyCode() == KeyEvent.VK_UP) 
	            	ownShip.setDirection(MoveShip.UP);
	            else if(k.getKeyCode() == KeyEvent.VK_DOWN) 
	            	ownShip.setDirection(MoveShip.DOWN);
	            else if(k.getKeyCode() == KeyEvent.VK_SPACE)
	            	System.out.println("space");
	            else if(k.getKeyCode() == KeyEvent.VK_ESCAPE)
	            	System.exit(0);
	        }
		});
		setVisible(true);
	}
	
	public static void main(String[] args) {
		new Controller();
		//Client2.runClient();
	}
}
```

Container:


```
package spaceships;

import java.awt.Container;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Toolkit;


public class ShipContainer extends Container {
	
	private int maxX;
	private int maxY;
	
	public ShipContainer() {
		//Bildschirmauflösung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		maxX = d.getSize().width;
		maxY = d.getSize().height;
		setSize(maxX, maxY);
	}
	
	public int getMaxX() {
		return maxX;
	}
	
	public int getMaxY() {
		return maxY;
	}
	
	public void addShip(MoveShip ship) {
		this.add(ship);
	    ship.setShipContainer(this);
	    ship.init();
	}

	public void paint() {
		Graphics g = super.getGraphics();
		super.paint(g);
	}
}
```

Ein Schiff erscheint trotz fehlender Exceptions nicht.

Übrigens, SlaterB, danke für deine bisherige Hilfe...


----------



## Wildcard (15. Nov 2006)

Du hast immer noch ein großes Problem in deinem Programm:
Nur der EventDispatcherThread darf zeichnen. Du zeichnest aber in einem eigenen Thread. Das funktioniert manchmal, und manchmal eben überhaupt nicht.
Folgender Ansatz:
Jedes bewegte Objekt ist ein eigenes Objekt.
Jedes dieser Objekte hat einen Bewegungsvektor.
Ein Thread durchläuft eine Endlosschleife und ruft auf allen bewegten Objekten eine move Methode auf (woraufhin diese Objekte ihre Position anhand ihres Bewegungsvektor neu berechnen), fordert Swing mit repaint() zum Neuzeichnen auf und schläft anschließend.
Dein derzeitiges Konstrukt führt zu nicht-deterministischen Ergebnissen.


----------



## Redfrettchen (15. Nov 2006)

Wildcard hat gesagt.:
			
		

> Dein derzeitiges Konstrukt führt zu nicht-deterministischen Ergebnissen.


haha, hat auch was für sich, siehe Java2K ^^


----------



## Wildcard (15. Nov 2006)

*lach* Ja, Java2K hat schon was


----------



## stevewilson (23. Nov 2006)

Hallo,

habe den Code jetzt komplett umgebastelt. Auf 2 Windows-Maschinen laufen die Schiffe gleich schnell, auf ner Linux-Kiste läuft dat Ding leider immernoch langsamer...

ier der Code:


```
package spaceships;

import java.awt.Color;
import java.awt.Rectangle;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;

import javax.swing.JFrame;

public class GuiTest extends JFrame {
	private static final long serialVersionUID = 1L;

	Space s;

	Ship p, q;

	public GuiTest() {
		final Client client = new Client();
		this.add(s = new Space(500, 500)); //Space-Koordinaten unwichtig?????
		s.add(p = new Ship(new Rectangle(5, 5, 50, 50), 2, Color.WHITE));
		q = new Ship(new Rectangle(30, 30, 10, 10), 5, Color.GREEN);
		s.add(q);
		this.setSize(800, 600); //An Screensize anpassen!
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent k) {
				switch (k.getKeyCode()) {
				case KeyEvent.VK_LEFT:
					client.send("left");
					p.setDirection(Direction.left);
					break;
				case KeyEvent.VK_RIGHT:
					client.send("right");
					p.setDirection(Direction.right);
					break;
				case KeyEvent.VK_UP:
					client.send("up");
					p.setDirection(Direction.up);
					break;
				case KeyEvent.VK_DOWN:
					client.send("down");
					p.setDirection(Direction.down);
					break;
				case KeyEvent.VK_SPACE:
					client.send("space");
					p.setDirection(Direction.stop);
					break;
				/*case KeyEvent.VK_A:
					q.setDirection(Direction.left);
					break;
				case KeyEvent.VK_D:
					q.setDirection(Direction.right);
					break;
				case KeyEvent.VK_W:
					q.setDirection(Direction.up);
					break;
				case KeyEvent.VK_S:
					q.setDirection(Direction.down);
					break;
				case KeyEvent.VK_X:
					q.setDirection(Direction.stop);
					break;*/
				}
			}
		});
	}

	public static void main(String[] args) {
		new GuiTest();
		Server server = new Server();
		server.start();
		Client client = new Client();
		client.start();
	}
}
```


```
package spaceships;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.Rectangle;

public class Ship implements Runnable {
		
	int speed;

	Direction direction;

	Color shipcolor;

	volatile Rectangle pos, oldpos;

	Space s;
	
	int heightdiv2, widthdiv2;

	public Ship(Rectangle pos, int speed, Color shipcolor) {
		this.shipcolor = shipcolor;
		this.pos = pos;
		oldpos = new Rectangle(pos);
		this.direction = Direction.stop;
		this.speed = speed;
		heightdiv2 = pos.height / 2;
		widthdiv2 = pos.width / 2;
	}

	public void paint(Graphics g) {
		// g.setColor(Color.BLACK);
		// g.fillOval(oldpos.x, oldpos.y, oldpos.width, oldpos.height);
		// oldpos.setBounds(pos);
		// System.out.println("ship "+g.getClipBounds());
		int cx = pos.x + widthdiv2;
		int cy = pos.y + heightdiv2;

		//Wenn das Schiff über den Bildschirmrand hinausfliegt, soll
		//es wieder auf der gegenüberliegenden Seite erscheinen
		

		if (cx < 0)
			pos.x = s.getWidth() - widthdiv2;
		else if (cx > s.getWidth())
			pos.x = -widthdiv2;
		if (cy < 0)
			pos.y = s.getHeight() - heightdiv2;
		else if (cy > s.getHeight())
			pos.y = -heightdiv2;

		// Je nachdem in welche Richtung das Schiff fliegt, bekommt
		// es unterschiedliche Koordinaten
		/*Polygon left = new Polygon();
		left.addPoint(pos.x, pos.y + heightdiv2);
		left.addPoint(pos.x + pos.width - 1, pos.y + pos.height - 1);
		left.addPoint(pos.x + pos.width - 1, pos.y);
		Polygon right = new Polygon();
		right.addPoint(pos.x + pos.width - 1, pos.y + heightdiv2);
		right.addPoint(pos.x, pos.y + pos.height - 1);
		right.addPoint(pos.x, pos.y);
		Polygon up = new Polygon();
		up.addPoint(pos.x + widthdiv2, pos.y);
		up.addPoint(pos.x, pos.y + pos.height - 1);
		up.addPoint(pos.x + pos.width - 1, pos.y + pos.height - 1);
		Polygon down = new Polygon();
		down.addPoint(pos.x + widthdiv2, pos.y + pos.height - 1);
		down.addPoint(pos.x + pos.width - 1, pos.y);
		down.addPoint(pos.x, pos.y);*/
		
		Polygon left = new Polygon();
		left.addPoint(pos.x, pos.y + heightdiv2);
		left.addPoint(pos.x + pos.width, pos.y + pos.height);
		left.addPoint(pos.x + pos.width, pos.y);
		Polygon right = new Polygon();
		right.addPoint(pos.x + pos.width, pos.y + heightdiv2);
		right.addPoint(pos.x, pos.y + pos.height);
		right.addPoint(pos.x, pos.y);
		Polygon up = new Polygon();
		up.addPoint(pos.x + widthdiv2, pos.y);
		up.addPoint(pos.x, pos.y + pos.height);
		up.addPoint(pos.x + pos.width, pos.y + pos.height);
		Polygon down = new Polygon();
		down.addPoint(pos.x + widthdiv2, pos.y + pos.height);
		down.addPoint(pos.x + pos.width, pos.y);
		down.addPoint(pos.x, pos.y);

		g.setColor(shipcolor);
		//Fallunterscheidung für 4 unterschiedliche Flugrichtungen
		switch (direction) {
		case left:
			g.fillPolygon(left);
			break;
		case right:
			g.fillPolygon(right);
			break;
		case up:
			g.fillPolygon(up);
			break;
		case down:
			g.fillPolygon(down);
			break;
		case stop:
			g.fillOval(pos.x, pos.y, pos.width - 1, pos.height - 1);
		}
	}

	public void run() {
		while (true) {
			oldpos.setBounds(pos);
			//Position des Schiffes je nach Flugrichtung um vorher 
			//festgelegte Anzahl an Pixeln verschieben
			switch (direction) {
			case up:
				pos.y -= speed;
				break;
			case down:
				pos.y += speed;
				break;
			case left:
				pos.x -= speed;
				break;
			case right:
				pos.x += speed;
				break;
			case stop:
				break;
			}
			s.repaint(oldpos.union(pos));
			//Eine kurze Pause, damit das Schiff nicht rast
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}

	public Direction getDirection() {
		return direction;
	}

	public void setDirection(Direction direction) {
		this.direction = direction;
	}

	public void setS(Space s) {
		this.s = s;
		new Thread(this).start();
	}
}
```


```
package spaceships;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.util.Vector;

import javax.swing.JComponent;

public class Space extends JComponent implements Runnable {

	private static final long serialVersionUID = 1L;

	Vector<Ship> ships = new Vector<Ship>();

	Rectangle size, oldsize;

	Image image;

	Graphics graphics;

	public Space(int width, int height) {
		Dimension d = new Dimension(width, height); //this.width/this.height??
		size = new Rectangle(d);
		this.setBackground(Color.BLACK);
		this.setMaximumSize(d);
		this.setMinimumSize(d);
		this.setPreferredSize(d);
		this.setSize(d);
		this.setDoubleBuffered(true);
		//		Thread t = new Thread(this);
		//		t.start();
	}

	public void add(Ship s) {
		s.setS(this);
		ships.add(s);
	}

	public void update(Graphics g) {
		paint(g);
	}

	public void paint(Graphics g) {
		//		System.out.println("space "+g.getClipBounds());
		g.getClipBounds(size);
		g.setColor(Color.BLACK);
		g.fillRect(size.x, size.y, size.width, size.height);
		for (Ship s : ships) {
			s.paint(g);
		}
		g.setColor(Color.BLACK);
	}

	public void run() {
		while (true) {
			repaint();
			try {
				Thread.sleep(1);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}
```


```
package spaceships;

public enum Direction {
	up, down, left, right, stop;
}
```


----------



## Wildcard (23. Nov 2006)

Das sieht schon deutlich besser als am Anfang aus, aber 2 Dinge fallen mir ins Auge die dich massig Rechenleistung kosten:
1. Thread.sleep(1); 
Diese sleep Zeit ist viel zu kurz. Sie ist sogar so kurz dass das OS sie nicht exakt messen kann.
2. Du machst zu viele Threads auf.
Dein Programm sollte nur aus 2 Threads bestehen:
dem EvenDispatcher der zeichnet und einem Thread der alle beweglichen Objekte verschiebt.
Du machst für jedes Schiff einen Thread, das bedeutet zum einen mehr arbeit für die CPU und zweitens kann es passieren das die Schiffe unterschiedlich viel Rechenzeit bekommen.


----------



## Guest (23. Nov 2006)

Jetzt habe ich im Space nur ein Thread für alle Schiffe, da lauf ich den Vektor mit allen Schiffen durch
und aktualisiere für jedes die Position, die Schiff-Klasse zeichnet dann. Allerdings nicht in ienem Thread. Oder meinst du mit dem EventDispatcher die paint-Methode?

Hier der Code:


```
package spaceships;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Vector;

public class Controller {
	public static void main(String[] args) {
		GuiTest g = new GuiTest();
		Server server = new Server(g);
		server.start();
		Client client = new Client();
		client.start();
	}
}

class Server extends Thread {
	
	GuiTest g;
	
	public Server(GuiTest g) {
		this.g = g;
	}

	public void run() {
		try {
			MulticastSocket multicastsocket = new MulticastSocket(4445);
			InetAddress multicastgroup = InetAddress.getByName("228.5.6.7");
			multicastsocket.joinGroup(multicastgroup);
			byte[] buffer = new byte[1024];
			while (true) {
				DatagramPacket receivedPacket = new DatagramPacket(buffer,
						buffer.length);
				multicastsocket.receive(receivedPacket);
				String receivedMessage = new String(buffer);
				String own = InetAddress.getLocalHost().getHostAddress();
				own = own.trim();
				if (receivedMessage.indexOf(own) == -1) {
					int pos = receivedMessage.indexOf(" - ");
					receivedMessage = receivedMessage.trim();
					System.out.println(receivedMessage + "\n");
					String action = receivedMessage.substring(pos+3, receivedMessage.length());
					Vector<Ship> ships = Space.getShips();
					int createShip = 1;
					for(Ship s : ships) {
						if(receivedMessage.substring(0, pos) == s.getIPAddr()) {
							createShip = 0;
						}
					}
					if(createShip == 1) {
						g.createShip(receivedMessage.substring(0, pos));
					}
					Ship newShip = null;
					for(Ship s : ships) {
						if(receivedMessage.substring(0, pos) == s.getIPAddr()) {
							newShip = s;
					if(action.equals("up")) {
						newShip.setDirection(Direction.up);
						System.out.println("UP");
					}
					else if(action.equals("right")) {
						newShip.setDirection(Direction.right);
						System.out.println("RIGHT");
					}
					else if(action.equals("down")) {
						newShip.setDirection(Direction.down);
						System.out.println("DOWN");
					}
					else if(action.equals("left")) {
						newShip.setDirection(Direction.left);
						System.out.println("LEFT");
					}
					else if(action.equals("space")) {
						newShip.setDirection(Direction.stop);
						System.out.println("SPACE");
					}				
						}
					}
				}
				for (int i = 0; i < buffer.length; i++) {
					buffer[i] = '\0';
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

class Client extends Thread {
	public void run() {
		try {
			send("spielwut");
			BufferedReader ttyin = new BufferedReader(new InputStreamReader(
					System.in));
			while (true) {
				System.out.print("Client? ");
				String input = ttyin.readLine();
				send(input);

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void send(String input) {
		try {
			InetAddress multicastgroup = InetAddress.getByName("228.5.6.7");
			MulticastSocket multicastsocket = new MulticastSocket(4445);
			String sendMessage = InetAddress.getLocalHost().getHostAddress()
					+ " - " + input;
			DatagramPacket sendPacket = new DatagramPacket(sendMessage
					.getBytes(), sendMessage.length(), multicastgroup, 4445);
			multicastsocket.send(sendPacket);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
```


```
package spaceships;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.net.InetAddress;
import java.net.UnknownHostException;

import javax.swing.JFrame;

public class GuiTest extends JFrame {
	private static final long serialVersionUID = 1L;

	public Space s;

	public Ship ownShip, b;
	
	public void createShip(String IPAddr) {
		Ship newShip = new Ship(new Rectangle(5, 5, 50, 50), 3, Color.RED, IPAddr);
		s.add(newShip);
	}

	public GuiTest() {
		final Client client = new Client();
		s = new Space(500, 500);
		this.add(s);
		try {
			ownShip = new Ship(new Rectangle(5, 5, 50, 50), 3, Color.WHITE, (String)InetAddress.getLocalHost().getHostAddress());
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		s.add(ownShip);
		//s.add(b);
		//Bildschirmaufloesung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		//Fenster soll ganz oben links beginnen  
		setLocation(0, 0);
		//Vollbild
		//setSize(d.getSize().width, d.getSize().height);
		setSize(d.getSize().width, d.getSize().height);
		setResizable(false);
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent k) {
				switch (k.getKeyCode()) {
				case KeyEvent.VK_LEFT:
					client.send("left");
					ownShip.setDirection(Direction.left);
					break;
				case KeyEvent.VK_RIGHT:
					client.send("right");
					ownShip.setDirection(Direction.right);
					break;
				case KeyEvent.VK_UP:
					client.send("up");
					ownShip.setDirection(Direction.up);
					break;
				case KeyEvent.VK_DOWN:
					client.send("down");
					ownShip.setDirection(Direction.down);
					break;
				case KeyEvent.VK_SPACE:
					client.send("space");
					ownShip.setDirection(Direction.stop);
					break;
				}
			}
		});
	}
}
```


```
package spaceships;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.Rectangle;

public class Ship {
		
	int speed;

	Direction direction;

	Color shipcolor;
	
	String IPAddr;

	volatile Rectangle pos, oldpos;

	Space s;
	
	int heightdiv2, widthdiv2;

	public Ship(Rectangle pos, int speed, Color shipcolor, String IPAddr) {
		this.shipcolor = shipcolor;
		this.pos = pos;
		oldpos = new Rectangle(pos);
		this.direction = Direction.stop;
		this.speed = speed;
		this.IPAddr = IPAddr;
		heightdiv2 = pos.height / 2; //Koordinaten zwecks Effizienz 
		widthdiv2 = pos.width / 2;   //vorher berechnen
	}

	public void paint(Graphics g) {
		int cx = pos.x + widthdiv2;
		int cy = pos.y + heightdiv2;

		//Wenn das Schiff ï¿½ber den Bildschirmrand hinausfliegt, soll
		//es wieder auf der gegenï¿½berliegenden Seite erscheinen
		if (cx < 0)
			pos.x = s.getWidth() - widthdiv2;
		else if (cx > s.getWidth())
			pos.x = -widthdiv2;
		if (cy < 0)
			pos.y = s.getHeight() - heightdiv2;
		else if (cy > s.getHeight())
			pos.y = -heightdiv2;

		Polygon left = new Polygon();
		left.addPoint(pos.x, pos.y + heightdiv2);
		left.addPoint(pos.x + pos.width, pos.y + pos.height);
		left.addPoint(pos.x + pos.width, pos.y);
		Polygon right = new Polygon();
		right.addPoint(pos.x + pos.width, pos.y + heightdiv2);
		right.addPoint(pos.x, pos.y + pos.height);
		right.addPoint(pos.x, pos.y);
		Polygon up = new Polygon();
		up.addPoint(pos.x + widthdiv2, pos.y);
		up.addPoint(pos.x, pos.y + pos.height);
		up.addPoint(pos.x + pos.width, pos.y + pos.height);
		Polygon down = new Polygon();
		down.addPoint(pos.x + widthdiv2, pos.y + pos.height);
		down.addPoint(pos.x + pos.width, pos.y);
		down.addPoint(pos.x, pos.y);

		g.setColor(shipcolor);
		//Fallunterscheidung fï¿½r 4 unterschiedliche Flugrichtungen
		switch (direction) {
		case left:
			g.fillPolygon(left);
			break;
		case right:
			g.fillPolygon(right);
			break;
		case up:
			g.fillPolygon(up);
			break;
		case down:
			g.fillPolygon(down);
			break;
		case stop:
			g.fillOval(pos.x, pos.y, pos.width - 1, pos.height - 1);
		}
	}

//	public void run() {
//		while (true) {
//			oldpos.setBounds(pos);
//			//Position des Schiffes je nach Flugrichtung um vorher 
//			//festgelegte Anzahl an Pixeln verschieben
//			switch (direction) {
//			case up:
//				pos.y -= speed;
//				break;
//			case down:
//				pos.y += speed;
//				break;
//			case left:
//				pos.x -= speed;
//				break;
//			case right:
//				pos.x += speed;
//				break;
//			case stop:
//				break;
//			}
//			s.repaint(oldpos.union(pos));
//			//Eine kurze Pause, damit das Schiff nicht rast
//			try {
//				Thread.sleep(10);
//			} catch (InterruptedException e) {
//				e.printStackTrace();
//			}
//		}
//	}

	public Direction getDirection() {
		return direction;
	}

	public void setDirection(Direction direction) {
		this.direction = direction;
	}
	
	public String getIPAddr() {
		return IPAddr; 
	}

	public void setS(Space s) {
		this.s = s;
//		new Thread(this).start();
	}
}
```


```
package spaceships;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.util.Vector;

import javax.swing.JComponent;

public class Space extends JComponent implements Runnable {

	private static final long serialVersionUID = 1L;

	static Vector<Ship> ships = new Vector<Ship>(); //Inhalt muss vom Typ Ship sein

	Rectangle size, oldsize;

	Graphics graphics;

	public Space(int width, int height) {
		Dimension d = new Dimension(width, height); //this.width/this.height??
		size = new Rectangle(d);
		this.setBackground(Color.BLACK);
		this.setMaximumSize(d);
		this.setMinimumSize(d);
		this.setPreferredSize(d);
		this.setSize(d);
		this.setDoubleBuffered(true);
		new Thread(this).start();
	}

	public void add(Ship s) {
		s.setS(this);
		ships.add(s);
	}
	
	public static Vector<Ship> getShips() {
		return ships;
	}

/*	public void update(Graphics g) {
		paint(g);
	}*/

	public void paint(Graphics g) {
		//		System.out.println("space "+g.getClipBounds());
		g.getClipBounds(size);
		g.setColor(Color.BLACK);
		g.fillRect(size.x, size.y, size.width, size.height);
		for (Ship s : ships) {
			s.paint(g);
		}
		g.setColor(Color.BLACK);
	}
	
	public void run() {
		while (true) {
			for (Ship s : ships) {
				s.oldpos.setBounds(s.pos);
				// Position des Schiffes je nach Flugrichtung um vorher
				// festgelegte Anzahl an Pixeln verschieben
				switch (s.direction) {
				case up:
					s.pos.y -= s.speed;
					break;
				case down:
					s.pos.y += s.speed;
					break;
				case left:
					s.pos.x -= s.speed;
					break;
				case right:
					s.pos.x += s.speed;
					break;
				case stop:
					break;
				}
				repaint(s.oldpos.union(s.pos));
				// Eine kurze Pause, damit das Schiff nicht rast
				try {
					Thread.sleep(5);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
}
```

Ist der so in Ordnung?


----------



## Wildcard (23. Nov 2006)

Anonymous hat gesagt.:
			
		

> Jetzt habe ich im Space nur ein Thread für alle Schiffe, da lauf ich den Vektor mit allen Schiffen durch
> und aktualisiere für jedes die Position, die Schiff-Klasse zeichnet dann. Allerdings nicht in ienem Thread. Oder meinst du mit dem EventDispatcher die paint-Methode?


Ja, paint wird vom EventDispatcher aufgerufen.
5ms ist allerdings immer noch sehr knapp. XP zB kann eigentlich alles <15ms nicht auflösen.


----------



## stevewilson (30. Nov 2006)

Als wir noch pro Schiff ein Thread hatten, lief das Programm, zwar immernoch unterschiedlich schnell, aber ohne Exception. Jetzt bekommen wir beim "connecten"(ist UDP, deswegen die Anführungszeichen) folgende Exception:


Exception in thread "Thread-3" java.util.ConcurrentModificationException
	at java.util.AbstractList$Itr.checkForComodification(Unknown Source)
	at java.util.AbstractList$Itr.next(Unknown Source)
	at spaceships.Space.run(Space.java:72)
	at java.lang.Thread.run(Unknown Source)

Wahrscheinlich kommt er nicht damit klar, dass im Schiffcontainer(Space.java) mehrere Clients auf die Schiffe zugreifen. (siehe for-Schleife in der Runmethode)

Hier der Quellcode:

Controller:



```
package spaceships;

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.MulticastSocket;
import java.util.Vector;

public class Controller {
	public static void main(String[] args) {
		GuiTest g = new GuiTest();
		Server server = new Server(g);
		server.start();
		Client client = new Client();
		client.start();
	}
}

class Server extends Thread {

	GuiTest g;

	public Server(GuiTest g) {
		this.g = g;
	}

	public void run() {
		try {
			MulticastSocket multicastsocket = new MulticastSocket(4445);
			InetAddress multicastgroup = InetAddress.getByName("228.5.6.7");
			multicastsocket.joinGroup(multicastgroup);
			byte[] buffer = new byte[1024];
			while (true) {
				DatagramPacket receivedPacket = new DatagramPacket(buffer,
						buffer.length);
				multicastsocket.receive(receivedPacket);
				String receivedMessage = new String(buffer);
				String own = InetAddress.getLocalHost().getHostAddress();
				own = own.trim();
				if (receivedMessage.indexOf(own) == -1) {
					int pos = receivedMessage.indexOf(" - ");
					receivedMessage = receivedMessage.trim();
					System.out.println(receivedMessage + "\n");
					String action = receivedMessage.substring(pos + 3,
							receivedMessage.length());
					int createShip = 0;
					Vector<Ship> ships = Space.getShips();
					System.out.println("Vor dem for()");
					for (Ship s : ships) {
						System.out.println("Im for()");
						System.out.println("IPAddr: " + s.getIPAddr());
						System.out.println("recvMes: " + receivedMessage.substring(0, pos));
						if (receivedMessage.substring(0, pos).equals(s.getIPAddr())) {
							System.out.println("ICH: " + s.getIPAddr());
							if (action.equals("up")) {
								s.setDirection(Direction.up);
								System.out.println("UP");
							} else if (action.equals("right")) {
								s.setDirection(Direction.right);
								System.out.println("RIGHT");
							} else if (action.equals("down")) {
								s.setDirection(Direction.down);
								System.out.println("DOWN");
							} else if (action.equals("left")) {
								s.setDirection(Direction.left);
								System.out.println("LEFT");
							} else if (action.equals("space")) {
								s.setDirection(Direction.stop);
								System.out.println("SPACE");
							}
						}
						else {
							System.out.println("Im else");
							if(receivedMessage.indexOf("spielwut") != -1) {
								createShip = 1;
							}
							System.out.println("hinterm createn");
						}
					}
					if(createShip == 1) {
						g.createShip(receivedMessage.substring(0, pos));
						createShip = 0;
					}
				}
				for (int i = 0; i < buffer.length; i++) {
					buffer[i] = '\0';
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

}

class Client extends Thread {
	public void run() {
		try {
			send("spielwut");
			BufferedReader ttyin = new BufferedReader(new InputStreamReader(
					System.in));
			while (true) {
				System.out.print("Client? ");
				String input = ttyin.readLine();
				send(input);

			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	public void send(String input) {
		try {
			InetAddress multicastgroup = InetAddress.getByName("228.5.6.7");
			MulticastSocket multicastsocket = new MulticastSocket(4445);
			String sendMessage = InetAddress.getLocalHost().getHostAddress()
					+ " - " + input;
			DatagramPacket sendPacket = new DatagramPacket(sendMessage
					.getBytes(), sendMessage.length(), multicastgroup, 4445);
			multicastsocket.send(sendPacket);
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
```

GuiTest


```
package spaceships;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.net.InetAddress;
import java.net.UnknownHostException;

import javax.swing.JFrame;

public class GuiTest extends JFrame {
	private static final long serialVersionUID = 1L;

	volatile private Space s;

	volatile private Ship ownShip, b;
	
	public void createShip(String IPAddr) {
		Ship newShip = new Ship(new Rectangle(5, 5, 50, 50), 3, Color.RED, IPAddr);
		s.add(newShip);
	}

	public GuiTest() {
		final Client client = new Client();
		s = new Space(500, 500);
		this.add(s);
		try {
			ownShip = new Ship(new Rectangle(5, 5, 50, 50), 3, Color.WHITE, (String)InetAddress.getLocalHost().getHostAddress());
		} catch (UnknownHostException e) {
			e.printStackTrace();
		}
		s.add(ownShip);
		//s.add(b);
		//Bildschirmaufloesung herausfinden
		Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
		//Fenster soll ganz oben links beginnen  
		setLocation(0, 0);
		//Vollbild
		//setSize(d.getSize().width, d.getSize().height);
		setSize(800, 600);
		setResizable(false);
		this.setVisible(true);
		this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		addKeyListener(new KeyAdapter() {
			public void keyPressed(KeyEvent k) {
				switch (k.getKeyCode()) {
				case KeyEvent.VK_LEFT:
					client.send("left");
					ownShip.setDirection(Direction.left);
					break;
				case KeyEvent.VK_RIGHT:
					client.send("right");
					ownShip.setDirection(Direction.right);
					break;
				case KeyEvent.VK_UP:
					client.send("up");
					ownShip.setDirection(Direction.up);
					break;
				case KeyEvent.VK_DOWN:
					client.send("down");
					ownShip.setDirection(Direction.down);
					break;
				case KeyEvent.VK_SPACE:
					client.send("space");
					ownShip.setDirection(Direction.stop);
					break;
				}
			}
		});
	}
}
```

Ship:


```
package spaceships;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.Polygon;
import java.awt.Rectangle;

public class Ship {
		
	int speed;

	Direction direction;

	Color shipcolor;
	
	String IPAddr;

	volatile Rectangle pos, oldpos;

	volatile Space s;
	
	int heightdiv2, widthdiv2;

	public Ship(Rectangle pos, int speed, Color shipcolor, String IPAddr) {
		this.shipcolor = shipcolor;
		this.pos = pos;
		oldpos = new Rectangle(pos);
		this.direction = Direction.stop;
		this.speed = speed;
		this.IPAddr = IPAddr;
		heightdiv2 = pos.height / 2; //Koordinaten zwecks Effizienz 
		widthdiv2 = pos.width / 2;   //vorher berechnen
	}

	public void paint(Graphics g) {
		int cx = pos.x + widthdiv2;
		int cy = pos.y + heightdiv2;

		//Wenn das Schiff ï¿½ber den Bildschirmrand hinausfliegt, soll
		//es wieder auf der gegenï¿½berliegenden Seite erscheinen
		if (cx < 0)
			pos.x = s.getWidth() - widthdiv2;
		else if (cx > s.getWidth())
			pos.x = -widthdiv2;
		if (cy < 0)
			pos.y = s.getHeight() - heightdiv2;
		else if (cy > s.getHeight())
			pos.y = -heightdiv2;

		Polygon left = new Polygon();
		left.addPoint(pos.x, pos.y + heightdiv2);
		left.addPoint(pos.x + pos.width, pos.y + pos.height);
		left.addPoint(pos.x + pos.width, pos.y);
		Polygon right = new Polygon();
		right.addPoint(pos.x + pos.width, pos.y + heightdiv2);
		right.addPoint(pos.x, pos.y + pos.height);
		right.addPoint(pos.x, pos.y);
		Polygon up = new Polygon();
		up.addPoint(pos.x + widthdiv2, pos.y);
		up.addPoint(pos.x, pos.y + pos.height);
		up.addPoint(pos.x + pos.width, pos.y + pos.height);
		Polygon down = new Polygon();
		down.addPoint(pos.x + widthdiv2, pos.y + pos.height);
		down.addPoint(pos.x + pos.width, pos.y);
		down.addPoint(pos.x, pos.y);

		g.setColor(shipcolor);
		//Fallunterscheidung fï¿½r 4 unterschiedliche Flugrichtungen
		switch (direction) {
		case left:
			g.fillPolygon(left);
			break;
		case right:
			g.fillPolygon(right);
			break;
		case up:
			g.fillPolygon(up);
			break;
		case down:
			g.fillPolygon(down);
			break;
		case stop:
			g.fillOval(pos.x, pos.y, pos.width - 1, pos.height - 1);
		}
	}
/*
	public void run() {
		while (true) {
			oldpos.setBounds(pos);
			//Position des Schiffes je nach Flugrichtung um vorher 
			//festgelegte Anzahl an Pixeln verschieben
			switch (direction) {
			case up:
				pos.y -= speed;
				break;
			case down:
				pos.y += speed;
				break;
			case left:
				pos.x -= speed;
				break;
			case right:
				pos.x += speed;
				break;
			case stop:
				break;
			}
			s.repaint(oldpos.union(pos));
			//Eine kurze Pause, damit das Schiff nicht rast
			try {
				Thread.sleep(10);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}*/

	public Direction getDirection() {
		return direction;
	}

	public void setDirection(Direction direction) {
		this.direction = direction;
	}
	
	public String getIPAddr() {
		return IPAddr; 
	}

	public void setS(Space s) {
		this.s = s;

	}
}
```

Space:


```
package spaceships;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.util.Vector;

import javax.swing.JComponent;

public class Space extends JComponent implements Runnable{

	private static final long serialVersionUID = 1L;

	volatile static Vector<Ship> ships = new Vector<Ship>(); //Inhalt muss vom Typ Ship sein

	Rectangle size, oldsize;

	Graphics graphics;

	public Space(int width, int height) {
		Dimension d = new Dimension(width, height); //this.width/this.height??
		size = new Rectangle(d);
		this.setBackground(Color.BLACK);
		this.setMaximumSize(d);
		this.setMinimumSize(d);
		this.setPreferredSize(d);
		this.setSize(d);
		this.setDoubleBuffered(true);
		start();
	}

	public void add(Ship s) {
		s.setS(this);
		ships.add(s);

	}
	
	public static Vector<Ship> getShips() {
		return ships;
	}
	
/*	public void update(Graphics g) {
		paint(g);
	}*/
	
	public void start() {
		new Thread(this).start();
	}

	public void paint(Graphics g) {
		//		System.out.println("space "+g.getClipBounds());
		g.getClipBounds(size);
		g.setColor(Color.BLACK);
		g.fillRect(size.x, size.y, size.width, size.height);
		for (Ship s : ships) {
			try {
				s.paint(g);
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		g.setColor(Color.BLACK);
	}
	

	public synchronized void run() {
		while (true) {
			System.out.println(ships.size());
			if (ships.size() >= 1)
			for (Ship s : ships) {
				try {
					s.oldpos.setBounds(s.pos);
					// Position des Schiffes je nach Flugrichtung um vorher
					// festgelegte Anzahl an Pixeln verschieben
					switch (s.direction) {
					case up:
						s.pos.y -= s.speed;
						break;
					case down:
						s.pos.y += s.speed;
						break;
					case left:
						s.pos.x -= s.speed;
						break;
					case right:
						s.pos.x += s.speed;
						break;
					case stop:
						break;
					}
					repaint(s.oldpos.union(s.pos));
					// Eine kurze Pause, damit das Schiff nicht rast
					try {
						Thread.sleep(15);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				} catch (RuntimeException e) {
					e.printStackTrace();
				}
			}
		}
	}
	
}
```

Direction:


```
package spaceships;

public enum Direction {
	up, down, left, right, stop;
}
```

Gar nicht so einfachm ein Echtzeitspiel über peer-to-peer zu schreiben...


----------



## Wildcard (30. Nov 2006)

Du veränderst irgendetwas an der Liste und das schmeckt dem Iterator gar nicht.
Fügst du ein Element in der run hinzu, oder entfernst eins?  ???:L


----------



## stevewilson (30. Nov 2006)

Wir fügen ein Schiff hinzu beim connecten. Jetzt hab ich mal ein try-catch um die for-Schleife gemacht und das Ding läuft, nur total langsam! Als jedes Schiff noch in einem Thread war, war es viel schneller


----------



## Wildcard (30. Nov 2006)

stevewilson hat gesagt.:
			
		

> Wir fügen ein Schiff hinzu beim connecten. Jetzt hab ich mal ein try-catch um die for-Schleife gemacht und das Ding läuft, nur total langsam! Als jedes Schiff noch in einem Thread war, war es viel schneller


Das ist definitiv keine Lösung  :bae: 
Mach das try catch weg und ersetze die foreach Schleife mit einer normalen For-schleife.
Die foreach Schleife verwendet implizit einen Iterator, kann also nicht funktionieren wenn da verschieden Threads Sachen hinzufügen.


----------



## stevewilson (30. Nov 2006)

Erschien mir auch ungeschickt, hab ich gemacht, aber dat Teil läuft immernoch ziemlich langsam...


----------



## Wildcard (30. Nov 2006)

langsam oder ruckelt?
Wenn's nur langsam ist, musst du die Objekte pro Durchlauf um mehr Einheiten bewegen.
Langsamer wird ein Programm übrigens nicht dadurch das man weniger Threads benutzt.
Jeder Thread ist ein zusätzlicher Verwaltungsoverhead der Ressourcen verbraucht.


----------



## stevewilson (30. Nov 2006)

Ja okay, speed kann ich verändern, so richtig klappt das aber mit der Synchronisation auch noch nicht. Die Linux-Kiste ist immernoch langsamer...


----------



## Wildcard (30. Nov 2006)

Setz zum testen die sleeptime mal auf 500ms oder so und sag ob sich dadurch was ändert. Ausserdem währen Angaben zur CPU load interessant.


----------



## stevewilson (7. Dez 2006)

So, bei sleeptime 500 ist es trotzdem nicht synchron. Die CPU-Auslastung bei den Windows-Rechnern leigen bei 0% bis 2%, bei der Linux-Kiste sind die Schwankungen größer, könnte aber auch an mysql- und Apache-Dämonen liegen. Jedenfalls kommen wir da meist nicht unter 5%


----------



## Wildcard (7. Dez 2006)

Ist der Unterschied sehr groß? Kleine Abweichungen sind natürlich normal, übers Netzwerk musst du später eh synchronisieren, aber wirklich groß sollte der Unterschied eigentlich nicht sein  ???:L 
2-5% ist gar nichts, es kann also nicht daran liegen das der Linux Rechner nicht hinterherkommt.
Am wahrscheinlichsten scheinen mir da noch Ungenauigkeiten in der Zeitmessung auf einer der beiden Maschinen.


----------



## stevewilson (11. Dez 2006)

Wir machen das jetzt so, dass wir die Koordinaten dauernd rüberschicken, jetzt zappeln die Schiffe zwar, laufen aber Synchron.


----------

