Create board for Catan with SFML - c++

I want to create the board for Catan game with SFML, and all i need is 19 shapes(hexagons) for each of them i can take all the 6 corners and the 6 sides, to build cities or roads.
For shapes i make this:
std::vector<sf::CircleShape> shape(19);
int n = 0;
int shape_y = 100;
for (size_t index = 0; index < shape.size(); index++) {
if (index < 3) {
sf::CircleShape sh(80, 6);
sh.setPosition(200 + n, shape_y);
sh.setFillColor(sf::Color::Magenta);
shape[index] = sh;
n += 140;
}
if (index == 3)
n = 0;
if (index < 7 && index >= 3) {
sf::CircleShape sh(80, 6);
sh.setPosition(130 + n, shape_y + 120);
sh.setFillColor(sf::Color::Blue);
shape[index] = sh;
n += 140;
}
if (index == 7)
n = 0;
if (index >= 7 && index < 12) {
sf::CircleShape sh(80, 6);
sh.setPosition(60 + n, shape_y + 240);
sh.setFillColor(sf::Color::Red);
shape[index] = sh;
n += 140;
}
if (index == 12)
n = 0;
if (index >= 12 && index < 16) {
sf::CircleShape sh(80, 6);
sh.setPosition(130 + n, shape_y + 360);
sh.setFillColor(sf::Color::Green);
shape[index] = sh;
n += 140;
}
if (index == 16)
n = 0;
if (index >= 16 && index < 19) {
sf::CircleShape sh(80, 6);
sh.setPosition(200 + n, shape_y + 480);
sh.setFillColor(sf::Color::Yellow);
shape[index] = sh;
n += 140;
}
}
This looks like this:
But how i get the corners and the sides from shapes? If i use getPoint(0) for corner, it don't draw the point where its belongs.
If this is not a good idea, what can i use for this problem?

I did that mechanism long time ago, a simple way to achieve that.
My approach was to represent each hexagon as a circle. The drawn hexagon was embedded into that circle. To check if the mouse was over a corner or a side, I did a simple check:
If the point was inside 3 circles simultaneously, it was a corner (the meeting corner of those 3 hexagons)
If the point was inside 2 circles, it was a side.
If the point was inside 1 circle, it was a whole hexagon
Proof of concept:
The blue hexagons conform the proper board, each of these have a red circle (larger than the hexagon itself).
The green hexagons are out of the board (they aren't part of the game board) and they help to know if mouse is over sides or corners of the outter hexagons.
Full code is in my Github repository, but is quite old and may be out of date

Related

tbb increment number of vector element without using mutex

Currently I am working on paralizing an image processing algorithm to extract edges from a given image. I recently started with code parallelizing.
Anyway a part of the program requires me to compute the histogram of the image and count the number of occurding pixels from 1 to its maximum gradient Intensity.
I have implemented it as the following:
tbb::concurrent_vector<double> histogram(32768);
tbb::parallel_for(tbb::blocked_range<size_t>(1, width - 1),
[&](const tbb::blocked_range<size_t>& r)
{
unsigned int idx;
for (size_t w = r.begin(); w != r.end(); ++w) //1 to (width -1)
{
for (size_t h = 1; h < height - 1; ++h)
{
idx = h * width + w;
//DO SOME STUFF BEFORE
//Get max gradient intensity
if (pgImg[idx] > maxGradIntensity)
{
maxGradIntensity = pgImg[idx];
}
//Get histogram information
if (pgImg[idx] > 0)
{
tbb::mutex::scoped_lock sync(locked);
++histogram[(int)pgImg[idx]];
++totalGradPixels;
}
}
}
});
histogram.resize(maxGradIntensity);
So the part where it becomes tricky for me is the following:
if (pgImg[idx] > 0)
{
tbb::mutex::scoped_lock sync(locked);
++histogram[(int)pgImg[idx]];
++totalGradPixels;
}
How can I avoid using tbb::mutex? I had no luck with setting the vector to tbb::atomic. Maybe I did something wrong there. Any help on this topic would be appreciated.

How do I prevent over-correcting in my autonomous driving solution?

I am working on an autonomous driving solution for Euro Truck Simulator 2 with OpenCV in C++.
Here is where we detect the curve of the road:
int bottom_center = 160;
int sum_centerline = 0;
int count_centerline = 0;
int first_centerline = 0;
int last_centerline = 0;
double avr_center_to_left = 0;
double avr_center_to_right = 0;
//#pragma omp parallel for
for (int i = 240; i > 30; i--){
double center_to_right = -1;
double center_to_left = -1;
for (int j = 0; j < 150; j++) {
if (contours.at<uchar>(i, bottom_center + j) == 112 && center_to_right == -1) {
center_to_right = j;
}
if (contours.at<uchar>(i, bottom_center - j) == 112 && center_to_left == -1) {
center_to_left = j;
}
}
if (center_to_left != -1 && center_to_right != -1){
int centerline = (center_to_right - center_to_left + 2 * bottom_center) / 2;
if (first_centerline == 0) {
first_centerline = centerline;
}
cv::circle(outputImg, Point(centerline, i), 1, Scalar(30, 255, 30), 3);
cv::circle(outputImg, Point(centerline + center_to_right+20, i), 1, Scalar(255, 30, 30) , 3);
cv::circle(outputImg, Point(centerline - center_to_left+10, i), 1, Scalar(255, 30, 30) , 3);
sum_centerline += centerline;
avr_center_to_left = (avr_center_to_left * count_centerline + center_to_left) / count_centerline + 1;
avr_center_to_right = (avr_center_to_right * count_centerline + center_to_right) / count_centerline + 1;
last_centerline = centerline;
count_centerline++;
}
else {}
}
And here is my current solution for steering:
int diff = 0;
if (count_centerline != 0) {
diff = sum_centerline / count_centerline - bottom_center;
int degree = atan2(last_centerline - first_centerline, count_centerline) * 180 / PI;
//diff = (90 - degree);
int move_mouse_pixel = diff;
cout << "Steer: " << move_mouse_pixel << "px ";
if (diff <= 20 || diff >= -20){
SetCursorPos(pt.x + (move_mouse_pixel / 10), height / 2);
}
else{
SetCursorPos(pt.x + (move_mouse_pixel / 25), height / 2);
}
}
Finally, here is a video of what my program currently does: https://www.youtube.com/watch?v=rqyvoFuGKKk&feature=youtu.be
The current problem I have is that the steering does not center fast enough, leading it to continually over-correct until it swerves off the lane. I have tried to increase steering sensitivity in-game, to allow for faster or slower turning, but this either makes the truck spin out of control or not turn enough when driving along a large curve.
My current method just divides slight movements (between -20px and 20px) by 10, and large movements by 20. I've also tried reversing this but did not fix the over-correcting problem.
There are two possible solutions that I have found so far:
I could incrementally increase the divider for which we apply to move_mouse_pixel, therefore reducing the force of steering done between small movements.
Or, I could somehow make the program center the steering wheel more quickly. I am not sure how I would implement this.
What do you guys think?
I believe that PID controller would be suitable for this task.
https://en.wikipedia.org/wiki/PID_controller
In your situation it would look similar to this:
diffOld = diff;
diff = sum_centerline / count_centerline - bottom_center;
SetCursorPos(width/2 + Kp* diff + Kd*(diff - diffOld) , height / 2);
Do not use if statement in this controller. You need to keep steering even if there is no error to corect. I would suggest to skip integral part, because your object integrate (when you do not drive straight you integrate error). You need to experimentally choose values of Kp and Kd parameters, for example with Ziegler–Nichols method https://en.wikipedia.org/wiki/Ziegler%E2%80%93Nichols_method.

Shrinking images using recursion incorrect positioning

I am writing code that takes an image and creates subimages within the original image. I am doing this recursively with a rectangle class that keeps track of starting and stopping positions of the subimage. After the 3rd recursive call is where i run into trouble. The new subimages are being placed in the incorrect spots. They should be shrinking as they approach the top right corner of the image. I have run through the debugger and watched the start and stop positions change with each call and they reflect movement toward the top right corner. The only place I think the error could be is where I create a new rectangle called rRight to be put into the recursive call.
int main()
{
CImage original("test256.gif");
Rectangle rPrev(0, 0, original.getRows(), original.getCols());
Rectangle r(0, 0, (original.getRows() / 2), (original.getCols() / 2));
CImage final = fractal(original, r, rPrev);
final.output("output.gif");
system("PAUSE");
return 0;
}
CImage fractal(CImage &origin, Rectangle &r, Rectangle &rPrev)
{
if (r.getX2() - r.getX1() > 0 && r.getY2() - r.getY1() > 0)
{
drawTopLeft(origin, r, rPrev);
Rectangle rRight(0, r.getY2(), (r.getX2() / 2), (r.getY2() + ((r.getY2() - r.getY1()) / 2)));
fractal(origin, rRight, r);
}
return origin;
}
void drawTopLeft(CImage &origin, Rectangle &r, Rectangle &rPrev)
{
for (int row = rPrev.getX1(); row < rPrev.getX2(); row += 2)
{
for (int col = rPrev.getY1(); col < rPrev.getY2(); col += 2)
{
pixel p1 = origin.getPixel(row, col);
pixel p2 = origin.getPixel(row + 1, col);
pixel p3 = origin.getPixel(row, col + 1);
pixel p4 = origin.getPixel(row + 1, col + 1);
int avgRed = (p1.red + p2.red + p3.red + p4.red) / 4;
int avgGreen = (p1.green + p2.green + p3.green + p4.green) / 4;
int avgBlue = (p1.blue + p2.blue + p3.blue + p4.blue) / 4;
origin.setPixel((row / 2) + r.getX1(), (col / 2) + r.getY1(), avgRed, avgGreen, avgBlue);
}
}
}

Qt Linear gradient for polygons

I want to fill the polygons with linear gradient color and am not sure how to implent it. So far am using the following code.
std::vector<Element*> elems = m_mesh->getElements();
for (unsigned int i=0; i<elems.size(); ++i)
{
std::vector<Node*> nodes = elems[i]->getNodes();
QPolygon elepolygon;
unsigned int j;
for (j=0; j<nodes.size(); ++j)
{
elepolygon << QPoint(nodes[j]->x()*scalex+shiftx,nodes[j]->y()*scaley+shifty);
}
int r = qrand() % ((255 + 1) - 0);
int g = qrand() % ((255 + 1) - 0);
int b = qrand() % ((255 + 1) - 0);
QBrush brush(QColor(r,g,b));
QPainterPath tmpPath;
tmpPath.addPolygon(elepolygon);
painter.fillPath(tmpPath,brush);
painter.drawPolygon(elepolygon);
}
You can create a QLinearGradient, set the colors at different stop points using setColorAt function and set the brush of the painter to the created QLinearGradient :
painter->setPen(QPen(Qt::black, 3));
QLinearGradient gradient(-400,-400,400,400);
gradient.setColorAt(0, QColor(110,110,110));
gradient.setColorAt(0.27, QColor(230,230,230));
gradient.setColorAt(0.44, QColor(110,110,110));
gradient.setColorAt(0.76, QColor(230,230,230));
gradient.setColorAt(1, QColor(110,110,110));
painter->setBrush(gradient);
painter->drawPolygon(elepolygon);
In this example the interpolation area is between (-400,-400) and (400,400). You can have arbitrary ones which define the direction of the gradient.

SFML mouse position and collision loading from file

Okay so I have two problems. First off I have made a square that is locked to a grid the same size as my tiles. This is what will be used for changing tiles. It works fine except for when I start scrolling. I know why it is. It's because the mouse position is relative to the window, not the map. I was wondering if there was a way I could code the squares to follow my mouse even when I scroll.
Current code:
if (Event.type == sf::Event::MouseMoved)
{
rect.setFillColor(sf::Color(255, 0, 255));
rect.setSize(sf::Vector2f(BLOCKSIZE, BLOCKSIZE));
int x_offset = (Window.getView().getCenter().x - Window.getSize().x /2);
int y_offset = (Window.getView().getCenter().y - Window.getSize().y /2);
rect.setPosition(((sf::Mouse::getPosition(Window).x/32 *32) + (x_offset/32 *32)), ((sf::Mouse::getPosition(Window).y/32 * 32) + (y_offset/32 * 32)));
std::cout << "Mouse position: x:" << ((sf::Mouse::getPosition(Window).x/32 *32) + (x_offset/32 *32)) << " y:" << ((sf::Mouse::getPosition(Window).y/32 * 32) + (y_offset/32 * 32)) << ")\n\n";
}
Next problem is loading collision.
Code:
for(int i = 0; i < CollisionVector.size(); i++)
{
//Loop through the height of the MapVector
for(int j = 0; j < CollisionVector[i].size(); j++)
{
sf::RectangleShape rect;
//If the stored number is 1
if(CollisionVector[i][j] == 1)
{
rect.setFillColor(sf::Color(255, 0, 255));
rect.setSize(sf::Vector2f(BLOCKSIZE, BLOCKSIZE));
//Set the position of the rectangle
rect.setPosition(j * BLOCKSIZE, i * BLOCKSIZE);
}
//Draw the rectangle
Window.draw(rect);
}
}
I get a blank screen if I add that in. I wanted the rectangles to be transparent but I changed it to pink just in case that was the problem (Which it wasn't)
Screen scrolling code:
void Camera::Update(float x, float y)
{
cameraX = x - (ScreenWidth / 2);
cameraY = y - (ScreenHeight / 2);
if (cameraX < 0)
cameraX = 0.0;
if (cameraY < 0)
cameraY = 0.0;
CameraPosition.reset(sf::FloatRect(cameraX, cameraY, ScreenWidth, ScreenHeight));
CameraPosition.setViewport(sf::FloatRect(0,0,1,1));
}
For the first one: since you are scrolling by changing the sf::View, calculate the view offset and add it to your coordinates:
[...]
float x_offset = Window.getView().getCenter().x - Window.getSize().x * .5f;
float y_offset = Window.getView().getCenter().y - Window.getSize().y * .5f;
rect.setPosition(sf::Mouse::getPosition(Window).x/32 * 32 + x_offset,
sf::Mouse::getPosition(Window).y/32 * 32 + y_offset;
For the second one... uhhh I've got nothing right now. I've checked SFML and a sf::RectangleShape is default-initialized to have a size of (0, 0) so that's not the issue. Maybe the problem is in surrounding code?