【发布时间】:2013-08-12 16:55:56
【问题描述】:
假设您有一个 2D 瓷砖网格(这是基于 2D 瓷砖的游戏),大多数瓷砖占据 1 个位置,但一些较大的“对象”可以填充多个位置。我在我的数组上使用索引器来自动将这些对象“引用”到它们的基本图块。因此,如果我在 3,4 处有一个 2x2 对象,并且我访问 4,4,它将自动重定向并获取 3,4 处的图块。但是,如果我需要获取确切的图块,我可以指定一个参数来绕过此功能。 (GameDev 上的my old question 对此有更好的解释)
另一种看待它的方式是游戏世界中的门对象,用户可以单击它的任意位置来打开它,但每个单独的部分都可以包含其他属性,例如不同的背景和照明值。
注意我只是一个业余程序员,所以这可能不对(以及为什么我要征求你的意见)每个“超大”磁贴都会以X,Y 位置的形式存储对其基础磁贴的引用(这应该是对内存中实际对象的引用吗?)
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];
}
/// <summary>
/// Accessor for tiles
/// </summary>
/// <param name="x">X Position</param>
/// <param name="y">Y Position</param>
/// <param name="overide">Bool to "override" the get, if true, it wont get the reference tile and will bypass the checks</param>
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 > than 1x1
if (!override && 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 && 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;
}
}
抱歉,如果使用 2D 到 1D 转换有点难以阅读,但经过一些测试后,内部使用 1D 数组似乎要快一些。
IsLarge 是一个属性,用于简单地检查图块是否很大(大于 1x1)
我已经有适当的逻辑来在放置大图块时填充相邻图块的引用,并相应地删除它们。
在分析游戏时,我发现 tile 的 get 访问器占用了大量 CPU,每帧获取数百次 tile 用于照明、渲染、碰撞等。
如何提高这段代码的性能和效率?
基准测试(英特尔四核 i7 2670QM 上 30k 次迭代的平均值)
Tile t = tiles[100, 100]; - 160 ns 和 175 ns 带 2D 内部阵列
Tile t = tiles[100, 100, true]; - 137 ns 和 264 ns 带 2D 内部阵列(奇数)
100,100 顺便说一下不是大图块,注意这些图块不是很常见。我在屏幕上有一座房子,你可以有几块大瓷砖(门、桌子),但有很多泥土/石头/木头。
【问题讨论】:
-
我的建议是重载索引器,而不是使用布尔值的默认参数。也许对其中一个使用命名方法。然后,您可以消除数组访问中的分支。
-
目前使用这个的代码需要多长时间?需要多长时间才能达到您的目的“足够快”?您有什么迹象表明这是当前应用程序性能的瓶颈?
-
@lukegravitt 我以前做过,没有任何收获/损失@Servy 几分钟,我会回顾分析器的结果
-
Tile 是结构还是类?
-
我肯定会使用对内存中对象的引用。这样您就可以删除额外的计算和递归方法调用。
标签: c# arrays performance xna accessor