Spielprogrammierung mit bewegung und kollision

jannig10

Mitglied
Guten abend leute!

muss sagen, dass ich ziemlich am anfang bin in java und vieles mit kleinen tipps nicht einfach umsetzen kann..

Nun zum Spiel:

ich möchte drei Klassen erstellen. 1. klasse wird die Spielfäche sein, 2.Klasse die Spielfigur, die man per tastatur bewegen kann und die dritte klasse
sollen die figuren sein, die sich selbst bewegen können und somit auch die gegner sind.

bis jetzt habe ich leider nicht viel hinbekommen.

ich habe soweit die 2. klasse fertig und teilweise die erste..

zu den Problemen:

1. ich weiß nicht wie ich die 2. und 3. klasse umschreiben soll, damit man sie mit hilfe der 1. klasse anzeigen kann.
2. ich weiß auch nicht, wie ich die "gegner" zum selbständigen bewegen bringen soll.
3. kollission zwischen der spielfigur und dem gegner realisieren.

habe zwar hilfestellungen bekommen wie z.b linked list, for-schleife und timer zu erstellen aber ich habe zu wenig erfahrung um damit weiter zu kommen.

ich hoffe ihr habt lust und laune mir dabei zu helfen =)


Java:
package spiel;

import java.awt.*;

import javax.swing.*;


public class Spielfeld extends JFrame
{
	
	static JLabel straße2 = new JLabel(new ImageIcon(Spielfigur.class.getResource("straße2.gif")));

	public Spielfeld()
	{		
			
		JPanel Sf1 = new JPanel();
		
		Sf1.add(straße2);
		setContentPane(Sf1);
	}
	
	 
	
	
	
	public static void main(String[] args) 
	{
		
		Spielfeld Spielfeld = new Spielfeld();
			
		Spielfeld.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		Spielfeld.setBounds(100, 0, 800, 540);
		
		Spielfeld.setVisible(true);
		
	}
}

Java:
package spiel;
import java.awt.*;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.*;

public class Spielfigur extends JFrame implements KeyListener 
{
	static JLabel fly = new JLabel(new ImageIcon(Spielfigur.class.getResource("fly.gif")));
	static JLabel straße2 = new JLabel(new ImageIcon(Spielfigur.class.getResource("straße2.gif")));
	
	public Spielfigur()
	{
		int width = 400;
		int height = 300;
		JPanel Spielfigur = new JPanel();
		Spielfigur.setBackground(Color.BLACK);
		
		fly.setPreferredSize(new Dimension(width , height));
						
		Spielfigur.add(fly);
		setContentPane(Spielfigur);
		
		addKeyListener(this);
		setFocusable(true);
	}
	

	
	public void keyPressed(KeyEvent e) 
	{
		switch (e.getKeyCode())
		{
		
		case KeyEvent.VK_RIGHT:
		fly.setLocation((int)fly.getLocation().getX() + 10, (int)fly.getLocation().getY());
			break;
			
		case KeyEvent.VK_LEFT:
			fly.setLocation((int)fly.getLocation().getX() -10, (int)fly.getLocation().getY());
				break;	
			
		case KeyEvent.VK_UP:
			fly.setLocation((int)fly.getLocation().getX() , (int)fly.getLocation().getY() -10);
				break;
		
		case KeyEvent.VK_DOWN:
			fly.setLocation((int)fly.getLocation().getX() , (int)fly.getLocation().getY() + 10);
				break;
		}
	}


	
	public void keyReleased(KeyEvent e) {
		if((fly.getLocation().getX() < WIDTH-170)) 
		{
			fly.setLocation(((int)fly.getLocation().getX() + 10), (int)fly.getLocation().getY());
		}
		
		if((fly.getLocation().getX() > WIDTH+565)) 
		{
			fly.setLocation(((int)fly.getLocation().getX() - 10), (int)fly.getLocation().getY());
		}
		
		if((fly.getLocation().getY() < HEIGHT-120)) 
		{
			fly.setLocation(((int)fly.getLocation().getX() ), (int)fly.getLocation().getY()+10);
		}
		
		if((fly.getLocation().getY() > HEIGHT+330)) 
		{
			fly.setLocation(((int)fly.getLocation().getX() ), (int)fly.getLocation().getY()-10);
		}
		
		
	}



	public void keyTyped(KeyEvent e) {
		// TODO Auto-generated method stub
		
	}
	
	
}

Java:
package spiel;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.*;

public class GegnerFiguren extends Spielfigur
{	
	
	JLabel balloon = new JLabel(new ImageIcon(GegnerFiguren.class.getResource("balloon.gif")));
	 


		public  GegnerFiguren()
		{
			JPanel GegnerFiguren= new JPanel();
			GegnerFiguren.setBackground(Color.BLACK);
			
			balloon.setPreferredSize(new Dimension(400 , 100));
			
			
			GegnerFiguren.add(balloon);
			
			setContentPane(GegnerFiguren);
			
		}

				
		
}
 

jannig10

Mitglied
danke für die infos!

nun habe ich mir in einem link von dir, die pdf datei runtergeladen und hab langsam die beispiele abgeschrieben.

nur hab einpaar fehlermeldungen obwohl ich alles genau so hab wie im beispiel!

Fehlermeldungen:

Exception in thread "main" java.lang.IllegalArgumentException: input == null!
at javax.imageio.ImageIO.read(ImageIO.java:1378)
at spiel.Spielfeld.loadPics(Spielfeld.java:173)
at spiel.Spielfeld.doInitializations(Spielfeld.java:63)
at spiel.Spielfeld.<init>(Spielfeld.java:52)
at spiel.Spielfeld.main(Spielfeld.java:39)


bitte um hilfe =)
 

jannig10

Mitglied
danke nochmal für die infos !

nun hab ich mich bisschen eingelesen.

hab auch soweit ein kleines spiel programmiert.

hab dennoch einpaar fragen!

Java:
public void paintComponent(Graphics g) 
	{		
		super.paintComponent(g);
		g.drawImage(background, 0, 0,this);
		g.setFont(new Font("Arial",Font.BOLD,20));
		
		g.setColor(Color.RED);
			
		g.drawString("CLICK [ENTER] TO START THE GAME",50,200);
		

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


Also wie man da sehen kann, wird ein text im feld ausgegeben.
sobal man auf enter klickt, fängt das spiel an.

mein problem dabei ist es, dass der text "click enter.." nicht verschwindet sobald man auf enter klickt.
gibt es eine möglichkeit dieses als setvisible(false) zu setzen?
 

xehpuk

Top Contributor
Der Text soll ja nur gezeichnet werden, wenn das Spiel noch nicht gestartet wurde.

Weiter unten wird schon abgefragt, ob das Spiel gestartet wurde. Da kannst du dann den Text reinsetzen:
Java:
        if(!isStarted())
        {
            g.setFont(new Font("Arial",Font.BOLD,20));
            g.setColor(Color.RED);
            g.drawString("CLICK [ENTER] TO START THE GAME",50,200);
            return;
        }
Den Font solltest du übrigens auslagern, damit er nicht jedes Mal neu geladen werden muss.
 
Zuletzt bearbeitet:

jannig10

Mitglied
vielen dank für die schnelle antwort!

eine weitere frage:

ich möchte oben rechts wenn das spiel gestartet worden ist die punkte anzeigen.
jedoch möchte ich, dass jede 30 sekunden 50 pkt gutgeschrieben werden.

allerding sollte die zeit oben stehen..

wie mach ich das?
 
Zuletzt bearbeitet:

Quaxli

Top Contributor
...

wie mach ich das?

In dem Du einen Integer für Deine Punkte in einen String umwandelst und da oben hinschreibst. Diese Aussage bringt Dir jetzt vermutlich nicht viel, oder? Nach Deiner Frage weiter oben bzgl. des Textes in paintComponent habe ich nämlich den Eindruck, daß Du erst mal noch an den Basics feilen solltest, bevor Du mit einer komplexeren Aufgabenstellung anfängst. Ein if-Bedingung sollte man innerhalb einer Methode schon so anwenden können, daß das gewünschte Ergebnis dabei heraus kommt.

Es bringt Dir wenig, wenn Du Dir hier alles vorkauen läßt. Und die hilfsbereiten Forenmitglieder, werden schnell die Lust verlieren, Dir zu helfen, wenn offensichtlich wird, das Du nicht erst mal selbst etwas ausprobierst.
Also, probier es erst mal selbst und wenn Du es dann nicht hinkriegst, poste Deinen Code, dann wird Dir auch geholfen.
 

jannig10

Mitglied
Also gut! hab deine anweisungen befolgt(selber ausprobieren) und hab das hinbekommen =)

nun gibt es ein weiteres problem, bei der ich der meinung bin, dass ich mir selber nicht helfen kann.

mein spiel startet ganz normal. sobald man dieses aber öffters spielt, hängt es auf einmal und man muss neu starten.

in meinem spiel geht es dadrum, dass eine fliege per tastatur bewegt wird und von den flammen gerettet wird.
sobal sich die flammen aneinander prallen, entsteht eine explosion (so soll es auch sein) und dann verschwinden diese.(hab das so gemacht, damit man ne chance hat zu entfliehen)

nun zum problem:

sobald die flammen mit der figur aneinander prallen oder auch mit den eiflammen, kommen diese fehlermeldungen und mal läuft es denoch weiter mal hängt es.

Java:
Exception in thread "AWT-EventQueue-0" java.util.ConcurrentModificationException
	at java.util.Vector$Itr.checkForComodification(Vector.java:1119)
	at java.util.Vector$Itr.next(Vector.java:1096)
	at spiel.Spielfeld.paintComponent(Spielfeld.java:418)
	at javax.swing.JComponent.paint(JComponent.java:1029)
	at javax.swing.JComponent.paintToOffscreen(JComponent.java:5138)
	at javax.swing.BufferStrategyPaintManager.paint(BufferStrategyPaintManager.java:302)
	at javax.swing.RepaintManager.paint(RepaintManager.java:1145)
	at javax.swing.JComponent._paintImmediately(JComponent.java:5086)
	at javax.swing.JComponent.paintImmediately(JComponent.java:4896)
	at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:740)
	at javax.swing.RepaintManager.paintDirtyRegions(RepaintManager.java:696)
	at javax.swing.RepaintManager.prePaintDirtyRegions(RepaintManager.java:676)
	at javax.swing.RepaintManager.access$700(RepaintManager.java:57)
	at javax.swing.RepaintManager$ProcessingRunnable.run(RepaintManager.java:1550)
	at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:226)
	at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:647)
	at java.awt.EventQueue.access$000(EventQueue.java:96)
	at java.awt.EventQueue$1.run(EventQueue.java:608)
	at java.awt.EventQueue$1.run(EventQueue.java:606)
	at java.security.AccessController.doPrivileged(Native Method)
	at java.security.AccessControlContext$1.doIntersectionPrivilege(AccessControlContext.java:105)
	at java.awt.EventQueue.dispatchEvent(EventQueue.java:617)
	at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:275)
	at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:200)
	at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:190)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:185)
	at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:177)
	at java.awt.EventDispatchThread.run(EventDispatchThread.java:138)
 

Marco13

Top Contributor
Also hier auf meinem alten 1.4er mit GeForce2 (!) ist es unerträglich langsam und ruckelnd - das könnte aber auch am Sound liegen, die Soundkarte auf der Kiste hier spinnt irgendwie...

Die Sache mit der ConcurrentModificationException muss doch hinzukriegen sein...

@Quaxli: Bin nicht so auf dem Laufenden, gibt's von dem Tutorial eine "Und-das-kommt-am-Ende-dabei-raus.ZIP" die man direkt öffnen und Compilieren kann (und wo das Problem auftritt)?
 

Quaxli

Top Contributor
@Marco: Nö, gibt's nicht. Ich hatte diese Fehlermeldung auch seltersamerweise lange selbst nicht. Daher habe ich auch nicht so eine "Hier ist der Fehler".zip.

Bei mir ist das Spiel übrigens gut gelaufen (neuer, 2 Wochen alter Büro-Laptop) - ohne Fehlermeldung. Ich habe aber nur 5 Runden gespielt.
Die Fehlermeldung scheint auch nicht jeder zu haben. Oder beschwert sich bloß keiner? Das wäre natürlich unschön. :( Ich werde immer wieder mal bei Fragen via PN angeschrieben, aber wg. dieser Fehlermledung fragt eigentlich keiner. :bahnhof:

@jannig10:
Üblicherweise tritt der Fehler aber früher auf, oder?
In dem Beispielen aus dem anderen Thread, der oben verlinkt ist, brachte das Vermeiden der for-each-Schleife eine deutliche Besserung.
Kannst Du mir mal den Code schicken (ohne Sound und Bilder)?

Was mir sonst noch so aufgefallen ist:

- Durch die Flammen läuft ein "Balken". Ist das Absicht? Bei mir ist das üblicherweise ein Hinweis, daß ich die Bilder falsch eingelesen habe.

- Warum hat so ein kleines Spielchen 18 MB? Wie hast Du denn Deine Grafiken gespeichert?
 

Marco13

Top Contributor
Ggf. hängt das auch davon ab, wie viele Cores man hat usw. Solche Probleme werden bei 4, 8 und mehr Kernen eher häufiger auftreten ...
Ggf. mal einen "Stresstest" machen, wo in jedem Schritt pratkisch die komplette Liste ersetzt wird oder so...
 

Quaxli

Top Contributor
Das mit dem Stresstest ist eine gute Idee. Da hätte ich eigentlich selbst drauf kommen können... :(
Ich hab' gerade mal ein kurzes Programm zusammen gefrickelt und es scheint, daß der "Bösewicht" die 2. Collection ist, in der zu entfernende Objekte gesammelt werden.
Bevor die reingepackt wurde war alle gut.

Hier mal das Beispiel:

Java:
import javax.swing.*;
import java.awt.*;
import java.util.*;

public class Stress extends JPanel implements Runnable{

	private static final long	serialVersionUID	= 1L;
	JFrame frame;
	Vector<Rect> actors;
	
	
	public static void main(String[] args){
		new Stress();
	}
	
	//Konstruktor. Vector füllen,  Fenster basteln, etc.
	public Stress(){
		setPreferredSize(new Dimension(800,800));
		
		actors = new Vector<Rect>();
		for(int i=0;i<200;i++){
      addNewRect();
		}
		
		frame = new JFrame("Stresstest");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLocation(100,100);
		frame.add(this);
		frame.pack();
		frame.setVisible(true);
		
		Thread th = new Thread(this);
		th.start();
		
	}

	public void run() {
		
		int count = 0;

		//GameLoop
		while(frame.isVisible()){
			
			//Move - alles bewegen
			for(Rect r:actors){
				r.move();
			}
			
			//Logic
			Vector<Rect> trash = new Vector<Rect>();  //Sammeln von zu entfernenden Objekten
			
			for(Rect r:actors){
				r.doLogic();
				//Wenn boolen = true, wird das Objekt zum entfernen vorgemerkt
				if(r.remove){
					trash.add(r);
					addNewRect();
				}
			}
			
			//alles raus, was weg soll
			actors.removeAll(trash);
			trash.clear();
			
			
			//counter - ab und an noch ein Objekt rein packen
			count++;
			if(count==10){
				count=0;
				addNewRect();
				System.out.println("noch eins");
			}
			
			
       try {
				Thread.sleep(10);
			} catch (InterruptedException e) {}			
			
			
			//Malen - irgendwann.....
			repaint();
			
		}
		
	}
	
	//neues Rechteck reinpacken
	private void addNewRect(){
		int x = (int)(Math.random()*800);
		int y = (int)(Math.random()*800);
		actors.add(new Rect(x,y,this));
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		for(Rect r:actors){
			r.paintRect(g);
		}
	}
	
	
	
}

class Rect extends Rectangle{
	
	private static final long	serialVersionUID	= 1L;
	
	int dx;
	int dy;
	Stress parent;
	boolean remove = false;
	
	public Rect(int x, int y, Stress s){
		super(x,y,10,10);
		parent = s;
		dx = (int) (Math.random()*5);
		dy = (int) (Math.random()*5);
		
		if(dx==0){
			dx=1;
		}
		if(dy==0){
			dy=1;
		}
	}
	
	public void move(){
	  x+= dx;
	  y+= dy;
	}
	
	public void doLogic(){
		if(x>parent.getWidth()){
			remove = true;
		}
		if(y>parent.getHeight()){
			remove = true;
		}
	}
	
	public void paintRect(Graphics g){
		Graphics2D g2 = (Graphics2D) g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setColor(Color.BLUE);
		g2.drawRect(x, y, width, height);
	}
	
}

Das sollte man ja lösen können. Ich probiere mal ein bißchen rum.
 

Quaxli

Top Contributor
So, es scheint eine einfache Lösung zu geben:

Statt mit einer for-each-Schleife iteriere ich "manuell" über den Vector. Für die move-Methode z. B. so.:

Java:
			//Move - alles bewegen
			for(int i=0;i<actors.size();i++){
				Rect r = actors.elementAt(i);
				r.move();
			}

Damit ist die ConcurrentModificationException bei mir nicht mehr aufgetreten. Wäre nett, wenn das nochmal jemand auf anderen Rechnern überprüfen könnte.

Ich habe bei der Suche nach Hinweisen auch einen Thread im Forum von eRaaaa gefunden: http://www.java-forum.org/entwuerfe/109419-fail-fast-iterator-concurrentmodificationexception.html

Dort steht noch einmal schön verständlich, was man auch mit Hilfe von Google auf diversen Seiten findet. Das einzige was meiner Ansicht nach nicht paßt, ist dort im Thread der Lösungsvorschlag 1. Denn das ist ja genau das, was mein Testprogramm macht: Alle zu entfernenden Objekte in einer Collection merken und erst entfernen, nachdem man der aktuelle Iterator beendet wurde.

Da muß ich noch mal ein bißchen suchen. Evtl. greift hier Marcos Vermutung, daß die Anzahl der Kerne relevant ist? :bahnhof:
Mein Rechner hier hat 4 Kerne (Intel i5). Hat noch jemand einen Einkern-Rechner irgendwo laufen und kann das mal gegen prüfen? Ich hab' meinen leider vor einem halben Jahr weggeschmissen, nachdem ich zuhause mal wieder aufgerüstet habe.
 

Marco13

Top Contributor
Eigentlich meinte ich den "Stresstest" möglichst ähnlich dem, wie es im Tutorial beschrieben wurde.

An sich ist die Ursache für die ConcurrentModificationException ja klar: Eine Collection wird verändert, während drüberiteriert wird. Das "manuelle" Drüberiterieren bewirkt zwar, dass keine ConcurrentModificationException mehr geworfen wird, aber es besteht weiterhin das Problem, das durch die CME angedeutet werden sollte. (Die CME dient ja nur dem Zweck, möglichst früh zu sagen: "Oiii, da stimmt was nicht", statt dass später (noch) "undeterministische(re)s" Verhalten auftritt).

Das eigentliche Problem ist beim manuellen Drüberiterieren nur "verlagert". Wenn ein Thread diesen Code abarbeitet....
Java:
for(int i=0;i<actors.size();i++){   // Hier ist actors.size()==3, und irgendwann i==2

    // Hier funkt ein anderer Thread dazwischen, und entfernt etwas aus 'actors'
    // Jetzt ist actors.size()==2 und i==2
 
    Rect r = actors.elementAt(i); // Und dann kracht's hier
    r.move();
}
Das tritt natürlich "seltener" auf, als die CME (und vielleicht auch "gar nicht" (reproduzierbar)), aber es KANN auftreten.

Eigentlich sollte die CME verhindert werden, indem man das drüberiterieren in einen synchronized-Block packt (zusammen mit einer synchronized Collection, wie eben Vector)
Java:
synchronized (actors)
{
    for (Rect rect : actors)  { .... }
}
In anderen Threads zu diesem Thema hatte ich das auch schon erwähnt, dort wurde aber dann gesagt, dass es langsamer wird und ruckelt. Klar, das kann sein - dann kann man sich eben noch andere Sachen überlegen, wie die Liste zu Kopieren und über die Kopie zu iterieren, oder eine CopyOnWriteArrayList verwenden (was in diesem Fall aber beides potentiell ineffizient wäre). Ich werd' mal schauen, ob ich den "Stresstest" bei Gelegenheit näher ansehen kann...
 

Quaxli

Top Contributor
Das unten ist möglichst ähnlich.... :)
Das grobe Konzept ist das Gleiche. Es sind ein paar Methoden weniger, es ist nicht schön programmiert, die doLogic- und Move-Methoden sind sehr simpel, ABER: das "Konstrukt" mit Vectoren, GameLoop und paintComponent, Thread, etc. ist das Gleiche.
Nach meinem Dafürhalten ausreichend, um den Fehler finden zu können. ;) Vor allem nachdem sofort eine ConcurrentModification geworfen wird. ;)

Ja, das mit dem synchronized hatten wir schon mal und haben es damals verworfen, weil es das Ganze ausbremst. Ich suche hier zugegebenermaßen noch nach einem goldenen Mittelweg, der mir noch nicht recht klar ist. Es handelt sich um ein Anfänger-Tutorial und ich würde es gern möglichst simpel halten, da ich davon ausgehe, daß es auch von Leuten gelesen wird, die gerade mal ein Fenster mit Swing gebastelt haben.
Ob das ein guter Ansatz ist, darüber läßt sich sicherlich streiten, ich bin da selbst unentschlossen. Ursprüngliche Absicht war ja mal, Spieleprogrammierung mit JLabels und JPanels zu verhindern. Es sollte bei einem möglichst geringen Umfang bleiben und nicht vom 100sten ins 1000ste führen. Andererseits IST es ein potentielle Fehlerquelle, die man den Lesern bewußt machen sollte.

Ich muß mir wohl mal wieder richtig Zeit für das Thema nehmen und nicht immer nur mal gucken, wenn jemand aufschreit. :autsch:
 

Quaxli

Top Contributor
Nachtrag:

Wie es scheint, könnte es eine einfache Lösung geben. Ich muß mir die nochmal ansehen, aber folgendes Konzept sieht bis jetzt gut aus:

1. Zum Iterieren über den Vector ausschließlich einen ListIterator verwenden.
2. Objekte hinzufügen/entfernen ebenfalls nur über ListIterator
3. Zum Zeichnen eine Kopie des Vectors mit clone() anlegen und diese verwenden.

Somit wäre zum Zeichnen eine Kopie des Vectors zum Zeitpunkt x da, über die man "in Ruhe" iterieren kann, während Änderungen am Vector nur im GameLoop vorgenommen werden und dort auch nur über die Methoden des Iterators. Das sieht soweit gut aus.

Falls jetzt jemandem ein dickes ABER einfällt, laßt es mich wissen. :)
 

Marco13

Top Contributor
AAABER... ;) Vector ist schon synchronized, d.h. eigentlich sollte man die Änderungen auch direkt (ohne Iterator) machen können, sofern das Drüberiterieren von einem anderen Thread entweder innerhalb eines synchronized-blocks oder NUR über die Kopie gemacht wird. (Abgesehen davon erschließt sich mir (noch) nicht 100%ig, warum ein ListIterator da grundsätzlich helfen sollte). Es gibt schon einen Tradeoff: Wenn man sich vorstellt, dass der Vector erstmal 100000 Elemente enthält, dann wird ein clone() ggf. schon ziemlich teuer (und evtl. teurer als ein synchronized).
 

jannig10

Mitglied
also Jungs danke dass ihr eure Ideen hier geäußert habt!

also ich hab nicht viel verstanden, bin ich ganz ehrlich =)
ich dnke mal das problem taucht bei mir hier auf :

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

wenn dort das problem sein sollte, wir würdet ihr das denn umschreiben?
macht dann mal bitte ein beispiel damit.
 

Quaxli

Top Contributor
Du nun wieder - ich hab's gewußt. ;) Welcher Anfänger will 100.000 Elemente bewegen. ;)
Soll ja kein Partikelsystem werden. :D

Mal im Ernst, was mich zu dieser Lösung bewogen hat:

Auszug aus der API zu ConcurrentModifikationException:
...Note that this exception does not always indicate that an object has been concurrently modified by a different thread. If a single thread issues a sequence of method invocations that violates the contract of an object, the object may throw this exception. For example, if a thread modifies a collection directly while it is iterating over the collection with a fail-fast iterator, the iterator will throw this exception.....

Der letzte Satz hat mich bewogen, die Lösung mit den Iteratoren auszuprobieren: Keine direkte Modifikation mehr, sondern nur noch über Iterator. Insbesondere da die Exception bei mir immer innerhalb eines Threads geworfen wurde.

azu noch folgender Satz aus der Beschreibung für Vector:
...The Iterators returned by Vector's iterator and listIterator methods are fail-fast: if the Vector is structurally modified at any time after the Iterator is created, in any way except through the Iterator's own remove or add methods, the Iterator will throw a ConcurrentModificationException...

Ich vermute mal, daß for-each so zugreift (sicher bin ich nicht, ich hab keinen Hinweis gefunden) und deswegen immer wieder mal die Exception geworfen wurde, wenn man zusätzlich noch am Vector rumgefummelt hat. Insofern könnte der Verzicht auf for-each in der ersten Version schon das Problem gelöst haben, wenn Vector synchronized ist.
Die jetztige Version gefällt mir aber noch ein bißchen besser.

Letzten Endes setzt sie das um, was eRaaaa mal gepostet hat (vgl. Lösungsmöglichkeit 3 und 4). Den gleichen Text habe ich auch nochmal auf englisch gefunden.

Im Folgenden mal das umgebaute Programm. Das hat auch noch mit 200.000 Rechtecken funktioniert. Die FPS waren runter auf um die 40 und geruckelt hat es auch ein bißchen. :D (Der Code für fps ist übrigens nicht mehr enthalten).
Auf Ressourcen-Verbrauch habe ich zugegebenermaßen nicht geachtet. :oops:

Java:
import javax.swing.*;
import java.awt.*;
import java.util.*;

public class Stress extends JPanel implements Runnable{

	private static final long	serialVersionUID	= 1L;
	JFrame frame;
	Vector<Rect> actors;
	Vector<Rect> painter;
	
	public static void main(String[] args){
		new Stress();
	}
	
	//Konstruktor. Vector füllen,  Fenster basteln, etc.
	public Stress(){
		setPreferredSize(new Dimension(800,800));
		
		actors = new Vector<Rect>();
		for(int i=0;i<200;i++){
      addNewRect();
		}
		
		frame = new JFrame("Stresstest");
		frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
		frame.setLocation(100,100);
		frame.add(this);
		frame.pack();
		frame.setVisible(true);
		
		Thread th = new Thread(this);
		th.start();
		
	}

	@SuppressWarnings("unchecked")
	public void run() {
		
		int count = 0;
		
		//GameLoop
		while(frame.isVisible()){
			
			//Jetzt iterieren über ListIterator - Veränderungen in diesem Thread nur darüber
			
			for(ListIterator<Rect> it = actors.listIterator();it.hasNext();){
				Rect r = it.next();
				r.move();
			}
			
			//Logic
			int n = 0; //Zähler, wieviel neue Objekte entfernt wurden und neu erzeugt werden sollen

			for(ListIterator<Rect> it = actors.listIterator();it.hasNext();){
				Rect r = it.next();
				r.doLogic();
				//Wenn boolen = true, wird das Objekt über den Iterator entfernt
				if(r.remove){
					it.remove();
					n++;
				}
			}
			
			//neue Objekte hinzufügen - auch in der Methode über einen Interator
			for(int i=0;i<n;i++){
				addNewRect();
			}
			
			//counter - ab und an noch ein Objekt rein packen
			count++;
			if(count==10){
        count=0;
				addNewRect();
			}
			
			
			//Clone - Eigenen Vector für's Zeichnen, der nicht verändert wird
			painter = (Vector<Rect>) actors.clone();
			
       try {
				Thread.sleep(10);
			} catch (InterruptedException e) {}			
			
			
			//Malen - irgendwann.....
			repaint();
			
		}
		
	}
	
	//neues Rechteck
	private void addNewRect(){
		//add ebenfalls über ListIterator
		ListIterator<Rect> it = actors.listIterator();
		int x = (int)(Math.random()*50);
		int y = (int)(Math.random()*50);
		it.add(new Rect(x,y,this));
	}

	@Override
	protected void paintComponent(Graphics g) {
		super.paintComponent(g);
		
		for(ListIterator<Rect> it = painter.listIterator();it.hasNext();){
			Rect r = it.next();
			r.paintRect(g);
		}
		
		g.setColor(Color.RED);
		g.drawString(Integer.toString(actors.size()), 600, 20);

	}
	
	
	
}

class Rect extends Rectangle{
	
	private static final long	serialVersionUID	= 1L;
	
	int dx;
	int dy;
	Stress parent;
	boolean remove = false;
	
	public Rect(int x, int y, Stress s){
		super(x,y,10,10);
		parent = s;
		dx = (int) (Math.random()*5);
		dy = (int) (Math.random()*5);
		
		if(dx==0){
			dx=1;
		}
		if(dy==0){
			dy=1;
		}
	}
	
	public void move(){
	  x+= dx;
	  y+= dy;
	}
	
	public void doLogic(){
		if(x>parent.getWidth()){
			remove = true;
		}
		if(y>parent.getHeight()){
			remove = true;
		}
	}
	
	public void paintRect(Graphics g){
		Graphics2D g2 = (Graphics2D) g;
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
		g2.setColor(Color.BLUE);
		g2.drawRect(x, y, width, height);
	}
	
}
 

Quaxli

Top Contributor
also Jungs danke dass ihr eure Ideen hier geäußert habt!

also ich hab nicht viel verstanden, bin ich ganz ehrlich =)
ich dnke mal das problem taucht bei mir hier auf :

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

wenn dort das problem sein sollte, wir würdet ihr das denn umschreiben?
macht dann mal bitte ein beispiel damit.

Das ist anhand einer einzigen Methode schlecht erklärt, da noch ein paar Änderungen mit rein spielen.

Schau Dir die beiden Beispiele an (vorher/nachher).
Beide Programme habe die Struktur des Tutorials, nur etwas einfacher, so daß z. B. an die move-Methode im Beispiel keine delta übergeben wird und die Berechnung sehr viel einfacher ist.

Dein Beispiel könnte z. B. so aussehen:

Java:
			for(ListIterator<Sprite> it = actors.listIterator();it.hasNext();){
				Sprite r = it.next();
				r.move(delta);
			}

Aber es wurde auch beim Zeichnen und beim Löschen nicht mehr benötigter Objekte etwas geändert.
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
F Spielprogrammierung , einbinden des Keyboards Spiele- und Multimedia-Programmierung 2
S spielprogrammierung für anfänger Spiele- und Multimedia-Programmierung 14
S Saubere Spielprogrammierung Spiele- und Multimedia-Programmierung 13
YangLee Ausgabe von einer Bewegung bei mehrzeiligen Strings Spiele- und Multimedia-Programmierung 1
D Arrays auf Bewegung prüfen (2048) Spiele- und Multimedia-Programmierung 1
Furtano Vektoren für Bewegung für eine 2D-Simulation Spiele- und Multimedia-Programmierung 3
K Bewegung falsch Spiele- und Multimedia-Programmierung 6
B Webcam Bewegung markieren Spiele- und Multimedia-Programmierung 3
R Asteroid unschöne Bewegung Spiele- und Multimedia-Programmierung 13
G Bewegung eines Grafikobjektes Spiele- und Multimedia-Programmierung 7
F Probleme bei Bewegung Spiele- und Multimedia-Programmierung 7
T Flüssige Bewegung Spiele- und Multimedia-Programmierung 7
U Freie Bewegung Realisierung Spiele- und Multimedia-Programmierung 13
M Bomberman: Bewegung der Spielfigur in windows viel schneller Spiele- und Multimedia-Programmierung 12
F Brauche Hilfe bei Bewegung eines Rechtecks [Applet] Spiele- und Multimedia-Programmierung 5
F Bewegung/Kollision von Objekten auf Tastendruck Spiele- und Multimedia-Programmierung 6
B Kollision Spiele- und Multimedia-Programmierung 5
A Kollision funktioniert nicht richtig bei zu schneller Geschwindigkeit des Spielers Spiele- und Multimedia-Programmierung 0
N Kollision von zwei ImageIcons Spiele- und Multimedia-Programmierung 8
D Kollision funktioniert unten aber nicht oben Spiele- und Multimedia-Programmierung 4
J Kollision (libgdx) Spiele- und Multimedia-Programmierung 2
S Kollision Spiele- und Multimedia-Programmierung 2
J Kollision genau erkennen mit intersects Spiele- und Multimedia-Programmierung 27
K a* kollision der einheiten Spiele- und Multimedia-Programmierung 3
S Probleme bei Breakout - Brick kollision Spiele- und Multimedia-Programmierung 2
F Rechteck Kollision Spiele- und Multimedia-Programmierung 10
H 2- D Kollision Spiele- und Multimedia-Programmierung 14
C Zeldaklon Problem mit Wand-Kollision Spiele- und Multimedia-Programmierung 8
O Kollision Polygon und Rechteck Spiele- und Multimedia-Programmierung 2
S Pacman Kollision von Münzen und Mauern Spiele- und Multimedia-Programmierung 11
P Gridpane Kollision Spiele- und Multimedia-Programmierung 3
Androbin Kollision zwischen Raster und Nicht-Raster Spiele- und Multimedia-Programmierung 2
L Kollision soll nur an oberer Seite (Breite) möglich sein Spiele- und Multimedia-Programmierung 6
Hercules Kisten Kollision Spiele- und Multimedia-Programmierung 2
S 3D-Kollision mit zwei ArrayLists Spiele- und Multimedia-Programmierung 7
T Pixelgenaue Kollision Spiele- und Multimedia-Programmierung 5
A LWJGL 3D Objekte Kollision Spiele- und Multimedia-Programmierung 3
S Kollision tile-based 2D Plattformer Spiele- und Multimedia-Programmierung 2
D Greenfoot Kollision Spiele- und Multimedia-Programmierung 5
D Kollision verhindern Spiele- und Multimedia-Programmierung 2
R Frage zur Kollision Spiele- und Multimedia-Programmierung 5
Maxim6394 [Java3D] Probleme bei Kollision Spiele- und Multimedia-Programmierung 7
Kr0e Kollision zweier Kugeln... Wo ist Newton ?? Spiele- und Multimedia-Programmierung 9
C Kollision zwischen 2 Kreisen Spiele- und Multimedia-Programmierung 3
Helgon Kollision von jeder Seite des Blocks Spiele- und Multimedia-Programmierung 3
Fab1 Kollision die 100ste Spiele- und Multimedia-Programmierung 5
D Jump'n'run Kollision bei Blöcken Spiele- und Multimedia-Programmierung 10
P PingPong Spiel - Kollision Spiele- und Multimedia-Programmierung 2
C Bitmaske und Kollision Spiele- und Multimedia-Programmierung 2
S Kollision Kreis Rechteck Spiele- und Multimedia-Programmierung 8
aze Java3D: Gegenstände aufeinander zubewegen ohne Kollision Spiele- und Multimedia-Programmierung 4
baddestpoet pixelgenaue Kollision Spiele- und Multimedia-Programmierung 4
S Kollision in 2D Spiele- und Multimedia-Programmierung 12
B Gedrehte Rechtecke Kollision Spiele- und Multimedia-Programmierung 4
J Kollision mit Block (Wand) Spiele- und Multimedia-Programmierung 11
C Kollision in Java3D Spiele- und Multimedia-Programmierung 4
J Kollision von Objekten Spiele- und Multimedia-Programmierung 7
M Asteroids Clone: Kollision zwischen Schuss und Feind Spiele- und Multimedia-Programmierung 13
Z Kollision Spiele- und Multimedia-Programmierung 3
F Kollision für Arkanoid Spiele- und Multimedia-Programmierung 2
N Kollision abfragen Spiele- und Multimedia-Programmierung 3
K Sprites / Kollision Spiele- und Multimedia-Programmierung 3
S Jump'n'Run: Probleme mit Kollision Spiele- und Multimedia-Programmierung 13

Ähnliche Java Themen


Oben