# Problem mit laufen vom Player



## Templon (22. Aug 2007)

Hallo zusammen,

Also ich bin zurzeit ein kleines Spiel am programmieren so im Stil von Diablo II, nun hab ich aber ein kleines Problem

Man soll sich mit der Maus im Spiel bewegen können, also irgendwo hin klicken und dann läuft der Player dort hin. Ich hab so gelöst wie ihr hier unten sehen könnt. (Die if abfrage ist wichtig) Nur ist das eine nicht ganz so schöne Lösung finde ich und es funktioniert auch nicht immer gleich. Hat jemand eine Idee wie ich das schön Lösen könnte?


```
@Override
	public void moveCharacter(double deltaT, double x, double y, Game game) {
		super.moveCharacter(deltaT, x, y, game);

		double distanceOnScreenX = x - (game.WIDTH / 2 - super.imagesArrayList.get(8)[0].getWidth() / 2) 
              - super.actualImage.getWidth() / 2;
		double distanceOnScreenY = y - (game.HEIGHT / 2- super.imagesArrayList.get(8)[0].getHeight()) 
              - super.actualImage.getHeight();
		
		double distanceOnMapX = game.getMouseOnMapX() - super.xOnMap - super.actualImage.getWidth() / 2;
		double distanceOnMapY = game.getMouseOnMapY() - super.yOnMap - super.actualImage.getHeight();
		
		angel = Math.toDegrees(Math.atan2(distanceOnScreenY, distanceOnScreenX));
		
		double moveDistance = super.speed * deltaT;
		double moveDistanceX = moveDistance * Math.cos(Math.toRadians(angel));
		double moveDistanceY = moveDistance * Math.sin(Math.toRadians(angel));
		
		if (Math.abs(distanceOnMapX) < 5 && Math.abs(distanceOnMapY) < 5) {
			super.isMoveing = false;
			return;
		} else {
			super.isMoveing = true;
		}
		
		this.yOnMap +=  moveDistanceY;
		this.xOnMap += moveDistanceX;
	}
```


----------



## Quaxli (23. Aug 2007)

So, so. Gleich Diablo2 nachprogrammieren..... 

Ich würde das Ganze nicht in eine einzige Methode packen. Üblicherweise verwendet man für ein Spiel eine Spiel-Schleife (neudeutsch. GameLoop) in der die wichtigsten Methoden ständig ausgeführt werden. Ich hole dazu mal etwas weiter aus....

Bei mir sieht die Spielschleife z. B. ungefähr so aus (das ist meine Lösung, nicht das 11. Gebot...) : 


```
while(active){

     getDelta();
     checkKeys();
     doLogic(delta);
     move(delta);
     paintGraphics(g);

     Thread.sleep();

   }
```

In den einzelnen Methoden passiert folgendes:

getDelta: Errechne wie lang der letzte Schleifendurchlauf benötigt hat (mit System.nanoTime()).

checkKeys:  Abfrage von boolean-Werten, die durch Tastatureingaben oder MouseListener gesetzt werden

doLogic: alle meine Objekte habe so eine Mehtode. Innerhalb dieser Methode in der Spielschleife, wird für alle vorhandenen Objekte die doLogic()-Methode aufgerufen. Das kann komplexer Code sein oder einfach nur ein Abfrage, ob ein Objekt (z. B. ein Schuß) außerhalb des sichtbaren Bereichs ist und gelöscht werden kann. Auch Animationslogik packe ich hier rein.

move: Hier rufe ich für alle Objekte die Move-Methode auf und bewege sie abhängig von der Zeit, die seit dem letzten Durchlauf der Spielschleife vergangen ist (x += dx/delta * mod). 

drawAll: Eigentlich selbsterklärend. Das Graphics-Objekt wird an alle meine Objekte übergeben, so daß diese ihren aktuellen Zustand da reinzeichnen können.


Mit dem oben skiziertem Vorgehen würde ich jetzt Dein Vorhaben wie folgt realiseren:

Mit einem MouseListener wird der Mouse-Klick abgefangen. Die entsprechende Methode enthielte dann folgende Schritte:

- erzeugen eines Objekts vom Typ Rectangle, dessen Mittelpunkt der Mouseklick ist. Als Zielrechteck zumHinlaufen
- errechnen der notwendigen Veränderung von x und y der Spielfigur, wie bei Dir schon realisiert

Meine Spielobjekte erben im Übrigen alle von Rectangle. Bei mir würde dann folgendes passieren. 
In den Methoden:

- checkKeys: in diesem Fall nix

- doLogic: die Logik-Methode meiner Spielfigur würde Code enthalten, die prüft, ob das Zielrechteck ungleich null ist. Wenn dies der Fall ist würde für meine Spielfigur und das Zielrechteck solange auf Intersection (Rectangle.intersects(....) )geprüft werden, bis der Wert true zurück gegeben wird. In diesem Fall ist die Spielfigur dann angekommen und weiterführender Code kann ausgelöst werden. Da meine Objekte von Rectangle erben funzt das üblicherweise wunderbar. Das Zielrechteck sollte halt nicht zu groß und nicht zu klein sein.l

- move: In Abhängigkeit der von delta wird die Figur ein Stück in x- und y-Richtung bewegt. Wenn mein Figur angekommen ist, wird durch die doLogic()-Methode das deltax und deltay meiner Figur auf 0 gesetzt und diese Methode hier trotzdem im Schleifenverlauf aufgerufen. Sie bewegt sich dann halt nicht mehr, fängt aber sofort zu laufen an, wenn ich die Delta-Werte der Spielfigur verändere.

- paint: selbsterklärend.

Mit diesem Szenario wäre es mir möglich, die Figur beliebig laufen zu lassen und durch Mouseklicks (= Veränderung des Zielrechtecks und Neuberechnung des Lauf-Winkels) Änderungen der Bewegungsrichtung zu veranlassen. 

Ich hoffe, ich habe mich einigermaßen verständlich ausgedrückt


----------



## Templon (23. Aug 2007)

Danke erstmal für die Antwort!  :wink: 



			
				Quaxli hat gesagt.:
			
		

> So, so. Gleich Diablo2 nachprogrammieren.....



 :bae:



			
				Quaxli hat gesagt.:
			
		

> Ich würde das Ganze nicht in eine einzige Methode packen. Üblicherweise verwendet man für ein Spiel eine Spiel-Schleife (neudeutsch. GameLoop) in der die wichtigsten Methoden ständig ausgeführt werden. Ich hole dazu mal etwas weiter aus....



So ein Game-Loop habe ich auch, das oben ist nur die Funktion die aufgerufen wird wenn der Spieler läuft. Der Parameter DeltaT ist die Zeit die verstrichen ist seit dem letzten mal. Hier ist der Game-Loop:


```
/**
	 * 
	 * 
	 *
	 */
	
	class GameThread extends Thread {
		public void run() {
			long time = System.nanoTime();
			while (true) {

				if (gameThreadisRunning) {
					
					try {
						Thread.sleep(20);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					
					
					long time2 = System.nanoTime();
					double deltaT = (time2 - time) / 1E9D;
					time = time2;
					
					// handles all things of the player, like move etc.
					diabloPlayer.think(DiabloGameManager.this, deltaT);

					// adjust the camera
					diabloCamera.adjustCamera();
					
					repaint();
				} else {
					time = System.nanoTime();
					repaint();
				}
			}
		} // end GameThread
	}
```



			
				Quaxli hat gesagt.:
			
		

> - erzeugen eines Objekts vom Typ Rectangle, dessen Mittelpunkt der Mouseklick ist. Als Zielrechteck zumHinlaufen
> - errechnen der notwendigen Veränderung von x und y der Spielfigur, wie bei Dir schon realisiert



Danke das werde ich mal Probieren.  :toll: 

Hab gleich noch ein weiters Problem bei dem du oder sonst wer mir vielleicht helfen kann...  

Also wenn ihr das Spiel startet (Unten ist der Link mit dem Source und den Bildern), dann ruckeln die NPC's immer irgendwie herum wenn man herum läuft... Es läuft eigentlich ganz flüssig aber das sieht seeehr kompisch aus mit den NPC's hier mal den Code wo die NPC's gezeichnet werden:


```
// just paint the NPC's which the player can see
		if (diabloGameManager.getScreenPosition().x < super.xOnMap + super.getActualImage().getWidth()
				&& diabloGameManager.getScreenPosition().y < super.yOnMap + super.getActualImage().
                  getHeight()
				&& diabloGameManager.getScreenPosition().x + DiabloGameManager.WIDTH > super.
                  xOnMap - super.getActualImage().getWidth()
				&& diabloGameManager.getScreenPosition().y + DiabloGameManager.HEIGHT > super.
		            yOnMap - super.getActualImage().getHeight()) {
			g2D.drawImage(actualImage,(int) (super.xOnMap - diabloGameManager.getScreenPosition().x),
					(int) (super.yOnMap - diabloGameManager.getScreenPosition().y), null);		
									
		}
```

Download des Source: http://www.file-upload.net/download-379292/diablo.zip.html


----------



## Quaxli (24. Aug 2007)

Ich darf den Link von hier leider nicht aufrufen und aus dem Stück Code kann man auch nicht sehr viel heraus lesen ohne den Rest zu kennen. ABER: Für meinen Geschmack ist die if-Bedingung mit den vielen &&'s einfach zu groß.
Nach meinem Dafürhalten ruft man in er paint-Methode des GameLoops nur die paint-Methode auf. Etwa 

NPC.paint(g);

Fertig. Ob der NPC überhaupt sichtbar ist und welches Image gerade das aktuellste ist hätte ich vorher in einer doLogic()-Methode entschieden - die beim NPC direkt implementiert ist. Das höchste der Gefühle wäre für mich an der Stelle höchstens noch eine if-Bedingung, die einen boolean abfragt, etwa so:

if(NPC.isVisible()){
  NPC.paint(g);
}

Ob es jetzt daran liegt oder nicht, weiß ich nicht, da die Hauptlogik wohl in Deinem GameManager steckt, aber ich würde mal über eine "Verschlankung" der paint-Methode nachdenken. Vor allem habe ich in Deiner Hauptschleife keine Methode erkennen können, die da heißt NPC.think() oder ähnliches. Das scheint es nur für die Spielfigur zu geben. Aber genau das brauchst Du auch für die NPC's.


----------

