Welcome, Guest. Please login or register. Did you miss your activation email?

Author Topic: mini-map using views  (Read 7379 times)

0 Members and 1 Guest are viewing this topic.

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
mini-map using views
« on: February 11, 2016, 03:21:10 am »
Hey Folks,

So I've setup a main window using a portion of the map that I want the player to use. Scrolling is working fine using keys and mouse.

Then in the bottom corner, I have a mini-map view which shows the entire map but obviously in mini format. Here is the calc function that I am using to determine the mini map sizes.


void drawEngine::calcMiniMapView()
{
        int xSize = gameWindow.getSize().x * 0.25;
        int ySize = gameWindow.getSize().y * 0.23;

        float xFloat = (float)xSize/gameWindow.getSize().x;
        float yFloat = (float)ySize/gameWindow.getSize().y;

        miniMapView.reset(sf::FloatRect(0.f, 0.f, xSize, ySize));
        miniMapView.setViewport(sf::FloatRect(0.f, 0.77, xFloat, yFloat));
}

 


So what I am trying to do now is to draw a small thin rectangle on the mini-map view, showing the location on the mini-map of what is displayed in the main mapview and I am really struggling to get my head around this idea.

I am struggling to understand how I can get the position from the main view of what is displayed and then convert that to the mini-map. So I was hoping for ideas on how to perform this task.

Do I need to:-

(1) To draw a rectangle, I need to set it's position? So I need to get m_center of the map_view and calc the top-left and bottom-right? I believe the below should do that.


sf::Vector2i topLeft, bottomRight;

        int x = (mapView.getCenter().x - mapView.getSize().x / 2);
        int y = (mapView.getCenter().y - mapView.getSize().y / 2);

        topLeft.x = x;
        topLeft.y = y;

        x = (mapView.getCenter().x + mapView.getSize().x / 2);
        y = (mapView.getCenter().y + mapView.getSize().y / 2);
         
        bottomRight.x = x;
        bottomRight.y = y;

 

(2) Once I get that top-left, I can use that to set the size and position of a rectangle.
(3) However these seem to be the values for the mapview. How can I convert that to a value appropraite to the mini-map dimensions?

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: mini-map using views
« Reply #1 on: February 11, 2016, 05:21:37 am »
You want to know the corners of the mini-map?
Which co-ordinate system will you be using? mapView's? pixels? window's default view?

Or do you want the co-ordinates that you use during mapView to be converted to the co-ordinates that you use during miniMapView?

If it's the latter, as I'm starting to think that it might be, you simply need to set the view of the window (or other render target) to miniMapView instead of mapView before drawing to that window.

For example:
If your mapView has a centre of (0, 0) and a size of (200, 200), the window displays (-100, -100) - (100, 100).
Your miniMapView should mirror the mapView's centre and size so should also be: centre (0, 0) and size (200, 200). The mini-map will the also display (-100, -100) - (100, 100). This is because you are drawing the same thing but adjusting the viewport to make it smaller.
Set the mini-map's viewport to match the part of the screen, which you have done.
When you draw to the normal map:
window.setView(mapView);
window.draw(normalStuff);
When you draw to the mini-map:
window.setView(miniMapView);
window.draw(miniMapStuff);

Remember that the co-ordinates are the same. The mini-map is just resized and moved by changing its viewport.
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: mini-map using views
« Reply #2 on: February 11, 2016, 09:00:04 am »
Hi Hapax,

Sorry I don't think I explained myself very well last time. Hopefully a screenshot will show up better. For some reason when I use the IMG code to display this PNG, it doesn't show the full width of it, so I am just putting the tinypic link instead.

So mapview is the main window that I can scroll around.
The minimapview is static is in the bottom left corner. See the yellow highlight box?

http://tinypic.com/r/25uo5eq/9

I need a way to be able to ensure the size of this rectangle is the same as what is shown in the mapview.
I need a way to be able to ensure the position of this rectangle is the same as what is shown in the mapview.
Finally, the position of the rectangle should move when I scroll in the mapview. (I scroll with a mapview.move call).

I got the rectangle position as per the above screenshot using the below, but it isn't quite right. It doesn't cover all of Italy when it is displayed in the mapview. Also I am not sure when I move the mapview, how to get the border to move in tandem in the minimapview. If I just use the same value in minimap.move it goes flying off-screen.

        sf::Vector2f borderSize(miniMapView.getSize().x * miniMapView.getViewport().width, miniMapView.getSize().y * miniMapView.getViewport().height);
        sf::Vector2f borderPos(miniMapView.getCenter().x - borderSize.x, miniMapView.getCenter().y - borderSize.y);
 

Here is now I am defining the map and mini-views

void drawEngine::calcMapView()
{
        int xSize = gameWindow.getSize().x;
        int ySize = gameWindow.getSize().y * 0.800;

        float xFloat = (float)xSize/gameWindow.getSize().x;
        float yFloat = (float)ySize/gameWindow.getSize().y;

        mapView.reset(sf::FloatRect(0.f, 0.f, xSize, ySize));
        mapView.setViewport(sf::FloatRect(0.f, 0.f, xFloat, yFloat));
}

void drawEngine::calcMiniMapView()
{
        int xSize = gameWindow.getSize().x * 0.25;
        int ySize = gameWindow.getSize().y * 0.23;

        float xFloat = (float)xSize/gameWindow.getSize().x;
        float yFloat = (float)ySize/gameWindow.getSize().y;

        miniMapView.reset(sf::FloatRect(0.f, 0.f, xSize, ySize));
        miniMapView.setViewport(sf::FloatRect(0.f, 0.77, xFloat, yFloat));
}

 

Then to draw the minimap, I change the scale of the images of the regions to fit into the minimapview.
I then define a rectangle, try to work out position and size. Then I draw that


void drawEngine::drawMiniMap()
{
        gameWindow.setView(miniMapView);

        sf::Vector2f origPos;

        for (int i = 0; i < regionListPtr->size(); i++)
        {
                regionListPtr->at(i).getRegionSprite()->setPosition(regionListPtr->at(i).getImagePosition());
                regionListPtr->at(i).getRegionSprite()->setScale(0.35f, 0.33f);
                gameWindow.draw(*regionListPtr->at(i).getRegionSprite());


        sf::Vector2f borderSize(miniMapView.getSize().x * miniMapView.getViewport().width, miniMapView.getSize().y * miniMapView.getViewport().height);
        sf::Vector2f borderPos(miniMapView.getCenter().x - borderSize.x, miniMapView.getCenter().y - borderSize.y);
        sf::RectangleShape border = createArmyUnitBorder(borderPos, borderSize, 4);    
        gameWindow.draw(border);
}

sf::RectangleShape drawEngine::createArmyUnitBorder(sf::Vector2f borderPos, sf::Vector2f borderSize, int borderThickness)
{
        sf::RectangleShape returnBorder;

        returnBorder.setOutlineThickness(borderThickness);
        returnBorder.setOutlineColor(sf::Color::Yellow);
        returnBorder.setFillColor(sf::Color::Transparent);
        returnBorder.setSize(borderSize);
        returnBorder.setPosition(borderPos);

        return returnBorder;
}
 

So I assumed I would have to work out what is being displayed in the mapview and somehow convert it to the minimapview. However I don't fully understand whether this is correct and I don't quite follow what you are saying. I am setting the view to minimap when I draw the rectangle but the position and size are not correct?

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: mini-map using views
« Reply #3 on: February 11, 2016, 06:03:01 pm »
Ah, it makes a little more sense now.

I suggest that you use SFML's vectors instead of using separate x and y components. That's what they're for! It can really increase code clarity.
(click to show/hide)

However, you are creating the view size of the mini-map to match its actual size. If you think about it conceptually, the mini-map should be showing more of the map so its view size should be larger.
Work out the map size, then work out the mini-map size by specifying the normal map's limits.
Then, when you draw to the mini-map, use the normal map's co-ordinates and they will automagically match!
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: mini-map using views
« Reply #4 on: February 12, 2016, 03:12:55 am »
oh I see what you are saying now. sorry I was in the mode that the mini-map should be smaller. There is an example of a mini-map in this tutorial where the viewport is set smaller.....and I was assuming the size should be smaller too.

http://www.sfml-dev.org/tutorials/2.3/graphics-view.php

See below, where I am increasing the viewSize now to match the scale up factor that I assuming when I scale up the region sprites.


void drawEngine::calcMiniMapView()
{
        const sf::Vector2f zeroVector(0.f, 0.f);
        const sf::Vector2f viewportSize(0.39f, 0.6f);
        const sf::Vector2f viewportOffset(0.f, 0.77f);
        sf::Vector2f viewSize(gameWindow.getSize());
        viewSize.x = gameWindow.getSize().x * getScaledRegionFactors().x;
        viewSize.y = gameWindow.getSize().x * getScaledRegionFactors().y;

        miniMapView.reset(sf::FloatRect(zeroVector, viewSize));
        miniMapView.setViewport(sf::FloatRect(viewportOffset, viewportSize));

        initMiniMapScreenBackground();
}

 

Now when I draw the border, I simply use the mapview as you specified but ensuring to set the view correctly before drawing.


        sf::Vector2f borderPos(mapView.getCenter().x - mapView.getSize().x / 2, mapView.getCenter().y - mapView.getSize().y / 2);
        sf::Vector2f borderSize(mapView.getSize().x, mapView.getSize().y);

 

Thanks Hapax - much appreciated.




Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: mini-map using views
« Reply #5 on: February 12, 2016, 05:23:08 am »
You're welcome. I'm glad you got it sorted  :)

        sf::Vector2f viewSize(gameWindow.getSize());
        viewSize.x = gameWindow.getSize().x * getScaledRegionFactors().x;
        viewSize.y = gameWindow.getSize().x * getScaledRegionFactors().y;
The viewSize is getting initialised with the size of gameWindow and then you're overwriting those values with new calculations based on the gameWindow size.
You could do (similar to what I did above):
        sf::Vector2f viewSize(gameWindow.getSize());
        viewSize.x *= getScaledRegionFactors().x;
        viewSize.y *= getScaledRegionFactors().y;

If you're going to calculate them directly, you could just do:
sf::Vector2f viewSize(
    gameWindow.getSize().x * getScaledRegionFactors().x,
    gameWindow.getSize().y * getScaledRegionFactors().y);

I don't know if you noticed but this line in your code looks like it could be wrong:
viewSize.y = gameWindow.getSize().x * getScaledRegionFactors().y;
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: mini-map using views
« Reply #6 on: February 12, 2016, 09:28:19 pm »
Oh good point, thanks. And no I didn't spot that error until you said - it explains why my sizing was way off.

I had another question on views. I want when user clicks on minimap, the map view centers on that point.
Now first I need to detect if left mouse was pressed in the minimap view, right?

This where I get confused as there is no get position on views. So do I have get the viewport height and width, then multiply it by the game window sizes? I.e above set viewport is 0.f for x position and 0.77 for y position. So I would need to get game window size.y and multiply by 0.77?

I guess I was wondering if there was an easier method to do that?

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: mini-map using views
« Reply #7 on: February 13, 2016, 03:42:43 am »
there is no get position on views.
Well, actually, all positions are view co-ordinates.
When you specify a position, you are specifying where it will go in the view that happens to be currently active. If you set one view, draw at a position, set a different view, then draw at the same position, it would be drawn at a visible different screen location.
Remember, where co-ordinates/positions go on the screen/window/target is defined by the view.

If you want to get the mouse position in a co-ordinate system of a view, you need to do co-ordinate conversions (from screen pixels to view co-ordinates). It shows you how to do this here: http://www.sfml-dev.org/tutorials/2.3/graphics-view.php#coordinates-conversions
You will need to either set the active view to the one you want to convert to (in your question, it would be miniMapView) or you can also pass the view to the converter function: http://www.sfml-dev.org/documentation/2.3.2/classsf_1_1RenderTarget.php#a46eb08f775dd1420d6207ea87dde6e54

What this does is first get the mouse's pixel position on the window, then convert it to the co-ordinates used in the specified view.
In the scenario you gave "where you click on the mini-map centres the main map at that location" should be, in your case, something like (pseudo code):
getMousePosition();
convertMousePositionToMiniMapView();
if (mouseClicked && mouseIsInsideMiniMap)
    mapView.setCenter(convertedMousePosition);
This should work in your case as your co-ordinate systems in both maps should match, following from previous parts of this discussion.  :)
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

starkhorn

  • Jr. Member
  • **
  • Posts: 55
    • View Profile
    • Email
Re: mini-map using views
« Reply #8 on: February 14, 2016, 05:12:46 am »
In the scenario you gave "where you click on the mini-map centres the main map at that location" should be, in your case, something like (pseudo code):
getMousePosition();
convertMousePositionToMiniMapView();
if (mouseClicked && mouseIsInsideMiniMap)
    mapView.setCenter(convertedMousePosition);
This should work in your case as your co-ordinate systems in both maps should match, following from previous parts of this discussion.  :)

Awesome - thank Hapax, this worked a treat. As you said the fact that you got me to co-ordinate both views made this really straight forward in the end. Thanks again.