# 2D Welt bewegen



## GeRrItK. (8. Mai 2011)

Hallo Leute,

ich habe meinen Fahrsimulator nun soweit ausgebaut das eine Textur als Untergrund vorhanden ist. Auf dieser Textur sind Straßen eingezeichnet. Dann habe ich eine weitere Textur, auf der Bäume oder andere Gegenstände eingezeichnet sind, welche beim durchfahren über dem Auto sein sollen. Unter der Bodentextur befinden sich 2 weitere Texturen. Einmal eine "crashMap", auf der Hindernisse eingezeichnet sind und einmal eine "grasMap" auf der Grasflächen makiert sind, auf der das Auto langsamer fährt. 

Erste Frage:
Habt ihr Tipps womit ich die beiden EigenschaftenMaps auf eine zusammenpacken kann?
Das erkennen funktioniert derzeit mit der Pixelgenauen Kollision von Quaxli. Kann man da iwie mit unterschiedlichen Farbtönen arbeiten?

Zweite Frage:
Wie mache ich es, dass das Auto auf der Map fährt und die Map sich bewegt?
Also die Karte größer sein kann als das Fenster an sich. Mein Ansatz war jetzt die Map anstatt dem Auto zu bewegen. Dies macht aber bei meinen 4 Maps iwie nicht soviel Sinn und schluckt einiges an Performance. (60FPS statt vorher 100FPS) Die Maps bewegen sich auch nicht 100% übereinander. An den Rändern sieht man z.B. das eine Map unter der anderen hervor schaut.

Dritte Frage:
Ich habe oben am Framerand über DrawString Text eingeblendet, welcher die Steuerung erklärt. Allerdings verschwindet der Text unter der Map wenn ich sie bewege. Wie kann ich den Text OnTop setzen?

Ich hoffe auf hilfreiche Antworten.

Gruß,
Gerrit


----------



## Fu3L (8. Mai 2011)

Den Text setzt du oben drauf, indem du ihn ganz zum Schluss in paintComponent() schreiben lässt. Des weiteren brauchst du nur 2 der 4 Maps zeichnen. Die anderen beiden (bzw. eine, wenn du einfach verschieden Farben festlegst) brauchst du nicht zu zeichnen, nur mitbewegen. Die Kontrolle findet ja unabhängig vom Gezeichneten statt. (Vorrausgesetzt du trennst die Logik vom Zeichnen, wie in Quaxlies Tutorial).
Wenn du für alle Maps den gleichen Code (im Logikteil) aufrufst, müsste doch auch die Verschiebung gleich laufen und immer deckungsgleich sein oder nicht? Aners als durch Verschieben von Kartenausschnitten wirst du das wohl nicht lösen können, wenn das Auto immer in der Mitte des Bildes bleiben soll (was ja dein ziel ist).


----------



## GeRrItK. (8. Mai 2011)

Naja Problem ist, dass der Text schon beim starten gezeichnet wird. Die Karte etc. wird erst beim Drücken von Enter gezeichnet und auch nicht in der Paint Methode sondern über eine weitere Methode.

Naja die Verschiebung ist ja auch gleich aber es guckt ab und zu immer minimal nen Stück an der Seite hervor wenn ich das Auto bewege.

Wie kann ich denn in den Collisions abhängig von Farbe arbeiten?!

EDIT: In wie fern denn nicht zeichnen? Also das sieht bei mir so aus:

```
private void createTerrain() {
		world = new Vector<Sprite>();
		painterW = new Vector<Sprite>();
		tgras = new TGras(gras, 0, 10, 100, this);
		tstreet = new TStreet(streets, 0, 10, 100, this);
		tcrashmap = new crashMap(crashmap, 0, 10, 100, this);
		tvegetation = new TVegetation(vegetation, 0, 10, 100, this);
		
		world.add(tgras);
		world.add(tcrashmap);
		world.add(tstreet);
		actors.add(tvegetation);
	}
```

EDIT²: Hab jetzt in der Klasse in der DrawMethode einfach den Befehl zum Zeichnen rausgenommen. Die Map wird auch nicht mehr gezeichnet allerdings sind die FPS immernoch bei 60.


----------



## Fu3L (8. Mai 2011)

GeRrItK. hat gesagt.:


> Naja Problem ist, dass der Text schon beim starten gezeichnet wird. Die Karte etc. wird erst beim Drücken von Enter gezeichnet und auch nicht in der Paint Methode sondern über eine weitere Methode.
> 
> Naja die Verschiebung ist ja auch gleich aber es guckt ab und zu immer minimal nen Stück an der Seite hervor wenn ich das Auto bewege.
> 
> ...



Also bezüglich der Schattenmaps mit Farben siehe Quaxlies Tutorial Seite 138ff.^^ 
Das davor sollte auch Aufschluss geben, wie man eine Karte bewegen kann. Du musst ja sowieso noch in die Logikmethode eine Funktion zum Bewegen der Karten einfügen. In paintComponent() sollten nur noch die zu zeichnenden Bilder von den Objekten abgefragt werden, bzw. eine Methode paintMap(g); aufgerufen werden, damit die einzelne Karte intern das Zeichnen übernimmt.
Die meisten deiner Fragen sollten wirklich in dem Tutorial beantwortet werden. Wenn dann noch etwas unklar ist, frage dann etwas konkreter.

Die Methode zum zeichnen des Textes kannst du ja des öfteren ruhig aufrufen^^


----------



## GeRrItK. (8. Mai 2011)

Okay. Der Header bleibt schonmal oben drüber  Hat eben gerade klick gemacht. immer wieder dran vorbei geschaut 

Die FPS sind leider immernoch bei nur 60FPS :S Werd mir das Tuto nochmal durchlesen

Danke schonmal


----------



## GeRrItK. (8. Mai 2011)

So.. Hab jetzt nen Problem mit der Farberkennung. Ich habe die Opaque Methoden kopiert und für Rot ausgelegt. 


```
protected boolean isRed(int rgb) {
		int red = (rgb >> 16) & 0xff;
		
		if(red == 0) {
			return true;
		}
		
		return false;
	}
```

Wenn ich über schwarz fahre dann werde ich langsamer, wie gewollt. Wenn ich über Rot fahre passiert aber nix. das Auto explodiert nicht.


----------



## Fu3L (9. Mai 2011)

Mit diesen Bitverschiebungen bin ich leider nie besonders warm geworden und nutze sie dementsprechend nie (auch wenn ich es mir mal aneignen sollte^^). Übergib doch rgb an ein Color-Objekt und prüfe 
	
	
	
	





```
if(new Color(rgb).equals(Color.RED))
```

Edit: An der Performance wird das nichts oder fast unmerkbar wenig ändern, weil du pro Frame ja nur ein paar solcher Vergleiche führen musst^^


----------



## Marco13 (9. Mai 2011)

Letzeres dürfte SEHR ineffizient sein, und prüft auch nur, ob die Farbe GENAU Rot ist (und nicht, ob sie einen vollkomment roten Rotanteil hat). 

@GeRrItK: Wenn du zu dem letzten Codeschnipsel ein KSKB posten würdest, würde es wahrscheinlich funktionieren  Debug-Ausgaben oder ein Debugger-Durchlauf könnten helfen...


----------



## Fu3L (9. Mai 2011)

Marco13 hat gesagt.:


> Letzeres dürfte SEHR ineffizient sein, und prüft auch nur, ob die Farbe GENAU Rot ist (und nicht, ob sie einen vollkomment roten Rotanteil hat).
> 
> @GeRrItK: Wenn du zu dem letzten Codeschnipsel ein KSKB posten würdest, würde es wahrscheinlich funktionieren  Debug-Ausgaben oder ein Debugger-Durchlauf könnten helfen...



Danke für die beiden Hinweise.

Die Zeile etwas abgewandelt, würde aber zumindest vom Sinn her das gleiche bedeuten, oder?

```
if(new Color(rgb).getRed() == 255)
```
Dann könnte sie zumindest zum Test herhalten, ob es an der Methode oder an anderer Stelle liegt, dass es nicht funktioniert bzw. zeigen, dass es woanders dran hapern muss, wenn ich den zweiten Satz richtig verstanden habe^^


----------



## Marco13 (9. Mai 2011)

Ja, das wäre dann wohl das gleiche. Dass dort immernoch ein Color-Objekt erzeugt wird, wäre für einen ersten Test vielleicht egal.


----------



## Kr0e (9. Mai 2011)

@Marco13:

Ich glaube du überschätzt etwas die Kosten, die die Erstellugn eines neuen Objektes verursacht. Es ist klar, dass das nich unbedingt die optimale Lösung ist, aber normalerweise hat soetwas kaum Einfluss auf die Endperformance, davon abgesehen nutzt er sowieso Java2D, wodurch die Flaschenhälse eh woanders liegen.. nämlcih beim zeichnen ...

Die JVM optimiert ja sowieso intern endlos viel, damit solche Sachen dann hinther kaum Einfluss haben...


----------



## GeRrItK. (9. Mai 2011)

Das ganze Funktioniert iwie nicht. Wenn ich über Rot fahre explodiert es nicht. Wenn ich über Schwarz fahre wird er langsamer. Wenn ich über Transparent fahre fährt er normal. Und manchmal (auf unerklärliche Weise) explodiert es dann iwie auf der Map.


----------



## Marco13 (9. Mai 2011)

Naja, je nach Anwendungsfall kann es da schon nicht um "ein paar Prozent" sondern um Facktor 4 oder so gehen...

```
import java.awt.Color;
import java.util.Random;

public class ColorBench
{
    public static void main(String[] args)
    {
        Random random = new Random(0);
        
        for (int s=5000; s<=8000; s+=500)
        {
            int colors[] = new int[s*s];
            for (int x=0; x<colors.length; x++)
            {
                int rgb = random.nextInt();
                colors[x] = rgb;
            }
            long before = 0;
            long after = 0;

            before = System.nanoTime();
            int countA = countA(colors);
            after = System.nanoTime();
            System.out.println("countA "+countA+" for size "+s+" time "+((after-before)/1e9));

            before = System.nanoTime();
            int countB = countB(colors);
            after = System.nanoTime();
            System.out.println("countB "+countB+" for size "+s+" time "+((after-before)/1e9));
            
        }
    }
    
    private static int countA(int colors[])
    {
        int count = 0;
        for (int x=0; x<colors.length; x++)
        {
            int rgb = colors[x];
            if(new Color(rgb).getRed() > 128)
            {
                count++;
            }
        }
        return count;
    }

    private static int countB(int colors[])
    {
        int count = 0;
        for (int x=0; x<colors.length; x++)
        {
            int rgb = colors[x];
            if(getRed(rgb) > 128)
            {
                count++;
            }
        }
        return count;
    }

    private static int getRed(int rgb)
    {
        return (rgb >> 16) & 0xFF;
    }
    
    
}
```

Wenn man das ganze aber auf einem BufferedImage macht und sich die Pixel mit getRGB(x,y) abholt, ist der Check und die Umwandlung mit ColorModel & Co so aufwändig, dass es wirklich nicht mehr viel ausmacht.


----------



## Marco13 (9. Mai 2011)

Sow ie du es zuletzt gepostet hast, war es auch gerade falschrum: 

```
if(red == 0) {
            return true;
        }
```
-> Wenn es NICHT Rot ist, gib 'true' zurück.


----------



## GeRrItK. (9. Mai 2011)

Also ich habe jetzt wieder 2 unterschiedliche Maps. Es funktioniert wieder so wie es soll und ich bekomme genausoviele FPS wie nur mit 3 Maps. 

Ich weiß immernoch nicht wie ich die Performance optimieren kann. Hilft es wenn ich statt PNG GIF nehme als Grafikformat?!

EDIT: Also auf meinem Netbook 2x 1.5GHz läuft das Spiel gerade mal mit 20-30FPS. Auf meinem Desktop PC mit nem Quadcore mit 50-60FPS. CPU Auslastung bei 40%. Das kann doch nicht wirklich so rechenaufwendig sein


----------



## Fu3L (9. Mai 2011)

Ja, bei Bildern, die keine Transparenz erfordern, unbedingt auf png verzichten, das macht wirklich eine Menge aus.


----------



## GeRrItK. (9. Mai 2011)

Also die Maps (bis auf die Vegetation) hab ich jetzt als GIF. Geändert an der Performance hat sich komischerweise nix :S

Ein Problem, das ich gefunden habe ist z.B. Actors und World. Hab ja da zwei Vectoren erstellt, damit die Welt immer unten liegt und die Actors immer oben. Wenn ich nun meine Vegetation bei World einschreibe bekomme ich mehr FPS als wenn ich sie (gezwungenermaßen) bei Actors einschreibe, da sie ja über dem Auto liegen muss.

Gibts da iwelche anderen Wege?

EDIT: Eben festgestellt, wenn ich alle auf Actors setze ändert sich nix...


----------



## Marco13 (9. Mai 2011)

Vermutlich nicht. Am Ende ist beides ein BufferedImage, und der Aufwand für getRGB kann zwar je nach internem Format (ColorModel etc.) leicht unterschiedlich sein, aber vermutlich nicht soo sehr. Mir fehlt aber noch der Überlick, einzuschätzen, wo da wie viel Zeit verloren geht, und wie man das ggf. effizienter machen könnte...


EDIT: Da war ich etwas langsam - In Anlehung an Fu3Ls Aussage: Ob z.B. das BufferedImage ein TYPE_INT_RGB ist, wenn das PNG keine Transparenzen enthält (oder ob es immer RGBA ist) weiß ich nicht - aber gezeichnet werden die Bilder doch ohnehin nicht, oder? ???:L


----------



## GeRrItK. (9. Mai 2011)

Wenn jemand Zeit hätte könnte ich demjenigen mal meinen Source Ordner schicken. Vllt findet jemand erfahreneres ja eher Fehler als ich selbst?


----------



## Fu3L (9. Mai 2011)

Also ich habe damals hier einen Thread erstellt, weil mein Spiel alleine durch Zeichnen des Hintergrundbildes bei 60 FPs meinen Einkernprozessor (3 GHz) auslastete (PNG) und das ohne Transparenz! Nach Ändern in JPG liefs auf 20% Auslastung hinaus.
Deswegen würde ich Transparenz bei den Schattenmaps auf jeden Fall vermeiden (wenn du die immer noch zeichnen lässt^^)... 
Ob ein gif mit Transparenz schneller ist, kann ich ebenfalls nicht sagen.


----------



## GeRrItK. (9. Mai 2011)

Naja wenn mir jemand sagt wie ich bei den Schatten Maps die Transparenzerkennung auf Schwarz/Weiß umschreibe kann ich es ja mal versuchen :S Zudem muss die Schattenmap vom Fahrzeug Transparenz und von der Map Weiß/Schwarz erkennen.


----------

