如何确保只绘制视口中可见的精灵

时间:2013-06-05 13:35:08

标签: c# xna viewport monogame side-scroller

我正在尝试创建一个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方法时都会递增它。但是,我不认为这是一个很好的解决方案,但是我想不出更好的方法来确保只绘制视口中的图块。

2 个答案:

答案 0 :(得分:0)

您需要跟踪ViewPort的起始XY,因为您总是从示例中的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中的相应属性替换startXstartY

答案 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);
    }