2
\$\begingroup\$

I am working on a 2D grand strategy game (like Hearts of Iron from Paradox but as I said only 2D game) and I would like to render the area names on the map. I made the Polygons for each area. How can I render a String inside that polygon?

Here is the image from my game (I put some area names onto the image to show what I would like to achieve): enter image description here Here is the code where the polygon is being made (please check it because this is the first time I use polygons):

private Polygon pol;


    public Polygon polygon(Map m) {
        if (pol == null) {
            float[] vertices = new float[border().size * 2]; // the border() method returns a collection of 2D vectors/points which are the borders.
            for (int i = 0; i < vertices.length; i += 2) {
                Vector2 v = border().get(i / 2);
                vertices[i] = v.x;
                vertices[i + 1] = m.height - v.y - 1; // m.height is the map's height which is 2160; I convert here the coords (not sure if it is neceseray, the top left corner is the 0,0 coord in the map)
            }
            pol = new Polygon(vertices);
            pol.setPosition(0, 0);
            pol.setOrigin(0, 0);
        }
        return pol;
    }

How I checked if the area is on the screen:

private Vector3 ivm = new Vector3();
    public boolean isVisible(Camera cam) {
        for (Vector2 vec : points) {
            ivm.set(vec, 0);
            if (cam.frustum.pointInFrustum(ivm)) {
                return true;
            }
        }
        return false;
    }
\$\endgroup\$
  • \$\begingroup\$ Try concave decomposition and then put the text inside the biggest convex's centroid, possibly varying font size depending on the size of the convex. \$\endgroup\$ – Ocelot Aug 29 at 18:10
  • \$\begingroup\$ Can you please help me how I can do that? \$\endgroup\$ – FiveShipHUN Aug 29 at 18:28
  • \$\begingroup\$ Do all 3000 of your regions need to show a label simultaneously, or only the ones currently on-screen / at sufficient zoom to be legible? Think of Google Maps - you don't see every label all at once. ;) \$\endgroup\$ – DMGregory Aug 29 at 18:31
  • \$\begingroup\$ I have tried the labels but I could not do it (maybe I did something wrong). It took more time to check wether the area is on the screen than rendering everything. EDIT: I put the method how I checked. \$\endgroup\$ – FiveShipHUN Aug 29 at 19:54
1
\$\begingroup\$

I suggest.

Find right text size for your world. For example you can dynamically create font:

public static BitmapFont getFontInWorldUnits(float size, float worldHeght) {
   FreeTypeFontGenerator generator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/simpleprintbold.ttf"));
   FreeTypeFontGenerator.FreeTypeFontParameter parameter = new FreeTypeFontGenerator.FreeTypeFontParameter();
   int calcSize = (int)(size/worldHeght * Gdx.graphics.getHeight());
   parameter.size = calcSize>72?72:calcSize;
   parameter.color = Color.WHITE; parameter.borderWidth = 2; parameter.borderStraight = true;
   parameter.characters ="0123456789LHAASDGGMATEJ CAPHEIW:.F,-+";
   parameter.minFilter = Texture.TextureFilter.Linear; parameter.magFilter = Texture.TextureFilter.Linear;
   BitmapFont tmp = generator.generateFont(parameter);
   tmp.getData().markupEnabled = true;
   tmp.getData().setScale((float)calcSize/tmp.getCapHeight());
   generator.dispose(); // avoid memory leaks, important
   return tmp;
}

Calculate "semi-center" for each polygon shape (find max, min for X, Y axis and then calculate center X ((maxX-minX)/2f), same for Y axis). Yes this is not exactly what you are asking for, but in most cases simple solutions are good enough. If this would produce too many mistakes, you can upgrade it later. Than, draw your text on calculated position (center text):

   //Vector3 inWordCoordinate = new Vector3(x ,y, 0);
   //Vector3 inScreeCoordinates = boardCam.project(inWordCoordinate); 
   GlyphLayout layout = new GlyphLayout(font, text); //this line is needed to get text box
   //font.setColor(color);
   font.draw(game.batch, layout , inScreeCoordinates.x-layout.width/2, inScreeCoordinates.y+layout.height/2); //draw text

Possible improvements:

  • When you calculate polygon "semi center" move it in y direction to be sure that it is in polygon (try not to do it in game loop). For this you can scan y-ax from top to bottom use Polygons contains(x,y) method. From max/min you can calculate new center.

  • You can have different font sizes, based on polygon size (distance between polygon max, min values) you select font that fits best.

  • If area is upright (height>width) rotate text for 90 degrees or calculate even more precise angle, ...

Also there are other options (most likely not in your case). For example, if you have fix areas, write text/labels in some paint program directly on map, than make textures for each area (make some util program too automate it)...

\$\endgroup\$
  • \$\begingroup\$ Thanks a lot :) \$\endgroup\$ – FiveShipHUN Aug 30 at 18:27

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.