Note that there are some explanatory texts on larger screens.

plurals
  1. POMost efficient way of using multidimensional array indexers
    text
    copied!<p>Say you have a 2D grid of tiles (This is for a 2D tile based game), most tiles occupy 1 spot, however some larger "objects" can fill in multiple spots. I use an indexer on my array to automatically "refer" these objects to their base tile. So If I have a 2x2 object at 3,4, and I access 4,4, it will automatically redirect and get the tile at 3,4. However I can specify an argument to go around this functionality in the event that I need to get the exact tile. (Better explanation on <a href="https://gamedev.stackexchange.com/q/33967/13911">my old question</a> on GameDev about this)</p> <p>Another way to look at it is a door object in the game world, the user can click anywhere on it to open it, but each individual part can contain other properties, like different backgrounds and lighting values.</p> <p>Note I am just a hobbyist programmer, so this may not be right (and why I am seeking your advice) Each "extra large" tile will store a reference to it's base tile in the form of a <code>X,Y</code> position (Should this instead be a reference to the actual object in memory?)</p> <pre><code>public class TileWrapper { public int Width = 0; public int Height = 0; private Tile[] tiles; //Backing Store public TileWrapper() { tiles = new Tile[Width * Height]; } public TileWrapper(int width, int height) { Width = width; Height = height; tiles = new Tile[Width * Height]; } /// &lt;summary&gt; /// Accessor for tiles /// &lt;/summary&gt; /// &lt;param name="x"&gt;X Position&lt;/param&gt; /// &lt;param name="y"&gt;Y Position&lt;/param&gt; /// &lt;param name="overide"&gt;Bool to "override" the get, if true, it wont get the reference tile and will bypass the checks&lt;/param&gt; public Tile this[int x, int y, bool override = false] { get { //If we do not want to bypass the checks, AND the current tile is &gt; than 1x1 if (!override &amp;&amp; tiles[y * Width + x].IsLarge) return tiles[tiles[y * Width + x].refY * Width + tiles[y * Width + x].refX]; //Use the reference positions to get the main position of the tile //If we want to bypass the checks or the tile wasn't large, get the absolute position else return tiles[y * Width + x]; } set { //Same thing for SET if (!override &amp;&amp; tiles[y * Width + x].IsLarge) //Set base tile if the large tile has a reference tiles[tiles[y * Width + x].refY * Width + tiles[y * Width + x].refX] = value; else //Set absolute tile tiles[y * Width + x] = value; } } </code></pre> <p>Sorry if it is a bit hard to read with the 2D to 1D conversion, but after doing some testing it looks like using a 1D array internally is a bit faster.</p> <p><code>IsLarge</code> is a property that simply checks if a tile, well, is large (greater than 1x1)</p> <p>I already have logic in place to fill the adjacent tile's references when a large tile is placed, and to remove them accordingly.</p> <p>While profiling the game I found that the get accessor for the tile was eating up a lot of CPU, getting tiles hundreds of times per frame for lighting, rendering, collision, etc. </p> <p>How can I improve the performance and efficiency of this code?</p> <p><strong>Benchmarks</strong> (Average of 30k iterations on an Intel Quad Core i7 2670QM)</p> <p><code>Tile t = tiles[100, 100];</code> - 160 ns and 175 ns WITH 2D Internal Array</p> <p><code>Tile t = tiles[100, 100, true];</code> - 137 ns and 264 ns WITH 2D Internal Array (odd)</p> <p><code>100,100</code> is not a large tile by the way, note that these tiles are not very common. I you had a house on screen, you could have a few large tiles (doors, tables), but lots of dirt/stone/wood.</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload