我正在尝试创建一个2D滚动XNA游戏作为学习练习,但是在滚动背景中遇到了一些问题。我正在从文本文件中加载一个级别,解析以创建适当的切片并将它们存储在矩阵中(tiles [,])。
然后我有一个更新方法,它改变了瓷砖的位置,所以当它重新绘制时会移动。
目前,我循环遍历所有瓷砖以在移动之前绘制所有瓷砖。这显然效率不高。理想情况下,我只想在屏幕上绘制瓷砖。我可以通过获取视口并使用图块的高度/宽度来确定屏幕上适合的图块数量,并且仅循环显示这些图块,如下所示:
private void DrawTiles(SpriteBatch spriteBatch)
{
float tileWidth = 40;
float tileHeight = 32;
for (int y = 0; y < (int)Math.Ceiling(mViewport.Height / tileHeight); ++y)
{
for (int x = 0; x < (int)Math.Ceiling(mViewport.Width / tileWidth); ++x)
{
tiles[x, y].Draw(spriteBatch);
}
}
}
但是,这只会在原始视口中绘制iles。外面的瓷砖永远不会被绘制,即使它们的位置确实会被看到。
我认为这可以通过使用计数器来启动和结束循环来解决,每次调用draw方法时都会递增它。但是,我不认为这是一个很好的解决方案,但是我想不出更好的方法来确保只绘制视口中的图块。
答案 0 :(得分:0)
您需要跟踪ViewPort的起始X
和Y
,因为您总是从示例中的0
开始。 e.g。
var startX = 10; // Should increment as viewport scrolls
var startY = 10; // Should increment as viewport scrolls
...
for (int y = startY; y < (int)Math.Ceiling(mViewport.Height / tileHeight); ++y)
{
for (int x = startX; x < (int)Math.Ceiling(mViewport.Width / tileWidth); ++x)
{
tiles[x, y].Draw(spriteBatch);
}
}
另一方面,您的ViewPort可能有一个Top和Left或者X和Y来跟踪它。在这种情况下,请使用ViewPort中的相应属性替换startX
和startY
。
答案 1 :(得分:0)
我在设计中实现的是一个包含属性IsInView和碰撞属性的继承接口,或者在您的情况下可以替换位置。然后我创建了一个单独的线程,它将循环并确定对象是否在视图中。然后,您可以在每个对象中添加InView和OutView,并将其从绘图列表中删除。
使用循环从单独的线程运行。 - 这可以调整以确定瓷砖是否可见
public void CalculateObjsInView()
{
foreach (Obj o in new List<Obj>(ObjInstanceList))
{
if (o == null)
continue;
if (Camera.CollisionMask.Intersects(o.CollisionMask))
o.IsInView = true;
else
o.IsInView = false;
}
}
在Obj课程中
private bool _isInView = false;
public bool IsInView
{
get { return _isInView; }
set
{
if (_isInView != value)
{
if (value)
InView();
else
OutView();
}
_isInView = value;
}
}
private void InView()
{
Game.ObjectDrawEventHandler.Add(Draw);
}
private void OutView()
{
Game.ObjectDrawEventHandler.Remove(Draw);
}