SFML2.6 图形模块--使用视图控制2D相机

什么是视图?

在游戏中,通常会有比窗口大得多的关卡。你只能看到其中的一小部分。这通常是RPG,平台游戏和许多其他类型的情况。开发人员可能会忘记的是,它们在一个2D世界中定义实体,而不是直接在窗口中定义。窗口只是一个视图,它显示整个世界中的特定区域。并行绘制相同世界的多个视图是完全可以的,或者将世界绘制到纹理而不是绘制到窗口中。世界本身保持不变,改变的只是它的观察方式。

由于在窗口中看到的只是整个2D世界的一小部分,因此需要一种指定在窗口中显示哪个部分世界的方法。此外,您还可能希望定义此区域将如何在窗口内显示/放置。这些是SFML视图的两个主要特征。

总之,如果您想滚动、旋转或缩放您的世界,您需要使用视图。它们也是创建分屏和迷你地图的关键。

定义视图显示的内容

在SFML中,封装视图的类是sf::View。可以直接用要查看的区域进行构造:

// create a view with the rectangular area of the 2D world to show
sf::View view1(sf::FloatRect(200.f, 200.f, 300.f, 200.f));

// create a view with its center and size
sf::View view2(sf::Vector2f(350.f, 300.f), sf::Vector2f(300.f, 200.f));

这两种定义是等效的:这两个视图都将显示2D世界的同一区域,即以点(350,300)为中心的300x200矩形。
在这里插入图片描述
如果您不想在构造期间定义视图,或者想稍后修改它,则可以使用等效的setter函数:

sf::View view1;
view1.reset(sf::FloatRect(200.f, 200.f, 300.f, 200.f));

sf::View view2;
view2.setCenter(sf::Vector2f(350.f, 300.f));
view2.setSize(sf::Vector2f(200.f, 200.f));

一旦您定义了视图,就可以对其进行变换,以使其显示您的2D世界的平移/旋转/缩放版本。

移动(滚动)视图

与图形实体(例如精灵或形状)不同,它们的位置是由它们的左上角定义的(并可以更改为任何其他点),视图始终由它们的中心进行操作——这只是更方便而已。这就是为什么更改视图位置的函数命名为 setCenter,而不是 setPosition。

// move the view at point (200, 200)
view.setCenter(200.f, 200.f);

// move the view by an offset of (100, 100) (so its final position is (300, 300))
view.move(100.f, 100.f);

在这里插入图片描述

旋转视图

要旋转视图,请使用setRotation 函数。

// rotate the view at 20 degrees
view.setRotation(20.f);

// rotate the view by 5 degrees relatively to its current orientation (so its final orientation is 25 degrees)
view.rotate(5.f);

在这里插入图片描述

缩放视图

缩放视图(放大或缩小)是通过调整大小来完成的,因此要使用的函数是setSize。

// resize the view to show a 1200x800 area (we see a bigger area, so this is a zoom out)
view.setSize(1200.f, 800.f);

// zoom the view relatively to its current size (apply a factor 0.5, so its final size is 600x400)
view.zoom(0.5f);

在这里插入图片描述

定义如何查看视图

现在你已经定义了窗口中可见的2D世界的部分,让我们定义它在哪里显示。默认情况下,所观看的内容占据整个窗口。如果视图与窗口大小相同,则一切都被渲染为1:1。如果视图比窗口小或大,则一切都被缩放以适应窗口。

这种默认行为适用于大多数情况,但有时需要进行更改。例如,在多人游戏中分割屏幕,您可能希望使用两个视图,每个视图仅占窗口的一半。您还可以通过绘制整个世界到一个视图中,并在窗口角落的小区域中呈现该视图来实现小地图。视图内容显示的区域称为视口。

要设置视图的视口,您可以使用setViewport函数。

// define a centered viewport, with half the size of the window
view.setViewport(sf::FloatRect(0.25f, 0.25, 0.5f, 0.5f));

在这里插入图片描述
你可能已经注意到了一个非常重要的事情:视口并不是以像素为单位定义的,而是以窗口大小的比率定义的。这更加方便:它允许您不必跟踪调整大小事件,以便在窗口大小更改时每次更新视口的大小。这也更直观:您可能会将视口定义为整个窗口区域的一部分,而不是固定大小的矩形。

使用视口,分割多人游戏屏幕非常简单:

// player 1 (left side of the screen)
player1View.setViewport(sf::FloatRect(0.f, 0.f, 0.5f, 1.f));

// player 2 (right side of the screen)
player2View.setViewport(sf::FloatRect(0.5f, 0.f, 0.5f, 1.f));

在这里插入图片描述
…或者一张小地图:

// the game view (full window)
gameView.setViewport(sf::FloatRect(0.f, 0.f, 1.f, 1.f));

// mini-map (upper-right corner)
minimapView.setViewport(sf::FloatRect(0.75f, 0.f, 0.25f, 0.25f));

在这里插入图片描述

使用视图

要使用视图绘制某些内容,您必须在调用目标(sf::RenderWindow或sf::RenderTexture)的setView函数之后绘制它。

// let's define a view
sf::View view(sf::FloatRect(0.f, 0.f, 1000.f, 600.f));

// activate it
window.setView(view);

// draw something to that view
window.draw(some_sprite);

// want to do visibility checks? retrieve the view
sf::View currentView = window.getView();
...

视图在您设置另一个视图之前一直处于活动状态。这意味着始终有一个视图定义了在目标中显示什么以及在哪里绘制它。如果您不显式设置任何视图,则渲染目标将使用其自己的默认视图,与其大小匹配1:1。您可以使用getDefaultView函数获取渲染目标的默认视图。如果您想基于默认视图定义自己的视图或将其恢复以在场景之上绘制固定实体(如GUI),则此功能可能很有用。

// create a view half the size of the default view
sf::View view = window.getDefaultView();
view.zoom(0.5f);
window.setView(view);

// restore the default view
window.setView(window.getDefaultView());

当你调用setView函数时,渲染目标会复制视图,并不会存储传递的视图的指针。这意味着,每当您更新视图时,您需要再次调用setView函数以应用修改。不要害怕复制视图或即时创建视图,它们不是昂贵的对象(它们只保存几个浮点数)。

当窗口改变大小时显示更多内容

由于默认视图在窗口创建后永远不会改变,因此查看的内容始终相同。因此,当窗口大小改变时,所有内容都会被挤压/拉伸到新的大小。

如果您想根据窗口的新大小显示更多/更少的内容,您只需使用窗口大小更新视图的大小即可。

// the event loop
sf::Event event;
while (window.pollEvent(event))
{
    ...

    // catch the resize events
    if (event.type == sf::Event::Resized)
    {
        // update the view to the new size of the window
        sf::FloatRect visibleArea(0.f, 0.f, event.size.width, event.size.height);
        window.setView(sf::View(visibleArea));
    }
}

坐标转换

当你使用自定义视图,或者在没有使用上述代码的情况下调整窗口大小时,显示在目标上的像素不再对应2D世界中的单位。例如,点击像素(10,50)可能会命中你的世界中的点(26.5,-84)。这时你需要使用转换函数来将像素坐标映射到世界坐标:mapPixelToCoords。

// get the current mouse position in the window
sf::Vector2i pixelPos = sf::Mouse::getPosition(window);

// convert it to world coordinates
sf::Vector2f worldPos = window.mapPixelToCoords(pixelPos);

默认情况下,mapPixelToCoords使用当前视图。如果你想使用非活动视图来转换坐标,你可以将其作为该函数的额外参数传递。

相反地,使用mapCoordsToPixel函数可以将世界坐标转换为像素坐标。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值