-
Notifications
You must be signed in to change notification settings - Fork 30
Views
In many 2D games, scrolling is a fundamental functionality that makes it possible to show different parts of the scene by moving a "camera".
#Views In JSFML, the View class represents such a camera. Every RenderTarget (e.g. a RenderWindow) has a view attached to it that is used to determine which part of the scene is currently visible.
A View is defined by the following properties:
- The position of the center.
- The size (width and height).
- The rotation angle around the center.
By modifying these properties, the whole scene can be scrolled, zoomed and rotated. These three operations will be presented in this chapter.
##Switching views In order to use a view, the render target must be switched to it. Every render target has a default view which can be obtained using the [getDefaultView](http://jsfml.org/javadoc/org/jsfml/graphics/RenderTarget.html#getDefaultView(\)) method. The default view has half the size of the render target (below you will find out why), its center is located in the render target's center and it is not rotated.
However, the default view cannot be altered. This is to ensure that the render target can always fall back to it. Therefore, in order to make a render target use a custom view, the [setView](http://jsfml.org/javadoc/org/jsfml/graphics/RenderTarget.html#setView(org.jsfml.graphics.View\)) method is used.
The current view of a render target can be changed at any point during the rendering process. Picture a platformer game where you have a level that you scroll around in, and a HUD display that always displays the player's score in the top right corner of the screen. You would use two views here: one for the level (which is moved around for the scrolling) and one for the HUD (which always stays in the same position, the default view could also be used here).
##Scrolling - Moving the view's center Scrolling is a way to make every object appear at a different position without moving those objects, but by moving the camera. More precisely, it is done by moving the view's center. This can be done using the [setCenter](http://jsfml.org/javadoc/org/jsfml/graphics/View.html#setCenter(float, float)) method, or using the [move](http://jsfml.org/javadoc/org/jsfml/graphics/View.html#move(float, float)) to move the view's current center by a certain amount.
The following example will create two circles and put them near the center of the screen (assuming a 640x480 video mode). A view is then used to "scroll" right - thus making the circles get drawn left of the center.
// ... (create window)
//Create the first circle, which will appear left of the center
CircleShape circle1 = new CircleShape(50);
circle1.setOrigin(50, 50);
circle1.setPosition(320 - 50, 240);
//Create the second circle, which will appear right of the center
CircleShape circle2 = new CircleShape(50);
circle2.setOrigin(50, 50);
circle2.setPosition(320 + 50, 240);
//Get the window's default view
View defaultView = window.getDefaultView();
//Create a new view by copying the window's default view
View view = new View(defaultView.getCenter(), defaultView.getSize());
//Scroll right 100 pixels by moving the view's center to the right
view.move(100, 0);
//Make the window use the view
window.setView(view);
// ... (main loop)
The circles will both appear left of the window's center, because the view (the "camera") was moved to the right.
##Zooming - Changing the view's size Zooming means making every object appear larger or smaller, depending on the zoom factor, and also defines how much of the scene can be seen. This is achieved by changing the view's size. When you change the size of a view, this will not affect the size of render target (the window), but instead, the scene will be stretched or shrinked so that what the view deems visible is visible on the target - not more and not less.
Using the [zoom](http://jsfml.org/javadoc/org/jsfml/graphics/View.html#zoom(float\)) method, the size of the view can be changed proportionally (ie the width/height ratio stays the same) by a certain zoom factor. A factor greater than 1 will make the view smaller and all objects appear larger, this is called "zooming in". A zoom factor smaller than 1 (but always greater than zero) will enlarge the view and thus make all objects appear smaller, which is known as "zooming out".
The view's size can also be set manually using [setSize](http://jsfml.org/javadoc/org/jsfml/graphics/View.html#setSize(float, float)). This has less practical use, but it allows a finer control over the view's size. If the view's size is equal to the render target's size, everything will appear normal, everything else will cause a zooming effect. Using this method, you can also change the view's proportions. For example, by making the view more narrow but keeping the height, everything will be stretched horizontally.
##Rotating The whole scene can easily be rotated around its center using the [setRotation](http://jsfml.org/javadoc/org/jsfml/graphics/View.html#setRotation(float\)) and [rotate](http://jsfml.org/javadoc/org/jsfml/graphics/View.html#rotate(float\)) methods. This should need no further explanation.
##Reset The [reset](http://jsfml.org/javadoc/org/jsfml/graphics/View.html#reset(org.jsfml.graphics.FloatRect\)) method is a powerful tool to determine the view's area. The rectangle passed to this method will be used to set the view's center and size correctly. Furthermore, this method resets the view's rotation to zero.
For instance, if you want the view to show the exact area of 400x300
pixels with (100, 100)
as the top left corner, you would use reset like this:
view.reset(new FloatRect(100, 100, 400, 300));
##Coordinate conversion When changing the view's properties, coordinates will be obscured. Coordinates on the window do no longer equal coordinates in the scene and vice versa.
For instance, if an object is at (100, 100)
in the scene, and the current view is moved left by 200 pixels, the object will appear at (300, 100)
on the render target. This gets a lot more complicated when zooming and rotation is used.
In many use cases, it is important to be able to convert scene coordinates to window coordinates or vice versa. This is needed when you want to find the object that is where the user clicked a mouse button, or you need to draw non-transformed HUD elements (e.g. health bars) above an object.
The RenderTarget interface provides two methods for these use cases: [mapCoordsToPixel](http://jsfml.org/javadoc/org/jsfml/graphics/RenderTarget.html#mapCoordsToPixel(org.jsfml.system.Vector2f\)) and [mapPixelToCoords](http://jsfml.org/javadoc/org/jsfml/graphics/RenderTarget.html#mapPixelToCoords(org.jsfml.system.Vector2i\)).
mapCoordsToPixel will convert a world coordinate to a window point (pixel) using the current view. For example, let's assume that we have a Sprite and want to find out where it is located on the window:
Vector2i windowPos = window.mapCoordsToPixel(sprite.getPosition());
mapPixelToCoords does the opposite, it converts a window point (pixel) to a world coordinate. Let's assume that the user clicked somewhere on the window (given a MouseEvent) and we need the position this is at in our world:
Vector2f worldPos = window.mapPixelToCoords(mouseEvent.position);
Both methods can optionally be given a View object. The render target will then do the conversion using the view that was passed, instead of its current view.
##Viewports Sometimes it makes sense to have the contents of a view only take a certain portion of the screen. A good example for this is split-screen multiplayer, where there would be 4 views that appear in different corners of the render target.
This concept is called a viewport. It makes sure that the contents of a view are relative to a certain position on the render target and limits the space it uses. The viewport for a view can be set using the [setViewport](http://jsfml.org/javadoc/org/jsfml/graphics/View.html#setViewport(org.jsfml.graphics.FloatRect\)) method. Note that the metric system used for the rectangle is not pixels. A view is independent of the render target it will be used for, therefore the position and size of a viewport is measured in percent of the render target's size.
As a simple example, let us assume that we a border around our scene that takes 2% of the screen on each side. This would mean that we place the viewport at (2%, 2%)
and it has a size of (96%, 96%)
(100% - 2 * 2%). This particular viewport would be set like this:
view.setViewport(new FloatRect(0.2f, 0.2f, 0.96f, 0.96f));
In most cases, the width and height of the render target are not the same. A full-screen render window on a 16:10 screen would be a perfect example. In the example above, this would mean that the border would use more space at the top and bottom sides of the screen than it does at the left and right sides. Let us say our border should be exactly 5 pixels on every side of the screen. This can be achieved by calculating the respective percentage of the width and height:
//Calculate what percentage of the width and height 5 pixels are
float pctX = 5.0f / window.getSize().x;
float pctY = 5.0f / window.getSize().y;
//Set the viewport
view.setViewport(pctX, pctY, 1.0f - 2 * pctX, 1.0f - 2 * pctY);