【问题标题】:How to only draw tiles (sprites) visible on the screen如何仅绘制屏幕上可见的图块(精灵)
【发布时间】:2013-06-02 15:55:10
【问题描述】:

我正在尝试创建一个简单的 2d 滚动游戏,作为 monogame (XNA) 的学习练习。目前,我从一个文本文件加载平铺信息,创建一个数组 (tiles[,]),其中包含一个平铺对象存储有关平铺写入位置以及调用 draw 方法时应使用的纹理的信息。目前我一次绘制数组中的每个图块,然后简单地更新图块的位置以在屏幕上移动它。显然,一次绘制所有图块有点痛苦,我认为如果我只绘制屏幕上可见的图块会更好,这样随着图块在屏幕上移动,会绘制更多图块。我不确定如何最好地做到这一点?对于如何判断应该绘制哪些瓷砖,我有点迷茫。 任何帮助将不胜感激。 这是我的关卡类中的绘制和更新方法 - 它只是调用 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);
            }
        }
    }

【问题讨论】:

  • 我刚刚创建的简单 2D 相机示例:pastebin.com/jrGXWfNh 它仅演示了相机的功能以及它如何使用绘制的矩形作为参考。使用起来非常简单,完全理解非常先进。如果你知道你的屏幕有限制,你只需检查相机的位置并检查另一个矩形是否在屏幕“内部”,然后直接绘制或不绘制。
  • 谢谢 Deukalion,我想我明白了。

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


【解决方案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 以图块为单位。如果不是,请适当地转换它们。

【讨论】:

  • 再次感谢迈克,我对相机的这个概念有点迷茫。目前我只根据数组位置定位图块,然后根据以下内容更改图块的位置:theSpriteBatch.Draw(mSpriteTexture, Position * sizeVector, Color.White);你知道有什么教程可以让我了解如何设置相机吗?
  • 在本例中,相机是屏幕的中心,所以只需将其更改为您的播放器位置或其他东西,以便它“跟随”它
  • @Pectus Excavatum 如果在您的 spriteBatch 中为世界设置一个矩阵,您可以轻松转换整个“二维屏幕”。如果您的屏幕是 400x400 并且您的相机位于 X = 0, Y = 0 它将开始在 0,0 到 400, 400 处渲染所有内容。除非您缩放或旋转它。矩阵相机 = Matrix.CreateScale(Zoom) * Matrix.CreateRotationZ(MathHelper.ToRadians(Degrees)) * Matrix.CreateTranslation(PositionX, PositionY, 0);然后您只需将位置调整为您想要显示的任何内容。现在您可以将对象的位置设置为 400, 0(未渲染),但如果您稍微移动一下相机,它就会显示出来。
  • 周围有一大堆 2D 相机示例。我找不到我自己用过的,但这里有一个类似的adambruenderman.wordpress.com/2011/04/05/…
  • 好的,我明白 Mike 建议的前提,即只循环浏览屏幕上的图块。我认为这是一个很好的计划。但我无法弄清楚为什么我不能使用视口让它工作 - 请参阅我修改后的代码问题。任何想法都将不胜感激,因为当我尝试仅循环浏览屏幕上的图块时,不会绘制任何图块:-(
【解决方案2】:

创建名为 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);
            }
        }
    }
}

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2013-08-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-07-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多