Spieleprogrammierung

Status
Nicht offen für weitere Antworten.

Paladin

Bekanntes Mitglied
Hi,

ich bin gerade dabei mich in die Spieleprogrammierung in Java einzuarbeiten. Als Übung will ich ein kleines 2D Spiel á la TeacherBusters (C64) schreiben. Bei dem genannten Spiel fährt der Spieler mit einem kleinen Panzer durch
eine horizontal/vertikal scrollende Welt.

Meine Frage ist jetzt welche API sich am besten für die Umsetzung eines solchen Projekts eignet. Ich habe schon ein wenig mit swing und swt rumprobiert aber hatte das Gefühl, dass dies nicht die optimale Lösung ist. JOGL oder LWJGL scheint für diese Art von Spiel passend zu sein. Gibt es noch andere die für ein solches Projekt noch besser geeignet sind? Was ist mit Java2D? Wäre Java2D für mein Projekt noch besser geeignet als JOGL/LWJGL?
Hat jemand Erfahrungen wie schwer es ist sich in diese APIs einzuarbeiten? Zumindestens LWJGL (JOGL und Java2D kenne ich noch nicht) ist für einen Anfänger der Spieleentwicklung nicht gerade leicht zu handhaben.

Vielen Dank im voraus.

Gruß

Paladin
 

LoN_Nemesis

Bekanntes Mitglied
Ich weiss nicht, aber wenn du es nicht super komplex machen willst, dann halte ich die Benutzung von OpenGL für Overkill. Für solch ein einfaches 2D Spiel reicht locker auch Java2D. Dabei ist Einarbeitungszeit auch recht gering, wenn man schon allgemeine Java bzw Programmierkenntnisse hat.
 

Campino

Top Contributor
Java2D. Das baut im Übrigen auf Swing auf ;) Also eigentlich Java2D mit Swing. Was hattest du den für Probleme?
 
G

Guest

Gast
Mein Problem mit Swing war, dass mein Testszenario schon mit relativ wenigen Sprites arg geruckelt hat. Wie schon gesagt bin ich was Spieleentwicklung angeht noch ein Anfänger also nehme ich mal an, dass mein code nicht optimal
war. Aber ein so kleines Programm sollte meiner Meinung nach eben auch mit schlechtem Code gut laufen.
 

Wildcard

Top Contributor
Anonymous hat gesagt.:
Aber ein so kleines Programm sollte meiner Meinung nach eben auch mit schlechtem Code gut laufen.
Das stimmt so einfach nicht. Swing ist ein extrem leistungsfähiges Toolkit wird von weniger erfahrenen Entwicklern aber fast immer falsch benutzt.
 

LoN_Nemesis

Bekanntes Mitglied
Wenn du mal den "schlechten Code" postest können wir dir höchstwahrscheinlich sagen wo das Problem liegt. An Java2D/Swing jedenfalls nicht. Wie gesagt sollte es für dein Problem sehr angemessen und locker ausreichend sein.
 

Paladin

Bekanntes Mitglied
Also in meinem Beispielprogramm gibt es nur ein Gebäude und ein Fahrzeug. Das Fahrzeug sollte sich mit den Cursortasten links und rechts drehen lassen und mit der Cursortaste Hoch in die entsprechende Richtung fahren.
Das Problem ist jetzt, dass der Bildschirm bei der Darstellung extrem flimmert was höchstwahrscheinlich an der
paint() Methode liegt. Ich nehme an, dass ich das Problem mit dem flimmern durch Double Buffering in den Griff
bekommen könnte aber der Versuch das in meine Paint Methode einzubauen war wenig erfolgreich - daher arbeite
ich zur Zeit auch wieder mit der alten paint Methode.

Und die sieht so aus:

Code:
public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
				
    AffineTransform trans_org = new AffineTransform();
    AffineTransform trans = new AffineTransform();
    
    //amucity_lower = BufferedImage    Die Plattform auf der das Gebäude steht
    //acd = Die Klasse AmuCityData welche die Gebäudedaten enthält		
    g2.drawImage(amucity_lower, (int)acd.getXpos(), (int)acd.getYpos(),this);

    //td = Die Klasse TankData welche alle Daten zu dem Fahrzeug enthält				
    trans.translate((int)td.getXAxis(), (int)td.getYAxis());
    trans.rotate((int)td.getRotation());
    trans.translate((int)-td.getXAxis(), (int)-td.getYAxis());
    g2.setTransform(trans);
		
    //tank_solo = BufferedImage    Das Fahrzeug
    g2.drawImage(tank_solo, (int)td.getXpos(), (int)td.getYpos(),this);

    g2.setTransform(trans_org);
		
    //amucity_upper = BufferedImage    Das Gebäude
    g2.drawImage(amucity_upper, (int)acd.getXpos()+acd.getCeilingCorrection_x(), (int)acd.getYpos()
        +acd.getCeilingCorrection_y(),this);
    
}

Neben der Klasse paint gibt es noch einen Thread welcher den Screen dauernd neuzeichnet.
Dieser sieht so aus.

Code:
class painter implements Runnable {

    public void run() {
			
        while(true) {
		
	if(td.getSpeed()!=0) {
	    tank_x_delta = (Math.cos(td.getRotation()/58)*td.getSpeed());
	    tank_y_delta = (Math.sin(td.getRotation()/58)*td.getSpeed());
				
	    if(checkCollision(tank_x_delta,tank_y_delta)==false) { 
	        if(((td.getXpos()+tank_x_delta) > 500)||((td.getXpos()+tank_x_delta) < 200)||((td.getYpos()
                                +tank_y_delta) > 500)||((td.getYpos()+tank_y_delta) < 200)) {
	            acd.setXpos(-tank_x_delta);
	            acd.setYpos(-tank_y_delta);
	        }
	    else {
	        td.setXpos(tank_x_delta);
	        td.setYpos(tank_y_delta);
	    }
                }
            }
            if(td.isBrake()) {
	if(td.getSpeed()>0) td.setSpeed(-0.01);
	else td.setBrake(false);
            }
            try {
                Thread.sleep(20);
            } catch (InterruptedException e) {
	e.printStackTrace();
            }
            
            repaint();
				
        }
    }
}

Ich habe jetzt bewusst darauf verzichtet die Methoden für Fensterbau, Keylistener und laden der Bilder
darzustellen weil ich denke, dass der Fehler schon bei den beiden oberen Methoden liegt.
 

Campino

Top Contributor
Versuch mal alles erst in ein BufferedImage zu zeichnen und das dann auf den Bildschirm, manchmal hilft das. Dann kommt mir der sleep relativ klein vor.
 

Paladin

Bekanntes Mitglied
Ich habe die paint() Funktion jetzt wie folgt abgeändert aber es macht keinen Unterschied:

Code:
public void paint(Graphics g) {
    Graphics2D g2 = (Graphics2D) g;
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);

    //buffer = Graphics2D
    //offscreen = BufferedImage		
    buffer = (Graphics2D) offscreen.getGraphics();
				
    buffer.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
			
    AffineTransform trans_org = new AffineTransform();
    AffineTransform trans = new AffineTransform();
		
    buffer.drawImage(amucity_lower, (int)acd.getXpos(), (int)acd.getYpos(),this);
					
    trans.translate((int)td.getXAxis(), (int)td.getYAxis());
    trans.rotate((int)td.getRotation());
    trans.translate((int)-td.getXAxis(), (int)-td.getYAxis());
    buffer.setTransform(trans);
		
    buffer.drawImage(tank_solo, (int)td.getXpos(), (int)td.getYpos(),this);

    buffer.setTransform(trans_org);
				
    buffer.drawImage(amucity_upper, (int)acd.getXpos()+acd.getCeilingCorrection_x(), (int)acd.getYpos()
            +acd.getCeilingCorrection_y(),this);
    buffer.drawString("Rotation=" + td.getRotation(),10,10);
		
    g2.drawImage(offscreen, 0, 0, this);
}
 

Paladin

Bekanntes Mitglied
Hi EgonOlsen,

vielen Dank für deine Hilfe!
Die Lösung meines Problems heisst BufferStrategy. :D

Um das Problem zu lösen habe ich das folgende getan:

1.) Methode paint() und update() wie folgt überschreiben:

Code:
    public void paint(Graphics g) {}

    public void update(Graphics g) {}

2.) Eigene paint Methode schreiben in welcher BufferStrategy genutzt wird.
Die eigene paint Methode wird vom Timer dann immer wieder aufgerufen.

Code:
    public void myUpdate() {
				
    g2 = (Graphics2D) bufstrat.getDrawGraphics();
    g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
					
    AffineTransform trans_org = new AffineTransform();
    AffineTransform trans = new AffineTransform();
		
    g2.drawImage(amucity_lower, (int)acd.getXpos(), (int)acd.getYpos(),this);
					
    trans.translate((int)td.getXAxis(), (int)td.getYAxis());
    trans.rotate((int)td.getRotation());
    trans.translate((int)-td.getXAxis(), (int)-td.getYAxis());
    g2.setTransform(trans);
		
    g2.drawImage(tank_solo, (int)td.getXpos(), (int)td.getYpos(),this);

    g2.setTransform(trans_org);
				
    g2.drawImage(amucity_upper, (int)acd.getXpos()+acd.getCeilingCorrection_x(), (int)acd.getYpos()
            +acd.getCeilingCorrection_y(),this);
    		
    bufstrat.show();		
		
}

3.) BufferStrategy nach der Erstellung der GUI und start des Timers initialisieren:

Code:
public Main_Swing() {
    loadImages();                                             //Grafiken für das Spiel laden
    timer = new Thread(new painter());              //Timer initialisieren
    timer.setPriority(Thread.MIN_PRIORITY);
    buildGUI();                                                  //GUI bauen
    timer.start();                                               //Timer starten
    super.createBufferStrategy(2);                     
    bufstrat = super.getBufferStrategy();            //BufferStrategy initialisieren
}

Gruß

Paladin
 
Status
Nicht offen für weitere Antworten.

Neue Themen


Oben