IntMaps creating junk

Monkey Forums/Monkey Programming/IntMaps creating junk

Raz(Posted 2012) [#1]
I've noticed that through XNA and Android, iterating through an IntMap causes a lot of junk. (I will say though, this is literally the only thing that causes junk when I run my game through XNA, which is pretty damn impressive :)

For Local t:Int = EachIn ThisMap.Keys()
    ThisMap.Get(t).Draw(X,Y)
Next


Am I right in thinking that I can't really use any list type structures without creating junk?

Is a 1d array the only real alternative?


muddy_shoes(Posted 2012) [#2]
You could change the iterator so that you can hold a reference and reset it rather than creating a new one every loop via the EachIn.


Raz(Posted 2012) [#3]
Ahh so have a field in the parent class that is "ThisMap.Keys" (whatever type of object that is)?


muddy_shoes(Posted 2012) [#4]
One level down. You'd hold onto a KeyEnumerator returned by ThisMap.Keys().ObjectEnumerator(). You also need to change the KeyEnumerator code so that you can reset it back to the start before using it to loop. The enumerator will have to hold a reference to the map so it can call FirstNode().


Raz(Posted 2012) [#5]
Got ya :) I'll give this a look when I get home thanks!


Paul - Taiphoz(Posted 2012) [#6]
would like to see your code once you figure it out if thats alright.


Raz(Posted 2012) [#7]
I've been thinking about it actually, and as the list doesn't change its size or order at all during run time, I think I probably only need to use a simple 1d array (that I resize as required during initialisation). As long as no junk gets created during the game, I am not fussed :)

I just chucked this together quickly to be used with my code when I get home.

[monkeycode]
Import mojo

Class TestApp Extends App

Field NMData:MapUnit[][]

Method OnCreate()
SetUpdateRate(5)
NMData = New MapUnit[10][]
For Local y:Int = 0 To 9
NMData[y] = New MapUnit[20]
For Local x:Int = 0 To 19
NMData[y][x] = New MapUnit()

' Randomly create between 1 and 7 layers
' for this specific map tile
Local Target:Int = Rnd(1,8)
For Local i:Int = 0 To Target
NMData[y][x].SetTile(i,i,i)
Next

Next
Next


End

Method OnUpdate()

End

Method OnRender()
Cls
For Local y:Int = 0 To 9
For Local x:Int = 0 To 19
SetColor(64,64,64)
DrawRect(x*16,y*16,15,15)
SetColor(255,255,255)
NMData[y][x].Draw(x * 16,y * 16)
Next
Next
End

End

Function Main()
New TestApp
End

Class MapUnit

Field MapUnitTiles:MapUnitTile[]
' Is this tile an obstacle or not?
Field IsObstacle:Bool
' The main type this tile is (grass/sand/tress)
Field MainType:Int
' How many tiles are to be drawn for this Map unit?
Field MUTCount:Int

Method New()
MapUnitTiles = New MapUnitTile[0]
MUTCount = 0
MainType = -1
IsObstacle = False
End

Method SetTile:Void(tT:Int,tX:Int,tY:Int)

Local length:Int = MapUnitTiles.Length()
MapUnitTiles = MapUnitTiles.Resize(length + 1)
MapUnitTiles[length] = New MapUnitTile(tX,tY)
MUTCount = length + 1

If tT > MainType
MainType = tT
End

End

Method Draw:Void(X:Int,Y:Int)
For Local i:Int = 0 Until MUTCount
MapUnitTiles[i].Draw(X,Y)
Next
End


End

Class MapUnitTile

' Will be used to hold the draw locations on the sprite atlas
Field DX:Int
Field DY:Int

Method New(tX:Int,tY:Int)

DX = tX
DY = tY

End

Method Draw:Void(X:Int,Y:Int)
' Pixel drawn with an offset to demonstrate multiple layers
DrawRect(X+(DX * 2),Y,1,1)
End

End

[/monkeycode]


ziggy(Posted 2012) [#8]
Keeping a local copy of the enumerator will make it impossible to nest for-each loops of the same map. I would not recommend it. Maybe a reusable stack for iterators would be much safer, but a bit more complex


Raz(Posted 2012) [#9]
Just got it running and for what I am doing a 1D array is absolutely fine :) Glad it was a relatively simple solution.

Have to admit though, I slightly shamed myself because I then thought I had to do some quite elaborate coding to reverse the order of said arrays to make sure items are drawn correctly..... before realising I could just go through the array backwards... :B

Very happy to have absolutely no garbage being created which is very important for Xbox releases


Tibit(Posted 2012) [#10]
Yeah, Arrays seems to be the way to go to avoid garbage.

You can of course create your own "List" that wraps the Array to get a more dynamic and robust "ArrayList".

The Diddy Framework has some great collection classes worth checking out :)


Raz(Posted 2012) [#11]
Oh pants, I forgot about the ArrayList of Diddy!

I did notice that performance on Android improved when I stopped using IntMaps and assume this is because of the garbage being created.


muddy_shoes(Posted 2012) [#12]
Keeping a local copy of the enumerator will make it impossible to nest for-each loops of the same map.


Not at all. You just have another enumerator instance for the nested loop if you need it.


Shinkiro1(Posted 2012) [#13]
You can also keep the IntMap for quick lookups and use the array for iterating.

Recently I have thought about replacing Lists with Stacks because they use arrays internally.
Also you don't have to use an enumerator because there is the Get(index) method and they resize dynamically.


Samah(Posted 2012) [#14]
The enumerator for ArrayList lets you go back and forward and has a Reset method. You can call Remove to delete the last call to NextObject or PreviousObject, and it keeps track of the state of the list so that you don't get weird concurrency issues.