How does one iterate through a tilemap and check each tile?
Is there a correct way to do this, is there a built in function to in cocos2d to check a tile?
Or could it be done e.g. take the tile size set when creating the tile, make a nested for loop and take (x,y) for the middle of the first tile and just iterate by adding tilesize to the x on the inner loop and tilesize to the y on the outer loop?
I am wondering if there is a built in, more performance aware approach.
Thanks
I think you might be able to do it using a for loop and CGPoints.
I'm going to for examples sake get color
and store it in an array I guess
CGPoint myPt;
NSMutableArray *tilesofGray;
for (int x = 0; x < tilemapLength)
{
for (int y = 0; y < tilemapHeight)
{
myPt.x = x;
myPt.y = y;
if([[[tilemap layerNamed:#"background"] tileAt:myPt] getColor] == Grey)
{
[tilesofGray addObject:[[tilemap layerNamed:#"background] tileAt:myPt]];
}
}
}
Is this for a game, for like collision detection or, simply for rendering based on tile type?
Your question here is really ambiguous. Please be specific in what you want. The 3rd sentence in particular would make more sense if you explain what you are needing.
But i'll try to answer based on the title alone....
How big is the tileset? if it's not very big, brute-force may be perfectly fine.
If performance is a concern/issue, or if the tileset is large and not all tiles are ever drawn within the screen at any given time, you need to do scene management of some sort.
scene management:
i think there is a technical term/phrase for this, but basically based on some x,y pt on the tileset (i.e. matrix), you can determine (by a function) which tiles you will need to iterate thru. it should be fun to figure it out as it's presumably a 2d array.
Related
I have a for loop that I use to draw a grid of tiles with sdl on a game. Since the grid is quite huge with more than 50k elements I want to optimize it.
So there is this function that use to check if I should draw a tile, so if it's outside of the screen I ignore it.
bool Camera::isInViewport(int &x, int &y, int &w, int &h) {
int translatedX = x + offsetX;
int translatedY = y + offsetY;
if (translatedX + w >= 0 && translatedX <= 0 + sdl.windowWidth) {
if (translatedY + h >= 0 && translatedY <= 0 + sdl.windowHeight) {
return true;
}
}
return false;
}
I checked this function it's eating 15% of the CPU alone when the grid is big. Will be possible to make this faster? I can't think of way that will make it eat less resources.
There is not a lot that you can do with this funciton. Do not pass ints as references, it internally passes them as pointers, and it increases costs by dereferencing them. Merge conditions into one if statement and start from those that most probably will be evaluated into false to make early short-circuiting possible.
What I would do instead to solve this performance issue is to organize your tiles in 2D array where index and coordinates could be calculated from each other. In this case you just need to understand index boundaries of tiles covered by your viewport. Instead of checking result of this function on every cell you will be able to just tell left and right X index and top and down Y index. Then just draw them in two nested loops like that:
for (int y = topY; y <= bottomY; ++y)
for (int x = leftX; x <= rightX; ++x)
// do drawing with tile[y][x];
Another approach would be to cache the previous results. If camera is not moving and tiles are not moving - then result of this function is not going to change. Just storing flag that indicates you whether each tile is visible could work here (but not a good practice in big game), update them every time camera moves or recalculate tile if it moves (if it is possible in your app). Still recalculation of all visibility flags on camera movement will be expensive, so try to use first optimization and reduce the task by finding what tile range is affected by camera at all
I'm currently trying to combine the inbuilt PhysicsBody and TileMap classes in cocos2d-x to create the levels (walls) for my physics-based sidescroller. I have maps of size 80*24 tiles and each tile is 30*30 pixels big - I need to assign a static box shaped physics body to each tile.
for (int x=0; x < 80; x++) //width of map
{
for (int y = 0; y < 24; y++) //height of map
{
auto spriteTile = wallLayer->getTileAt(Vec2(x,y));
if (spriteTile != NULL)
{
PhysicsBody* tilePhysics = PhysicsBody::createBox(Size(30.0f, 30.0f), PhysicsMaterial(1.0f, 1.0f, 0.0f));
tilePhysics->setDynamic(false); //static is good enough for walls
spriteTile->setPhysicsBody(tilePhysics);
}
}
}
The above code works, but is very slow and brings performance down from 60 fps to around 20. Is there a less brute-force approach, which can more efficiently create the physics bodies? Note: most the map is blank, so I dont think the number of bodies/tiles is the main problem.
Any insight would be helpful, thanks
First, check whether debug draw is on for physics, as it can reduce FPS considerably. Also, make sure you're measuring FPS on the device and not on the simulator, as it's not reliable there.
If that doesn't help, then you'll have to employ some method of contour tracing to avoid creating a static body for each tile in your tile map. It's better to create 1 static body for each contour that you trace out of the tile map. That way, you will end up with much fewer physics bodies and your performance won't be hurt that much.
One method of doing it is the so called marching squares algorithm. Another one is Moore neighborhood algorithm.
I am trying to create a dot matrix in a QGraphicsScene. I have a button, which fills a 2d-array with random numbers and than i will paint a pixel on every position where the array has a 0.
Now, when I wants to generate the matrix again i want to check every pixel and array-field whether they are empty or not. If the pixel is empty and the array not, i want to set a pixel. If there is a pixel but the array is empty i want to remove the pixel. Now the problem is, the function itemAt() always returns 0 even if i can clearly see existen pixels.
What is my problem?
//creating the scene in the constructor
QPainter MyPainter(this);
scene = new QGraphicsScene(this);
ui.graphicsView->setScene(scene);
//generating matrix
void MaReSX_ClickDummy::generate(void)
{
QGraphicsItem *item;
int x, y;
for(x=0; x< 400; x++)
{
for(y=0; y<400; y++)
{
dataArray[x][y] = rand()%1001;
}
}
for(x=0; x < 400; x++)
{
for(y=0; y<400; y++)
{
item = scene->itemAt(x, y, QTransform());//supposed to check whether there is already a pixel on that place but always returns zero
if(dataArray[x][y] == 0 && item == 0)
scene->addEllipse(x, y, 1, 1);
//does not work
else if(dataArray[x][y] != 0 && item != 0)
scene->removeItem(item);
}
}
}
Also the generating of the matrix is very slow. Since the matrix is supposed to show realtime data later, it should run as fast as possible. (and the scene will be bigger than 400*400 pixels like now). Any ideas how to improve the code?
And can somebody explain what the third parameter of itemAt() is supposed to do?
Thank you!
400x400 'dot matrix' is up to 16000 dots, or up to 2500 characters, which quite big.
The QGraphicsScene is designed to handle a small number of large shapes, and was probably not designed to handle this many shapes. Using it in this way to create thousands of identical tiny 'pixel' objects is incredibly inefficent.
Could you create a 400x400 bitmap(QBitmap?) instead, and set the individual pixels that you want?
You are supposed to be using a QGraphicsPixmapItem instead of an array of dots!
I have some collision detection working when my player hits an object. But this only works when my players x & y co-ordinates hit my marker (which is the centre of my character).
Would making a method returning a vector of all of the coordinates that the players texture cover work and what is the best way to implement this?
This is being done in c++ creating a top down game
There are many ways to do it, most simply is probably(depending on you use of classes etc).
This is the simplest, but no where near the best, or infact very good at all. This way means changing your "marker" to the bottom left of the rectangle.
void collisions()
{
//check if the x-coord is between the furthest left and furthest right x coords
if(rect.Getx() > someObject.Getx() && rect.Getx() < someObject.Getx() + someObject.GetWidth())
{
rect.SetMoveSpeed(0);
}
if(rect.Gety() > someObject.Gety() && rect.Gety() < someObject.Gety() + someObject.GetHeight())
{
rect.setMoveSpeed(0);
}
}
You would then have to set the move speed to normal when it is not colliding. That could be done with an else after each if, setting the move speed again. This is a quick fix and is not recommended for use in a game you plan to distribute anywhere.
I'm trying to write a program that handles detection of various objects. The objects have an origin, width, height, and velocity. Is there a way to set up a data structure/algorithm so that every object isn't checking with every other object?
Some sample code of the problem I'm trying to avoid:
for (int i = 0; i < ballCount; i++)
{
for (int j = i + 1; j < ballCount; j++)
{
if (balls[i].colliding(balls[j]))
{
balls[i].resolveCollision(balls[j]);
}
}
}
You can use a quadtree to quickly find all rectangles that intersect with another rectangle. If you need to handle non-rectangular shapes, you can first find objects whose bounding boxes intersect.
Some common uses of quadtrees
...
Efficient collision detection in two dimensions
...
As mentioned by other answer(s), you can use a quadtree structure to make your collision detection faster.
I would recommend the GEOS open-source C++ library, which has a good quadtree implementation. Here are the docs for their quadtree class.
So your pseudo code would look like this:
Quadtree quadtree;
// Create and populate the quadtree.
// Change it whenever the balls move.
// Here's the intersection loop:
for (int i=0; i<ballCount; ++i) {
Envelope envelope = ...; // Get the bounds (envelope) of ball i
std::vector<void*> possiblyIntersectingBalls;
quadtree.query(envelope, possiblyIntersectingBalls);
// Now loop over the members of possiblyIntersectingBalls to check
// if they really intersect, since quadtree only checks bounding
// box intersection.
}