Best Way to do Layers?

Monkey Forums/Monkey Programming/Best Way to do Layers?

Chroma(Posted 2013) [#1]
I'd like to do a 2D map editor that uses up to 8 layers. What's the best/fastest way to store and draw the data/image? Think mario bros type platformer.


Rushino(Posted 2013) [#2]
Reuse existing code. That probably the best way to do it. Get a framework or a library that enable you to do this such Diddy, Ignition or even phantom engine. You could do it yourself but you would reinvent the wheel.

If you ask me.. i don't see any other way to do it than using an 2D array and iterate through it to draw the tiles.


Goodlookinguy(Posted 2013) [#3]
I use code similar to below, although I just made that here, it's untested, and by no means ready for instant use. I've had my similar code run upwards of 500 frames per second with 10 layers on lower end computers.

I should note that my code is a bit more flexible than this, but this is a pretty simple jumping off point.




Chroma(Posted 2013) [#4]
So a 2D array is fastest for Layer use as opposed to a List or Stack then.

Alrighty. Thanks.


Gerry Quinn(Posted 2013) [#5]
If you want ultimate speed, a 1D array is fastest.

But you don't. After all, you are building a level designer which is a GUI. 1D arrays are for when you want superfast cellular automatons, pathfinding, chess programs etc.

So don't worry about optimisation, as you only need to run at GUI speed - and it's also unlikely that the data structure will matter too much in your game.

Choose the data structure that is simplest: probably a 2D or 3D array.


Goodlookinguy(Posted 2013) [#6]
So a 2D array is fastest for Layer use as opposed to a List or Stack then.

Alrighty. Thanks.


Like Gerry Quinn said, typically a 1D array is the fastest, like I used in my example. Although I disagree about not using it as a level designer. It's not hard to find the location of x and y in the 1D array. The calculation is simply 'y * widthInTiles + x'. I'm not sure of any reason to bother using a 2D array for things related to this.


Gerry Quinn(Posted 2013) [#7]
I find 2D a bit simpler sometimes. Even small extraneous indexing calculations are still indexing calculations. (Though it's also true that in certain cases the 1D array is simpler, mainly because a coordinate is an int rather than a point object.)

If Monkey had inline methods and functions I'd be more inclined to use 1D more often.


Shinkiro1(Posted 2013) [#8]

It's not hard to find the location of x and y in the 1D array. The calculation is simply 'y * widthInTiles + x'. I'm not sure of any reason to bother using a 2D array for things related to this.


Because it's easier/more natural to imagine? A tilemap is a perfect example. With a 2d array you immediately see what you are doing at which position (without playing computer and calculating the numbers in your head). But if you find it more easy to map a single index to one map cell than an x,y representation I won't argue with you.

Going from this data: http://pointlessdiversions.blogspot.co.nz/2012/05/1d-vs-2d-arrays-performance-reality.html
the performance gain is minimal.
Best thing to do is using a profiler and see where your bottleneck is. Just to put this in perspective:

I had a tilbased game with around 10 layers, each a 2d array of ints representing the tile index. Every update I run through the whole visible part of the array (20x15) and draw that.

Simply looping through all layers and accessing data shows up in my profiler as < 0.01% of the time (in iOS & glfw).
So if you want to optimise that you will maybe get out another 0.005% which is a waste of your precious time.


Goodlookinguy(Posted 2013) [#9]
But if you find it more easy to map a single index to one map cell than an x,y representation I won't argue with you.


This and I'm currently in the middle of creating a tactical game. A 2D array would actually hinder my progress and make it much harder to do a lot of the calculations. Ever since I started working on this tactical game I've become much more attached to using the 1D array style of tiling. I used to use the 2D array style, but it actually makes it harder in my case. The speed benefit is a bonus.

If Monkey had inline methods and functions I'd be more inclined to use 1D more often.


Are you talking about anonymous functions? I'd love to see those as well.


Samah(Posted 2013) [#10]
@Goodlookingguy: Are you talking about anonymous functions? I'd love to see those as well.

This would be so ridiculously easy to implement, I'm quite disappointed it hasn't. In fact, I'm still half tempted to just add it to monkey-ext myself. Yet another reason we need an official repository.


Chroma(Posted 2013) [#11]
I'm using a basic Layer system I created off the 1D array mentioned in this thread. Code is below. It's pretty featureless at the moment but it will grow.

Class Layer<T>
	Field Map:T[]
	Field Width:Int
	Field Height:Int
	
	Method New(width:Int, height:Int)
		Width = width
		Height = height
		Map = Map.Resize(Width * Height)
	End Method
	
	Method Poke(obj:T, x:Int, y:Int)
		Map[y * Width + x] = obj
	End Method
	
	Method Peek:T(x:Int, y:Int)
		Return Map[y * Width + x]
	End Method
		
	Method Get:T(index:Int)
		Return Map[index]
	End Method
	
	Method Draw(offset:Vec2 = Null)
		For Local obj:T = Eachin Map
			obj.Draw(offset)
		Next
	End Method
End Class

Class Tile
	Field image:Image
	Field x:Float, y:Float
	Field isSolid:Bool

	Method New(image_file:String, x:Int = 0, y:Int = 0)
			Self.image = LoadImage(image_file, 0, Image.MidHandle)
			Self.x = x
			Self.y = y
	End Method
	
	Method Draw(offset:Vec2 = 0)
		DrawImage Self.image, Self.x + offset.x, Self.y + offset.y
	End Method
End Class



Gerry Quinn(Posted 2013) [#12]
I was talking about inline functions like in C++. They look the same as ordinary functions but the compiler is encouraged to generate code in place when they are called. Thus:

Inline Method GetVal:Int( x:Int, y:Int )
	Return x + y * ARRAYWIDTH
End

Method SomeMethod:Void()
	' ...
	Local tileVal:Int = GetVal( xShip, yShip )
	' ...
End


...would be converted by Monkey into

Method SomeMethod:Void()
	' ...
	Local tileVal:Int = xShip + yShip * ARRAYWIDTH
	' ...
End


... avoiding the cost of an actual function call.


Goodlookinguy(Posted 2013) [#13]
@Gerry Quinn

Oh, that's neat and does actually have some valid uses. I used to use C++, but it's been ages and I actually didn't remember that feature existing. Guess that shows how much I knew...

@Samah

Digressing for a second, I haven't used monkey-ext because it hasn't had anything in it that was really useful to me, but a feature like that would definitely have me. Oh, and operator overloading, which while I can live without, I really think Monkey should have.

I think these things need to be brought up in a new thread for wanted features though. These are features that could definitely be added to all targets via real implementation or simulated implementation.

@Chroma

One thing to take away from the code I wrote was that there was no tile class. Each tile was nothing more than some simple data inside a few different arrays. If each tile is an object that will have massive overhead and be extremely heavy to render. In fact, Samah made a great statement on here that for some reason stuck in my head.

If you can group that into five groups of 1200, it'll be way faster than drawing 1200 groups of five.
From: http://www.monkeycoder.co.nz/Community/posts.php?topic=2114


Chroma(Posted 2013) [#14]
You mean like just storing an id number of what to render right?


Goodlookinguy(Posted 2013) [#15]
Yeah. In mine, I store the layers which then contain the tileset index/id reference and the index/id of said tileset. I also make sure to make index 0 draw nothing. This allows for multiple layers to be lightweight because it skips drawing any that are 0.


Shinkiro1(Posted 2013) [#16]
Also be sure to only iterate to over what's on the screen.
That way your maps can be as big as you want (well, at least in theory).