# Hintergrund & Koordinaten Probleme



## Black_ixx (21. Sep 2013)

Hey Leute!

Ich schreibe nun schon seit knapp zwei Jahren mit Java "Plugins" für das Spiel Minecraft und habe mich jetzt heute zum ersten Mal an einem eigenem Game versucht.

Die Basics kenne ich zwar aber mit Klassen wie JFrame oder JPanel habe ich noch nie vorher gearbeitet.

Nach einer kurzen Suche habe ich Quaxlis Tutorial gefunden. Einfach der Hammer!! Es ist ausführlich, detailiert und perfekt für Beginner. Vielen Dank dafür Quaxli :toll:

Ich habe mich bis zu Seite 40 vorgearbeitet, bin dort allerdings auf zwei Probleme gestoßen...
Ich habe schon alles Mögliche probiert aber das will einfach nicht funktionieren....


Meine Klassen sehen im Moment so aus:


*GamePanel*

```
package org.black_ixx.firstgame;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.net.URL;
import java.util.Random;
import java.util.Vector;

import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;

public class GamePanel extends JPanel implements Runnable, KeyListener{

	private static final long serialVersionUID = 5989649846550855813L;
	boolean game_running = true;
	boolean started=false;
	boolean once = false;

	long delta = 0;
	long last = 0;
	long fps = 0;

	boolean up = false;
	boolean down = false;
	boolean left = false;
	boolean right = false;
	int speed = 50;

	Heli copter;
	Vector<Sprite> actors;


	public static void main(String[] args){
		new GamePanel(800, 600);
	}


	public GamePanel(int w, int h){
		this.setPreferredSize(new Dimension(w, h));
		this.setBackground(Color.cyan);
		JFrame frame = new JFrame("GameDemo");
		frame.setLocation(100, 100);
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.addKeyListener(this);
		frame.add((this));
		frame.pack();
		frame.setVisible(true);
		doInitializations();
	}

	private void doInitializations(){

		last = 0;

		actors = new Vector<Sprite>();
		BufferedImage[] heli = this.loadPics("org/black_ixx/firstgame/pics/heli.gif", 4);
		copter = new Heli(heli, 400, 300, 100, this);
		actors.add(copter);

		createClouds();


		if (!once){
			once=true;
			Thread t = new Thread(this);
			t.start();
		}

	}

	@Override
	public void run() {

		while (game_running){

			if (isStarted()){
				computeDelta();
				checkKeys();
				doLogic();
				moveObjects();
			}

			repaint();

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


			}
		}
	}


	private void computeDelta(){

		delta = System.nanoTime()- last;
		last = System.nanoTime();
		fps = ((long) 1e9/delta);

	}



	@Override
	public void paintComponent(Graphics g){
		super.paintComponents(g);

		g.setColor(Color.red);
		g.drawString("FPS: "+Long.toString(fps), 20, 10);

		if (!isStarted()){
			return;
		}

		if (actors!=null){
			for (Drawable draw : actors){
				draw.drawObjects(g);
			}
		}



	}


	private BufferedImage[] loadPics(String path, int pics ){

		BufferedImage[] anim = new BufferedImage[pics];
		BufferedImage source = null;

		URL pic_url = getClass().getClassLoader().getResource(path);

		try{
			source = ImageIO.read(pic_url);
		}catch (IOException e){
		}


		for (int x = 0; x <pics; x++){
			anim[x] = source.getSubimage(x*source.getWidth()/pics, 0,  source.getWidth()/pics, source.getHeight());
		}

		return anim;

	}



	private void doLogic(){
		for(Moveable mov : actors){
			mov.doLogic(delta);
		}
	}

	private void moveObjects(){
		for (Moveable mov : actors){
			mov.move(delta);
		}
	}

	@Override
	public void keyPressed(KeyEvent e) {

		if (e.getKeyCode() == KeyEvent.VK_DOWN){
			down = true;
		}		

		if (e.getKeyCode() == KeyEvent.VK_UP){
			up = true;
		}

		if (e.getKeyCode() == KeyEvent.VK_LEFT){
			left = true;
		}

		if (e.getKeyCode() == KeyEvent.VK_RIGHT){
			right = true;
		}

	}

	@Override
	public void keyReleased(KeyEvent e) {


		if (e.getKeyCode() == KeyEvent.VK_DOWN){
			down = false;
		}		

		if (e.getKeyCode() == KeyEvent.VK_UP){
			up = false;
		}

		if (e.getKeyCode() == KeyEvent.VK_LEFT){
			left = false;
		}

		if (e.getKeyCode() == KeyEvent.VK_RIGHT){
			right = false;
		}

		if (!up&!down){
			copter.setVerticalSpeed(0);
		}
		if (!left&!right){
			copter.setHorizontalSpeed(0);
		}


		if (e.getKeyCode() == KeyEvent.VK_ENTER){
			if (!isStarted()){
				doInitializations();
				setStarted(true);
			}
		}


		if (e.getKeyCode() == KeyEvent.VK_ESCAPE){
			if (isStarted()){
				setStarted(false);
			}else{
				setStarted(false);
				System.exit(0);
			}
		}

	}

	@Override
	public void keyTyped(KeyEvent arg0) {
		// TODO Auto-generated method stub

	}


	private void checkKeys(){

		if (up){
			copter.setVerticalSpeed(-speed);
		}
		if (down){
			copter.setVerticalSpeed(speed);
		}
		if (left){
			copter.setHorizontalSpeed(-speed);
		}
		if (right){
			copter.setHorizontalSpeed(speed);
		}


	}


	public boolean isStarted(){
		return started;
	}

	public void setStarted(boolean started){
		this.started=started;
	}

	private void createClouds(){
		BufferedImage[] ci = this.loadPics("org/black_ixx/firstgame/pics/todeswolke.png", 1);
		for (int y=10; y < getHeight(); y+= 50)
		{
			int x = (int)(Math.random()*getWidth());
			Cloud cloud = new Cloud(ci, x, y,1000, this);
			actors.add(cloud);
		}

	}




}
```


*Sprite*

```
package org.black_ixx.firstgame;

import java.awt.Graphics;
import java.awt.geom.Rectangle2D;
import java.awt.image.BufferedImage;

public abstract class Sprite extends Rectangle2D.Double implements Moveable, Drawable {

	long delay;
	
	GamePanel parent;
	long animation = 0;
	BufferedImage[] pics;
	int currentpic = 0;
	
	protected double dx;
	protected double dy;
	
	public Sprite(BufferedImage[] i, double x, double y, long delay, GamePanel p){
		
		pics = i;
		this.x=x;
		this.y=y;
		this.delay=delay;
		this.width=pics[0].getWidth();
		this.height=pics[0].getHeight();
		parent = p;
		
		
	}
	
	
	
	@Override
	public void drawObjects(Graphics g) {
		g.drawImage(pics[currentpic], (int)x, (int)y,null);
	}

	@Override
	public void doLogic(long delta) {
		
		animation+=(delta/1000000);
		if (animation > delay){
			animation = 0;
			computeAnimation();			
		}
	}

	@Override
	public void move(long delta) {

		if (dx!=0){
			x+=dx*(delta/1e9);
		}
		
		if (dy!=0){
			y += dy*(delta/1e9);
		}
	}
	
	
	
	private void computeAnimation(){
		
		currentpic++;
		
		if (currentpic>=pics.length){
			currentpic=0;
		}
	}
	
	
	public void setVerticalSpeed(double d){
		dy=d;
	}
	
	public void setHorizontalSpeed(double d){
		dx=d;
	}
	
	public double getVerticalSpeed(){
		return dy;
	}
	
	public double getHorizontalSpeed(){
		return dx;
	}
	
	public void setX(double i){
		x=i;
	}
	
	public void setY(double i){
		y=i;
	}
	
	
}
```

*Heli*

```
package org.black_ixx.firstgame;

import java.awt.image.BufferedImage;

public class Heli extends Sprite{

	public Heli(BufferedImage[] i, double x, double y, long delay, GamePanel p) {
		super(i, x, y, delay, p);
	}
	
	@Override
	public void doLogic(long delta){
		super.doLogic(delta);
		
		if (getX()<0){
			setHorizontalSpeed(0);
			setX(0);
		}
		
		if (getX()+getWidth() > parent.getWidth()){
			setX((parent.getWidth()-getWidth()));
			setHorizontalSpeed(0);			
		}
		
		if (getY()<0){
			setY(0);
			setVerticalSpeed(0);
		}
		
		if (getY()+getHeight()>parent.getHeight()){
			setY(parent.getHeight()-getHeight());
			setVerticalSpeed(0);
		}
		
		
	}

}
```


*Cloud*

```
package org.black_ixx.firstgame;

import java.awt.image.BufferedImage;
import java.util.Random;

public class Cloud extends Sprite {

	final int SPEED = 20;
	
	
	public Cloud(BufferedImage[] i, double x, double y, long delay, GamePanel p) {
		super(i, x, y, delay, p);
		

		if (new Random().nextInt(2)==0){ 
			setHorizontalSpeed(-SPEED);
		}else{
			setHorizontalSpeed(SPEED);
		}	
	}
	
	@Override
	public void doLogic(long delta){
		super.doLogic(delta);

		if (getHorizontalSpeed()>0 && getX() > parent.getWidth()){
			setX(-getWidth());
		}
		
		if (getHorizontalSpeed() < 0 && (getX() + getWidth()) <0){
			setX(parent.getWidth()+getWidth());
		}
		
		
	}
	
}
```


Ich hoffe dass der Thread durch den ganzen Code nicht zu unübersichtlich wird...
Gibt es denn irgendeine Möglichkeit Code in einen ausklappbaren Spoiler zu packen?


Naja kommen wir zu den zwei Problemen.

*1. Hintergrund*

Irgendwie bleibt mein Hintergrund immer grau. Genauer gesagt es gibt gar keinen Hintergrund...
Meine GamePanel Klasse enthält folgenden Code:

```
this.setBackground(Color.cyan);
```
Ich habe auch schon andere Farben ausgetestet (macht wenig Sinn aber es war einen Versuch wert xD) bzw. 
	
	
	
	





```
frame.getContentPane().setBackground(Color.CYAN);
```
 habe ich auch schon getestet. Mein Bildschirm sieht in etwa so aus:







Wisst ihr vielleicht woran das liegt? Wurde vielleicht irgendetwas bei Java verändert? Oder enthält mein Code Fehler? Ich wäre wirklich dankbar über ein paar Antworten 


*2. Position der Wolken*
Mein zweites Problem sind die Wolken.
Ich konnte nirgendwo Quaxlis Wolken-Bild finden also habe ich mir einfach meine eigene Wolke zusammengebastelt.

Mit diesem Code werden die Wolken auch korrekt gespawnt:

```
private void createClouds(){
		BufferedImage[] ci = this.loadPics("org/black_ixx/firstgame/pics/todeswolke.png", 1);
		for (int y=10; y < getHeight(); y+= 50)
		{
			int x = (int)(Math.random()*getWidth());
			Cloud cloud = new Cloud(ci, x, y,1000, this);
			actors.add(cloud);
		}
	}
```

innerhalb der nächsten Millisekunden aber denkt das Spiel, dass die Wolken ausserhalb des sichtbaren Bereiches wären und bewegt sie zurück zu dem Rand des Fensters...

Ich habe stundenlang versucht das zu beheben. Ohne Erfolg 

Was ich bisher herausgefunden habe (mithilfe von system.out.print(X variable / width of window):


```
int x = (int)(Math.random()*getWidth());
	Cloud cloud = new Cloud(ci, x, y,1000, this);
```

Hier werden sie bei einer zufälligen Position gespawnt. In der Mitte des Fensters.
Ich habe auch schon 
	
	
	
	





```
int x = Random.nextInt(getWidth())
```
 versucht aber es kommt beidesmal auf das gleiche heraus. Das Problem liegt in einer anderen Methode.


Ich habe diesen Part hier genauer untersucht:

```
@Override
	public void doLogic(long delta){
		super.doLogic(delta);
#p1
		if (getHorizontalSpeed()>0 && getX() > parent.getWidth()){
#p2
			setX(-getWidth());
		}
		
		if (getHorizontalSpeed() < 0 && (getX() + getWidth()) <0){
#p3
			setX(parent.getWidth()+getWidth());
		}
		
	}
```

Anfangs als die Wolken gespawnt werden liegt X irgendwo zwischen 0 und 800.

Das erste Mal aber wenn doLogic ausgeführt wird ist X irgendeine riesige Zahl.
Diese Zahlen hier wurden geprintet: "684832.5869867401  685315.5869867401  685112.5869867401  684797.5869867401  685194.5869867401  685009.5869867401  684830.5869867401  685286.5869867401  "
X wird sofort wieder zurückgesetzt und von dem Moment an verhalten sich alle Wolken normal und fliegen quer über den Bildschirm.

Ich frage mich, wann und wieso X zu diesen Zahlen gesettet wird. Liegt das auch an einem Fehler in meinem Code? Ich habe den ganzen Code danach durchsucht...



Antworten sind wilkommen!


----------



## Black_ixx (21. Sep 2013)

Das Hintergrund-Problem wurde gelöst!

Der Fehler war folgender: Anstatt von "super.paintComponent(g)" hatte ich "super.paintComponents(g)" geschrieben. Das letzte "s "war fehl am Platz.


Danke an JCODA für die Hilfe 



Jetzt ist nur noch das Wolken Problem ungelöst.


----------



## Bananabert (25. Sep 2013)

Ich würde behaupten es liegt an deinem "delta".
Beim ersten Durchlauf errechnest du 
	
	
	
	





```
delta = System.nanoTime() - last;
```
Da "last" am Anfang auf 0 ist, wird hier wohl auch ein sehr hoher wert rauskommen.


----------

