I want to blit surfaces that I've created in two classes. One is called Map, that holds the relevant map vector as well as some other stuff. The other is a Tile class. There is a problem when I run the program.
I get no errors, and the program runs as it should. Any ideas? It's probably a stupid mistake somewhere.
Map populate
void map::Populate(map M)
for(int x=0;x<=19;x++)
{
for(int y=0;y<=15;y++)
{
int y2 = (y*32);
int x2 = (y*32);
Tile T(x2,y2);
M.AddToMap(&T);
printf("Added Tile");
Render
void map::Render(SDL_Surface* screen)
{
for(int x=0;x<grid.size();x++)
{
printf("test");
Tile* T = grid[x];
SDL_Surface* k = T->GetIcon();
SDL_Rect dstrect;
dstrect.x = (screen->w - k->w) / 2;
dstrect.y = (screen->h - k->h) / 2;
SDL_BlitSurface(k, 0, screen, &dstrect);
You're not stating what the problem actually is, just that the program "runs as it should".
Problems in your code:
int x2 = (y*32); should likely be x*32.
void map::Populate(map M) takes a map by value - this copies the map you pass, and any changes will not be visible in the passed map. map & M passes a reference, so changes will be seen in the map you pass.
M.AddToMap(&T) adds a pointer to the local Tile variable, which gets invalidated each iteration of the inner loop. More likely you want new Tile(T) there, or better yet a smart pointer such as boost's shared_ptr. Remember that you also need to delete those Tiles if you don't use a smart pointer.
New code:
void map::Populate(map & M)
for(int x=0; x<20; x++)
{
for(int y=0; y<16; y++)
{
int y2 = (y*32);
int x2 = (x*32);
M.AddToMap(new Tile(x2,y2));
printf("Added Tile");
You are adding a reference to a local variable to your map in Populate. If the method doesn't make a copy of the input, this is most likely wrong. Make a copy (pass by value) or store a smart pointer to your Tile. Of course you can store a plain old pointer, but make sure to delete those Tiles in the end!
Assuming your problem is that the image doesn't show up you may need to post the setup code for the screen and surfaces so we can see if that is the problem.
Related
To give context to my question I will describe what it is I am ultimately trying to achieve - I am developing a game, I have a .obj model that I am using as my terrain and I must update the players height as they traverse the terrain (because the terrain is far from flat). I am achieving this currently by doing the following - when I load the mesh (terrain.obj) I store all its vertices (each vertex is a Vector3f object that has an x y and z value) in a std::vector<Vector3f> meshVertices, then every second in the "main game loop" I loop through every one of the Vector3f objects in meshVertices and check its x and z value against the players x and z value, if they are colliding I set the players height as the y value of the matched Vector3f object.
This system actually works and updates my players height as they traverse through the terrain, the only issue is this - my approach of checking every single mesh vertex against player position every second kills my frame rate, I need a much better system.
I will now describe my new optimized approach in the attempt of saving my frame rate - Firstly, when creating the mesh I don't just store each Vector3f vertex in a single std::vector<Vector3f>, I store the x y and z values of each Vector3f vertex of the mesh in three seperate std::vector<Vector3f>'s, named meshVerticesX, mechVerticesY and meshVerticesZ. These std::vector's can be seen in the following code:
for (Vector3f currentVertex : meshVertices) {
meshVerticesX.push_back((int)currentVertex.GetX());
}
for (Vector3f currentVertex : meshVertices) {
meshVerticesZ.push_back((int)currentVertex.GetZ());
}
for (Vector3f currentVertex : meshVertices) {
meshVerticesY.push_back((int)currentVertex.GetY());
}
Now every second I get the x and z value of the players position (casted to an int because I feel like making this system work with int values and not float values will be much easier for comparisons later) and then send them to functions that check to see if they exist in the before mentioned meshVerticesX and mechVerticesZ by returning a bool, the code responsible for this is as follows:
int playerPosX = (int) freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->GetX();
int playerPosZ = (int) freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->GetZ();
bool x = meshObjects[0]->checkMeshVerticesX(playerPosX);
bool z = meshObjects[0]->checkMeshVerticesZ(playerPosZ);
The functions checkMeshVerticesX and checkMeshVerticesZ are as follows:
bool Mesh::checkMeshVerticesX(int playerPosX)
{
return std::find(meshVerticesX.begin(), meshVerticesX.end(), playerPosX) != meshVerticesX.end();
}
bool Mesh::checkMeshVerticesZ(int playerPosZ)
{
return std::find(meshVerticesZ.begin(), meshVerticesZ.end(), playerPosZ) != meshVerticesZ.end();
}
Using the returned boolean values (true if the players position was in the respective std::vector or false if it was not) I then call another function (getMeshYHeight) that also gets passed the players x and z position that then checks the index of the respective std::vector's (meshVerticesX & meshVerticesZ) were the match was found, then checks if these indexes are equal and if so returns an int of that index from the meshVerticesY std::vector mentioned earlier, this code can be seen in the following:
if (x == true & z == true) {// boolean values returned by checkMeshVerticesX & checkMeshVerticesZ
int terrainVertexYHeight = meshObjects[0]->getMeshYHeight(playerPosX, playerPosZ);
freeMoveObjects[0]->GetParent()->GetTransform()->GetPos()->SetY(terrainVertexYHeight);
}
The function getMeshYHeight is as follows:
int Mesh::getMeshYHeight(int playerXPos, int playerZPos) {//15/2/20
auto iterX = std::find(meshVerticesX.begin(), meshVerticesX.end(), playerXPos) != meshVerticesX.end();
auto iterZ = std::find(meshVerticesZ.begin(), meshVerticesZ.end(), playerZPos) != meshVerticesZ.end();
int indexX = std::distance(meshVerticesX.begin(), iterX);
int indexZ = std::distance(meshVerticesZ.begin(), iterZ);
if (indexX == indexZ)
{
return meshVerticesY[indexX];
}
}
The idea here is that if the index from the meshVerticesX and meshVerticesZ std::vectors's for the original check match, then they must be the x and z values from an original Vector3f object when I first made the mesh as described earlier, and so that same index in meshVerticesY must contain that same Vector3f's objects y value, therefore return it and use it to set the players height.
The issue is that I cant even test if this works because the line of code int indexX = std::distance(meshVerticesX.begin(), iterX); gives an error saying the arguments supplied to std::distance are wrong (it says iterX is a bool instead of an int which is what I thought it would be).
So my question is - Firstly, if I diden't have this error would my approach even work? and if so, how can I fix the error?
I kind of lost track of your logic somewhere in the middle there, but to address the issue at hand: iterX is a bool!
auto iterX = std::find(...) != meshVerticesX.end();
In this statement, find returns an iterator, which you compare to another iterator, meshVerticesX.end(). The result of that expression (the comparison operator) is a bool, which is then assigned to iterX, so auto deduces that iterX needs to be of type bool.
could you convert your terrain's x,y coordinates to ints, you may need to scale it, then when you load the mesh you could just store the z value for every x,y point (you may have to take some sort of average over the 1x1 square). Now you don't have to look for collisions, instead for each object in the game you can just look up it's z value by it's (scaled) x,y coordinates.
I hae been playing around with Thread building blocks with Free Image Plus on linux. I have been trying to compare the speeds between a sequential and parallel approach when subtracting one image from another, however I noticed that the final outcome when using the parallel approach generates some anomalies that I am unsure now to solve and am in need of some advice.
my question is: Why does the image seem to generate more array comparison errors when using parallel but work fine when using sequential (The image is supposed to be black with a few white spots, so the white pixels in the second image are comparison errors between the 2 image pixel arrays (of type RGBQUAD)).
RGBQUADs are declared before the call to these methods and act as global variables.
RGBQUAD rgb;
RGBQUAD rgb2;
https://imgur.com/Qs6G3z7 "Sequential".
for (auto y = 0; y < height; y++)
{
for(auto x= 0; x < width; x++)
{
inputImage.getPixelColor(x, y, &rgb);
inputImage2.getPixelColor(x, y, &rgb2);
rgbDiffVal[y][x].rgbRed = abs(rgb.rgbRed - rgb2.rgbRed);
rgbDiffVal[y][x].rgbBlue = abs(rgb.rgbBlue - rgb2.rgbBlue);
rgbDiffVal[y][x].rgbGreen = abs(rgb.rgbGreen - rgb2.rgbGreen);
}
}
https://imgur.com/Yd3v1ko "with TBB parallel".
parallel_for(blocked_range2d<int,int>(0,height, 0, width), [&] (const blocked_range2d<int,int>&r) {
auto y1 = r.rows().begin();
auto y2 = r.rows().end();
auto x1 = r.cols().begin();
auto x2 = r.cols().end();
for (auto y = y1; y < y2; y++) {
for (auto x = x1; x < x2; x++) {
inputImage.getPixelColor(x, y, &rgb);
inputImage2.getPixelColor(x, y, &rgb2);
rgbDiffVal[y][x].rgbRed = abs(rgb.rgbRed - rgb2.rgbRed);
rgbDiffVal[y][x].rgbBlue = abs(rgb.rgbBlue - rgb2.rgbBlue);
rgbDiffVal[y][x].rgbGreen = abs(rgb.rgbGreen - rgb2.rgbGreen);
}
}
});
I believe it may have something to do with passing the reference pointer inside a lambda that is copying values by reference anyway as this is the only thing I can think of that may affect the process. (rgb, rgb2). I have observed that If I change the parallel for blocked range to height and width, this solves the issue, however this then defeats the point of using a parallel method in the first place.
The first thing I would do is put a spin mutex lock around the update (The last three lines of the inner loop where you are storing the result.) This will slow the program down a lot but will tell you if there is a synchronization problem with your update. (It is not obvious, but you are storing adjacent values in the same cache lines for some of the results. Testing is the only way to answer this.)
If it is, you can do atomic swaps to update the result, but that is super-expensive. If not, sorry I didn't spot your problem.
Even if this is not a problem, you might get better performance by using a 1-D blocked_range which is cache-aligned. I'll leave it to you to do the gory implementation.
If these variables are supposed to temporarily store pixel colors, maybe you just need to move the declarations into the lambda, making variables local to each thread. – Alexey Kukanov.
Variables were indeed placed outside the bounds for the lambda so each thread was modifying the referenced variable causing a race condition where one thread would try to read the data from the variable as another was modifying it.
for my application I need to create a fixed size buffer (3 elements) of point clouds.
To do this I tried the naive way in my callback (I'm working on ROS):
vector< vector<Point2d> > points_buffer(3); // buffer of point clouds ,fixed size = 3
void laserToWorldCallback(const icars_laser_roi::stx_points::ConstPtr& laser_points, const icars_2d_map_manager::Status::ConstPtr& car_pos){
double x_w, y_w;
double x, y;
vector<Point2d> temp;
for(int i = 0; i < laser_points->points_x.size(); i++){
// get the coordinates
x = laser_points->points_x[i];
y = laser_points->points_y[i];
// tranform the coordinates
x_w = car_pos->xGlobal + x*cos(car_pos->yaw) - y*sin(car_pos->yaw);
y_w = car_pos->yGlobal + x*sin(car_pos->yaw) + y*cos(car_pos->yaw);
temp.push_back(Point2d(x_w, y_w));
}
if(points_buffer.size() != 3){ // the buffer is not empty
points_buffer.push_back(temp);
}else{ // the buffer is empty, delete last element and push_back
// delete last element
points_buffer[0] = points_buffer[1];
points_buffer[1] = points_buffer[2];
points_buffer[3] = temp;
}
}
}
But this way seems to me a bit rough and not efficient at all.
Might someone suggest me a more elegant and efficient way to do what I want?
Thank you
Regards
To fix some efficiency problems. First after declaration of temp you can already reserve the memory it will use with
temp.reserve(laser_points->points_x.size());
So there will be no reallocation of memory in push_back method.
If you are using c++11 or greater, in the case buffer is not yet full, you can move the content of the temp with std::move.
points_buffer.push_back(std::move(temp));
This is a O(1) operation. The content of temp after this is valid but unspecified.
Then in the deleting the last element use vector::swap instead of copy as it will swap the content and is guaranteed to be constant in time.
points_buffer[0].swap(points_buffer[1]);
points_buffer[1].swap(points_buffer[2]);
points_buffer[2].swap(temp); //There is a typo here index should be 2 not 3.
The program would be more readable, if you would wrap point_buffer in a class. Then you could also consider not rotating the content of whole vector but keeping track of the first index. This would work well also for larger point_buffer than 3. Then adding new element to buffer would be just
point_buffer[fist_element_].swap(temp);
first_element=(first_element_+1)%3;
then to access the element at position i you could implement the operator[] as
vector<Point2d>& operator[](int i){
return point_buffer[(i+first_element)%3];
}
So I know this is a very broad topic, but I'm not sure how to describe it and I'm not sure where the bug is. So I'm making a game in the console window, a roguelike-rpg, (I haven't done the random dungeon yet, but I've done it in other languages.) and I'm having problems dealing with walls.
I have a function called placeMeeting(REAL X, REAL Y) that I use to check for collisions, but it appears to be returning bad values and I couldn't tell you why. I have couple of macros defined: #define AND && and #define REAL double.
Here is the function:
bool GlobalClass::placeMeeting(REAL X, REAL Y)
{
//The return value -- False until proven otherwise
bool collision = false;
//Loop through all walls to check for a collision
for(int i = 0; i < wallCount; i++)
{
//If there was a collision, 'say' so
if (X == wallX[ i ] AND Y == wallY[ i ])
{
//Set 'collision' to true
collision = true;
}
}
return collision;
}
But the strange catch is that it only doesn't work when displaying the screen. The player collides with them all the same even though there not displayed. Even stranger, only the first wall is being displayed.
Here is where the walls are defined:
int wallCount;
//Array of walls
REAL wallX[ 1 ];
REAL wallY[ 1 ];
and
wallCount = 1;
//Basic wall stuff; basically just a placeholder
wallX[ 0 ] = 10;
wallY[ 0 ] = 10;
So I have a function used to render the screen (In the console window of course.) and it looks like this:
for (int y = oGlobal.viewY; y < oGlobal.viewY + oGlobal.viewHeight; y++)
{
//The inner 'x' loop of the view
for(int x = oGlobal.viewX; x < oGlobal.viewX + oGlobal.viewWidth; x++)
{
//Call the function to check this spot and print what it returns
screen += oGlobal.checkSpot(x, y);
}
}
That's not the whole function, just the actual screen refreshing. After 'screen' is printed to the screen, to reduce buffer time. And of course, checkSpot:
STRING GlobalClass::checkSpot(REAL x, REAL y)
{
STRING spriteAtSpot;
//First check for the player
if (x == oPlayer.x AND y == oPlayer.y)
{
spriteAtSpot = oPlayer.sprite;
}
else if (placeMeeting(x, y)) //ITS TEH WALL SUCKAS
{
spriteAtSpot = WALL_SPRITE;
}
else //Nothing here, return a space
{
spriteAtSpot = EMPTY_SPRITE;
}
//Return the sprite
return spriteAtSpot;
}
I know it's a lot of code, but I really don't know where I screwed up.
I really appreciate any help!
P.S. Here is an image to help understand
http://i.imgur.com/8XnaHIt.png
I'm not sure if I'm missing something, but since rogue-like games are tile-based, is it necessary to make the X and Y values doubles? I remember being told that doubles are finicky to compare, since even if you assume they should be equal, they could be very slightly off, causing comparison to return false when you'd think it would return true.
I'm not sure we have enough of your code to debug it, but I have developed a Rogue-like console game, and here is my $.02...
Start over. You seem to be doing this in a very non-OO way (GlobalClass?). Consider objects such as Level (aggregates entire level), DungeonObject (essentially each space on the level; it's a base class that can be inherited from into Wall, Player, etc.). Doing this will make the programming much easier.
Embrace the suck. C++ syntax may suck, but the more you fight against it, the harder it will be to learn. Use && and the built-in datatypes. It won't take long to get used to.
Rouge-like locations are essentially integer-based. Use integer for x, y locations, not doubles (the biggest built-in data-type). Not only is it more efficient, you'll find debugging much easier.
Start in the small. Start with a 5 x 5 dungeon level to get the basics down. Then, if you've designed it correctly, scaling up to a 10x10 or 25x25 will be much easier.
That's how I developed my game; I hope it helps.
Apart from the use of double instead of int, I see something strange in your definition of walls:
int wallCount;
//Array of walls
REAL wallX[ 1 ];
REAL wallY[ 1 ];
and
wallCount = 1;
//Basic wall stuff; basically just a placeholder
wallX[ 0 ] = 10;
wallY[ 0 ] = 10;
You are defining a variable called wallCount, which you later use to go through the elements of your array in your placeMeeting function:
//Loop through all walls to check for a collision
for(int i = 0; i < wallCount; i++)
Then why don't you use wallCount to define the size of your arrays? Of course you can't use that syntax, because the size of a static array must be known at compile time, so you should either use new or std::vector, but still you shouldn't have a variable that defines the length of the array and then use another value when you actually create the array, it is a source of bugs if you fail to keep them aligned. So for example you could do this:
const int wallCount = 1;
int* wallX = new int[wallCount];
int* wallY = new int[wallCount];
But there's a bigger problem: why are you creating arrays of size 1? You are having only one wall! It doesn't really make sense to have arrays of size 1, unless you intend to use another value but you have reduced it to 1 for debugging purposes. But, you wrote this:
Even stranger, only the first wall is being displayed.
That's because you only have 1 wall!
By the way, the way you have designed your data isn't the one I would use. From your checkSpot I understand this: oPlayer.x and oPlayer.y are the coordinates of your player, and x and y are the coordinates of the tile you have to draw (and for which you need to choose the appropriate sprite). If in your map you have 3 walls, you have to put 3 values in wallX and 3 in wallY, and you must make sure that you keep the 2 arrays "aligned" (if the coordinates of your second wall are for example x=10 and y=20, you could get confused, or have buggy code, and instead of saving it as
wallX[1] = 10;
wallY[1] = 20;
you might write
wallX[1] = 10;
wallY[2] = 20; // wrong index!
so it's one more source of bugs), and worse, you must check that they are consistent with other arrays of other objects: you could have, for example, doors, and then following your approach you'd have doorX[] and doorY[], and how can you be sure that you don't have a wall and a door at the same place? Like, if you had
doorX[0] = 10;
doorY[0] = 20;
it would be at the same place as the wall, and the error isn't obvious, because you'd have to cross-check all your arrays to find it. So I would suggest to have a level[height][width] instead, and to have a wall at x=10 and y=20 you could use level[10][20] = 'w';. This would ensure that you only have ONE object per tile. Besides, checking for collisions would be faster: with your approach, if you have 50 walls you need 50 checks; with mine, you always only need one. Ok, performance is certainly not an issue in these games, but still I think you should consider my approach (unless there are other reasons to prefer yours, of course).
I have an assignment to make a robot controller for a University project. At the moment it is going quite well, but I have a niggling bug that is just darn annoying and I can't seem to correct it.
Basically, I have to design a contrasting controller to enable random movement while avoiding obstacles. So, I have a robot which appears as "R" on the console, which is within a 10 by 10 area. Here is the code I use to initialise my 2D vector, and then draw the grid:
void matrix::init() // init my 2D vector
{
dot = 10; // 10 by 10 area
vector2D.resize(dot);
for (int i=0; i<dot; i++)
{
vector2D[i].resize(dot);
}
}
void matrix::draw() // drawing the vector to the screen
{
for(int i=0; i<dot; i++)
{
for(int j=0; j<dot; j++)
{
cout <<vector2D[i][j]<<"."; // I being the Y access, J the X access
}
cout<<endl;
}
}
void matrix::update()
{
init();
draw();
}
This is in its own class called matrix.cpp, which is then called in the main.cpp with m.update(); m being an object of matrix
Now, the robot position on screen is being set with this code within the matrix.cpp class
void matrix::robotPosition(int x, int y)
{
bot = 'R';
cout << "X Pos"<< x <<endl;
cout << "Y Pos"<< y <<endl;
vector2D[x][y] = bot; // Outputting location of robot onto the grid / matrix
}
There is more code I have developed to control the position on screen, but I don't think that is needed at this point in my question.
int main()
{
matrix m;
robot r;
while(true)
{
m.update(); // vector2D init and draw
m.robotPosition(r.getX(), r.getY());
r.update();
system("pause");
}
}
Every time my program loops through the while loop it draws another robot on the screen, but doesn't seem to remove the old one. The code works by assigning a certain X and Y in the 2D vector with the char 'R' (Which is my Robot). Is my thinking correct that I will have to draw the 2D matrix after each movement cycle?
Thanks
When you first set the robot position to, say, (5,5), you will set vector2D[5][5] to R. Then if you set the position to something like (5,6), you will set vector2D[5][6] to R. Now both elements [5][5] and [5][6] are set to R, so the robot is in both positions.
There are a few solutions that depend on how you want to design it:
You can store the current robot position in matrix and at the beginning of robotPosition set that position to whatever the non-robot character is. This will clear the previous position before setting the new one.
You can clear the entire matrix at the beginning of each frame. You are calling update at the beginning of each frame, which attempts to resize the vectors to exactly the same size they already are - this doesn't clear it. Instead, you should do that work in the constructor, and you can turn init into a clear function.
If you want to use a different matrix for each time step, then you need to move the declaration of matrix m; into the while loop. Then you have one for each frame which should be cleared during construction (if you move the init stuff to the constructor).