# Pixel-genaue Kollisionserkennung



## Androbin (5. Mai 2014)

Hallo Leute, opcorn:
ich dachte mir, ich mache heute einen kleinen "Artikel" zum Thema "Pixel-genaue Kollision" :toll:
[TIPP]
Vorab möchte ich auf die Quelle der folgenden Methode verweisen: Quaxli's Spiele-Tutorial :applaus:
[/TIPP]
Also erstens existiert zu diesem und weiteren Zwecken eine Klasse "Sprite". :rtfm:



Spoiler: Hier meine Version der Klasse



package de.androbin.lib;

import java.applet.Applet;
import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;
import com.sun.xml.internal.ws.api.ResourceLoader;

public class Sprite extends Rectangle implements Drawable, Movable {

	// Deklarationen

	private static final long serialVersionUID = 1L;

	protected int x, y, width, height;
	protected HashMap<Integer, BufferedImage> tiles;
	protected int pic;

	protected int speed = 5;

	// Konstruktoren

	public Sprite() { }

	public Sprite( String url, int x, int y, int width, int height ) {

		this.x = x; this.y = y; this.width = width; this.height = height;

		for ( int i = 0; new File( url + i + ".png" ).exists(); i++ ) {

			try { tiles.put( i, ImageIO.read( ResourceLoader.class.getResource( url + i + ".png" ) ) ); }
			catch ( IOException e ) { break; }

		}

	}

	public Sprite( String url, Sprite parent ) { this( url, parent.x, parent.y, parent.width, parent.height ); }

	// Methoden

	@ Override
	public void paint( Graphics g ) { if ( pic == tiles.size() ) pic = 0; g.drawImage( tiles.get( pic++ ), x, y, width, height, null ); }

	@Override
	public boolean checkCollisions( Sprite s ) {

		for ( int x = 0; x < tiles.get( pic ).getWidth(); x++ ) {

			for ( int y = 0; y < tiles.get( pic ).getHeight(); y++ ) {

				int c1 = tiles.get( pic ).getRGB( x, y );
				int c2 = s.tiles.get( s.pic ).getRGB( x, y );

				if ( ( ( ( c1 >> 24 ) & 0xff ) != 0 ) && ( ( ( c2 >> 24 ) & 0xff ) != 0 ) ) return true;

			}

		}

		return false;

	}

	public static String dirToString( Direction dir ) {

		switch ( dir ) {

			case Up : return "U";
			case Down : return "D";
			case Left : return "L";
			case Right : return "R";

		}

		return "";

	}

	@ Override
	public void moveTo( Direction dir ) { moveBy( dir, speed ); }

	@ Override
	public void moveBy( Direction dir, int speed ) {

		switch ( dir ) {

			case Up : y -= speed;
			case Down : y += speed;
			case Left : x -= speed;
			case Right : x += speed;

		}

	}

	@ Override
	public void moveAt( int x, int y ) { this.x = x; this.y = y; }

	protected void playSound( String url ) { if ( new File( url + ".wav" ).exists() ) { Applet.newAudioClip( ResourceLoader.class.getResource( url + ".wav" ) ).play(); } }
	protected void loopSound( String url ) { if ( new File( url + ".wav" ).exists() ) { Applet.newAudioClip( ResourceLoader.class.getResource( url + ".wav" ) ).loop(); } }

	protected void playAnimation( String url, Graphics g ) { new Sprite( url, this ).paint( g ); }

}





Spoiler: Und eine Klasse "Player" zur Erweiterung von "Sprite"



package de.androbin.lib;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;
import com.sun.xml.internal.ws.api.ResourceLoader;

public class Player extends Sprite {

	// Deklarationen

	private static final long serialVersionUID = 1L;

	protected HashMap<String, BufferedImage> tiles;
	protected Direction dir;

	// Konstruktoren

	public Player( String url, Direction dir, int x, int y, int width, int height ) {

		this.dir = dir; this.x = x; this.y = y; this.width = width; this.height = height;

		for ( int i = 0; new File( url + dirToString() + i + ".png" ).exists(); i++ ) {

			try { tiles.put( dirToString() + i, ImageIO.read( ResourceLoader.class.getResource( url + dirToString() + i + ".png" ) ) ); }
			catch ( IOException e ) { break; }

		}

	}

	// Methoden

	public String dirToString() { return dirToString( dir ); }

	public void turn( Direction dir ) { this.dir = dir; }

	@Override
	public boolean checkCollisions( Sprite s ) {

		for ( int x = 0; x < tiles.get( dirToString() + pic ).getWidth(); x++ ) {

			for ( int y = 0; y < tiles.get( dirToString() + pic ).getHeight(); y++ ) {

				int c1 = tiles.get( dirToString() + pic ).getRGB( x, y );
				int c2 = s.tiles.get( s.pic ).getRGB( x, y );

				if ( ( ( ( c1 >> 24 ) & 0xff ) != 0 ) && ( ( ( c2 >> 24 ) & 0xff ) != 0 ) ) return true;

			}

		}

		return false;

	}

	@ Override
	public void moveTo( Direction dir ) { super.moveTo( dir ); this.dir = dir; }

	@ Override
	public void moveBy( Direction dir, int speed ) { super.moveBy( dir, speed ); this.dir = dir; }

	@ Override
	public void moveAt( int x, int y ) { super.moveAt( x, y ); dir = Direction.Down; }

	@Override
	public void paint( Graphics g ) { if ( pic == tiles.size() ) pic = 0; g.drawImage( tiles.get( dirToString() + pic++ ), x, y, width, height, null ); }

}





Spoiler: Diese werden abgelegt in einer Klasse "World" abgeleitet von JPanel



package de.androbin.lib;

import java.applet.AudioClip;
import java.awt.Graphics;
import java.util.ArrayList;
import java.util.HashMap;
import javax.swing.JPanel;

public class World extends JPanel implements Runnable {

	// Deklarationen

	private static final long serialVersionUID = 1L;

	protected ArrayList<Sprite> objects;
	protected HashMap<String, AudioClip> sounds;

	// Methoden

	public void moveTo( Sprite s, Direction dir ) { for ( int i = 0; i < objects.size(); i++ ) if ( s.checkCollisions( objects.get( i ) ) ) s.moveTo( dir ); }
	public void moveBy( Sprite s, Direction dir, int speed ) { for ( int i = 0; i < objects.size(); i++ ) if ( s.checkCollisions( objects.get( i ) ) ) s.moveBy( dir, speed ); }
	public void moveAt( Sprite s, int x, int y ) { for ( int i = 0; i < objects.size(); i++ ) if ( s.checkCollisions( objects.get( i ) ) ) s.moveAt( x, y ); }

	@Override
	public void paint( Graphics g ) { super.paint( g ); for ( int i = 0; i < objects.size(); i++ ) { objects.get( i ).paint( g ); } }

	@Override
	public void run() {

		while ( true ) {

			try { Thread.sleep( 500 ); } catch ( InterruptedException e ) { e.printStackTrace(); }

			repaint();

		}

	}

}


Kritik und vor allem Verbesserungsvorschläge sind erwünscht, ebenso weitere "Lösungsmöglichkeiten" :toll:

PS. Im Anhang findet ihr die komplette Library, die ich mir dazu erstellt habe :rtfm:


----------



## Androbin (5. Mai 2014)

[EDIT]


Spoiler: Nachtrag zur Klasse "Player" im Konstruktor



[JAVA=22]
	public Player( String url, Direction dir, int x, int y, int width, int height ) {

		this.dir = dir; this.x = x; this.y = y; this.width = width; this.height = height;

		for ( int i = 0; i < Direction.values().length; i++ ) {

			for ( int j = 0; new File( url + dirToString( Direction.values()[ i ] ) + j + ".png" ).exists(); j++ ) {

				try { tiles.put( dirToString( Direction.values()[ i ] ) + j,
						ImageIO.read( ResourceLoader.class.getResource( url + dirToString( Direction.values()[ i ] ) + j + ".png" ) ) ); }
				catch ( IOException e ) { break; }
			}

		}

	}
[/code]


[/EDIT]


----------



## Ruzmanz (6. Mai 2014)

Die Quelltext-Formatierung ist eine Zumutung. Ob man bei einem Einzeiler-IF/FOR unbedingt Klammern braucht, ist stark umstritten ... undabhängig davon ist sowas assoizal:


```
public void paint( Graphics g ) { if ( pic == tiles.size() ) pic = 0; g.drawImage( tiles.get( pic++ ), x, y, width, height, null ); }
```

Es gibt sehr viele Dinge, da braucht man keine Kommentare. Egal wie hip die sind ... warum benennst du es nicht einfach gleich richtig?


```
public void save( Object object ) { // Welt speichern
```


```
public void saveWorld( Object object ) {
```

Clean Code und Code Smell sind so ein paar Punkte, die du dir anschauen könntest.


----------



## Androbin (6. Mai 2014)

Tut mir leid, das mit der Formatierung :autsch:

Hier die ( besser formatierten ) Updates : :toll:



Spoiler: World





```
package de.androbin.lib;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;

public abstract class World extends JPanel implements KeyListener, Runnable {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	protected ArrayList<Sprite> objects = new ArrayList<Sprite>();
	protected ArrayList<Mob>    mobs    = new ArrayList<Mob>   ();
	protected Player            player  = new Player( "", Direction.Down, 0, 0, 0, 0 );
	
	protected BufferedImage background  = new BufferedImage( getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB );
	
	protected AnimationLib animationlib = new AnimationLib();
	protected SoundLib     soundlib     = new SoundLib    ();
	
	// Methoden
	
	public boolean moveTo( Sprite s, Direction dir ) {
		
		for ( int i = 0; i < objects.size(); i++ ) if ( !s.checkCollisions( objects.get( i ) ) ) return false;
		for ( int i = 0; i < mobs   .size(); i++ ) if ( !s.checkCollisions( mobs   .get( i ) ) ) return false;
		
		s.moveTo( dir ); return true;
		
	}
	
	public void moveAt( Sprite s, int x, int y ) { s.moveTo( x, y ); }
	
	@Override
	public void paint( Graphics g ) {
		
		super.paint( g );
		
		g.drawImage( background, 0, 0, getWidth(), getHeight(), null );
		
		for ( int i = 0; i < objects.size(); i++ ) { objects.get( i ).paint( g ); }
		for ( int i = 0; i < mobs   .size(); i++ ) { mobs   .get( i ).paint( g ); }
		                                             player          .paint( g );
		
	}
	
	protected void playAnimation( Sprite s, ArrayList<BufferedImage> animation ) { s.playAnimation( animation ); }
	
	protected void loadSound( String name, String path ) { soundlib.loadSound( name, path ); }
	protected void playSound( String name              ) { soundlib.playSound( name       ); }
	protected void loopSound( String name              ) { soundlib.loopSound( name       ); }
	protected void stopLoopingSounds(                  ) { soundlib.stopLoopingSounds(    ); }
	
	@Override
	public void run() {
		
		while ( true ) {
			
			try { Thread.sleep( 500 ); } catch ( InterruptedException e ) { e.printStackTrace(); }
			
			for ( int i = 0; i < objects.size(); i++ ) if ( objects.get( i ).remove() ) objects.remove( i );
			for ( int i = 0; i < mobs   .size(); i++ ) if ( mobs   .get( i ).remove() ) mobs   .remove( i );
			
			for ( int i = 0; i < mobs   .size(); i++ ) moveTo( mobs.get( i ), Mob.randomDir() );
			
			repaint();
			
		}
		
	}
	
	@ Override
	public void keyPressed( KeyEvent e ) {
		
		switch ( e.getKeyCode() ) {
			
			case KeyEvent.VK_W     : player.moveTo( Direction.Up    ); break;
			case KeyEvent.VK_A     : player.moveTo( Direction.Left  ); break;
			case KeyEvent.VK_S     : player.moveTo( Direction.Down  ); break;
			case KeyEvent.VK_D     : player.moveTo( Direction.Right ); break;
			
			case KeyEvent.VK_UP    : player.moveTo( Direction.Up    ); break;
			case KeyEvent.VK_DOWN  : player.moveTo( Direction.Down  ); break;
			case KeyEvent.VK_LEFT  : player.moveTo( Direction.Left  ); break;
			case KeyEvent.VK_RIGHT : player.moveTo( Direction.Right ); break;
			
		}
		
	}
	
	@ Override
	public void keyReleased( KeyEvent e ) { }
	
	@ Override
	public void keyTyped( KeyEvent e ) { }
	
}
```






Spoiler: Sprite





```
package de.androbin.lib;

import java.awt.Graphics;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.imageio.ImageIO;
import com.sun.xml.internal.ws.api.ResourceLoader;

public class Sprite extends Rectangle implements Drawable, Movable {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	protected int x = 0, y = 0, width = 0, height = 0;
	protected HashMap<Integer, BufferedImage> tiles     = new HashMap<Integer, BufferedImage>();
	protected ArrayList       <BufferedImage> animation = new ArrayList       <BufferedImage>();
	protected int pic = 0;
	
	protected AnimationLib animationlib = new AnimationLib();
	protected SoundLib     soundlib     = new SoundLib    ();
	
	protected boolean playAnimation = false;	
	protected boolean remove = false;
	
	// Konstruktoren
	
	public Sprite() { }
	
	public Sprite( String url, int x, int y, int width, int height ) {
		
		this.x = x; this.y = y; this.width = width; this.height = height;
		
		for ( int i = 0; new File( url + i + ".png" ).exists(); i++ ) {
			
			try { tiles.put( i, ImageIO.read( ResourceLoader.class.getResource( url + i + ".png" ) ) ); }
			catch ( IOException e ) { break; }
			
		}
		
	}
	
	public Sprite( ArrayList<BufferedImage> animation, int x, int y, int width, int height ) {
		
		this.x = x; this.y = y; this.width = width; this.height = height;
		
		for ( int i = 0; i < animation.size(); i++ ) { tiles.put( i, animation.get( i ) ); }
		
	}
	
	public Sprite( String url, Sprite parent ) { this( url, parent.x, parent.y, parent.width, parent.height ); }
	
	// Methoden
	
	@ Override
	public void paint( Graphics g ) {
		
		if ( pic >=  tiles.size() ) pic = 0;
		g.drawImage( tiles.get( pic++ ), x, y, width, height, null );
		
		if ( animpic == -1 || playAnimation ) {
			
			if ( animpic == -1 ) { animpic = 0; playAnimation = true; }
			
			if ( animpic >=  animation.size() ) { animpic = 0; playAnimation = false; animation.clear(); return; }
			g.drawImage( animation.get( animpic++ ), x, y, width, height, null );
			
		}
		
	}
	
	@Override
	public boolean checkCollisions( Sprite s ) {
		
		for ( int x = 0; x < tiles.get( pic ).getWidth(); x++ ) {
			
			for ( int y = 0; y < tiles.get( pic ).getHeight(); y++ ) {
				
				int c1 =   tiles.get(   pic ).getRGB( x, y );
				int c2 = s.tiles.get( s.pic ).getRGB( x, y );
				
				if ( ( ( ( c1 >> 24 ) & 0xff ) != 0 ) && ( ( ( c2 >> 24 ) & 0xff ) != 0 ) ) return true;
				
			}
			
		}
		
		return false;
		
	}
	
	public static String dirToString( Direction dir ) {
		
		switch ( dir ) {
			
			case Up    : return "U";
			case Down  : return "D";
			case Left  : return "L";
			case Right : return "R";
			
		}
		
		return "";
		
	}
	
	@ Override
	public void moveTo( Direction dir ) {
		
		switch ( dir ) {
			
			case Up    : y--; break;
			case Down  : y++; break;
			case Left  : x--; break;
			case Right : x++; break;
			
		}
		
	}
	
	@ Override
	public void moveTo( int x, int y ) { this.x = x; this.y = y; }
	
	protected void playAnimation( ArrayList<BufferedImage> animation ) { this.animation = animation; playAnimation = true; }
	
	protected void loadSound( String name, String path ) { soundlib.loadSound( name, path ); }
	protected void playSound( String name              ) { soundlib.playSound( name       ); }
	
	protected boolean remove() { return remove; }
	protected void destroy()   { remove = true; }
	
	protected void explode() { playAnimation( animationlib.getAnimation( "explosion" ) ); destroy(); }
	
}
```






Spoiler: Player





```
package de.androbin.lib;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;
import com.sun.xml.internal.ws.api.ResourceLoader;

public class Player extends Sprite {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	protected HashMap<String, BufferedImage> tiles = new HashMap<String, BufferedImage>();
	protected Direction dir;
	
	// Konstruktoren
	
	public Player() { }
	
	public Player( String url, Direction dir, int x, int y, int width, int height ) {
		
		this.dir = dir; this.x = x; this.y = y; this.width = width; this.height = height;
		
		for ( int i = 0; i < Direction.values().length; i++ ) {
			
			for ( int j = 0; new File( url + dirToString( Direction.values()[ i ] ) + j + ".png" ).exists(); j++ ) {
				
				try { tiles.put( dirToString( Direction.values()[ i ] ) + j,
						ImageIO.read( ResourceLoader.class.getResource( url + dirToString( Direction.values()[ i ] ) + j + ".png" ) ) ); }
				catch ( IOException e ) { break; }
			}
		
		}
		
	}
	
	// Methoden
	
	public String dirToString() { return dirToString( dir ); }
	
	public void turn( Direction dir ) { this.dir = dir; }
	
	@Override
	public boolean checkCollisions( Sprite s ) {
		
		for ( int x = 0; x < tiles.get( dirToString() + pic ).getWidth(); x++ ) {
			
			for ( int y = 0; y < tiles.get( dirToString() + pic ).getHeight(); y++ ) {
				
				int c1 =   tiles.get( dirToString() + pic ).getRGB( x, y );
				int c2 = s.tiles.get(               s.pic ).getRGB( x, y );
				
				if ( ( ( ( c1 >> 24 ) & 0xff ) != 0 ) && ( ( ( c2 >> 24 ) & 0xff ) != 0 ) ) return true;
				
			}
			
		}
		
		return false;
		
	}
	
	@ Override
	public void moveTo( Direction dir ) { super.moveTo( dir ); this.dir = dir; }
	
	@ Override
	public void moveTo( int x, int y ) { super.moveTo( x, y ); dir = Direction.Down; }
	
	public void moveTo( Direction dir, int x, int y ) { super.moveTo( x, y ); this.dir = dir; }
	
	@Override
	public void paint( Graphics g ) {
		
		if ( pic >=  tiles.size() / Direction.values().length ) pic = 0;
		g.drawImage( tiles.get( dirToString() + pic++ ), x, y, width, height, null );
		
		if ( animpic == -1 || playAnimation ) {
			
			if ( animpic == -1 ) { animpic = 0; playAnimation = true; }
			
			if ( animpic >=  animation.size() ) { animpic = 0; playAnimation = false; animation.clear(); return; }
			g.drawImage( animation.get( animpic++ ), x, y, width, height, null );
			
		}
		
	}
	
}
```


----------



## Androbin (7. Mai 2014)

Update vom 07.05.14, 20:02 Uhr :



Spoiler: World





```
package de.androbin.lib.games;

import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.JPanel;

public abstract class World extends JPanel implements KeyListener, Runnable {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	protected ArrayList<Sprite> objects = new ArrayList<Sprite>();
	protected ArrayList<Mob>    mobs    = new ArrayList<Mob>   ();
	protected Player            player  = new Player( "", "", Direction.Down, 0, 0, 0, 0 );
	
	protected BufferedImage background  = new BufferedImage( getWidth(), getHeight(), BufferedImage.TYPE_INT_RGB );
	
	protected AnimationLib animationlib = new AnimationLib();
	protected SoundLib     soundlib     = new SoundLib    ();
	
	// Methoden
	
	public boolean moveTo( Sprite s, Direction dir ) {
		
		for ( int i = 0; i < objects.size(); i++ ) if ( !s.checkCollision( objects.get( i ) ) ) return false;
		for ( int i = 0; i < mobs   .size(); i++ ) if ( !s.checkCollision( mobs   .get( i ) ) ) return false;
		
		s.moveTo( dir ); return true;
		
	}
	
	public void moveAt( Sprite s, int x, int y ) { s.moveTo( x, y ); }
	
	@Override
	public void paint( Graphics g ) {
		
		super.paint( g );
		
		g.drawImage( background, 0, 0, getWidth(), getHeight(), null );
		
		for ( int i = 0; i < objects.size(); i++ ) { objects.get( i ).paint( g ); }
		for ( int i = 0; i < mobs   .size(); i++ ) { mobs   .get( i ).paint( g ); }
		                                             player          .paint( g );
		
	}
	
	protected void playAnimation( Sprite s, ArrayList<BufferedImage> animation ) { s.playAnimation( animation ); }
	
	protected void loadSound( String name, String path ) { soundlib.loadSound( name, path ); }
	protected void playSound( String name              ) { soundlib.playSound( name       ); }
	protected void loopSound( String name              ) { soundlib.loopSound( name       ); }
	protected void stopLoopingSounds(                  ) { soundlib.stopLoopingSounds(    ); }
	
	@Override
	public void run() {
		
		while ( true ) {
			
			try { Thread.sleep( 500 ); } catch ( InterruptedException e ) { e.printStackTrace(); }
			
			for ( int i = 0; i < objects.size(); i++ ) if ( objects.get( i ).remove() ) objects.remove( i );
			for ( int i = 0; i < mobs   .size(); i++ ) if ( mobs   .get( i ).remove() ) mobs   .remove( i );
			
			for ( int i = 0; i < mobs   .size(); i++ ) moveTo( mobs.get( i ), Mob.randomDir() );
			
			repaint();
			
		}
		
	}
	
	@ Override
	public void keyPressed( KeyEvent e ) {
		
		switch ( e.getKeyCode() ) {
			
			case KeyEvent.VK_W     : player.moveTo( Direction.Up    ); break;
			case KeyEvent.VK_A     : player.moveTo( Direction.Left  ); break;
			case KeyEvent.VK_S     : player.moveTo( Direction.Down  ); break;
			case KeyEvent.VK_D     : player.moveTo( Direction.Right ); break;
			
			case KeyEvent.VK_UP    : player.moveTo( Direction.Up    ); break;
			case KeyEvent.VK_DOWN  : player.moveTo( Direction.Down  ); break;
			case KeyEvent.VK_LEFT  : player.moveTo( Direction.Left  ); break;
			case KeyEvent.VK_RIGHT : player.moveTo( Direction.Right ); break;
			
		}
		
	}
	
	@ Override
	public void keyReleased( KeyEvent e ) { }
	
	@ Override
	public void keyTyped( KeyEvent e ) { }
	
}
```






Spoiler: Sprite





```
package de.androbin.lib.games;

import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import javax.imageio.ImageIO;
import com.sun.xml.internal.ws.api.ResourceLoader;

public class Sprite extends Rectangle2D.Double implements Drawable, Movable {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	protected int x = 0, y = 0, width = 0, height = 0;
	protected HashMap<Integer, BufferedImage> tiles     = new HashMap<Integer, BufferedImage>();
	protected ArrayList       <BufferedImage> animation = new ArrayList       <BufferedImage>();
	protected int pic = 0, animpic = 0;
	
	protected AnimationLib animationlib = new AnimationLib();
	protected SoundLib     soundlib     = new SoundLib    ();
	
	protected boolean playAnimation = false;	
	protected boolean remove = false;
	
	// Konstruktoren
	
	public Sprite() { }
	
	public Sprite( String url, int x, int y, int width, int height ) {
		
		this.x = x; this.y = y; this.width = width; this.height = height;
		
		for ( int i = 0; new File( url + i + ".png" ).exists(); i++ ) {
			
			try { tiles.put( i, ImageIO.read( ResourceLoader.class.getResource( url + i + ".png" ) ) ); }
			catch ( IOException e ) { break; }
			
		}
		
	}
	
	public Sprite( ArrayList<BufferedImage> animation, int x, int y, int width, int height ) { this.animation = animation; this.x = x; this.y = y; this.width = width; this.height = height; }
	
	public Sprite( String url, Sprite parent ) { this( url, parent.x, parent.y, parent.width, parent.height ); }
	
	// Methoden
	
	@ Override
	public void paint( Graphics g ) {
		
		if ( pic >=  tiles.size() ) pic = 0;
		g.drawImage( tiles.get( pic++ ), x, y, width, height, null );
		
		if ( animpic == -1 || playAnimation ) {
			
			if ( animpic == -1 ) { animpic = 0; playAnimation = true; }
			
			if ( animpic >=  animation.size() ) { animpic = 0; playAnimation = false; animation.clear(); return; }
			g.drawImage( animation.get( animpic++ ), x, y, width, height, null );
			
		}
		
	}
	
	protected Rectangle2D.Double getSubRec( Rectangle2D.Double source, Rectangle2D.Double part ) {
		
		Rectangle2D.Double sub = new Rectangle2D.Double();
		
		if ( source.x > part.x ) sub.x = 0;
		else sub.x = part.x - source.x;
		
		if( source.y > part.y ) sub.y = 0;
		else sub.y = part.y - source.y;
		
		sub.width = part.width;
		sub.height = part.height;
		
		return sub;
	}
	
	protected boolean isOpaque( int rgb ) { return !( ( ( rgb >> 24 ) & 0xff ) == 0 ); }
	
	@Override
	public boolean checkCollision( Sprite s ) {
		
		Rectangle2D.Double cut = (Double) this.createIntersection( s );
		
		if ( ( cut.width < 1 ) || ( cut.height < 1 ) ) return false;
		
		Rectangle2D.Double sub_me  = getSubRec( this, cut );
		Rectangle2D.Double sub_him = getSubRec( s   , cut );
		
		BufferedImage img_me  =   tiles.get(   pic ).getSubimage( (int) sub_me .x, (int) sub_me .y, (int) sub_me .width, (int) sub_me .height );
		BufferedImage img_him = s.tiles.get( s.pic ).getSubimage( (int) sub_him.x, (int) sub_him.y, (int) sub_him.width, (int) sub_him.height );
		
		for ( int x = 0; x < img_me.getWidth(); x++ ) {
			
			for ( int y = 0; y < img_him.getHeight(); y++ ) {
				
				int rgb1 = img_me .getRGB( x, y );
				int rgb2 = img_him.getRGB( x, y );
				
				if ( isOpaque( rgb1 ) && isOpaque( rgb2 ) ) { return true; }
				
			}
			
		}
		
		return false;
		
	}
	
	@ Override
	public void moveTo( Direction dir ) {
		
		switch ( dir ) {
			
			case Up    : y--; break;
			case Down  : y++; break;
			case Left  : x--; break;
			case Right : x++; break;
			
		}
		
	}
	
	@ Override
	public void moveTo( int x, int y ) { this.x = x; this.y = y; }
	
	protected void playAnimation( ArrayList<BufferedImage> animation ) { this.animation = animation; animpic = -1;; }
	
	protected void loadSound( String name, String path ) { soundlib.loadSound( name, path ); }
	protected void playSound( String name              ) { soundlib.playSound( name       ); }
	
	protected boolean remove() { return remove; }
	protected void destroy()   { remove = true; }
	
	protected void explode() { playAnimation( animationlib.getAnimation( "explosion" ) ); destroy(); }
	
}
```






Spoiler: Player





```
package de.androbin.lib.games;

import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import javax.imageio.ImageIO;
import com.sun.xml.internal.ws.api.ResourceLoader;

public class Player extends Sprite {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	protected HashMap<String, BufferedImage> tiles = new HashMap<String, BufferedImage>();
	protected String name = "";
	protected Direction dir;
	
	// Konstruktoren
	
	public Player() { }
	
	public Player( String name, String url, Direction dir, int x, int y, int width, int height ) {
		
		this.name = name; this.dir = dir; this.x = x; this.y = y; this.width = width; this.height = height;
		
		for ( int i = 0; i < Direction.values().length; i++ ) {
			
			for ( int j = 0; new File( url + dirToString( Direction.values()[ i ] ) + j + ".png" ).exists(); j++ ) {
				
				try { tiles.put( dirToString( Direction.values()[ i ] ) + j,
						ImageIO.read( ResourceLoader.class.getResource( url + dirToString( Direction.values()[ i ] ) + j + ".png" ) ) ); }
				catch ( IOException e ) { break; }
			}
		
		}
		
	}
	
	// Methoden
	
	public String dirToString() { return dirToString( dir ); }
	
	public static String dirToString( Direction dir ) {
		
		switch ( dir ) {
			
			case Up    : return "U";
			case Down  : return "D";
			case Left  : return "L";
			case Right : return "R";
			
		}
		
		return "";
		
	}
	
	public void turn( Direction dir ) { this.dir = dir; }
	
	@Override
	public boolean checkCollision( Sprite s ) {
		
		Rectangle2D.Double cut = (Double) this.createIntersection( s );
		
		if ( ( cut.width < 1 ) || ( cut.height < 1 ) ) return false;
		
		Rectangle2D.Double sub_me  = getSubRec( this, cut );
		Rectangle2D.Double sub_him = getSubRec( s   , cut );
		
		BufferedImage img_me  =   tiles.get( dirToString() + pic ).getSubimage( (int) sub_me .x, (int) sub_me .y, (int) sub_me .width, (int) sub_me .height );
		BufferedImage img_him = s.tiles.get(               s.pic ).getSubimage( (int) sub_him.x, (int) sub_him.y, (int) sub_him.width, (int) sub_him.height );
		
		for ( int x = 0; x < img_me.getWidth(); x++ ) {
			
			for ( int y = 0; y < img_him.getHeight(); y++ ) {
				
				int rgb1 = img_me .getRGB( x, y );
				int rgb2 = img_him.getRGB( x, y );
				
				if ( isOpaque( rgb1 ) && isOpaque( rgb2 ) ) { return true; }
				
			}
			
		}
		
		return false;
		
	}
	
	@ Override
	public void moveTo( Direction dir ) { super.moveTo( dir ); this.dir = dir; }
	
	@ Override
	public void moveTo( int x, int y ) { super.moveTo( x, y ); dir = Direction.Down; }
	
	public void moveTo( Direction dir, int x, int y ) { super.moveTo( x, y ); this.dir = dir; }
	
	@Override
	public void paint( Graphics g ) {
		
		if ( pic >=  tiles.size() / Direction.values().length ) pic = 0;
		g.drawImage( tiles.get( dirToString() + pic++ ), x, y, width, height, null );
		
		if ( animpic == -1 || playAnimation ) {
			
			if ( animpic == -1 ) { animpic = 0; playAnimation = true; }
			
			if ( animpic >=  animation.size() ) { animpic = 0; playAnimation = false; animation.clear(); return; }
			g.drawImage( animation.get( animpic++ ), x, y, width, height, null );
			
		}
		
		g.setColor( Color.WHITE );
		g.setFont( new Font( "TimesRoman", Font.PLAIN, 20 ) );
		g.drawString( name, x, y - 20 );
		
	}
	
}
```


----------



## Androbin (18. Mai 2014)

Update vom 18.05.2014, 18:29 *8*
  - ChangeLog *8*
    - Klasse World *8*
      - Hinzufügen weiterer Listener

    - Klasse Sprites *8*
      - Sprites können nun gedreht und ausgerichtet werden

  - SourceCode *8*


Spoiler: Klasse World





```
package de.androbin.lib.games;

import java.awt.*;
import java.awt.event.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.io.*;
import java.util.*;
import javax.swing.*;

public class World extends JPanel implements KeyListener, MouseListener, MouseMotionListener, Runnable, Serializable {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	protected ArrayList<Sprite> objects = new ArrayList<Sprite>();
	protected ArrayList<Mob   > mobs    = new ArrayList<Mob   >();
	protected Player            player  = new Player( "", "", Direction.Down, 0, 0, 0, 0 );
	
	protected BufferedImage background;
	
	protected AnimationLib animationlib = new AnimationLib();
	protected SoundLib         soundlib = new SoundLib    ();
	
	// Konstruktoren
	
	public World() { }
	
	public World( Player player ) {
		
		this.player = player;
		
		setFocusable          ( true );
		addKeyListener        ( this );
		addMouseListener      ( this );
		addMouseMotionListener( this );
		setVisible            ( true );
		
		new Thread( this ).start();
		
	}
	
	// Methoden
	
	public void changeBackground( BufferedImage background ) { this.background = background; }
	
	public void addObject( Sprite s ) { objects.add( s ); }
	public void addMob   ( Mob    m ) { mobs   .add( m ); }
	
	public boolean moveTo( Sprite s, Direction dir ) {
		
		for ( int i = 0; i < objects.size(); i++ ) if ( !s.checkCollision( objects.get( i ) ) ) return false;
		for ( int i = 0; i < mobs   .size(); i++ ) if ( !s.checkCollision( mobs   .get( i ) ) ) return false;
		
		s.moveTo( dir ); return true;
		
	}
	
	public void moveAt( Sprite s, int x, int y ) { s.moveTo( x, y ); }
	
	@Override
	public void paintComponent( Graphics g ) {
		
		super.paintComponent( g );
		
		Graphics2D g2 = (Graphics2D) g;
		
		g.drawImage( background, 0, 0, getWidth(), getHeight(), this );
		
		for ( int i = 0; i < objects.size(); i++ ) { objects.get( i ).paintComponent( g2, this ); }
		for ( int i = 0; i < mobs   .size(); i++ ) { mobs   .get( i ).paintComponent( g2, this ); }
		                                             player          .paintComponent( g2, this );
		
	}
	
	public void  addAnimation( String name, ArrayList<BufferedImage> animation ) { animationlib. addAnimation( name, animation ); }
	public void loadAnimation( String name, String                   path      ) { animationlib.loadAnimation( name, path      ); }
	public void playAnimation( Sprite s   , ArrayList<BufferedImage> animation ) { s.playAnimation(                  animation ); }
	
	public void loadSound( String name, String path ) { soundlib.loadSound( name, path ); }
	public void playSound( String name              ) { soundlib.playSound( name       ); }
	public void loopSound( String name              ) { soundlib.loopSound( name       ); }
	public void stopLoopingSounds(                  ) { soundlib.stopLoopingSounds(    ); }
	
	@Override
	public void run() {
		
		while ( true ) {
			
			try { Thread.sleep( 500 ); } catch ( InterruptedException e ) { e.printStackTrace(); }
			
			for ( int i = 0; i < objects.size(); i++ ) if ( objects.get( i ).remove() ) objects.remove( i );
			for ( int i = 0; i < mobs   .size(); i++ ) if ( mobs   .get( i ).remove() ) mobs   .remove( i );
			
			for ( int i = 0; i < mobs   .size(); i++ ) moveTo( mobs.get( i ), Mob.randomDir() );
			
			repaint();
			
		}
		
	}
	
	@ Override
	public void keyPressed( KeyEvent e ) {
		
		switch ( e.getKeyCode() ) {
			
			case KeyEvent.VK_W     : moveTo( player, Direction.Up    ); break;
			case KeyEvent.VK_A     : moveTo( player, Direction.Left  ); break;
			case KeyEvent.VK_S     : moveTo( player, Direction.Down  ); break;
			case KeyEvent.VK_D     : moveTo( player, Direction.Right ); break;
			
			case KeyEvent.VK_UP    : moveTo( player, Direction.Up    ); break;
			case KeyEvent.VK_DOWN  : moveTo( player, Direction.Down  ); break;
			case KeyEvent.VK_LEFT  : moveTo( player, Direction.Left  ); break;
			case KeyEvent.VK_RIGHT : moveTo( player, Direction.Right ); break;
			
		}
		
	}
	
	@ Override
	public void keyReleased( KeyEvent e ) { }
	
	@ Override
	public void keyTyped   ( KeyEvent e ) { }
	
	@ Override
	public void mouseDragged( MouseEvent e ) { }
	
	@ Override
	public void mouseMoved  ( MouseEvent e ) { player.moveRigthTo( (Point2D.Double) (Point2D) e.getPoint() ); }
	
	@ Override
	public void mouseClicked( MouseEvent e ) { }
	
	@ Override
	public void mouseEntered( MouseEvent e ) { }
	
	@ Override
	public void mouseExited( MouseEvent e ) { }
	
	@ Override
	public void mousePressed( MouseEvent e ) { }
	
	@ Override
	public void mouseReleased( MouseEvent e ) { }
	
}
```






Spoiler: Klasse Sprites





```
package de.androbin.lib.games;

import java.awt.*;
import java.awt.geom.*;
import java.awt.image.*;
import java.util.*;
import javax.imageio.*;
import javax.swing.*;
import com.sun.xml.internal.ws.api.*;

public class Sprite extends Rectangle2D.Double implements Drawable, Movable {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	protected double x = 0, y = 0, width = 0, height = 0;
	protected HashMap  <Integer, BufferedImage> tiles     = new HashMap  <Integer, BufferedImage>();
	protected ArrayList<         BufferedImage> animation = new ArrayList<         BufferedImage>();
	protected int pic = 0, animpic = 0;
	protected double degrees = 0;
	
	protected AnimationLib animationlib = new AnimationLib();
	protected     SoundLib     soundlib = new SoundLib    ();
	
	protected boolean playAnimation = false;	
	protected boolean remove        = false;
	
	// Konstruktoren
	
	public Sprite() { }
	
	public Sprite( String url, double x, double y, double width, double height ) {
		
		this.x = x; this.y = y; this.width = width; this.height = height;
		
		for ( int i = 0; i != -1; i++ ) { try { tiles.put( i, ImageIO.read( ResourceLoader.class.getResource( url + i + ".png" ) ) ); } catch ( Exception e ) { i = -1; } }
		
	}
	
	public Sprite( HashMap<Integer, BufferedImage> tiles, double x, double y, double width, double height ) { this.tiles = tiles; this.x = x; this.y = y; this.width= width; this.height = height; }
	
	public Sprite( ArrayList<BufferedImage> animation, double x, double y, double width, double height ) { this.animation = animation; this.x = x; this.y = y; this.width = width; this.height = height; }
	
	public Sprite( String url, Sprite parent ) { this( url, parent.x, parent.y, parent.width, parent.height ); }
	
	// Methoden
	
	@ Override
	public void paintComponent( Graphics g, JComponent comp ) {
		
		Graphics2D g2 = (Graphics2D) g;
		
		if ( pic >=  tiles.size() ) pic = 0;
		g2.drawImage( tiles.get( pic++ ), (int) x, (int) y, (int) width, (int) height, comp );
		
		if ( animpic == -1 || playAnimation ) {
			
			if ( animpic == -1 ) { animpic = 0; playAnimation = true; }
			
			if ( animpic >=  animation.size() ) { animpic = 0; playAnimation = false; animation.clear(); return; }
			g2.drawImage( animation.get( animpic++ ), (int) x, (int) y, (int) width, (int) height, comp );
			
		}
		
	}
	
	public double         getMidX  () { return getX() + getWidth () / 2; }
	public double         getMidY  () { return getY() + getHeight() / 2; }
	public Point2D.Double getMidPos() { return new Point2D.Double( getMidX(), getMidY() ); }
	
	public double getRotation() { return degrees; }
	public double getRotation(  Sprite s ) { return getRotation( s.getMidPos() ); }
	public double getRotation(  Point2D.Double  p ) { return getRotation( p.getX(), p.getY() ); }
	public double getRotation( double x, double y ) { return Math.toDegrees( Math.atan2( y - getMidY(), x - getMidX() ) ); }
	
	protected void setRotation(  Sprite s  ) { setRotation( s.getMidPos() ); }
	protected void setRotation(  Point2D.Double  p ) { setRotation( p.getX(), p.getY() ); }
	protected void setRotation( double x, double y ) { setRotation( getRotation( x, y ) ); }
	protected void setRotation( double degrees ) { this.degrees = degrees; }
	
	protected BufferedImage getRotatedImage() {
		
		if ( animpic == -1 || playAnimation ) {
			   return getRotatedImage( animation.get( animpic++ ), degrees );
		} else return getRotatedImage( tiles    .get(     pic++ ), degrees );
		
	}
	
	public static BufferedImage getRotatedImage( BufferedImage original, double degrees ) {
		
		AffineTransform at = AffineTransform.getRotateInstance( Math.toRadians( degrees + 90 ), original.getWidth() / 2, original.getHeight() / 2 );
		BufferedImage rotatedImage = new BufferedImage( original.getWidth(), original.getHeight(), original.getType() );
		
		Graphics2D g = (Graphics2D) rotatedImage.getGraphics();
		g.setTransform( at );
		g.drawImage( original, 0, 0, null );
		
		return rotatedImage;
		
	}
	
	public void moveRigthTo( Sprite s ) { moveRigthTo( s.getMidPos() ); }
	public void moveRigthTo( Point2D.Double p ) { moveRigthTo( p.getX(), p.getY() ); }
	public void moveRigthTo( double x, double y ) { moveRigthTo( getRotation( x, y ) ); }
	public void moveRigthTo( double degrees ) {
		
		x += Math.cos( Math.toRadians( degrees ) );
		y += Math.sin( Math.toRadians( degrees ) );
		
	}
	
	public static Rectangle2D.Double getSubRec( Rectangle2D.Double source, Rectangle2D.Double part ) {
		
		Rectangle2D.Double sub = new Rectangle2D.Double();
		
		if ( source.x > part.x ) sub.x = 0;
		else sub.x = part.x - source.x;
		
		if( source.y > part.y ) sub.y = 0;
		else sub.y = part.y - source.y;
		
		sub.width = part.width;
		sub.height = part.height;
		
		return sub;
	}
	
	public static boolean isOpaque( int rgb ) { return !( ( ( rgb >> 24 ) & 0xff ) == 0 ); }
	
	@Override
	public boolean checkCollision( Sprite s ) {
		
		Rectangle2D.Double cut = (Double) this.createIntersection( s );
		
		if ( ( cut.width < 1 ) || ( cut.height < 1 ) ) return false;
		
		Rectangle2D.Double sub_me  = getSubRec( this, cut );
		Rectangle2D.Double sub_him = getSubRec( s   , cut );
		
		BufferedImage img_me  =   tiles.get(   pic ).getSubimage( (int) sub_me .x, (int) sub_me .y, (int) sub_me .width, (int) sub_me .height );
		BufferedImage img_him = s.tiles.get( s.pic ).getSubimage( (int) sub_him.x, (int) sub_him.y, (int) sub_him.width, (int) sub_him.height );
		
		for ( int x = 0; x < img_me.getWidth(); x++ ) {
			
			for ( int y = 0; y < img_him.getHeight(); y++ ) {
				
				int rgb1 = img_me .getRGB( x, y );
				int rgb2 = img_him.getRGB( x, y );
				
				if ( isOpaque( rgb1 ) && isOpaque( rgb2 ) ) { return true; }
				
			}
			
		}
		
		return false;
		
	}
	
	@ Override
	public void moveTo( Direction dir ) {
		
		switch ( dir ) {
			
			default : return;
			
			case Up        :      y--; return;
			case Down      :      y++; return;
			case Left      : x--;      return;
			case Right     : x++;      return;
			
			case UpLeft    : x--; y--; return;
			case UpRight   : x++; y--; return;
			case DownLeft  : x--; y++; return;
			case DownRight : x++; y++; return;
			
		}
		
	}
	
	@ Override
	public void moveTo( double x, double y ) { this.x = x; this.y = y; }
	
	protected void playAnimation( ArrayList<BufferedImage> animation ) { this.animation = animation; animpic = -1;; }
	
	protected void loadSound( String name, String path ) { soundlib.loadSound( name, path ); }
	protected void playSound( String name              ) { soundlib.playSound( name       ); }
	
	protected boolean  remove() { return remove       ; }
	protected void    destroy() {        remove = true; }
	
	protected void explode() { playAnimation( animationlib.getAnimation( "explosion" ) ); destroy(); }
	
}
```


----------

