如何只在屏幕上绘制可见的瓷砖(精灵)

时间:2013-06-02 15:55:11

标签: c# xna 2d monogame side-scroller

我正在尝试创建一个简单的2D滚动游戏作为单一游戏(XNA)的学习练习。目前,我从文本文件加载切片信息,创建一个数组(tiles [,]),其中包含一个tile对象,该对象存储有关tile写入位置的信息以及调用draw方法时应使用的纹理。目前我一次绘制数组中的每个tile,然后简单地更新tile的位置以在屏幕上移动它。显然,一次性擦拭所有瓷砖有点痛苦,我认为如果我只在屏幕上绘制可见的瓷砖会更好,所以当瓷砖在屏幕上移动时会绘制更多的瓷砖。我不确定如何做到最好?关于我应该如何判断应该绘制什么样的瓷砖,我有点迷茫。 任何帮助将不胜感激。 这是我的关卡类中的draw和update方法 - 它只是调用Tile类中的方法来绘制/更新位置。

    /// <summary>
    /// Draws each individual tile in the level.
    /// </summary>
    private void DrawTiles(SpriteBatch spriteBatch)
    {
        // For each tile position
        for (int y = 0; y < Height; ++y)
        {
            for (int x = 0; x < Width; ++x)
            {
               tiles[x, y].Draw(spriteBatch);
            }
        }
    }



    public void Update(GameTime gameTime, int scrollSpeed, ScrollDirection direction)
    {
        // Update the positions of each of the Background sprites
        foreach (Tile tile in tiles)
        {
            tile.Update(gameTime, new Vector2(0, scrollSpeed), scrollDirection);
        }
    }
}

提前致谢

我现在尝试仅使用从图形设备传递的视口循环浏览屏幕上可见的图块。在尝试绘制它们之前,我基本上尝试获得可以放在屏幕上的瓷砖数量,方法是将屏幕的高度除以瓷砖的高度,并将宽度相同。这很好用,它会在视点中绘制所有可见的图块。

唯一的问题是它不再绘制任何从视口外部开始的图块,因此即使在更新图块移动到视口中,它们也不会被绘制,因为循环使用其原始位置。我想不出一种方法来解决这个问题而不会遍历所有的瓷砖: - (

作为一个级别可能很大,循环遍历所有区块只能绘制屏幕中的内容是非常低效的。

非常感谢任何建议。

这是更新后的绘图:

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

2 个答案:

答案 0 :(得分:1)

您需要有关相机的信息。如果您知道相机的中心位置以及屏幕尺寸,您可以进行如下绘制调用:

private void DrawTiles(SpriteBatch spriteBatch)
{
    // For each tile position
    for (int y = cameraOffset.Y - screenHeight / 2; y < cameraOffset.Y + (int)Math.Ceiling(screenHeight / 2); ++y)
    {
        for (int x = cameraOffset.X - screenWidth / 2; x < cameraOffset.X + (int)Math.Ceiling(screenWidth / 2); ++x)
        {
           tiles[x, y].Draw(spriteBatch);
        }
    }
}

我使用Math.Ceiling的原因是为了覆盖瓷砖是否部分在屏幕上。另一方面是Math.Floor,因为它是整数除法。

请注意,这假设cameraOffset,screenWidth和screenHeight以tile为单位。如果不是,请适当地转换它们。

答案 1 :(得分:0)

创建名为WINDOW_WIDTH和WINDOW_HEIGHT的常量,用于存储窗口的宽度和高度。然后,像你展示的那样绘制瓷砖,但只能使用WINDOW_WIDTH和WINDOW_HEIGHT值中的瓷砖。您还需要在Tile类中使用X和Y属性

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)
        {
            if (tiles[x, y].X <= WINDOW_WIDTH &&
                tiles[x, y].X >= 0 &&
                tiles[x, y].Y <= WINDOW_HEIGHT &&
                tiles[x, y].Y >= 0)
            {
                tiles[x, y].Draw(spriteBatch);
            }
        }
    }
}
相关问题