# Simulation



## Noodles (22. Dez 2012)

Hallo,

ich bin Student und habe zuviel Freiziet, also habe ich mich mit enderen Studenten zusammengetan und wir versuchen nun ein Spiel zu programmieren, ich bin wohl der fleißigste und weil niemand einen wirklich Ahnung von GUI hat werde ich das erstmal übernehmen.

Ich habe schon viele Versuche gestarten eine gute GUI zubauen für das Spiel aber es ist immer wieder an irgendwelceh Grenzen gestoßen, deshalb wollte ich hier mal nachfragen was ihr meint wie ich die Ideen realisieren soll.

Erstmal zu dem Spiel, man soll am Ende Gott über eine kleine Welt spielen können.
Momentan iszt es aber eher nur Simulation den ich hänge nebenbei noch an einer KI für die Menschen die dort leben sollen.

Was soll möglich sein?? Also:

-man soll scrollen können oder aber was mir lieber wäre man kann mit dem Maus auf die welt klicken um sich so hin und herzubewegen.

- man soll entweder also "Gott" auf die Map klicken können, sodass wie bei der rechten Maustaste eine Menü aufploppt oder aber es soll eine Menüleiste geben in der man seien seine Aktion auswählt und dann nur auf die Welt klicken muss.

- die Simulativen Objekte sollen mehrere Animationen besitzten, dh sie können in 8 verschiedene Richtungen laufen (ich habe eine Graphikerin die sich darum kümmert) und jede Richtung hat wie im altbewehrten RPG-Maker 3 Bilder um die Animation wirken zu lassen, es ist ausserdem ein Pixelbasiertes Spiel Momentan 16*16 Pixel pro Feld.

Bisherige Versuche :

- ein ganz normales JFrame mit einem Panel darauf repaint wird ständig aufgerufen und in der paint methode habe ich dann die Graphics g verändert, aber es wurde immer die gesamte Welt neu gezeichnet, also Perfomance FTL.

- dann habe ich im Internet die Idee des DoubleBuffering aufgeschnappt und habe ein Fenster gemacht das nur aus Canvas besteht und habe dor draufgezeichnet, dies ist auch die Momentane Lösung, aber ich weiß nicht wie ich das Scrollen realisieren soll, ausserdem weiß ich nicht wie ich Effektiv die Animationen realisieren soll.

Erstmal würde ich mich über ein paar Grundlegende Tipps freuen, genaueres kann man dann auch noch entscheiden.

Vielen Dank Wünscht
Die Nudel


----------



## Firephoenix (22. Dez 2012)

Mal auf der Basis, dass du Swing verwendest (ein Blick auf z.B. Slick2d für die Grafik schadet evtl auch nicht, zumindest wenn das ganze eh Richtung Spiel gehen soll).

Ein Ablauf zum Scrollen/Rendern/etc könnte so aussehen:

Angenommen du klickst auf einer Minimap die 100x100 groß ist auf x/y 23/68.
Deine Welt hat die Größe 7000x7000.
Dann hättest du in Welt-Koordinaten auf 1610/4760 geklickt.
Jetzt kannst du deine Kamera zu der Position bewegen.
Sagen wir mal, das Panel welches den Sichtbereich anzeigt ist 800x600 groß.
Wenn du zoom drin haben willst macht ein weiterer Skalierungsfaktor sinn welcher das Mapping von Weltkoordinaten zu Pixelkoordinaten angibt, sagen wir mal du hast gerade etwas reingezoomt, der zoomfaktor wäre also 2.5.
Eine "Einheit" in deiner Welt wird also als 2.5 Pixel angezeigt.
In deinen Sichtbereich passen also gerade 320x240 Welteinheiten die auf 800x600 Pixeln gerendert werden.
Da die Kamera bei 1610/4760 steht musst du also alle Spielobjekte im Bereich 1450/4640-1770/4880 Anzeigen.
Angenommen du zeichnest Pixelweise, dann könntest du jetzt einen Marker bei 0/0 in deinem Zeichenpanel setzen, einen 2. Marker bei 1450/4640 in deinen Weltkoordinaten.
Jetzt iterierst du über dein Zeichenfeld und alle 2.5 Pixel (evtl runden) rückst du auch den Marker in den Weltkoordinaten eins weiter. An jeden Pixel zeichnest du dann das Objekt oder den Ausschnitt der sich gerade an der entsprechenden Welt-Koordinate befindet.

Das ganze kann man natürlich noch beliebig optimieren oder an eigene Ansprüche anpassen. So in etwa könnte aber der Ablauf aussehen.
Gruß


----------



## Noodles (22. Dez 2012)

Also wenn ich immer über die Welt iteriere um zu zeichnen würde ich befürchten, dass es zu rechen intensiv wird, meine Idee ist eher jedes Objekt zeichnet sich ständig,bzw nur wenn es sich ändert ,auf ein Offscreen image und von dort aus könnte ich es auf die oberfläche übertragen, ich bin mir nur nicht zu sicher ob das möglich ist.

Also in der Momentanen Simulation gehe ich davon aus, das jedes Objekt auf der Welt Simuliert wird nicht nur was man sieht.

Meine Probleme liegen eher in kann ich hier Multithreading benutzten, bzw wäre es sinnvoll ??
Ausserdem ist mir nicht ganz klar wie ich die Animationen gestalten soll.

Momentan sieht das so aus : 

[JAVA=20]import java.awt.event.*;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Canvas;
//import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics2D;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferStrategy;
import java.awt.image.ImageObserver;
import java.awt.image.ImageProducer;

import javax.swing.JFrame;
import javax.swing.JPanel;

import Game.World.World;

public class Game extends Canvas{

	private static final long serialVersionUID = -1132646638851829536L;

	private BufferStrategy strategy;
	boolean gameRunning = true;
	World Welt = null;
	int Weltgroesse = 200;

	public Game() {
		JFrame container = new JFrame("GodLike");
		JPanel panel = (JPanel) container.getContentPane();
		panel.setPreferredSize(new Dimension(16*Weltgroesse,16*Weltgroesse));
		panel.setLayout(null);
		setBounds(0,0,16*Weltgroesse,16*Weltgroesse);
		panel.add(this);
		setIgnoreRepaint(true);
		container.pack();
		//container.setResizable(false);
		container.setVisible(true);
		container.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		requestFocus();
		createBufferStrategy(2);
		strategy = getBufferStrategy();
		Welt = new World(Weltgroesse);
		addMouseListener(new ClickEvent());
	}

	private int[] momAusschnitt = {0,0};

	class ClickEvent extends MouseAdapter {

		public void mouseClicked(MouseEvent e) {
			momAusschnitt[0]=16*26-e.getX();
			momAusschnitt[1]=16*26-e.getY();
			if (momAusschnitt[0]>0) {
				momAusschnitt[0]=0;
			}
			if (momAusschnitt[1]>0) {
				momAusschnitt[1]=0;
			}
		}
	}

	public void gameLoop() {
		Graphics2D g = (Graphics2D) strategy.getDrawGraphics();
		Welt.drawAll(g);
		strategy.show();

		long tv,tn;

		while (gameRunning) {
			g = (Graphics2D) strategy.getDrawGraphics();
			tv = System.currentTimeMillis();
			this.setLocation(momAusschnitt[0], momAusschnitt[1]);
			Welt.simulate();
			Welt.reDraw(g,0);
			strategy.show();
			tn = System.currentTimeMillis();
			try{
				  Thread.sleep(150-(tn-tv));
			}catch(InterruptedException ie){
			}
			for (int i=1;i<3;i++) {
				Welt.reDraw(g,i);
				strategy.show();
				try{
					  Thread.sleep(150);
				}catch(InterruptedException ie){
				}
			}
		}
	}

	public static void main(String[] args) {
		Game game=new Game();
		game.gameLoop();
	}

}[/code]

Die For Schleife kümmert sich Momentan um die Animationen, ich weiß nicht wie ich das besser lösen kann.


----------



## Noodles (25. Dez 2012)

Ich habe jetzt ein wenig and der Umsetzung gefeilt, ich habe mir zwei Threads gebaut die Simultan laufen können sollten, das Malen und das Simulieren, das Simulieren wartet immer darauf, dass das Malen alle Informationen von der Welt liest bevor es den nächsten Simulationsschritt vollführt.

Der Code zum Zusammenlegen der Layer ist noch nicht geschrieben.

[JAVA=30]import java.awt.Canvas;
import java.awt.Graphics2D;
import java.awt.GraphicsConfiguration;
import java.awt.GraphicsEnvironment;
import java.awt.Image;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.image.*;
import javax.swing.JFrame;
import Game.World.World;

public class GodLike extends JFrame{

	private static final long serialVersionUID = 1L;
	private int Weltgroesse = 50;
	boolean gameRunning = true;
	boolean gemalt,simuliert;
	World Welt = null;	

	int width,height;
	int[] MomAusschnitt = {0,0};
	Ausschnitt WeltBild;

	Thread Simulieren;

	GodLike () {
		setTitle("GodLike");
		setBounds(0,0,1366,768);
		setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		setVisible(true);
		WeltBild = new Ausschnitt();
		add (WeltBild);
		WeltBild.init();
		Welt = new World(Weltgroesse);
		Simulieren = new Simulieren();
		Simulieren.start();
	}

	class Ausschnitt extends Canvas {

		private static final long serialVersionUID = 1L;

                //hier sind die verschiedenen Layer die ich benutzte (Boden, Lebewesen(1,..,4), Strukturen)
		BufferedImage Welt0;
		BufferedImage Welt10;
		BufferedImage Welt11;
		BufferedImage Welt12;
		BufferedImage Welt13;
		BufferedImage Welt2;

		BufferStrategy strategy;

		Ausschnitt () {
			GraphicsConfiguration gfxConf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration(); 
			Welt0 = gfxConf.createCompatibleImage( Weltgroesse*16, Weltgroesse*16);
			Welt10 = gfxConf.createCompatibleImage( Weltgroesse*16, Weltgroesse*16);
			Welt11 = gfxConf.createCompatibleImage( Weltgroesse*16, Weltgroesse*16);
			Welt12 = gfxConf.createCompatibleImage( Weltgroesse*16, Weltgroesse*16);
			Welt13 = gfxConf.createCompatibleImage( Weltgroesse*16, Weltgroesse*16);
			Welt2 = gfxConf.createCompatibleImage( Weltgroesse*16, Weltgroesse*16);
			setVisible(true);
			this.addKeyListener(new MyKeyHandler());
		}

		class MyKeyHandler implements KeyListener {

			public void keyPressed(KeyEvent e) {
				int id = e.getKeyCode();
				switch (id) {
				case (37) : MomAusschnitt[0]-=1;break;
				case (38) : MomAusschnitt[1]-=1;break;
				case (39) : MomAusschnitt[0]+=1;break;
				case (40) : MomAusschnitt[1]+=1;break;
				default:break;
				}
		    }

			public void keyReleased(KeyEvent arg0) {

			}

			public void keyTyped(KeyEvent arg0) {

			}

		}

		public void init() {
			createBufferStrategy(2);
			strategy = getBufferStrategy();
		}	
	}

	class Malen extends Thread implements Runnable {

		public void run() {
			while (gameRunning) {
				BufferedImage Anim0,Anim1,Anim2,Anim3;
				GraphicsConfiguration gfxConf = GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration();
				int width = 50;
				int height = 50;
                                //hier würde die verschiedenen Layer auf einander gelegt mit Animationsstufen, also besteht eine Animation aus 4 stufen (stehen linkesbein stehen rechtesbein)
				Anim0 = gfxConf.createCompatibleImage(width, height);
				Anim1 = gfxConf.createCompatibleImage(width, height);
				Anim2 = gfxConf.createCompatibleImage(width, height);
				Anim3 = gfxConf.createCompatibleImage(width, height);
				synchronized (Simulieren) {
					Simulieren.notify();
				}				
				Graphics2D g = (Graphics2D) WeltBild.strategy.getDrawGraphics();
				g.drawImage(Anim0, 0, 0, width, height, MomAusschnitt[0], MomAusschnitt[1], MomAusschnitt[0]+width, MomAusschnitt[1]+height, null);
				WeltBild.strategy.show();
				try {sleep(50);} catch (InterruptedException e) {}
				g.drawImage(Anim1, 0, 0, width, height, MomAusschnitt[0], MomAusschnitt[1], MomAusschnitt[0]+width, MomAusschnitt[1]+height, null);
				WeltBild.strategy.show();
				try {sleep(50);} catch (InterruptedException e) {}
				g.drawImage(Anim2, 0, 0, width, height, MomAusschnitt[0], MomAusschnitt[1], MomAusschnitt[0]+width, MomAusschnitt[1]+height, null);
				WeltBild.strategy.show();
				try {sleep(50);} catch (InterruptedException e) {}
				g.drawImage(Anim3, 0, 0, width, height, MomAusschnitt[0], MomAusschnitt[1], MomAusschnitt[0]+width, MomAusschnitt[1]+height, null);
				WeltBild.strategy.show();
				try {sleep(50);} catch (InterruptedException e) {}
				System.out.println("Alles gemalt");
			}			
		}		
	}

	class Simulieren extends Thread implements Runnable {

		Thread Malen;

		public void run() {
			Malen = new Malen();
			Malen.start();
			while (gameRunning) {
				try {
					synchronized (this) {
						this.wait();
					}
				} catch (InterruptedException e1) {}
				Welt.simulate();
			}
		}

	}

	public static void main (String[] args) {
		GodLike Fenster = new GodLike();
	}

}
[/code]

ich frage jetzt gibt es eine bessere Lösung um Animationen darzustellen und wenn ja welche.
Ausserdem bin ich mir nicht sicher wie effizient die Methode mit den verschiedenen Layern ist.


----------



## BreeBree (26. Dez 2012)

Hi,

ersteinmal ist das vererben von Threads und das gleichzeitige implementieren von Runnable nicht nötig es reicht vollkommen einer Klasse nur Runnable mitzugeben und diese dann in einem neuen Thread laufen zu lassen.

2. Wenn ich ein Spiel Schreibe dann mache ich das immer so das ich eine Main Klasse habe in der alles Initialisiert wird, die eigendliche Gameloop läuft die dann eine update() und eine render() methode aufruft die render methode kann notfalls auch die paint() methode von z.B. JPanel oder sowas sein in dieser paint methode kann man dann wiederum die render() methoden von denn einzelnen objekten zeichnen lasse.
ich wüsste nicht wieso man auf mehreren bildern zeichen sollte auser wenn man mit doppel-, dreifach-, x-fachbuffern arbeitet.


----------



## Noodles (4. Jan 2013)

Ich hatte ein Problem beim implemetieren von Runnable bzw Thread, aus irgendeinem Grund konnte ich .run() nie auf solch einem Objekt ausführen, nachdem ich dann beides implementiert bzw extended hatte lief es dann.

Die mehreren Buffer benutze ich, weil es sozusagen 3 Ebenen Gibt auf denen Dinge passieren.
Die unterste Ebene ist für den UnterGrund der sich ab und zu verändert, denn es soll Jahreszeiten geben.
Die mittlere Ebene soll für alle Lebewesen sein, wobei immer nur das oberste oder größte Lebewesen angezeigt werden soll.
Die oberste Ebene ist für Strukturen, wie zB Höhlen Steine Bäume.

Da Die Lebewesen allerdings hinter diesen Strukturen verschwinden sollen wusste ich nicht wie ich es anders lösen sollte ausse, wie ich es zuvor getan hatte, indem ich erst die entität zeichne und daraufhin alle Strukturen zeichne die möglicherWeise über dieser Animation liegen, hier musste ich also bei jedem renderschritt 1 bis 4 Strukturen neuzeichnen pro Entität.
Jetzt mit dieser Methode müsste ich nur die Entitäen neu zeichnen und dann die 3 Ebenen zusammenlegen, ich war mir nur nicht ganz sicher welches besser für die Performance wäre.

Deshalb wäre ich froh wenn mich ein paar Leute vielleicht in die richtige Richtung weisen könnten.
Ich bin mir nicht sicher wie ich all diese Probleme lösen soll, also die Probleme der Animation der Entitäten!


----------



## Phash (5. Jan 2013)

koenntest du dich bitte in deinem Code auch an die Java Konvention halten:
Klassennamen gross (UpperCamelCase), Variablen und Methode klein (lowerCamelCase)
das ist sonst sehr schwer lesbar


----------

