# Zeichnen in Java



## Crymes (18. März 2013)

Hallo, ich will Pong in Java programmieren.
Aktuell hakts bei der 2d-Zeichnung, könnt ihr mir vll. folgenden Code um ein fertig gezeichnetes Viereck ergänzen, damit ich sehe wie ich das Zeichensystem Java2d initialisieren muss?


```
import javax.swing.*;

public class Mpspiel {
	
	public static void main(String[] args) {
		
		//Fenster erstellen
		JFrame Fenster = new JFrame("Multiplayer Spiel");
		Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Fenster.setSize(500, 500);
		Fenster.setVisible(true);
		
	}

}
```


----------



## Prieli (18. März 2013)

Die Main wird ja wohl kaum dein ganzer Code sein, oder? 
Poste mal bitte alles


----------



## fadade (18. März 2013)

Schau mal hier: *Java ist auch eine Insel – 14.10 Java 2D-API *auf etwas über der Hälfte der Seite. Ansonsten hier ( The Programmer's Weblog: Beginning Java 2D Game Programming Part 1 ) direkt mit dem Hintergrund eines Kleinen Spiels 

Der erste Link enthält folgendes:

```
[COLOR=#0000ff][B]package com.javatutor.insel.ui.g2d;[/B] [COLOR=#0000ff][B]import java.awt.*;[/B] 
[COLOR=#0000ff][B]import java.awt.geom.Line2D;[/B] [COLOR=#0000ff][B]import javax.swing.*;[/B] [B]
class[/B] [COLOR=#2040a0]First2DDemo [B]extends[/B] [COLOR=#2040a0]JPanel [COLOR=#4444FF][B]{
[/B]   @[COLOR=#2040a0]Override   [B]protected[/B] [B]void[/B] [COLOR=#2040a0]paintComponent[COLOR=#4444FF][B]([/B] [COLOR=#2040a0]Graphics [COLOR=#2040a0]g [COLOR=#4444FF][B])[/B]  
 [COLOR=#4444FF][B]{[/B]     [COLOR=#2040a0]Graphics2D [COLOR=#2040a0]g2 [COLOR=#4444FF]= [COLOR=#4444FF][B]([/B][COLOR=#2040a0]Graphics2D[COLOR=#4444FF][B])[/B] [COLOR=#2040a0]g[COLOR=#4444FF];   
  [COLOR=#2040a0]g2.[COLOR=#2040a0]setRenderingHint[COLOR=#4444FF][B]([/B] [COLOR=#2040a0]RenderingHints.[COLOR=#2040a0]KEY_ANTIALIASING, [COLOR=#2040a0]RenderingHints.[COLOR=#2040a0]VALUE_ANTIALIAS_ON[COLOR=#4444FF][B])[/B][COLOR=#4444FF];  
  [COLOR=#2040a0]g2.[COLOR=#2040a0]draw[COLOR=#4444FF][B]([/B] [B]new[/B] [COLOR=#2040a0]Line2D.[COLOR=#2040a0]Double[COLOR=#4444FF][B]([/B] [COLOR=#FF0000]10, [COLOR=#FF0000]10, [COLOR=#2040a0]getWidth[COLOR=#4444FF][B]([/B][COLOR=#4444FF][B])[/B][COLOR=#4444FF]-[COLOR=#FF0000]10, [COLOR=#FF0000]70 [COLOR=#4444FF][B])[/B] [COLOR=#4444FF][B])[/B][COLOR=#4444FF];
[COLOR=#4444FF][B]}[/B]   

[B]public[/B] [B]static[/B] [B]void[/B] [COLOR=#2040a0]main[COLOR=#4444FF][B]([/B] [COLOR=#2040a0]String[COLOR=#4444FF][B][[/B][COLOR=#4444FF][B]][/B] [COLOR=#2040a0]args [COLOR=#4444FF][B])[/B]   
[COLOR=#4444FF][B]{[/B]     
[COLOR=#2040a0]     JFrame [COLOR=#2040a0]f [COLOR=#4444FF]= [B]new[/B] [COLOR=#2040a0]JFrame[COLOR=#4444FF][B]([/B][COLOR=#4444FF][B])[/B][COLOR=#4444FF];[COLOR=#2040a0]     f.[COLOR=#2040a0]setDefaultCloseOperation[COLOR=#4444FF][B]([/B] [COLOR=#2040a0]JFrame.[COLOR=#2040a0]EXIT_ON_CLOSE [COLOR=#4444FF][B])[/B][COLOR=#4444FF];     [COLOR=#2040a0]f.[COLOR=#2040a0]setSize[COLOR=#4444FF][B]([/B] [COLOR=#FF0000]200, [COLOR=#FF0000]120 [COLOR=#4444FF][B])[/B][COLOR=#4444FF];     [COLOR=#2040a0]f.[COLOR=#2040a0]add[COLOR=#4444FF][B]([/B] [B]new[/B] [COLOR=#2040a0]First2DDemo[COLOR=#4444FF][B]([/B][COLOR=#4444FF][B])[/B] [COLOR=#4444FF][B])[/B][COLOR=#4444FF];     [COLOR=#2040a0]f.[COLOR=#2040a0]setVisible[COLOR=#4444FF][B]([/B] [B]true[/B] [COLOR=#4444FF][B])[/B][COLOR=#4444FF];   
[COLOR=#4444FF][B]}[/B] [COLOR=#4444FF][B]
}
[/B]
```
Was genau jetzt die "graphics" in der PainComponent-Methode sind könnte man dann recherchieren oder explorativ erschließen 

Edit: Siehe: http://stackoverflow.com/questions/1965347/how-do-i-intialize-a-graphics-object-in-java


----------



## Crymes (18. März 2013)

OK Ich hab jetzt mal ein Bisschen rumprobiert und folgende Fragen: 
-Wozu brauche ich das JPanel? Ist das eine Art zeichenfläche?
-Was macht das @Override?
-Wie soll ich folgende Zeile verstehen: f.add( new First2DDemo() ); ?


----------



## fadade (18. März 2013)

(Zeichnen mit Java habe nich selbst noch nicht gemacht, deswegen nur Vermutungen
1)
Das Panel ist wahrscheinlich eine Basisklasse/Interface für die Verwendung von einfachen grafischen Komponenten; quasi, wie die Übersetzung vermuten lässt eine einfache "Zeichenfläche" o.ä. Du trägst jetzt unten in der main im JFrame f deine First2DDemo ein, damit das Teil halt in deinem Fenster gezeichnet werden kann. Das JFrame unterstützt nun wahrscheinlich nur* Objekte/Klassen, die die Basisklasse/das Interface JPanel implementieren (weil dort die Methode paintComponent vorgesehen ist).
Intern ist es wahrscheinlich so, dass das JFrame nur eine Liste von JPanels hat und dort die Methode paintComponent einfach aufruft. Dazu ist halt JPanel da. _Könnte man auch "BasisklasseFuerZeichnen" nennen, wichtig ist eben diese pain-Methode._ Dann wird es wohl auch so sein, dass du 2D-Graphics überhaupt nicht initialisieren musst, sondern das kommt direkt in der painComponent bereits fertiginitialisiert (vom JFrame) als Parameter 
2)
Das @Override sagt dem Compiler, dass jetzt ein Codeabschnitt kommt, der einen anderen Abschnitt überschreiben soll. Das Interface bzw. die abstrakte Basisklasse JPanel implementieren wahrscheinlich keinen Code für die Methode paintComponent und jetzt bist du als Entwickler gefragt dort Code zu erzeugen, der dann das Programm ausmacht.
3)
Die letzte Zeile wird nun wie bereits erwähnt einfach dein Zeichenobjekt in eine Liste (im JFrame) eintragen. Das JFrame weiß nun wie/wann/wat/weshalb/wo/warum/... mit den in der Liste eingetragenen Objekten umzugehen ist.
Kurz: Du erstellst eine Klasse (hier First2DDemo) abgeleitet von JPanel (oder auch weiteren, damit halt verschiedene Funktionen gewährleistet sind und die vorgefertigen Java-Klassen damit umgehen können), überschreibst die paintComponent-Methode mit deinem gewünschten Zeichenverhalten und trägst dann die Objekte deiner Klasse einfach ins JFrame ein. 


* wen du Codevorschläge/"Intellisense" in deiner Entwicklungsumgebung für Java hast, wird dir bestimmt angezeigt, welche Typen du zu einem JFrame "adden" kannst


----------



## DarkMo (19. März 2013)

Java Standard: Grafische Oberflächen mit Swing: leightweight Container: javax swing JPanel
JPanel ist also einfach nur ein bereich, dem man etwas zuordnen kann. nen button, ne zeichen oberfläche, nen text... mit dem JPanel lässt sich der inhalt dann halt im fenster positionieren - ggf eben auch ausfüllend. mit.add fügst du deinem JPanel f halt deinen zeichenkrams hinzu. der wird dann mit dem JPanel zusammen irgendwo irgendwie positioniert ausgegeben.

Annotation (Java)
"@Override: Mit diesem Typ kann eine Methode gekennzeichnet werden, die die  Methode ihrer Oberklasse überschreibt. Der Compiler stellt dann sicher,  dass die Oberklasse diese Methode enthält und gibt einen Fehler aus,  wenn dies nicht der Fall ist."


----------



## freecrac (19. März 2013)

Vor einigen Jahren habe ich mit dem "JBuilder" mal ein wenig herumprobiert, ohne auch nur etwas von JAVA zu kennen.
Mit Javascript aufgerufen <applet code='javafrak.class' width='448' height='336'></applet> wird das Applet im Browser angezeigt.


```
// $Header: z:/javafrak.java 2.1
import java.awt.*;
import java.lang.*;

public class javafrak extends java.applet.Applet
implements Runnable
{
 Thread thread=null;
 int Max_X,Max_Y,Iter,X,Y,Col,ColR,ColG,ColB;
 double A,B,C,D,G,F,H,I,J,K,L,M,Zoom,verti,hori;
 double A1,B1,C1,D1,Step;
 String message1,message2,textfont;
 int textsize,textX,textY,textH,textW;
 Graphics offGraphics;
 Image offImage;

 public void init()
 {
  Max_X=size().width;
  Max_Y=size().height;
  offImage=createImage(Max_X,Max_Y);
  offGraphics=offImage.getGraphics();
  offGraphics.fillRect(0,0,Max_X+1,Max_Y+1);

  Iter  = 1250;
  hori  = .000036;             // nach rechts
  verti = .000035;             // höher
  Zoom  = .002500;             // tiefer
  Step  = Zoom/80;
  A     = -.765216+Zoom+hori;
  B     = -.765325-Zoom+hori;
  C     = .099886-Zoom+verti;
  D     = .099996+Zoom+verti;

  message1  = "Bitte etwas Geduld";
  message2  = "Fraktal wird berechnet";
  textfont  = "TimesRoman";
  textsize  = 36;
  Font myFont=new Font(textfont, Font.BOLD, textsize);
  FontMetrics myMetrix=getFontMetrics(myFont);
  textH=myMetrix.getHeight();
  textW=myMetrix.stringWidth(message1);
  textX=(int)((Max_X-textW)/2);
  textY=(int)((Max_Y-textH)/2)-myMetrix.getDescent();
  setFont(myFont);
 }

 public void start()
 {
  if(thread == null)
  {
   thread = new Thread(this);
   thread.start();
  }
 }

 public void stop()
 {
  thread = null;
  offImage = null;
  offGraphics = null;
 }

 public void run()
 {
  while (thread != null)
  {
   try {Thread.sleep(0);}
   catch (InterruptedException e) {}
   repaint();
  }
 }

 public void paint(Graphics g)
 {
  setBackground(Color.black);
  g.setColor(Color.green);
  g.drawString(message1,textX,textY);
  g.drawString(message2,textX-textsize,textY+textH);
  update(g);
 }

 public void update(Graphics g)
 {
  A1 = A;
  B1 = B;
  C1 = C;
  D1 = D;

  A -= Step;
  B += Step;
  C += Step;
  D -= Step;

  G=(D1-C1)/Max_Y;
  F=(B1-A1)/Max_X;
//----------------------------------------------
  for (Y = 0; Y < Max_Y; Y++)
  {
   for (X = 0; X < Max_X; X++)
   {
    Col=0;
    K=G*Y+C1;
    J=K;
    I=F*X+A1;
    H=I;
    L=J*J;
    M=H*H;
//----------------------------------------------
    frak: {
           while (Col<Iter)
           {
            J=2*H*J+K;
            H=M-L+I;
            L=J*J;
            M=H*H;
            Col++;

            if ((M+L)>4)
            {
             break frak;
            }
           }
          }
// --------------  Pixel-Setzer ----------------
    Col=(Col & 0x0000FF); // and

    ColR=(Col & 0xE0);

    ColG=(Col & 0x18);
    ColG=(ColG << 3);    // shl

    ColB=(Col & 0x07);
    ColB=(ColB << 5);

    offGraphics.setColor(new Color(ColR,ColG,ColB));
    offGraphics.drawLine(X,Y,X,Y);
//----------------------------------------------
   }   // next X
  }    // next Y
//----------------------------------------------
  g.drawImage(offImage,0,0,this);
 }
}
```
Ich habe wirklich keine Ahnung ob das so gemacht wird.
Hat jemand Verbesserungsvorschläge?

(Wegen den unendlich vielen Klammern und den damit verbundenen Fehlern die man damit machen kann finde ich die Sprache Java und auch Javascript einfach nur grauenhaft.)

Dirk


----------



## DarkMo (19. März 2013)

hast du über java oder js hinaus jemals mit was andrem geproggt? weil das mit den klammern ist überall so >< selbst bei html! un das is ned ma ne programmiersprache ^^ nur dass du da halt keine klammern, sondern tags hast. egal wie mans nennt oder in welcher form auch immer, blöcke werden halt mit irgendwas gekennzeichnet.


----------



## freecrac (19. März 2013)

DarkMo schrieb:


> hast du über java oder js hinaus jemals mit was andrem geproggt?


Ja das habe ich tatsächlich schon gemacht.



> weil das mit den klammern ist überall so >< selbst bei html! un das is ned ma ne programmiersprache ^^ nur dass du da halt keine klammern, sondern tags hast. egal wie mans nennt oder in welcher form auch immer, blöcke werden halt mit irgendwas gekennzeichnet.


Nö, hier möchte ich widersprechen, das ist nicht überall so.

Z.B. bei Assembler braucht man maximal nur zwei eckige Klammern[] pro Befehl und dann nur für den Fall, wenn auf Speicher-Adressen zugegriffen werden soll, oder eine Adressberechnung vollzogen werden soll.
Aber für die Mehrzahl aller anderen Assembler-Befehle werden gar keine Klammern benötigt. Auch Basic und Pascal kommen ebenfalls mit sehr viel weniger Klammen aus, womit es ja offensichtlich wird, dass so viele Klammern nicht unbedingt benötigt werden. Aber je mehr Klammern verwendet werden, desto häufiger können sich hier Fehler einschleichen und die Suche nach so einen blöden Fehler muss wirklich nicht sein.

Kannst du auch etwas über meinen Code sagen, darüber würde ich gerne Mal eine Kritik hören/lesen?

Dirk


----------



## DarkMo (19. März 2013)

pascal nuzt wörter anstelle von klammern um blöcke zu bilden. BEGIN und END nur so als bsp sind genau das gleiche wie { und }  btw solltest du dich dann vllt besser von lisp fernhalten - DAS ist klammernsalat xD


----------



## freecrac (19. März 2013)

DarkMo schrieb:


> pascal nuzt wörter anstelle von klammern um blöcke zu bilden. BEGIN und END nur so als bsp sind genau das gleiche wie { und }  btw solltest du dich dann vllt besser von lisp fernhalten - DAS ist klammernsalat xD


Danke, diesen Tip werde ich beherzigen, denn Klammersalat schmeckt mir nicht so gut.

Dirk


----------



## Crymes (19. März 2013)

So, jetzt hab ich das nächste Problem mit nem Key Listener. Ich möchte, dass wenn ich eine Taste drücke eine Funktion aufgerufen wird wo dann Code drinsteht. Ich hab jetzt folgendes:


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.*;

public class Mpspiel extends JPanel implements KeyListener {
	
	@Override
	protected void paintComponent( Graphics g )  
	{ 
		//Grafikobjekt erstellen und initialisieren
		Graphics2D graphics = (Graphics2D) g;   
		graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		//Zu Zeichnende Dinge
		
	}
	private static void Fenster()
	{
		//Fenster erstellen
		JFrame Fenster = new JFrame("Multiplayer Spiel");
		Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Fenster.setSize(500, 500);
		Fenster.setVisible(true);		
		Fenster.add(new Mpspiel());
	}
	private void keyPressed(KeyEvent event)
	{
		System.out.println("Key pressed");
	}
	private void keyReleased(KeyEvent event)
	{
		System.out.println("Key Released");
	}
	private void keyTyped(KeyEvent event)
	{
		System.out.println("Key Typed");
	}
	public static void main(String[] args) {
		
		//Initialisierung
		Fenster();
		
	}
}
```

Als Fehler kommt immer: 
Description	Resource	Path	Location	Type
Cannot reduce the visibility of the inherited method from KeyListener	Mpspiel.java	/Multiplayer Game/src	line 28	Java Problem
Cannot reduce the visibility of the inherited method from KeyListener	Mpspiel.java	/Multiplayer Game/src	line 32	Java Problem
Cannot reduce the visibility of the inherited method from KeyListener	Mpspiel.java	/Multiplayer Game/src	line 36	Java Problem


----------



## b14ckj4ck (19. März 2013)

```
[B]public[/B] void keyPressed(KeyEvent event)
    {
        System.out.println("Key pressed");
    }
    [B]public[/B] void keyReleased(KeyEvent event)
    {
        System.out.println("Key Released");
    }
    [B]public[/B] void keyTyped(KeyEvent event)
    {
        System.out.println("Key Typed");
    }
```
 
Da die Funktionen hier als public Methoden deklariert wurden musst du die Sichtbarkeit beibehalten, also auch public lassen.


Gruß b14ckj4ck


----------



## Crymes (19. März 2013)

Ok starten tut das Programm, aber es passiert nichts?


----------



## b14ckj4ck (19. März 2013)

Um Reaktionen zu erhalten, musst du dem Fenster noch einen Keylistener hinzufügen, bspw so:


```
private static void Fenster()
 {
  //Fenster erstellen
  JFrame Fenster = new JFrame("Multiplayer Spiel");
  Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
  Fenster.setSize(500, 500);
  Fenster.setVisible(true);
  Fenster.add(new main());
  Fenster.addKeyListener(new KeyListener() {
 
   @Override
   public void keyTyped(KeyEvent arg0) {
    System.out.println("Key Typed");    
   }
 
   @Override
   public void keyReleased(KeyEvent arg0) {
    System.out.println("Key Released");    
   }
 
   @Override
   public void keyPressed(KeyEvent arg0) {
    System.out.println("Key pressed");    
   }
  });
 }
```


----------



## Crymes (19. März 2013)

Jetzt habe ich deinen Code hinzugefügt und den aus der Main gelöscht


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.*;

public class Mpspiel extends JPanel implements KeyListener {
	
	@Override
	protected void paintComponent( Graphics g )  
	{ 
		//Grafikobjekt erstellen und initialisieren
		Graphics2D graphics = (Graphics2D) g;   
		graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		//Zu Zeichnende Dinge
		
	}
	private static void Fenster()
	{
		//Fenster erstellen
		JFrame Fenster = new JFrame("Multiplayer Spiel");
		Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Fenster.setSize(500, 500);
		Fenster.setVisible(true);		
		Fenster.add(new Mpspiel());
		
		//Eingabe behandeln
		Fenster.addKeyListener(new KeyListener() 
		{
			 
			@Override
			public void keyTyped(KeyEvent arg0) 
			{
				System.out.println("Key Typed");    
			}			 
			@Override
			public void keyReleased(KeyEvent arg0)
			{
				System.out.println("Key Released");    
			}			 
			@Override
			public void keyPressed(KeyEvent arg0) 
			{
				System.out.println("Key pressed");    
			}
		});
	}	
	public static void main(String[] args) {
		
		//Initialisierung
		Fenster();
		
	}
}
```

Jetzt erhalte ich folgende Fehler 3-Mal:
Description	Resource	Path	Location	Type
The type Mpspiel must implement the inherited abstract method KeyListener.keyTyped(KeyEvent)	Mpspiel.java	/Multiplayer Game/src	line 7	Java Problem

Wenn ich hinter die Klasse MPSpiel noch abstract schreibe, kommt noch ein anderer Fehler.
Was mache ich da falsch?


----------



## b14ckj4ck (19. März 2013)

Crymes schrieb:


> Wenn ich hinter die Klasse MPSpiel noch abstract schreibe, kommt noch ein anderer Fehler.
> Was mache ich da falsch?


Wenn du die Klasse abstrakt machst, kannst du keine Instanzen davon erstellen, was hier aber versucht wird:

```
Fenster.add(new Mpspiel());
```
 
--------------------------------------------------------------------------------------------------------------



Crymes schrieb:


> Jetzt erhalte ich folgende Fehler 3-Mal:
> Description Resource Path Location Type
> The type Mpspiel must implement the inherited abstract method KeyListener.keyTyped(KeyEvent) Mpspiel.java /Multiplayer Game/src line 7 Java Problem?


Da du das Interface _*KeyListener*_ implementierst musst du auch die darin deklarierten Funktionen definieren, also _*keyTyped(), keyReleased()*_ und _*keyPressed(), *_
also den gelöschten Code wieder hinzufügen.
Oder du entfernst einfach das *implements* *KeyListener*.


----------



## DarkMo (20. März 2013)

in der tat hängen beide probleme eng zusammen: Abstrakte Klasse
eine abstrakte klasse implementiert nur die prototypen der methoden, gestaltet (definiert) diese aber nicht aus. sprich: verwendet man eine abstrakte klasse, so muss man zwingend ihre (abstrakten) methoden überschreiben - und somit erstmal implementieren. aber das hat jack ja schon gesagt. wollte nur nochmal den link zum nachlesen anfügen


----------



## Crymes (20. März 2013)

So, jetzt habe ich schon wieder das nächste Problem: Ich habe ein paar Objekte und muss  vom KeyListener und der Zeichenmethode auf die zugreifen. (Wers noch nicht erraten hat: es soll ein 2-Spieler Pong werden  )
Das klappt nicht, weil beide die Objekte nicht kennen. Wisst ihr, wie ich die "bekannt" machen kann?

EDIT: Hab den Code mal agepasst, jetzt fehlen nur noch Ein- und Ausgabe 


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.*;

public class Mpspiel extends JPanel {
		
	@Override
	protected void paintComponent( Graphics g )  
	{ 
		//Grafikobjekt erstellen und initialisieren
		Graphics2D graphics = (Graphics2D) g;   
		graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		//Zu Zeichnende Dinge
		
	}
	private static void Fenster()
	{
		//Fenster erstellen
		JFrame Fenster = new JFrame("Multiplayer Spiel");
		Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Fenster.setSize(500, 500);
		Fenster.setVisible(true);		
		Fenster.add(new Mpspiel());
		
		//Eingabe behandeln
		Fenster.addKeyListener(new KeyListener() 
		{
			 
			@Override
			public void keyTyped(KeyEvent event) 
			{
				// W(87) und S(83) Spieler 1, Pfeil hoch(38)/runter(40) Spieler 2					
			}			 
			@Override
			public void keyReleased(KeyEvent event)
			{
				//Beenden
				if(event.getKeyCode() == KeyEvent.VK_ESCAPE)
				{
					System.exit(0);
				}
			}			 
			@Override
			public void keyPressed(KeyEvent event) 
			{
				// W und S Spieler 1, Pfeil hoch/runter Spieler 2
				if(event.getKeyCode() == KeyEvent.VK_W)
				{
					
				}
				if(event.getKeyCode() == KeyEvent.VK_S)
				{
					
				}
				if(event.getKeyCode() == KeyEvent.VK_UP)
				{
					
				}
				if(event.getKeyCode() == KeyEvent.VK_DOWN)
				{
					
				}
			}
		});
	}	
	public static void main(String[] args) {
		
		//Initialisierung
		Fenster();				
		
		//Objekte erstellen
		Kugel Ball = new Kugel(500, 500, 10);
		Balken SliderL = new Balken(30, 500);
		Balken SliderR = new Balken(470, 500);
		
		//main loop
		while(true)
		{
			//Ball bewegen
			Ball.Bewegung();
			
			//Ball auf Kollision mit Slider prüfen
			//SliderR
			if((Ball.PositionX() + Ball.GeschwindigkeitX() >= 470-Ball.Radius()) && (Ball.PositionX() + Ball.Radius() <= SliderR.UntenY() && Ball.PositionX() + Ball.Radius() >= SliderR.ObenY() ))
			{
				Ball.Slider();
			}
			//SliderL
			else if((Ball.PositionX() + Ball.GeschwindigkeitX() >= 30-Ball.Radius()) && (Ball.PositionX() + Ball.Radius() <= SliderL.UntenY() && Ball.PositionX() + Ball.Radius() >= SliderL.ObenY() ))
			{
				Ball.Slider();
			}
			
			//Ball auf GameOver überprüfen
			if(Ball.KollisionX() == true)
			{
				Ball = new Kugel(500, 500, 10);
			}
			
			//Bild ausgeben
			
			
			//Warten, ca. 33 FPS
			try 
			{
				Thread.currentThread();
				Thread.sleep(30);
			} catch (InterruptedException fehler) 
			{				
				
			}
		}
	}
}
```


----------



## b14ckj4ck (20. März 2013)

Wenn du in allen Memberfunktionen auf die Objekte zugreifen möchtest, solltest du diese als Attribute der Klasse definieren.
Wenn du sie auch in der *Fenster()* Methode verwenden möchtest, müssen diese zudem statisch sein, da die Methode selbst statisch ist

mfg b14ckj4ck


----------



## Crymes (20. März 2013)

Ok, ich glaub OOP mag mich nicht. Wenn ich das Programm in folgender Form ausführe, dann bekomme ich laufzeitfehler sowohl wenn eine eingabe stattfindet als auch wenn das Fenster wegen Größenänderung neu gezeichnet wird. Wenn ich das richtig verstehe kennen die Methoden die speicheradresse von meinen Objekten nicht, oder? 
Ich poste hier mal das komplette Programm:

Klasse Kugel:

```
import java.awt.Color;
import java.awt.Graphics2D;
import java.util.Random;

public class Kugel {
	
	//Variablen
	private int[] fenster;
	private int[] position;
	private int[] geschwindigkeit;
	private int radius;
	private int aufprall;
		
	//Zufallsgenerator erstellen
	private static Random zufallsgenerator = new Random();
	
	private void KollisionY()
	{
		if(position[1] + geschwindigkeit[1] >= fenster[1] || position[1] + geschwindigkeit[1] <= 0)
		{
			geschwindigkeit[1] *= -1;
		}		
	}	
	private int Geschwindigkeit()
	{
		if(aufprall >= 5)
		{
			aufprall = 0;
			return(2);
		}
		return(1);
	}
	public Kugel(int fensterx, int fenstery, int radius)
	{
		//Fenstergröße festlegen
		fenster = new int[2];
		fenster[0] = fensterx;
		fenster[1] = fenstery;
		
		//Geschwindigkeiten per Zufall festlegen
		geschwindigkeit = new int[2];
		geschwindigkeit[0] = zufallsgenerator.nextInt(5);
		geschwindigkeit[1] = zufallsgenerator.nextInt(5);
		
		//Ball soll in der Mitte des Fensters starten
		position = new int[2];
		position[0] = fenster[0]/2;
		position[1] = fenster[1]/2;
		
		//Ballradius festlegen
		this.radius = radius;
		
		//Geschwindigkeit resetten
		aufprall = 0;
	}
	public void Bewegung()
	{		
		position[0] += geschwindigkeit[0]*Geschwindigkeit();
		position[1] += geschwindigkeit[1]*Geschwindigkeit();
		
		//Ball auf Kollision prüfen 
		KollisionY();				
	}
	public void Slider()
	{
		geschwindigkeit[0] *= -1;
		aufprall++;
	} 
	public boolean KollisionX()
	{
		if(position[0] >= fenster[0] || position[0] <= 0)
		{
			return(true);
		}
		else
		{
			return(false);
		}
	}	
	public int PositionX()
	{
		return(position[0]);
	}	
	public int GeschwindigkeitX()
	{
		return(geschwindigkeit[0]);
	}
	public int Radius()
	{
		return(this.radius);
	}
	public void Zeichnen(Graphics2D graphics)
	{
		graphics.setColor(Color.red);
		graphics.fillArc(position[0], position[1], this.radius, this.radius, 0, 360);
	}
}
```

Klasse Balken:


```
import java.awt.Color;
import java.awt.Graphics2D;


public class Balken {

	private int[] punktoben;
	private int[] punktunten;
	
	public Balken(int linienabstandx, int fenstery)
	{
		//Linienpunkte  initialisieren
		punktoben = new int[2];		
		punktoben[0] = linienabstandx;
		punktoben[1] = (int)(fenstery*0.5 - fenstery/8);
		punktunten = new int[2];
		punktunten[0] = linienabstandx;
		punktunten[1] = (int)(fenstery*0.5 + fenstery/8);
	}
	public void MoveUp()
	{
		if(punktoben[1] > 0)
		{
			punktoben[1] -= 1;
			punktunten[1] -= 1;
		}
	}
	public void MoveDown()
	{
		if(punktunten[1] < 500)
		{
			punktoben[1] += 1;
			punktunten[1] += 1;
		}
	}
	public int ObenX()
	{
		return(punktoben[0]);
	}
	public int ObenY()
	{
		return(punktoben[1]);
	}
	public int UntenX()
	{
		return(punktunten[0]);
	}
	public int UntenY()
	{
		return(punktunten[1]);
	}
	public void Zeichnen(Graphics2D graphics)
	{
		graphics.setColor(Color.blue);	    
	    graphics.drawLine(punktoben[0], punktoben[1], punktunten[0], punktunten[1]);
	}
}
```

Main Klasse Mpspiel:


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.*;

public class Mpspiel extends JPanel {
	private static Kugel Ball;
	private static Balken SliderL;
	private static Balken SliderR;
	
	@Override
	protected void paintComponent( Graphics g )  
	{ 
		//Grafikobjekt erstellen und initialisieren
		super.paint(g);
		Graphics2D graphics = (Graphics2D) g;   
		graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		//Zu Zeichnende Dinge
		Ball.Zeichnen(graphics);
		SliderR.Zeichnen(graphics);
		SliderL.Zeichnen(graphics);
	}
	private static void Fenster()
	{
		//Fenster erstellen
		JFrame Fenster = new JFrame("Multiplayer Spiel");
		Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Fenster.setSize(500, 500);
		Fenster.setVisible(true);		
		Fenster.add(new Mpspiel());
		
		//Eingabe behandeln
		Fenster.addKeyListener(new KeyListener() 
		{
			 
			@Override
			public void keyTyped(KeyEvent event) 
			{
				// W(87) und S(83) Spieler 1, Pfeil hoch(38)/runter(40) Spieler 2					
			}			 
			@Override
			public void keyReleased(KeyEvent event)
			{
				//Beenden
				if(event.getKeyCode() == KeyEvent.VK_ESCAPE)
				{
					System.exit(0);
				}
			}			 
			@Override
			public void keyPressed(KeyEvent event) 
			{
				// W und S Spieler 1, Pfeil hoch/runter Spieler 2
				if(event.getKeyCode() == KeyEvent.VK_W)
				{
					SliderL.MoveUp();
				}
				if(event.getKeyCode() == KeyEvent.VK_S)
				{
					SliderL.MoveDown();
				}
				if(event.getKeyCode() == KeyEvent.VK_UP)
				{
					SliderR.MoveUp();
				}
				if(event.getKeyCode() == KeyEvent.VK_DOWN)
				{
					SliderR.MoveDown();
				}
			}
		});
	}	
	public static void main(String[] args) {
		
		//Initialisierung
		Fenster();				
				
		//Objekte erstellen
		Kugel Ball = new Kugel(500, 500, 10);
		Balken SliderL = new Balken(30, 500);
		Balken SliderR = new Balken(470, 500);
		
		//main loop
		while(true)
		{
			//Ball bewegen
			Ball.Bewegung();
			
			//Ball auf Kollision mit Slider prüfen
			//SliderR
			if((Ball.PositionX() + Ball.GeschwindigkeitX() >= 470-Ball.Radius()) && (Ball.PositionX() + Ball.Radius() <= SliderR.UntenY() && Ball.PositionX() + Ball.Radius() >= SliderR.ObenY() ))
			{
				Ball.Slider();
			}
			//SliderL
			else if((Ball.PositionX() + Ball.GeschwindigkeitX() >= 30-Ball.Radius()) && (Ball.PositionX() + Ball.Radius() <= SliderL.UntenY() && Ball.PositionX() + Ball.Radius() >= SliderL.ObenY() ))
			{
				Ball.Slider();
			}
			
			//Ball auf GameOver überprüfen
			if(Ball.KollisionX() == true)
			{
				Ball = new Kugel(500, 500, 10);
			}
			
			//Bild ausgeben
			
						
			//Warten, ca. 33 FPS
			try 
			{
				Thread.currentThread();
				Thread.sleep(30);
			} catch (InterruptedException fehler) 
			{								
			}
		}
	}
}
```


----------



## b14ckj4ck (20. März 2013)

Crymes schrieb:


> Main Klasse Mpspiel:
> 
> 
> ```
> ...


 
paint() solltest du eigentlich nie direkt aufrufen, so steht es zumindest in der Java Dokumentation.
Das Problem ist, dass diese Methode paintComponent() aufruft, welche du überschreibst, 
welche dann wieder paint() aufruft usw. , es kommt zum Stackoverflow.
Die Zeile kannst du einfach auslassen.







Crymes schrieb:


> ```
> public static void main(String[] args) {
> 
> //Initialisierung
> ...


 
Das ist ein weiteres Problem, hier werden neue Objekte erzeugt, was nicht so gut ist, stattdessen solltest du die "Attributs-Objekte" verwenden.
Die in der main() eigens definierten und erzeugten Objekte kann man in der Methode Fenster() nicht nutzen bzw. auf sie zugreifen.
Um eine NullPointerException zu vermeiden müssen die "Attributs-Objekte" auch erst definiert werden, bevor sie in der Methode Fenster aufgerufen werden können.


Kleiner Tipp, das Fenster sollte am besten auch noch ein Attribut der Klasse sein, da du auch in der while() - Schleife darauf zugreifen solltest (es neu zeichnen)


----------



## Crymes (21. März 2013)

So, große Freude - mein erstes Java Projekt läuft!!!!
Jetzt hab ich noch 2 Schönheitsfragen:
-Wie mache ich es, dass beide Spieler gleichzeitig ihre Slider bewegen können?
-Wie behebe ich das Problem, dass links und unten der Bildschirmrand nicht stimmt?

Ich poste hier die main, im Anhang ist noch die ausführbare .jar Datei im .zip Ordner 


```
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.geom.*;

public class Mpspiel extends JPanel {
	
	//Objekte erstellen
	private static Kugel Ball = new Kugel(500, 500, 10);
	private static Balken SliderL = new Balken(30, 500);
	private static Balken SliderR = new Balken(470, 500);
	private static JFrame Fenster = new JFrame("Multiplayer Spiel");
	
	@Override
	protected void paintComponent( Graphics g )  
	{ 
		//Grafikobjekt erstellen und initialisieren		
		Graphics2D graphics = (Graphics2D) g;   
		graphics.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		//Zu Zeichnende Dinge
		Ball.Zeichnen(graphics);
		SliderR.Zeichnen(graphics);
		SliderL.Zeichnen(graphics);
	}
	private static void Fenster()
	{
		//Fenster initialisieren		
		Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Fenster.setSize(500, 500);
		Fenster.setVisible(true);		
		Fenster.add(new Mpspiel());
		
		//Eingabe behandeln
		Fenster.addKeyListener(new KeyListener() 
		{
			 
			@Override
			public void keyTyped(KeyEvent event) 
			{				
			}			 
			@Override
			public void keyReleased(KeyEvent event)
			{
				//Beenden
				if(event.getKeyCode() == KeyEvent.VK_ESCAPE)
				{
					System.exit(0);
				}
			}			 
			@Override
			public void keyPressed(KeyEvent event) 
			{
				// W und S Spieler 1, Pfeil hoch/runter Spieler 2
				if(event.getKeyCode() == KeyEvent.VK_W)
				{
					SliderL.MoveUp();
				}
				if(event.getKeyCode() == KeyEvent.VK_S)
				{
					SliderL.MoveDown();
				}
				if(event.getKeyCode() == KeyEvent.VK_UP)
				{
					SliderR.MoveUp();
				}
				if(event.getKeyCode() == KeyEvent.VK_DOWN)
				{
					SliderR.MoveDown();
				}
			}
		});
	}	
	public static void main(String[] args) {
		
		//Initialisierung
		Fenster();				
				
		//main loop
		while(true)
		{
			//Ball bewegen
			Ball.Bewegung();
			
			//Ball auf Kollision mit Slider prüfen
			//SliderR
			if(Ball.PositionX() + Ball.GeschwindigkeitX() >= 470-Ball.Radius() && Ball.PositionY() + Ball.Radius() <= SliderR.UntenY() && Ball.PositionY() + Ball.Radius() >= SliderR.ObenY())
			{
				Ball.Slider();
			}
			//SliderL
			else if(Ball.PositionX() + Ball.GeschwindigkeitX() <= 30+Ball.Radius() && Ball.PositionY() + Ball.Radius() <= SliderL.UntenY() && Ball.PositionY() + Ball.Radius() >= SliderL.ObenY())
			{
				Ball.Slider();
			}
			
			//Ball auf GameOver überprüfen
			if(Ball.GameOver(30, 470) == true)
			{
				Ball = new Kugel(500, 500, 10);
			}
			
			//Bild ausgeben
			Fenster.repaint();
						
			//Warten, ca. 30 FPS
			try 
			{
				Thread.currentThread();
				Thread.sleep(34);
			} catch (InterruptedException fehler) 
			{								
			}
		}
	}
}
```


----------



## b14ckj4ck (21. März 2013)

Crymes schrieb:


> -Wie mache ich es, dass beide Spieler gleichzeitig ihre Slider bewegen können?


Das beste ware da meiner Meinung nach das Event zu cachen, du machst bspw. vier Variablen für die vier Tasten (W,S, UP, DOWN),
statt den Slider gleich zu bewegen kann man hier dann einfach die Variable auf true oder false setzen, jenachdem ob KeyReleased oder KeyPressed 
für die jeweilige Taste aufgerufen wurde. In der Hauptschleife kannst du diese Variablen dann überprüfen und dementsprechend die Slider bewegen.




Crymes schrieb:


> -Wie behebe ich das Problem, dass links und unten der Bildschirmrand nicht stimmt?


Dafür das "Spielfeld" nach unten um ein paar Pixel begrenzen, da der Fensterrad noch zu den 500px gehört.

Gruß b14ckj4ck


----------



## DarkMo (21. März 2013)

also wenn das wie bei C läuft, dann is das mit den Keys ned ganz so einfach *glaub* spieler A drückt W und die variable für sliderA.up wird true (oder wie auch immer). nu drückt, während A W noch gedrückt hält B aber DOWN zum bsp und dann wir ja W ned mehr registriert oder?

ahso, jetz versteh ich dich erst mit keyPresses/released. Auch wenn B DOWN drückt ist das event "W.KeyReleased" noch nich eingetreten und sliderA.up bleibt weiterhin true. aha aha ^^ klingt plausibel


----------



## b14ckj4ck (21. März 2013)

DarkMo schrieb:


> also wenn das wie bei C läuft, dann is das mit den Keys ned ganz so einfach *glaub* spieler A drückt W und die variable für sliderA.up wird true (oder wie auch immer). nu drückt, während A W noch gedrückt hält B aber DOWN zum bsp und dann wir ja W ned mehr registriert oder?


Genauso ist es auch bei Java mit den KeyPressed()/KeyReleased() Methoden, weshalb man so die Taste "tippen" müsste um das Event immer neu auszulösen, oder man speichert selbst ob die Taste gedrückt/losgeslassen wird 


bspw so:


Spoiler





```
import javax.swing.*;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
 
 
public class Mpspiel extends JPanel {
 /* .... */
 private static boolean vkDOWNPressed = false;
 private static boolean vkUPPressed = false;
 private static boolean vkWPressed = false;
 private static boolean vkSPressed = false;
 
 /* .... */
 
 private static void Fenster()
 {
   /* .... */
 
  //Eingabe behandeln
  Fenster.addKeyListener(new KeyListener() 
  {
 
   @Override
   public void keyTyped(KeyEvent event) 
   {
   }    
   @Override
   public void keyReleased(KeyEvent event)
   {
    //Beenden
    if(event.getKeyCode() == KeyEvent.VK_ESCAPE)
    {
     System.exit(0);
    }
    // W und S Spieler 1, Pfeil hoch/runter Spieler 2
    if(event.getKeyCode() == KeyEvent.VK_W)
    {
     vkWPressed = false;
    }
    if(event.getKeyCode() == KeyEvent.VK_S)
    {
     vkSPressed = false;
    }
    if(event.getKeyCode() == KeyEvent.VK_UP)
    {
     vkUPPressed = false;
    }
    if(event.getKeyCode() == KeyEvent.VK_DOWN)
    {
     vkDOWNPressed = false;     
    }
   }    
   @Override
   public void keyPressed(KeyEvent event) 
   {
    // W und S Spieler 1, Pfeil hoch/runter Spieler 2
    if(event.getKeyCode() == KeyEvent.VK_W)
    {
     vkWPressed = true;
    }
    if(event.getKeyCode() == KeyEvent.VK_S)
    {
     vkSPressed = true;
    }
    if(event.getKeyCode() == KeyEvent.VK_UP)
    {
     vkUPPressed = true;
    }
    if(event.getKeyCode() == KeyEvent.VK_DOWN)
    {
     vkDOWNPressed = true;    
    }
   }
  });
 } 
 
 
 public static void main(String[] args) {
 /* .... */
  //main loop
  while(true)
  {
   if(vkWPressed) SliderL.MoveUp();
   if(vkSPressed) SliderL.MoveDown();
   if(vkUPPressed) SliderR.MoveUp();
   if(vkDOWNPressed) SliderR.MoveDown();
 
 
   /* .... */  
 }
}
```


----------



## Crymes (21. März 2013)

So, jetzt funktioniert alles. Danke an alle, besonders am b14ckj4ck fürs Helfen. 
Ich kann mich aber mit OOP immer noch nicht so richtig anfreunden, da muss ich wahrscheinlich noch ein paar Programme produzieren . Aber 4 Tage find ich für den Anfang gar nicht mal so schlecht, auch wenn ich das jetzt wahrscheinlich in einer Stunde hinbekommen würde.


----------



## Crymes (24. März 2013)

Edit: Ich hab mal den code aktualisiert, das zeichnen geht soweit, nur habe ich das Problem, dass oben und links jeeils Balken sind, an denen das Fenster aufhört. Kennt ihr da eine Lösung?


```
import java.awt.*;
import java.awt.Window;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.*;

public class BallSimulation extends JPanel{
	
	//Variablen
	private static int blänge;
	private static int bbreite;	
	private static int ballradius;
	private static boolean escape;
	private static boolean safe;
		
	//Objekte
	private static GraphicsEnvironment Grafikumgebung;
	private static GraphicsDevice Grafikgerät;
	private static JFrame Fenster;
	private static Dimension Auflösung;
	private static Ballverwaltung Container = new Ballverwaltung(5000);
		
	@Override
	protected void paintComponent( Graphics g )  
	{ 
		//Grafikkontext erstellen und initialisieren		
		Graphics2D grafik = (Graphics2D) g;   
		grafik.setRenderingHint( RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		
		//Zu zeichnende Dinge		
		Container.DrawBalls(grafik);	
		
		//Test
		grafik.fillOval(50, 50, 50, 50);
	}
	private static void Initialisierung()
	{
		//Grafikhardware initialisieren
		Grafikumgebung = GraphicsEnvironment.getLocalGraphicsEnvironment();
		Grafikgerät = Grafikumgebung.getDefaultScreenDevice();
		
		//Auflösung auslesen			
		Auflösung = new Dimension();
		Auflösung = Toolkit.getDefaultToolkit().getScreenSize();
		
		//Variablen setzen
		blänge = Auflösung.width;
		bbreite = Auflösung.height;		
		ballradius = 50;
		escape = false;
		safe = true;
				
		//Fenster erstellen und initialisieren
		Fenster = new JFrame("Ball Simulation");	
		Fenster.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);						
		Fenster.setSize(blänge, bbreite);
		Fenster.add(new BallSimulation());
		Fenster.setUndecorated(true);
		Fenster.setBackground(Color.black);
		
				
		//Wenn unterstützt wird der Vollbildmodus aktiviert, sonst kommt ein Fenster
		if(Grafikgerät.isFullScreenSupported())
		{
			Fenster.setVisible(false);
			Grafikgerät.setFullScreenWindow(Fenster);			
		}
		else
		{
			Fenster.setVisible(true);
		}
		
		//Eingabe behandeln
	    //Tastatur
	    Fenster.addKeyListener(
	    new KeyListener()
	    {
			@Override
			public void keyPressed(KeyEvent event) 
			{		
				safe = false;		
				if(event.getKeyCode() == KeyEvent.VK_H)
				{
					if(ballradius > 1){ballradius++;};
				}
				else if(event.getKeyCode() == KeyEvent.VK_N)
				{
					if(ballradius > 1){ballradius--;};
				}
				else if(event.getKeyCode() == KeyEvent.VK_B)
				{						
					Container.AddBall(blänge, bbreite);
				}
				else if(event.getKeyCode() == KeyEvent.VK_L)
				{
					Container.DeleteBall();
				}				
			}

			@Override
			public void keyReleased(KeyEvent event)
			{					
				if(event.getKeyCode() == KeyEvent.VK_ESCAPE)
				{
					escape = true;								
				}
				safe = true;
			}

			@Override
			public void keyTyped(KeyEvent event) 
			{				
			}			    	
	    });
	    
	    //Maustasten
	    Fenster.addMouseListener(
	    new MouseListener()
	    {

			@Override
			public void mouseClicked(MouseEvent event)
			{				
				
			}

			@Override
			public void mouseEntered(MouseEvent event)
			{				
				
			}

			@Override
			public void mouseExited(MouseEvent event) 
			{
								
			}

			@Override
			public void mousePressed(MouseEvent event)
			{
								
			}

			@Override
			public void mouseReleased(MouseEvent event)
			{
								
			}
	    	
	    });
	    
	    //Mausbewegung
	    Fenster.addMouseMotionListener(
	    new MouseMotionListener()
	    {

			@Override
			public void mouseDragged(MouseEvent event) 
			{				
				
			}

			@Override
			public void mouseMoved(MouseEvent event)
			{
								
			}
	    	
	    });	    
	}
	private static void Ende()
	{
		Grafikgerät.setFullScreenWindow(null);
		System.exit(0);
	}
	public static void main(String[] args) {
		
		//Fenster und Eingabe handhaben
		Initialisierung();
				
		//main-Loop
		while(escape == false)
		{
			//Warten bis alle eingaben getätigt sind, da sonst nicht Thread-Safe
			if(safe == true)
			{
				//Bälle bewegen
				Container.Bewegung();
			
				//Kollision
				Container.KollisionBall();
				Container.KollisionRand(blänge, bbreite);
			
				//Bild ausgeben
				Fenster.repaint();
			}
		}
		
		//Beenden
		Ende();				
	}
}
```


----------

