# zwei ints als key in map (ohne long)



## Hm.... (10. Dez 2012)

Hallo,
ich würde gerne zu einem Koordinatenpaar eine id speichern. Das mache ich momentan,
indem ich die zwei Integer zu einem Long zusammen rechne und das ganze als key für eine Map benutz. 
	
	
	
	





```
#put((((long)x) << 32) | y, z);
```
Klappt wunderbar, gerne würde ich das ganze jetzt aber auf Android portieren und so weit ich weiß werden dort Fließkommazahlen nicht nativ von der Hardware unterstützt. Auch wollte ich wegen dem GC vermeiden, lauter 'Point' Objekte zu erstellen oder ähnliches. Mag mir einer einen Tipp geben wie ich das am besten angehe? Das ist für eine 2d tile map, die zu einer Koordinate eine tile id speichert.
MVG Hm...


----------



## TKausL (11. Dez 2012)

Was ich mich nun frage ist, was int und long mit Fließkommazahlen zutun haben...


----------



## Gonzo17 (11. Dez 2012)

Hm.... hat gesagt.:


> MVG Hm...



Und jetzt darf die wilde Spekulation darüber losgehen, was dieses ominöse 'V' bedeutet 

Ansonsten verstehe ich dein Problem nicht so richtig. Und ich verstehe ehrlich gesagt auch nicht so richtig, was das Stück Code da tut. Aber basierend auf der Aussage



Hm.... hat gesagt.:


> Das mache ich momentan,
> indem ich die zwei Integer zu einem Long zusammen rechne und das ganze als key für eine Map benutz



muss ich doch mal fragen - dir ist klar, dass die Koordinaten (1,2) und (2,1) nicht identisch sind, aber den gleichen Key in der Map haben? Warum verwendest du als Key nicht die Koordinaten-Objekte selbst? (was auch immer du da machen willst)


----------



## Landei (11. Dez 2012)

Gonzo17 hat gesagt.:


> Und jetzt darf die wilde Spekulation darüber losgehen, was dieses ominöse 'V' bedeutet


"Vreundlichen"



> muss ich doch mal fragen - dir ist klar, dass die Koordinaten (1,2) und (2,1) nicht identisch sind, aber den gleichen Key in der Map haben? Warum verwendest du als Key nicht die Koordinaten-Objekte selbst? (was auch immer du da machen willst)



In obigen Code werden die ja nicht einfach addiert, sondern mit Bitgeschubse aneinandergehängt - also schon eindeutig.

Einen besseren Rat als eine eigene "Punkt"-Klasse kann ich auch nicht geben (int-Arrays würden nicht funktionieren).


----------



## Gonzo17 (11. Dez 2012)

Landei hat gesagt.:


> In obigen Code werden die ja nicht einfach addiert, sondern mit Bitgeschubse aneinandergehängt - also schon eindeutig.



Ok, ich hab diese Zeile wie gesagt nicht verstanden, deswegen war mir nicht klar was genau getan wird. Aber meiner Meinung nach ist das nicht sonderlich schön und auch nicht gut nachzuvollziehen.


----------



## Spacerat (11. Dez 2012)

Hm.... hat gesagt.:


> ...Klappt wunderbar, gerne würde ich das ganze jetzt aber auf Android portieren...


Dann lass es wie es ist. Wird auf Android auch herforragend (tausche f gegen v :lol klappen, denn auch die Dalvik-VM kennt den Datentyp long und ihre Wrapperklasse und was nativ mit denen geschieht ist in jeder anderen VM ja auch völlig uninteressant (die VM macht das schon). Warum es also anders machen wollen?


----------



## schalentier (11. Dez 2012)

Gonzo17 hat gesagt.:


> Und jetzt darf die wilde Spekulation darüber losgehen, was dieses ominöse 'V' bedeutet



Mit vielen Gruessen?


----------



## Hm... (11. Dez 2012)

[OT]MVG = Mit vielen Grüßen[/OT]

Vielen dank erstmal für eure Ratschläge.
Leider habe ich das Gefühl, ist das Problem welches ich meine noch nicht ganz rüber gekommen.
Ich habe vereinfacht eine gesagt eine World classe mit den functionen:

```
public int getWidth();
public int getHeight();
public int setTile(int x, int y, byte id);
public byte getTile(int x, int y);
```

intern habe ich eine Map, die die tiles auf diese weise speichert:

```
tiles.put((((long) x) << 32)|y,id==0?null:id);
```
Und jetzt der Grund, warum ich ungerne 'point-objecte verwenden würde:
So wird gereedert: (ungefähr)

```
for (int x = (int) (cam.position.x - cam.viewportWidth / 2); x < cam.position.x + cam.viewportWidth / 2; ++x)
			for (int y = (int) (cam.position.y - cam.viewportHeight / 2); y < cam.position.y + cam.viewportHeight / 2; ++y)
				renderCodeFor(x,y,world);
```

Ungerne würde ich jetzt also für jedes tile erst ein 'point-object' erstellen, um den GC auf dem Handy nicht zu überlasten. Wenn ich also nur ein Brett vorm Kopf habe dann wäre ich froh, wenn mir jemand zwei löcher zum gucken rein bohren könnte .
M_V_G hm...


----------



## Hm.... (11. Dez 2012)

Spacerat hat gesagt.:


> (tausche f gegen v :lol


 hm, eigentlich habe ich im Browser ein rechtschreib Plugin. leider 'korrigiert' das ab und zu ohne, das ich das will. So wird dann aus gerändert 'gereedert' usw.


----------



## Titanpharao (11. Dez 2012)

Kann es sein, das du für jedes Objekt das du rendern willst, erstmal dir anhand deiner X/Y Koordinanten das Objekt aus der Map hohlst?
Falls das so ist, kann du das ganz schell vergessen. Das ist nicht nur langsam sondern stinkend lahm 
Wieso benutzt du nicht einfach ein 2D Array?

Bzw was meinst du mit "'point-objekte"?

```
for(int i=0;i<10;++i){
Object a=map.get(i);
}
```
das macht die Sache nicht langsamer. Also das reine zuweisen und das 'a' "erstellen".
Und wenn du map.put((long) machst, wird daraus auch ein Object nämlich ein Long Objekt.
Maps können nur mit Objekten. 
Würde mir aber merh gedanken machen über die Map, hatte meine Sprites auch da zwischengelagert ... nicht schön ... nicht schön^^


----------



## nillehammer (11. Dez 2012)

> Ungerne würde ich jetzt also für jedes tile erst ein 'point-object' erstellen, um den GC auf dem Handy nicht zu überlasten.


Code zu schreiben, der unleserlicher wird, nur, weil man angenommene Performanceprobleme umgehen möchte, ist selten eine gute Idee. Obwohl ich Deinen Ansatz, ein Long für zwei ints zu nehmen recht intelligent finde :toll:

Aber, wenn es sich hier um eine offensichtilich zweidimensionale Welt handelt, deren Tiles ein 
	
	
	
	





```
byte
```
 enthalten, nimm einen zweidimensionalen byte-Array. Speichereffizienter geht es nicht. Eine Map macht m.E. nur Sinn, wenn die Größe der Welt sich dynamisch ändert. Du hast aber ja konstante Größen oder habe ich das mit dem viewPortWidth und viewPortHeight falsch verstanden?


----------



## Hm... (11. Dez 2012)

Also würde mir hier eher zu so etwas geraten werden: Byte[][] ?.
Eine Map sieht z.b. so aus: (Rot sind dabei die benutzten 'tiles')


Spoiler: map











.
Auch können die Maps 'schön' groß werden, da ziemlich viele tiles nicht benutzt werden, erhoffte ich mir mit der HashMap speicher zu sparen.
Ich werde es einfach mal mit einem Array ausprobieren.
(Zu not habe ich hier von einem anderen Project auch noch ein 'chunk-world' System. Aber das wäre dann wohl die Kanone für den Spatzen)
MCG hm...


----------



## nillehammer (11. Dez 2012)

> Also würde mir hier eher zu so etwas geraten werden: Byte[][] ?.


Nein, eher zu 
	
	
	
	





```
byte[][]
```
. Jedenfalls habe ich das aus dem hier geschlossen:

```
public int setTile(int x, int y, byte id);
```
Der Gag ist eben, dass Du in einer Map mit Wrappern arbeiten *musst*, während Du in einem Array mit Primitives arbeiten *kannst*.


> da ziemlich viele tiles nicht benutzt werden, erhoffte ich mir mit der HashMap speicher zu sparen.


Das kann tatsächlich so sein. Das mit den vielen unbenutzten Tiles hatte ich jetzt so aus den bisherigen Infos nicht erkennen können.

Nochmal zusammengefasst die Punkte, die man vielleicht bedenken sollte:
- Deine longs werden per Autoboxing sowieso in Instanzen von Long umgewandelt. Gegenüber einer eigenen Point-Klasse mit zwei ints als Instanzvariablen vermeidest Du also weder Objekterzeugung noch Garbage Collection. Und Speicher sparst Du auch nicht wirklich.
- Eine eigene Point-Klasse ist auf jeden Fall verständlicher als das Bit-Geschiebe
- Eine eigene Point-Klasse erfordert aber wiederrum Schreibarbeit: Getter, Setter(wenn sie mutable sein soll), equals/hashCode müssen stimmen etc. Das sparst Du Dir bei den longs natürlich.
- Ein Array von Primitives spart Speicher gegenüber der gleichen Anzahl von Wrapper-Instanzen.
- Bei einer großen World mit vielen unbenutzten Tiles kann es tatsächlich sein, dass Du mit einer Map trotz Wrapper-Instanzen sehr viel weniger Referenzen speicherst als mit einem Array.

Sieh die hier geposteten Ansätze vielleicht mehr als Ideen, aus denen Du für Deinen Anwendungsfall den richtigen auswählen kannst.


----------



## Titanpharao (11. Dez 2012)

Das sollte auch nicht mehr Speicher benötigen, wenn du wirklich 
Byte[][] world=new Byte[10][10];
machst.
Denn überall ist "null" und somit kein Speicher.
Somit würde ich die freien Plätze auch wirklich null lassen.
Würde mir auch noch eine echte WorldTile Klasse oder ähnliches schreiben, da Byte doch wenig Eigenschaften haben kann, falls sowas noch kommt.

Und hier mein abschließender Tipp, 1024x1024 Byte große Map ergeben 1MB  Was verschwindend gering ist, lädst du ein Bild ist es schon viel größer. Oder ist die doch größer^^
Wie sagte mal unser Lehrer, Speicher != Performance oder anders rum. Nimmst du das Array ist es schneller, womöglich größer(wegen leer). Nimmst du die Map kannst du vllt Speicher einsparen, aber die Performance ist im Keller.


----------



## Hm... (11. Dez 2012)

Dann werde ich jetzt erstmal ein Array benutzen und erst wenn es zu Problemen kommt wechseln.
(Ich habe hier ein ziemlich schlechtes Handy, wenn es hier läuft, läuft es auf deinem Taschenrechner ).



Spoiler: OT



Zu der eigenen 'WorldTile' classe. Meine Tiles sind doch alle recht statisch, haben eine 'Form' und eine Textur (+id), existierend als Singleton.



Vielen dank nochmal.
Hm...


----------



## Landei (11. Dez 2012)

Vielleicht wäre auch ein Quadtree etwas für dich, insbesondere wenn du die Kartengröße quadratisch und gleich (oder knapp unterhalb) einer Zweierpotenz festlegen kannst.


----------



## Hm... (14. Dez 2012)

Ich bleibe erstmal bei dem array, bis jetzt macht es seinen job ganz gut. Sollte es zu Problemen kommen, werde ich sowohl den Quadtree als auch die Map nochmal implementieren.
Hm...


----------

