# Verschwindender Spieler in 2D-Game



## Androbin (14. Mrz 2014)

Hallo Leute, ich hab' grad' so 'n kleines 2D-Game angefangen, bei dem man, ihr kennt das bestimmt, mit seinem Spieler Felsen oder Sonstiges rollen lässt, bis sie irgendwo-gegen landen. ...

Das Problem ist, dass wenn man den Spieler ( mit WASD oder den Pfeiltasten ) bewegt, er verschwindet.
Könnt ihr mir da vielleicht weiterhelfen? Hier die Quelltexte ( meiner 4 Klassen ):

Schieberätsel:

```
// Imports
import java.awt.*;
import javax.swing.*;
import java.applet.*;

public class Schieberätsel extends Applet implements Runnable {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	public static boolean isRunning = false;
	
	public static JFrame frame;
	
	public static Graphics g;
		
	public static int size = 500;
	
	// Konstruktoren
	
	public Schieberätsel() {
		// Frame vorbereiten
		frame = new JFrame( "Schieberätsel" );
		frame.setSize( size - 22, size );
		frame.setResizable( false );
		frame.setLocationRelativeTo( null );
		frame.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		frame.setVisible( true );
		frame.addKeyListener( new Listener() );
		
		g = frame.getGraphics();
	}
	
	// Methoden
	
	public void start() {
		isRunning = true;
		Level.level = new Level( 1 );
		new Thread( this ).start();
	}
	
	public void stop() {
		isRunning = false;
	}	
	
	public void run() {		
		while ( isRunning ) {
			try {
				Thread.sleep( 5 );
			} catch ( Exception e ) { }
		}
	}	
	
	public static void main( String[] args ) {
		Schieberätsel schieberätsel = new Schieberätsel();
		schieberätsel.start();
	}
}
```

Level:

```
public class Level {
	
	// Deklarationen
	
	public static int LevelNummer = 0;
	public static Level level;
	public int[] solve = new int[ 2 ];
	
	public static Tile[][] Spielfeld = new Tile[ 10 ][ 10 ];
	public static int[] Spieler = new int[ 2 ];
	
	// Konstruktoren
	
	public Level( int LevelNummer ) {
		for ( int x = 0; x < Spielfeld.length; x++ ) {
			for ( int y = 0; y < Spielfeld[ 0 ].length; y++ ) {
				setFieldByID( x, y, 0);
			}
		}
		
		switch ( LevelNummer ) {
			case 1 :
				setFieldByID( 1, 1, 1 );
				solve[ 0 ] = 5;
				solve[ 1 ] = 5;
				break;
			case 2 :
				
				break;
			case 3 :
				
				break;
		}
	}
	
	// Methoden
	
	public static void setFieldByID( int x, int y, int id ) {
		Spielfeld[ x ][ y ] = new Tile( Tile.size * x + 10, Tile.size * y + 30, id );
		
		if ( id == 1 ) {
			Spieler[ 0 ] = x;
			Spieler[ 1 ] = y;
		}
	}
	
	public static void solved() {
		level = new Level( LevelNummer + 1 );
	}
}
```

Tile:

```
// Imports
import java.awt.image.*;
import java.io.*;
import javax.imageio.*;

public class Tile {
	
	// Deklarationen
		
	public static BufferedImage tiles;
	
	public static int size = ( Schieberätsel.size - 40 ) / 10;
	public static int TileSize = 20;
	
	public int Pos1, Pos2, id;
	
	// Konstruktoren
	
	public Tile( int Pos1, int Pos2, int id ) {		
		try {
			tiles = ImageIO.read( new File( "res/tiles.png" ) );
		} catch ( Exception e ) { }
		
		
		Schieberätsel.g.drawImage( tiles, Pos1, Pos2, Pos1 + size, Pos2 + size, id * TileSize, 0, id * TileSize + TileSize, TileSize, null );
	}
	
	// Methoden
	
	public static void move( int Px, int Py, int Mx, int My ) {
		if ( Level.Spielfeld[ Px - Mx ][ Py - My ].id == 0 ) {
			Level.setFieldByID( Px - Mx, Py - My, Level.Spielfeld[ Px ][ Py ].id );
			Level.setFieldByID( Px, Py, 0 );
		}
		
		if ( ( Px - Mx ) == Level.level.solve[ 0 ] && ( Py - My ) == Level.level.solve[ 1 ] ) {
			Level.solved();
		}
	}
}
```

Listener:

```
// Imports
import java.awt.event.*;

public class Listener implements KeyListener {
	
	// Deklarationen
	
	public static int[] dir = new int[ 2 ];
	
	// Methoden
	
	public void keyPressed( KeyEvent e ) { }
	
	public void keyReleased( KeyEvent e ) { }
	
	public void keyTyped( KeyEvent e ) {
		switch ( e.getKeyCode() ) {
			case KeyEvent.VK_W :
				dir[ 0 ] = 0;
				dir[ 1 ] = 1;
				break;
			case KeyEvent.VK_A :
				dir[ 0 ] = -1;
				dir[ 1 ] = 0;
				break;
			case KeyEvent.VK_S :
				dir[ 0 ] = 0;
				dir[ 1 ] = -1;
				break;
			case KeyEvent.VK_D :
				dir[ 0 ] = 1;
				dir[ 1 ] = 0;
				break;
			case KeyEvent.VK_UP :
				dir[ 0 ] = 0;
				dir[ 1 ] = 1;
				break;
			case KeyEvent.VK_LEFT :
				dir[ 0 ] = -1;
				dir[ 1 ] = 0;
				break;
			case KeyEvent.VK_DOWN :
				dir[ 0 ] = 0;
				dir[ 1 ] = -1;
				break;
			case KeyEvent.VK_RIGHT :
				dir[ 0 ] = 1;
				dir[ 1 ] = 0;
				break;
		}
		
		Tile.move( Level.Spieler[ 0 ], Level.Spieler[ 1 ], dir[ 0 ], dir[ 1 ] );
	}
}
```

Danke im Voraus!


----------



## Highchiller (16. Mrz 2014)

Ich habs nicht getestet hab aber einen Fehler gefunden.

Du hast im Konstruktor der Klasse Tile die Variable "id" überhaupt nicht gesetzt. Was bedeutet das jedes Tile immer die id = 0 hat (weil int ein primitiver Datentyp ist). Das bedeutet du führst in der Methode "move", Zeile 32 und 33, folgendes aus.


```
// denn Level.Spielfeld[ Px ][ Py ].id = 0 für alle Px, Py
Level.setFieldByID( Px - Mx, Py - My, 0 );
Level.setFieldByID( Px, Py, 0 );
```


----------



## Androbin (17. Mrz 2014)

@Highchiller
Danke für deine Antwort. Ich habe den Fehler ausgebessert, doch anstattdessen habe ich nun das Problem, dass er sich überhaupt nicht mehr bewegt. Mit System.out.println habe ich herausgefunden, dass die id eines jeden Feldes 1 zu sein scheint; weshalb? - ...


----------



## Highchiller (17. Mrz 2014)

Klingt als wenn sich bei deiner Ausbesserung ein neuer Fehler eingeschlichen hat :toll:
Nu musst du mal schicken was du geändert hast, sonst kann ich nicht sagen wieso auf einmal alle Felder die ID = 1 haben.

Grüßle


----------



## Androbin (17. Mrz 2014)

@Highchiller
Nach 24 Stunden Re-Coding, hier meine immernoch fehlerbehaftete Version 2.0:

MainFrame:

```
package net.diegamingbrueder.games.Schieberätsel;

import javax.swing.JButton;
import javax.swing.JFrame;

public class MainFrame
  extends JFrame
{
  private static final long serialVersionUID = 1L;
  public static MainFrame frame;
  public static JButton BPlay;
  public static JButton BHilfe;
  public static JButton BExit;
  
  public MainFrame()
  {
    super("Hauptmenü");
    setSize(200, 200);
    setResizable(false);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(3);
    setVisible(true);
    


    setLayout(null);
    
    BPlay = new JButton("Spiel starten");
    BHilfe = new JButton("So wird gespielt");
    BExit = new JButton("Spiel beenden");
    
    BPlay.addActionListener(new Listener());
    BHilfe.addActionListener(new Listener());
    BExit.addActionListener(new Listener());
    
    BPlay.setBounds(20, 20, 150, 30);
    BHilfe.setBounds(20, 70, 150, 30);
    BExit.setBounds(20, 120, 150, 30);
    
    add(BPlay);
    add(BHilfe);
    add(BExit);
  }
  
  public static void main(String[] args)
  {
    frame = new MainFrame();
  }
}
```

Level:

```
package net.diegamingbrueder.games.Schieberätsel;

import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.JFrame;

public class Level
  extends JFrame
{
  public static int sX = 3;
  public static int sY = 25;
  public static Feld[][] Spielfeld = new Feld[10][10];
  public static int[] Spieler = new int[2];
  public static int[] solve = new int[2];
  private static final long serialVersionUID = 1L;
  public static BufferedImage tiles;
  public static Graphics g;
  public int LevelNummer;
  
  public Level(int LevelNummer)
  {
    super("Level " + LevelNummer);
    setSize(456, 478);
    setResizable(false);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(1);
    setVisible(true);
    addKeyListener(new Listener());
    
    g = getGraphics();
    


    this.LevelNummer = LevelNummer;
    for (int x = 0; x < Spielfeld.length; x++) {
      for (int y = 0; y < Spielfeld[0].length; y++) {
        Spielfeld[x][y] = new Feld(x, y, 0);
      }
    }
    switch (LevelNummer)
    {
    case 1: 
      solve[0] = 5;
      solve[1] = 5;
      
      Spieler[0] = 3;
      Spieler[1] = 3;
      
      Spielfeld[3][3].id = 1;
      
      break;
    case 2: 
      break;
    }
    repaint();
  }
  
  public void paint(Graphics g)
  {
    try
    {
      tiles = ImageIO.read(new File("res/tiles.png"));
    }
    catch (Exception localException) {}
    for (int x = 0; x < Spielfeld.length; x++) {
      for (int y = 0; y < Spielfeld[0].length; y++) {
        g.drawImage(tiles, Spielfeld[x][y].Pos1 * Feld.size + sX, Spielfeld[x][y].Pos2 * Feld.size + sY, Spielfeld[x][y].Pos1 * Feld.size + Feld.size + sX, Spielfeld[x][y].Pos2 * Feld.size + Feld.size + sY, Spielfeld[x][y].id * Feld.size, 0, Spielfeld[x][y].id * Feld.size + Feld.size, Feld.size, null);
      }
    }
  }
  
  public void move(int Px, int Py, int Mx, int My)
  {
    if (Spielfeld[(Px + Mx)][(Py + My)].id == 0)
    {
      Spielfeld[(Px + Mx)][(Py + My)].id = Spielfeld[Px][Py].id;
      Spielfeld[Px][Py].id = 0;
      
      repaint();
    }
  }
}
```

Feld:

```
package net.diegamingbrueder.games.Schieberätsel;

public class Feld
{
  public static int size = 45;
  public int Pos1;
  public int Pos2;
  public int id;
  
  public Feld(int Pos1, int Pos2, int id)
  {
    this.Pos1 = Pos1;
    this.Pos2 = Pos2;
    this.id = id;
  }
}
```

Listener:

```
package net.diegamingbrueder.games.Schieberätsel;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.io.PrintStream;

public class Listener
  implements ActionListener, KeyListener
{
  public static Level level;
  public static int[] dir = new int[2];
  
  public void actionPerformed(ActionEvent e)
  {
    if (e.getSource() == MainFrame.BPlay) {
      level = new Level(1);
    }
    if (e.getSource() == MainFrame.BHilfe) {
      new Hilfe();
    }
    if (e.getSource() == MainFrame.BExit) {
      MainFrame.frame.dispose();
    }
  }
  
  public void keyPressed(KeyEvent e) {}
  
  public void keyReleased(KeyEvent e)
  {
    for (int x = 0; x < Level.Spielfeld.length; x++) {
      for (int y = 0; y < Level.Spielfeld[0].length; y++) {
        System.out.print(Level.Spielfeld[x][y].id);
      }
    }
    switch (e.getKeyCode())
    {
    case 87: 
      dir[0] = 0;
      dir[1] = -1;
      
      break;
    case 65: 
      dir[0] = -1;
      dir[1] = 0;
      
      break;
    case 83: 
      dir[0] = 0;
      dir[1] = 1;
      
      break;
    case 68: 
      dir[0] = 1;
      dir[1] = 0;
      
      break;
    case 38: 
      dir[0] = 0;
      dir[1] = -1;
      
      break;
    case 37: 
      dir[0] = -1;
      dir[1] = 0;
      
      break;
    case 40: 
      dir[0] = 0;
      dir[1] = 1;
      
      break;
    case 39: 
      dir[0] = 1;
      dir[1] = 0;
    }
    Level.Spieler[0] += dir[0];
    Level.Spieler[1] += dir[1];
    
    level.move(Level.Spieler[0], Level.Spieler[1], dir[0], dir[1]);
  }
  
  public void keyTyped(KeyEvent e) {}
}
```

Hilfe:

```
package net.diegamingbrueder.games.Schieberätsel;

import javax.swing.JFrame;
import javax.swing.JTextArea;

public class Hilfe
  extends JFrame
{
  private static final long serialVersionUID = 1L;
  public static JTextArea description = new JTextArea();
  
  public Hilfe()
  {
    super("Hilfe");
    setSize(300, 200);
    setResizable(false);
    setLocationRelativeTo(null);
    setDefaultCloseOperation(2);
    setVisible(true);
    


    setLayout(null);
    description.setBounds(20, 20, 250, 130);
    description.setText("Test, Test, 1, 2, 3!");
    description.setLineWrap(true);
    description.setEditable(false);
    add(description);
  }
}
```


----------



## Highchiller (18. Mrz 2014)

Aaaalso... erst mal kannst du jede Menge optimieren  aber das lassen wir ma eben außen vor.

Die IDs sind nicht überall 1, aber ich denke das Problem ist auch veraltet. 
Der Spieler bewegt sich nicht weil du in der Klasse Listener in Zeile 79 und 80 die Position des Spielers aktualisierst und DANN sagst, der spieler hat sich bewegt. (also neu zeichnest)
Das führt dazu das Spielfeld[Px][Py].id in Level, Zeile 78 wieder stets 0 ist. Denn Px und Py ist nicht die aktuelle Position des Spielers sondern schon die Position, auf der er jetzt landen soll. Da steht aber noch kein Spieler, du bewegst ihn ja grad.

Außerdem solltest du die Position des Spielers (also Zeile 79 und 80 in der Listener Klasse) auch nur dann aktualisieren, wenn du den Spieler tatsächlich bewegst. Also am besten in "move()" und zwar IN der IF-Abfrage und da sogar NACH dem repaint.

Das sollte weitere Fehler auch gleich minimieren.

--- Und jetz noch kleine Optimierungen ---

Außerdem musst du noch Sonderfälle abfangen, sowas wie, das der Spieler nicht aus dem Spielbrett rennen kann, das wirft bei dir eine muntere IndexOutOfBoundsException 
Ach und eins noch, das find ich furchtbar 
In deiner paint Methode lädst du deine tiles.png immer wieder neu wenn sich was ändert. Wieso? Die datei ändert sich doch nicht. Einfach einmal im Konstruktor laden (vor repaint natürlich) und gut ist.

Weitere hard-core optimierung wäre übrigens, wenn du nicht jedes mal das ganze Spielfeld neu zeichnest, sondern lediglich die alte und neue position des spielers übermalst. Überleg mal... 10*10 = 100 mal g.drawImage(blabla) oder nur 2 mal pro repaint? 

Ich hoffe ich konnte helfen.


----------



## Androbin (18. Mrz 2014)

@Highchiller
1. Danke ich dir recht herzlich für dein Engagement !!!
2. Heureka, funktioniert's für's erste, aber:
3. Kommen später noch mehr Sachen als nur der Spieler auf's "Spielbrett" ( Felsen, die gerollt werden können, Hindernisse + evtl. Mobs ) ( siehe Signatur von move() ) !!! und
4. Der derzeitige Stand des Quelltextes ( diesmal mir Auslagerung der Klasse "Feld" ):

MainFrame:

```
package net.diegamingbrueder.games.Schieberätsel;

// Imports

import javax.swing.*;

public class MainFrame extends JFrame {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	public static MainFrame frame;
	public static JButton BPlay, BHilfe, BExit;
	
	// Konstruktoren
	
	public MainFrame() {
		
		// Frame vorbereiten
		
		super( "Hauptmenü" );
		setSize( 200, 200 );
		setResizable( false );
		setLocationRelativeTo( null );
		setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
		setVisible( true );
		
		// Elemente hinzufügen
		
		setLayout( null );
		
		BPlay = new JButton( "Spiel starten" );
		BHilfe = new JButton( "So wird gespielt" );
		BExit = new JButton( "Spiel beenden" );
		
		BPlay.addActionListener( new Listener() );
		BHilfe.addActionListener( new Listener() );
		BExit.addActionListener( new Listener() );
		
		BPlay.setBounds( 20, 20, 150, 30 );
		BHilfe.setBounds( 20, 70, 150, 30 );
		BExit.setBounds( 20, 120, 150, 30 );
		
		add( BPlay );
		add( BHilfe );
		add( BExit );
		
	}
	
	// Methoden
	
	public static void main( String[] args ) {
		
		frame = new MainFrame();
		
	}
	
}
```

Level ( mit den meisten Änderungen ):

```
package net.diegamingbrueder.games.Schieberätsel;

// Imports

import javax.swing.*;

import java.awt.*;
import java.awt.image.*;
import java.io.*;

import javax.imageio.*;

public class Level extends JFrame {
	
	// Deklarationen
	
	private static final long serialVersionUID = 1L;
	
	public static BufferedImage tiles;
	
	public static Graphics g;
	
	public static int sX = 3, sY = 25;
	public static int size = 45;
	
	public static int[][] Spielfeld = new int[ 10 ][ 10 ];
	
	public static int[] Spieler = new int[ 2 ];
	
	public static int[] solve = new int[ 2 ];
	
	public int LevelNummer;
	
	// Konstruktoren
	
	public Level( int LevelNummer ) {
		
		// Frame vorbereiten
		
		super( "Level " + LevelNummer );
		setSize( 456, 478 );
		setResizable( false );
		setLocationRelativeTo( null );
		setDefaultCloseOperation( JFrame.HIDE_ON_CLOSE );
		setVisible( true );
		addKeyListener( new Listener() );
		
		g = getGraphics();
		
		// Texturen einlesen
		
		try {
			
			tiles = ImageIO.read( new File( "res/tiles.png" ) );
			
		} catch ( Exception e ) { }
		
		// Variablen übernehmen
		
		this.LevelNummer = LevelNummer;
		
		// Level generieren
		
		for ( int x = 0; x < Spielfeld.length; x++ ) {
			
			for ( int y = 0; y < Spielfeld[ 0 ].length; y++ ) {
				
				Spielfeld[ x ][ y ] = 0;
				
			}
			
		}
		
		switch ( LevelNummer ) {
			
			case 1 :
				
				solve[ 0 ] = 5;
				solve[ 1 ] = 5;
				
				Spieler[ 0 ] = 3;
				Spieler[ 1 ] = 3;
				
				Spielfeld[ 3 ][ 3 ] = 1;
				
				break;
			
			case 2 :
				
				break;
			
			case 3 :
				
				break;
			
		}
		
		repaint();
		
	}
	
	// Methoden
	
	public void paint( Graphics g ) {
		
		for ( int x = 0; x < Spielfeld.length; x++ ) {
			
			for ( int y = 0; y < Spielfeld[ 0 ].length; y++ ) {
				
				g.drawImage( tiles, x * Feld.size + sX, y * Feld.size + sY, x * Feld.size + Feld.size + sX, y * Feld.size + Feld.size + sY, Spielfeld[ x ][ y ] * Feld.size, 0, Spielfeld[ x ][ y ] * Feld.size + Feld.size, Feld.size, null );
				
			}
			
		}
		
	}
	
	public void move( int Px, int Py, int Mx, int My ) {
		
		if ( !( Px + Mx < 0 ) && !( Py + My < 0 ) && !( Px + Mx == Spielfeld.length ) && !( Py + My == Spielfeld[ 0 ].length ) ) {
			
			if ( Spielfeld[ Px + Mx ][ Py + My ] == 0 ) {
			
			Level.Spieler[ 0 ] += Mx;
			Level.Spieler[ 1 ] += My;
				
				Spielfeld[ Px + Mx ][ Py + My ] = Spielfeld[ Px ][ Py ];
				Spielfeld[ Px ][ Py ] = 0;
				
				repaint();
				
			}
			
		}
		
	}
	
}
```

Listener ( kleine Änderung ):

```
package net.diegamingbrueder.games.Schieberätsel;

// Imports

import java.awt.event.*;

public class Listener implements ActionListener, KeyListener {
	
	// Deklarationen
	
	public static Level level;
	
	public static int[] dir = new int[ 2 ];
	
	// Methoden
	
	public void actionPerformed( ActionEvent e ) {
		
		if ( e.getSource() == MainFrame.BPlay ) {
			
			level = new Level( 1 );
			
		}
		
		if ( e.getSource() == MainFrame.BHilfe ) {
			
			new Hilfe();
			
		}
		
		if ( e.getSource() == MainFrame.BExit ) {
			
			MainFrame.frame.dispose();
			
		}
		
	}
	
	public void keyPressed( KeyEvent e ) { }
	
	public void keyReleased( KeyEvent e ) {
		
		switch ( e.getKeyCode() ) {
			
			case KeyEvent.VK_W :
				
				dir[ 0 ] = 0;
				dir[ 1 ] = -1;
				
				break;
			
			case KeyEvent.VK_A :
				
				dir[ 0 ] = -1;
				dir[ 1 ] = 0;
				
				break;
			
			case KeyEvent.VK_S :
				
				dir[ 0 ] = 0;
				dir[ 1 ] = 1;
				
				break;
			
			case KeyEvent.VK_D :
				
				dir[ 0 ] = 1;
				dir[ 1 ] = 0;
				
				break;
				
			case KeyEvent.VK_UP :
				
				dir[ 0 ] = 0;
				dir[ 1 ] = -1;
				
				break;
			
			case KeyEvent.VK_LEFT :
				
				dir[ 0 ] = -1;
				dir[ 1 ] = 0;
				
				break;
			
			case KeyEvent.VK_DOWN :
				
				dir[ 0 ] = 0;
				dir[ 1 ] = 1;
				
				break;
			
			case KeyEvent.VK_RIGHT :
				
				dir[ 0 ] = 1;
				dir[ 1 ] = 0;
				
				break;
			
		}
		
		level.move( Level.Spieler[ 0 ], Level.Spieler[ 1 ], dir[ 0 ], dir[ 1 ] );
		
	}
	
	public void keyTyped( KeyEvent e ) { }
	
}
```

Die Klasse Help lasse ich erst mal außen vor!

P.S.: Es tut mir leid, aber ein paar Zeilenangaben deinerseits scheinen nicht zu stimmen, ist wahrscheinlich schon älter!

P.P.S.: Im Anhang die tiles.png ( und ja, ich hab's optimiert! ) + die Eclipse Umgebung als Zip


----------



## Highchiller (18. Mrz 2014)

Na dann wünsch ich fröhliches schaffen


----------

