# Schüsse zeichnen, Fehler?



## Guest (30. Okt 2008)

Folgender Code soll Schüsse generieren und anzeigen.
Alles wird fehlerfrei kompiliert aber ich sehe nichts und finde auch nach x-maligem Durchsehen keinen Fehler.. -.-

Wer kann helfen?




```
import java.applet.*;
import java.awt.*;
import java.util.*;
import java.net.*;


public class Ball
{

	// Initialisierung der Variablen
	private int x_pos;		// x - Position des Balles
	private int y_pos;		// y - Position des Balles
	private int speed;
	private int radius;		// Radius des Balles
	Color shotcol = new Color (250, 250, 250);
	
	public Ball()
	{
	// initialisieren ohne Parameter
	}
	
	public Ball(int x, int y, int sp, int r) // Konstruktor
	{
	x_pos = x;
	y_pos = y;
	speed = sp;
	radius = r;
	}
	
	public void move()
	{
	this.x_pos = this.x_pos + this.speed;
	}
	
	public boolean isOut()
	{
	 if(this.x_pos >= 500)
	 {
	 return true;
	 }
	 else
	 {
	 return false;
	 }
	}

	public boolean collision(Ball ball)
	{

		if(this.x_pos == ball.x_pos)
		{ 
		stop();
		return true;
		}
		else
		{
		return false;
		}
	}

	public void DrawBall (Graphics g)
	{
		g.setColor  (shotcol);
		g.fillOval (this.x_pos - this.radius, this.y_pos - this.radius, 2 * this.radius, 2 * this.radius);
	}

}
```


```
public class Player {

	private int x_pos;
	private int y_pos;
	
	public Player()
	{
	x_pos = 1;
	y_pos = 80;
	}
	
	public int gety()
	{
	return y_pos;
	}
	
	public Ball generateShot()
	{
	int inta = (int)((Math.random()*3)+1);
	int sped = (int)((Math.random()*5)+5);

	Ball shoot = new Ball(x_pos, y_pos, inta, sped);
	return shoot;
	}
	
	public void move(int yd)
	{
	this.y_pos += yd;
	}

}
```


```
import java.awt.*;
import java.util.*;
import java.applet.*;
import java.net.*;
import java.awt.event.*;


public class game extends Applet implements Runnable
{
	
	// Deklaration der Objektreferenzen
	private Ball[] shoot;	// Refferenz auf den Schuss
	private Player player;

	// Thread
	private Thread th;

    // Variablen für die Doppelpufferung
	private Image dbImage;
	private Graphics dbg;

	// Init - Methode
	public void init ()
	{
		// Neue Hintergrundfarbe
        Color superblue = new Color (50, 100, 150);
		setBackground (superblue);
		
		// Initialisierung der Spielobjekte
		player = new Player();
		shoot = new Ball[5];
	}


	// Start - Methode, hier beginnt das Applet zu laufen
	public void start ()
	{
		// Schaffen eines neuen Threads, in dem das Spiel läuft
		th = new Thread (this);
		th.start ();
	}
	

	// Stop - Methode, hier wird das Applet gestopt
	public void stop ()
	{
		th.stop();
	}

	public boolean keyDown (Event e, int key)
   { 

      // Spacetaste gedrückt
      if (key == 32)
      {
	  
			for(int i=0; i<shoot.length; i++)
			{
				// nur dann im Array speichern, wenn ein Platz frei ist
				if(shoot[i] == null)
				{
				int inta = (int)((Math.random()*3)+1);
				int sped = (int)((Math.random()*5)+5);
				//shoot[i] = new Ball(1,player.gety(),sped,inta);
				shoot[i] = player.generateShot();
				break;
				}
			}
			
      }
	  
	  return true;
   }
   
   
   	// Implementierung der Runmethode
	public void run ()
	{
		// Erniedrigen der ThreadPriority um zeichnen zu erleichtern
		Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

		while (true)
		{
			for(int i=0; i<shoot.length; i++)
			{

				if(shoot[i] != null)		// Wenn Schuss nicht außerhalb von Fenster --> move
				{
				shoot[i].move();
			    }
				
				if(shoot[i].isOut())
				{
				shoot[i] = null;
				}
			  
			}
			repaint();

			try
			{
				// Stoppen des Threads für 10 Millisekunden
				Thread.sleep (10);
			}
			catch (InterruptedException ex)
			{
				// do nothing
			}

			// Zurücksetzen der ThreadPriority auf Maximalwert
			Thread.currentThread().setPriority(Thread.MAX_PRIORITY);
		}
	}

	// Paint - Methode
	public void paint (Graphics g)
	{

		for(int i=0;i<shoot.length;i++)
			{
				if(shoot[i] != null)
				{
				shoot[i].DrawBall(g);
				}
			}
	}

	// Update - Methode, Realisierung der Doppelpufferung zur Reduzierung des Bildschirmflackerns
	public void update (Graphics g)
	{
		// Initialisierung des DoubleBuffers
		if (dbImage == null)
		{
			dbImage = createImage (this.getSize().width, this.getSize().height);
			dbg = dbImage.getGraphics ();
		}

		// Bildschirm im Hintergrund löschen
		dbg.setColor (getBackground ());
		dbg.fillRect (0, 0, this.getSize().width, this.getSize().height);

		// Auf gelöschten Hintergrund Vordergrund zeichnen
		dbg.setColor (getForeground());
		paint (dbg);

		// Nun fertig gezeichnetes Bild Offscreen auf dem richtigen Bildschirm anzeigen
		g.drawImage (dbImage, 0, 0, this);
	}
	
}
```


----------



## Quaxli (31. Okt 2008)

Hast Du ins Applet geklickt, damit es den Focus hat? 

Außerdem ist Dein Programm bei mir immer mit einer NullPointerException aufgeschlagen, bis ich folgenden Zeilen eingefügt hatte:


```
// Implementierung der Runmethode
	public void run() {
		// Erniedrigen der ThreadPriority um zeichnen zu erleichtern
		Thread.currentThread().setPriority(Thread.MIN_PRIORITY);

		while (true) {
			for (int i = 0; i < shoot.length; i++) {

                                //-> Beginn Modifikation
                                //--> shoot[i] ist am Anfang NULL!!!
				if(shoot[i]==null){
					continue;
				}
                               //<-- Ende Modifikation
				
				if (shoot[i] != null) // Wenn Schuss nicht außerhalb von Fenster --> move
				{
					shoot[i].move();
				}

                  .....
```

Du hast das zwar als Bedingung um den shoot_.move() auch schon, aber bei der Abrage weiter unten



		Code:In die Zwischenablage kopieren


				if (shoot[i].isOut()) {
					shoot[i] = null;
				}


hebelt es das Ganze dann wieder aus. Daher lieber gleich am Anfang eine generelle Abfrage, dann mußt Du später nicht mehr dran denken.

Ansonten noch ein paar Anmerkungen:

Klassennamen schreibt man groß (game -> Game)

Die stop-Methode von Thread is deprecated und sollte nicht verwendet werden. Die Lösung dafür ist auch ganz einfach, da Du schon fast alles dafür hast. Du definierst einen boolean als Instanz-Variable und packst den in die while-Schleife Deiner run-Methode (statt while(true) halt while(active) o. ä.).
Wenn Du jetzt diese boolean auf false setzt, läuft die run-Methode aus und der Thread ist beendet.

Die Ballbewegung über einen fixen Wert zu steuern ist nicht optimal. Wenn das Applet auf einem Rechner ausgeführt wird, der schneller oder langsamer ist als Deiner, läuft der Ball entsprechend schneller oder langsamer, weil der andere Rechner die while-Schleife (bzw. den GameLoop) mit einer anderen Geschwindigkeit ausführt und somit den speed-Wert unterschiedlich oft aufaddiert. Hier ist es sinnvoller, die Zeit, die für den letzten Schleifendurchlauf benötigt wurde zu messen (System.nanoTime()) und den Ball in Abhängigkeit dieser Zeit zu bewegen, dadurch läuft die Bewegung auf allen Rechnern gleich schnell.

Gibt noch ein paar Kleinigkeiten mehr, aber die findest Du mit etwas mehr Erfahrung selbst raus _


----------



## Gast (31. Okt 2008)

super!! Vielen Dank, es klappt nun soweit 

Kannst du mir vielleicht noch erklären, wieso die Bedingung 

if(shoot_==null){
               continue;
            } 

notwendig ist? Was bewirkt das continue und wieso funktioniert es nicht ohne?_


----------



## Quaxli (31. Okt 2008)

continue heißt "Brich diesen Schleifendurchlauf ab und beginne den nächsten ohne bis zum Ende zu laufen" 

Da Du beim Methodenaufruf shoot_.isOut() nicht prüfst, ob shoot auf ein existierendes Objekt referenziert, wirft Dein Programm eine NullPointerException. Solagen Du das Array nur definiert hast (shoot = new Ball[5]) existieren ja noch keine 6 Objekte vom Typ Ball, sondern nur Platzhalter.

Du könntest Dir das sparen, wenn Du statt Arrays eine Collection verwenden würdest, z. B. eine ArrayList oder einen Vector und auf diese mit einer for-each-Schleife losgehst._


----------

