如何在XNA(2D)中制作滚动地图?

4

我有一张地图,其中包含许多物体,该区域的大小为5000*5000。 我的屏幕大小为800*600。

如何滚动我的地图,我不想将所有对象向左和向右移动,我希望“相机”移动,但不幸的是我没有找到任何移动它的方法。

谢谢


http://stackoverflow.com/questions/12152662/having-the-background-or-camera-scroll-based-on-charcter-position/12167478#12167478 - Cyral
2个回答

7

视口

首先,您需要创建相机的视口。对于2D游戏来说,您可以定义要开始渲染的左下位置,并使用您的屏幕分辨率来扩展它,在这种情况下为800x600

Rectangle viewportRect = new Rectangle(viewportX, viewportY, screenWidth, screenHeight);

以下是您的相机偏移量为300,700时的外观示例(图仅供参考,仅用于让您更好地了解)。 视口 可见性检查 现在,您想要找到与红色正方形相交的每个精灵(可以理解为您的视口)。这可以使用类似以下内容的代码完成(此代码未经测试,只是演示其可能的样式)。
List<GameObject> objectsToBeRendered = new List<GameObject>();
foreach(GameObject obj in allGameObjects)
{
    Rectangle objectBounds = new Rectangle(obj.X, obj.Y, obj.Width, obj.Height);
    if(viewportRect.IntersectsWith(objectBounds))
    {
        objectsToBeRendered.Add(obj);
    }
}

这是图形化的展示,绿色的精灵被添加到objectsToBeRendered中。将对象添加到单独的列表中,如果你想在渲染之前按从BackFront排序它们,这样做会很容易! Visible 渲染 现在我们找出了哪些对象相交,我们需要弄清楚它们在屏幕上的位置。
spriteBatch.Begin();
foreach(GameObject obj in objectsToBeRendered)
{
    Vector2 pos = new Vector2(obj.X - viewportX, obj.Y - viewportY);
    spriteBatch.Draw(obj.GetTexture(), pos, Color.White);
}
spriteBatch.End();

如您所见,我们推导出视口的XY位置,以便将对象的世界坐标带入视口内的屏幕坐标中。 这意味着在此处给定的视口中,可能在400, 800世界坐标中的小正方形将在屏幕上呈现为100, 100编辑: 虽然我同意“正确答案”的更改,但请记住,在决定要处理哪些动画、更新哪些AI等方面,我在这里发布的内容仍然非常有用...让相机和GPU独自完成工作会阻止您知道实际上在屏幕上的是哪些对象!

这是我想要避免的。 如果我的分辨率是800 * 600,Xna将渲染从0,0开始,并在800,600结束的矩形中的所有内容.. 我希望它将屏幕上位于100,100和900,700之间的所有内容都渲染出来。 如何实现? - OopsUser
你正在尝试避免移动物体...如果你移动相机,它的“裁剪矩形”也会移动。当你想要渲染这些物体时,你需要将它们从一个坐标系转换到另一个坐标系(世界空间到屏幕空间),这就是你需要从相机的“裁剪矩形”中移除“顶部”和“左侧”的地方。精灵在世界中保持不变,但你正在以不同的方式映射它们,使它们与屏幕上的像素匹配。 - emartel
我知道如何在移动相机时计算屏幕位置。但我想避免这些计算,我想告诉XNA将其相机移动到特定位置,然后它将负责剪切和计算何时以及在哪里绘制。当您进行3D开发时,您不会移动世界,而只是移动相机。我想在2D中实现同样的事情,但据我所见.. XNA不支持此功能。 - OopsUser
在二维和三维中是一样的...当你使用三维时,需要对视锥内的物体进行“变换”以剔除它们,而不是将它们移动,我不明白你为什么会一直提到这个。 - emartel
1
好的,我明白你的意思了。 我以为我可以避免使用“obj.X-viewportX”。 - OopsUser
@OopsUser,我认为我的回答可能会澄清一些事情。 - Andrew Russell

7

我认为你正在寻找SpriteBatch.BegintransformMatrix参数(这个重载)。

你说你不想让对象移动,但是你希望相机移动。但是,在2D和3D渲染中,最底层都没有“相机”的概念。渲染总是发生在同一区域 - 你必须使用转换将你的顶点/精灵放置到该区域。

如果你想要相机的效果,你必须通过将整个世界向相反方向移动来实现它。

当然,你不需要实际存储移动后的数据。在渲染数据时,只需应用一个偏移量即可。Emartel的回答让你为每个精灵都这样做。然而,使用矩阵更加简洁,因为你不必为每个单独的Draw复制代码 - 你可以让GPU来完成它。

最后举个例子:假设你想把相机放在(100, 200)处。为了实现这个效果,传递Matrix.CreateTranslation(-100, -200, 0)SpriteBatch.Begin

(自己执行视锥体裁剪,如Emartel的回答中所述,可能是浪费时间的,除非你的世界真的很大。请参见这个回答以了解性能方面的考虑。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接