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

Author Topic: Hexagon grid  (Read 5528 times)

0 Members and 1 Guest are viewing this topic.

Eyfenna

  • Newbie
  • *
  • Posts: 12
    • View Profile
Hexagon grid
« on: May 12, 2019, 02:58:18 pm »
Hello,  I got a hexagonal grid, and it does display right and I can even put textures on each hexagon. My problem is following:

In an additional std::map I store the coordinates of the central point and the x-y coordinate of the hexagon in the grid in a std::map<sf::Vector2f, sf::Vector2i> now I try to get the sf::Vector2i as return of a map search for displaying the Hexgrid coordinates in console for the one mouse if hoovering over in the window.  I'm trying to do this with find_if algorithm on the map. The function is part of the Hexgrid class which holds the hexagonal grid:

(click to show/hide)

however compiler notifies me of an error on converting pairs.

I also tried with another lambda:

(click to show/hide)

Here the compiler can't convert pair to sf::vector2f.


So after a search I found that I might have to write something extra but can't realy bend my head around what it is and why this specific thing is lacking. Thanks for a response or a hint.

Laurent

  • Administrator
  • Hero Member
  • *****
  • Posts: 32498
    • View Profile
    • SFML's website
    • Email
Re: Hexagon grid
« Reply #1 on: May 12, 2019, 05:20:42 pm »
It would be very helpful to see that compiler error.
Laurent Gomila - SFML developer

Hapax

  • Hero Member
  • *****
  • Posts: 3379
  • My number of posts is shown in hexadecimal.
    • View Profile
    • Links
Re: Hexagon grid
« Reply #2 on: May 12, 2019, 05:28:58 pm »
You are checking equality using a floating point value, which is probably not your intention as that should be avoided, pretty much.

You can explictly convert between Vector2f and Vector2i by creating one and passing the other as a parameter to its constructor.
Since you need to use a Vector2 as a key for a map, it would be better to first convert it to integer values and then use that as the key. That is, use Vector2i as the map's key.


In case I presumed too much from the start, here's an explanation of why you shouldn't be checking equality using floating point values:
https://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
Selba Ward -SFML drawables
Cheese Map -Drawable Layered Tile Map
Kairos -Timing Library
Grambol
 *Hapaxia Links*

Eyfenna

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Hexagon grid
« Reply #3 on: May 13, 2019, 02:09:50 am »
The error message is (about translated) [same for std::map<sf::Vector2i, sf::Vector2i>]

Error C2664   "bool Hexgrid::GetGridPlace::<lambda_5b26f5554823591ff0c2ae8c47a36fad>::operator ()(std::pair<sf::Vector2i,sf::Vector2i> &) const" : Conversion from argument 1  "std::pair<const _Kty,_Ty>" to "std::pair<sf::Vector2i,sf::Vector2i> &" not possible. ConsoleApplication87   c:\program files (x86)\microsoft visual studio\2017\community\vc\tools\msvc\14.16.27023\include\algorithm   174   

Thanks for the hint with the floating point numbers.

Solved it one possible way:

I went a different way and safe the grid position (offset coordinates according to redblob site) inside the Hexagon and do an inRange comparison with the central point:

(click to show/hide)

and use this in a function inside the Hexgrid class:

(click to show/hide)

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re: Hexagon grid
« Reply #4 on: May 13, 2019, 02:18:01 pm »
The error happens, because sf::Vector2i can't be implcitly converted to sf::Vector2f. This should work:

sf::Vector2i Hexgrid::getCoordinate(sf::Vector2f avec)
{
   auto found = find_if(coordinate.begin(), coordinate.end(), [&](const std::pair<const sf::Vector2i, sf::Vector2i>& temp)->bool {return static_cast<sf::Vector2f>(temp.first) == avec; });
// or just (const auto& temp) in lambda
   return found->second;
}

Also note that in std::map the key has "const" type.

Also, maybe pass "avec" as Vector2i so not casts will be needed in lambda?
Also note that "found" is an iterator, so if find_if returns "end" iterator, calling "->second" on it will result in segfault, so you need to check if the coordinate was found or not.
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Eyfenna

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Hexagon grid
« Reply #5 on: May 20, 2019, 08:18:10 pm »
Thanks for the helpfull replies ;D

As I'm not so sure with Vertexarrays I went following way:
For the hexagonal grid I made a hexagon class(drawable) which holds the vertexarray to be more precise std::vector<vertex>. A templated GameGrid class holds a std::vector of Hexagons for example and generates the field.
I did some refractoring on it and except a pointer to a maploader - that holds the map information in an array - and three member function pointers on this class for the getters in this way I could remove the maploader header from the  GameGrid header.
I was wondering if that is still good c++ or overengineering things?

Well before describing it lengthily I post the source code for GameGrid and the hexagon class
The code for GameGrid template is all in a header now, moving things to an .inl when I played around with this format.
In so far the code for GameGrid is lengthy:

(click to show/hide)


Here the code for the Hexagon class:

the header
(click to show/hide)

and here the .cpp with the bodies of the memberfunction for Hexagon:

I left out the dependecy for VisualStudio
(click to show/hide)
« Last Edit: May 20, 2019, 08:20:05 pm by Eyfenna »

Elias Daler

  • Hero Member
  • *****
  • Posts: 599
    • View Profile
    • Blog
    • Email
Re: Hexagon grid
« Reply #6 on: May 21, 2019, 11:21:44 am »
Some things:

1)

virtual void draw(sf::RenderTarget& target, sf::RenderStates states) const

Should be

void draw(sf::RenderTarget& target, sf::RenderStates states) const override

2) This will do tons of copies per each frame:

for (Fieldtype a : mGrid)

Do this:

for (const auto& a : mGrid)

3) Maybe store pmResources and other stuff you can by reference, not by pointer. Seems safer (you're passing it into ctor, anyway)

4) In my opinion, it's more useful to list members in the following order: public, protected, private. I'm more interested in seeing what I can actually call first.

5) Maybe separate implementation into ".inl" files, don't have one giant header.

6) Think about providing default values to callbacks in some other way in GameGrid. Right its constructor looks scary - too many arguments.

7) I'd store all callbacks as std::function's, not as pointers to functions - it provides a lot more flexibilty.

8 ) In hexagon class you store vertices as this:

std::vector<sf::Vertex> oneHex;
std::vector<sf::Vertex> twoHex;
 

I'd store it like this:

std::array<sf::Vertex, 12> oneHex;
std::array<sf::Vertex, 12> twoHex;
 

^ no dynamic allocations!

9) The formulas for setting hexagon vertices look scary. Pretty sure it can be simplified and don't be full of copy-pasted
Tomb Painter, Re:creation dev (abandoned, doing other things) | edw.is | @EliasDaler

Eyfenna

  • Newbie
  • *
  • Posts: 12
    • View Profile
Re: Hexagon grid
« Reply #7 on: May 27, 2019, 09:22:27 pm »
The post lead to me doing thinking about the code.

9) The formulas for setting hexagon vertices look scary. Pretty sure it can be simplified and don't be full of copy-pasted

Good tip, I concluded that a

const sf::Vector2f Orientation[] = { {-.5f,-0.25f},{0.f,-0.5f}, {0.5f,-0.25f},{0.5f,0.25f},{0.f,0.5f},{-0.5,0.25f}, };
(imitating a thing from redblobgames)

allows to shorten the vertix location setting code for an empty hexagon(sf::LineStrip) to

int a;
for (int i = 0; i < 7; ++i)
{
if (i - 6 >= 0) a = i - 6;
else a = i;
mBare.push_back(sf::Vertex(sf::Vector2f((mPosition.x + width*Orientation[a].x), (mPosition.y +height*Orientation[a].y))));
}
 

similar for the textured vertices location.


7) I'd store all callbacks as std::function's, not as pointers to functions - it provides a lot more flexibilty.

Done, std::bind is sort of easiert to handle than pointers to memberfunction once one has understood it. The reason I used function pointers was that callback with them came to my mind at first and std::bind doesn't appear in tutorial pages about callbacks I found on google.

With std::function<> callback I found also that I can leave out the pointer to the class. That is nice, works with the maploader.

« Last Edit: May 27, 2019, 09:38:33 pm by Eyfenna »