Odd output from a for loop - c++

I'm using a for loop to iterate through some arrays I've created representing regions that the mouse can hover over. Then when the loop confirms the mouse is in a region it saves the iteration variable to a public variable that is used later in the main function to highlight the region the mouse is over. The problem is that the for loop is not giving the right value for the first iteration through.
{
//mouse offsets
int x = 0, y = 0;
//if mouse moves
if (event.type == SDL_MOUSEMOTION)
{
//get the mouse co-ords
x = event.motion.x;
y = event.motion.y;
for (int grid = 0; grid <= sizeof(grid_region); grid++)
{
if ((x > grid_region[grid].x) && (x < grid_region[grid].x + GRID_WIDTH) && (y > grid_region[grid].y) && (y < grid_region[grid].y + GRID_HEIGHT))
{
//set highlight region
highlight = grid;
}
}
}
}
grid_region is is made via "int grid_region[9];" and the strange part is that when I later do a print statement to see what "highlight" is when it's in grid_region[0] is prints 72. How is it possible that the iteration variable becomes 72 at any point in the loop??? Any help here? I later use highlight to apply a sprite in the grid_region and it's being applied incorrectly so this is a problem.

sizeof(grid_region) is the size in multiples of char, not the number of elements.
That is, it is sizeof(int) * 9, not nine, and apparently your int is 8 chars wide since you ended up at 72.
You can loop to < sizeof(grid_region) / sizeof(grid_region[0]) or, better, step into the 21st century and use std::vector, or std::array if your compiler is hip enough.

Related

Drag and Drop Item list not working properly on ImGUI

Im using ImGUI and I want to implement a layer menu for the images and to move them im using
Drag to reorder items in a vector.
Sometimes it works just fine but others the images just jumps from the current position to a random one.
for (int i = 0; i < this->Images->size(); i++) {
ImGui::Image((void*)(intptr_t)this->Images->at(i).texture, ImVec2(100 * temp_percentage, 100 * temp_percentage));
ImGui::SameLine();
ImGui::Selectable(this->Images->at(i).name.c_str());
if (ImGui::IsItemActive() && !ImGui::IsItemHovered())
{
int n_next = i + (ImGui::GetMouseDragDelta(0).y < 0.f ? -1 : 1);
if (n_next >= 0 && n_next < this->Images->size())
{
std::swap(this->Images->at(i), this->Images->at(n_next));
*this->CurrentImage = this->Images->front();
centerImage();
ImGui::ResetMouseDragDelta();
}
}
ImGui::Separator();
}
The problem lies at !ImGui::IsItemHovered(), there is small spacing between the lines (cell, selectable,... ), so when the mouse hovers over that spacing, the item isn't hovered but still is actived, and therefore will execute the swap and reset mouse delta multiple times making it goes to the top or bottom of the list. This will also happen if the mouse goes out of the table/window bounds.
To make the problem more visible, you can make the spacing bigger using ImGui::GetStyle().ItemSpacing.y = 50.f;.
To actually fix the problem, you'll have to calculate the item index using the mouse position, here is a way to do it, tho not perfect but it works.
ImGuiStyle& style = ImGui::GetStyle();
ImVec2 windowPosition = ImGui::GetWindowPos();
ImVec2 cursorPosition = ImGui::GetCursorPos();
// this is not a pixel perfect position
// you can try to make it more accurate by adding some offset
ImVec2 itemPosition (
windowPosition.x + cursorPosition.x,
windowPosition.y + cursorPosition.y - style.ItemSpacing.y
);
for (int i = 0; i < this->Images->size(); i++) {
ImGui::Image((void*)(intptr_t)this->Images->at(i).texture, ImVec2(100 * temp_percentage, 100 * temp_percentage));
ImGui::SameLine();
ImGui::Selectable(this->Images->at(i).name.c_str());
if (ImGui::IsItemActive() && ImGui::IsMouseDragging(0))
{
int n_next = floorf((ImGui::GetMousePos().y - itemPosition.y) / itemHeight);
if (n_next != i && n_next >= 0 && n_next < this->Images->size())
{
std::swap(this->Images->at(i), this->Images->at(n_next));
*this->CurrentImage = this->Images->front();
centerImage();
}
}
ImGui::Separator();
}
There is also another problem in your code, if there are multiple items with the same name, ImGui::IsItemActive() will return true for all of them if one is actived.
You can fix this easily by adding ##some_unique_string after the name, for example ImGui::Selectable("Image#image_1") will just display Image.

Alive neighbour cells not correctly counted

I know my title isn't very specific but that's because I have no idea where the problem comes from. I'm stuck with this problem since 2 or 3 hours and in theory everything should be working, but it's not.
This piece of code:
for ( int x = -1; x <= 1; x++ ) { //Iterate through the 8 neighbour cells plus the one indicated
for ( int y = -1; y <= 1; y++ ) {
neighbour = coords(locX + x, locY + y, width); //Get the cell index in the array
if (existsInOrtho(ortho, neighbour)) { //If the index exists in the array
if (ortho[neighbour] == 0) { //Cell is dead
cnt--; //Remove one from the number of alive neighbour cells
}
} else { //Cell is not in the zone
cnt--; //Remove one from the number of alive neighbour cells
}
}
}
Iterates through all the neighbour cells to get their value in the array (1 for alive, 0 for dead). The "coords" function, shown here:
int coords(int locX, int locY, int width)
{
int res = -1;
locX = locX - 1; //Remove one from both coordinates, since an index starts at 0 (and the zone starts at (1;1) )
locY = locY - 1;
res = locX * width + locY; //Small calculation to get the index of the pixel in the array
return res;
}
Gets the index of the cell in the array. But when I run the code, it doesn't work, the number of neighbour cells is not correct (it's like a cell is not counted every time there's some alive in the neighborhood). I tried decomposing everything manually, and it works, so I don't know what ruins everything in the final code... Here is the complete code. Sorry if I made any English mistake, it's not my native language.
This code ...
for ( int x = -1; x <= 1; x++ ) { //Iterate through the 8 neighbour cells plus the one indicated
for ( int y = -1; y <= 1; y++ ) {
Actually checks 9 cells. Perhaps you forgot that it checks (x,y) = (0,0). That would include the cell itself as well as its neighbours.
A simple fix is:
for ( int x = -1; x <= 1; x++ ) { //Iterate through the 8 neighbour cells plus the one indicated
for ( int y = -1; y <= 1; y++ ) {
if (x || y) {
Also, the simulate function (from your link) makes the common mistake of updating the value of the cell in the same array before processing state changes required for the cells beside it. The easiest fix is to keep two arrays -- two complete copies of the grid (two ortho arrays, in your code). When reading from orthoA, update orthoB. And then on the next generation, flip. Read from orthoB and write to orthoA.

p5.js - get a rectangle to move left and right repeatedly (bounce)

I'm trying out some sample code for a bigger project, and I'm having trouble getting my rectangle to bounce between two lines.
function draw() {
print(frameCount)
background(255)
var x = 150 + frameCount;
rect(x,200,15,15);
line(150,0,150,400);
line(250,0,250,400);
if (x >= 250) {
background(255)
x = 350-frameCount;
rect(x,200,15,15);
line(250,0,250,400);
line(150,0,150,400);
} if (x <= 145) {
background(255)
x = 145 + (frameCount % 100);
rect(x,200,15,15);
line(250,0,250,400);
line(150,0,150,400);
}
}
I'm getting the feeling that after the first instance, it's disregarding the original if statement, which dictates a bounce to the left. I'm really not sure what's going wrong, and any help would be appreciated.
You probably just want to store the current position and speed in a set of variables, and then move the rectangle based on those. Here's an example:
var x = 0;
var speed = 1;
function draw(){
x += speed;
if(x < 0 || x > width){
speed *= -1;
}
background(64);
line(x, 0, x, height);
}
I've written a tutorial on this available here. That's for regular Processing, but the ideas are the same in P5.js.

Flood Fill recursive stack overflow

If i try to Fill a 100x100 rectangle then i get an overflow.
A 50x50 works fine.
Is there a way to fix the overflow?
I also print out the Stack Number and sometimes the working rectangle Stack is higher then the big one (it crashes around 7000).
void draw(int x, int y)
{
if ((x >= 0 && x < 100) && (y >= 0 && y < 100))
{
canvas.set_pixel(x, y);
if (!canvas.get_pixel(x, y + 1))draw(x, y + 1);
if (!canvas.get_pixel(x, y-1))draw(x, y - 1);
if (!canvas.get_pixel(x - 1, y))draw(x - 1, y);
if (!canvas.get_pixel(x+1, y))draw(x + 1, y);
}
return;
}
The reason you get a stack overflow is that the recursion goes too deep.
How deep will it go? Well, with the algorithm the way you designed it - it will actually go to depth 100*100=10,000!
Let's look at in what order will the canvas be filled - assuming the canvas is empty and we start filling from the middle:
set the middle pixel
go to x,y+1
do that until you get to the edge
at the edge - move to x-1,0 (remember, we're at the top)
go down until the bottom
etc. etc.
The point is - you're going deeper and deeper until you fill the canvas, and then have a "chain" of recursion calls going all around the canvas and it's a waste :)
Benjamin is right that you can use a stack, but a stack basically does the exact same thing (just without the recursion), so the stack will get to depth 10,000 as well. Still a waste, and you run out of memory in some cases (for a bitmap canvas, each pixel takes 1 bit, but the stack will have 2 integers per pixel for x,y, and thus could take 64 times more memory than the canvas)
Instead - use a queue! Almost the same code:
void draw(int x, int y)
{
struct coordinate { int x, y; };
std::queue<coordinate> to_draw; // <- changed from stack to queue
to_draw.push({x, y});
while (!to_draw.empty())
{
auto top = to_draw.front(); // <- changed from top to front
to_draw.pop();
if ( (top.x >= 0 && top.x < 100)
&& (top.y >= 0 && top.y < 100)
&& !canvas.get_pixel(top.x, top.y))
{
canvas.set_pixel(top.x, top.y);
to_draw.push({top.x, top.y + 1});
to_draw.push({top.x, top.y - 1});
to_draw.push({top.x + 1, top.y});
to_draw.push({top.x - 1, top.y});
}
}
}
And now the memory needed will be <=4*100! In other words - by changing from stack to queue we changed the memory needed from N*N to 4*N.
Don't use recursion. Instead, use a stack to store the coordinates you want to draw. And iterate until the stack is empty.
void draw(int x, int y)
{
struct coordinate { int x, y; };
std::stack<coordinate> to_draw;
to_draw.push({x, y});
while (!to_draw.empty())
{
auto top = to_draw.top();
to_draw.pop();
if ( (top.x >= 0 && top.x < 100)
&& (top.y >= 0 && top.y < 100)
&& !canvas.get_pixel(top.x, top.y))
{
canvas.set_pixel(top.x, top.y);
to_draw.push({top.x, top.y + 1});
to_draw.push({top.x, top.y - 1});
to_draw.push({top.x + 1, top.y});
to_draw.push({top.x - 1, top.y});
}
}
}

Determine which tile is clicked in a window

I am drawing a tilemap on a SFML renderwindow. I want to determine which tile is clicked by the user, but I just cant seem to find a solution. First of all, each tile has 32 width and height.
What i try at the moment : Get the position of the click. Loop trough the tilemap until a tile is found which position is between 100. So if I click on (100,100) the tile should begin at (96,96) but this does not seem to work.
Here is my code snippet from the function getTile(mousepos x,mousepos y)
Tile* TileMap::getTile(int x, int y)
{
Tile *t = NULL;
for(int i = 0; i < tilemap.size(); i++)
{
for(int j = 0; j < tilemap[i].size(); j++)
{
if(x > tilemap[i][j].sprite.getPosition().x
&& x < (tilemap[i][j].sprite.getPosition().x+32))
{
if(y > tilemap[i][j].sprite.getPosition().y
&& y < (tilemap[i][j].sprite.getPosition().y+32))
{
t = &tilemap[i][j];
break;
}
}
}
}
return t;
}
Based on your code, I am going to assume that you are basing your tilemap on a 2d array of Tiles: tilemap[x][y]. I am also going to assume that tilemap[0][0] is the top left tile.
There should be a much easier way to find out which tile is being clicked on instead of testing every single tile.
If you are at 100,100 and tiles are 32x32, then we can get the x and y of the tile within the tilemap by doing something as simple as:
x = 100 / 32 = 3
y = 100 / 32 = 3
Therefor the tile in your tilemap that corresponds to a mouse position of (100,100) is tilemap[3][3].