Isometric map is returning wrong position for object

Hello,
I used Tiled tool to create isometric map with Cocos2dx 2.2.6 I added an object to the map to specify a spawn point.

I used the following code to get SpawnPoint position but It always gives wrong values

  CCTMXObjectGroup *objectGroup = tileMap->objectGroupNamed("Objects");
  
   CCDictionary *spawnPoint = objectGroup->objectNamed("SpawnPoint");
    
    float px = ((CCString*)spawnPoint->objectForKey("x"))->floatValue();
    float py = ((CCString*)spawnPoint->objectForKey("y"))->floatValue();
    sprite->setPosition(ccp(px, py));

I hope you help!

Couple things

  • “x” and “y” are in pixels relative to the top-left origin of the tilemap’s bounding box. If your tilemap is 10x10 iso tiles and your tiles are 32x16 (standard iso tile size) then the bounding box size would be 320x320 pixels.
  • The “y” value is “inverted” because tiled exports with top-left origin instead of cocos2d’s bottom-left origin
  • Isometric position is not the same as the “x”,“y” orthogonal tile position that exists in the object’s properties and so you need to transform first into tile coordinate and then into final cocos2d position
  • Finally the object is defined as x,y plus width,height, so you’ll have to consider that depending if you want to find the center of the object, the ‘bottom’ corner, etc.

1.Find Tile Coord from TMX x,y,width,height
(code that was here removed, see later reply)

2.Transform from Tile Coord to Cocos2d Position

// v3.x (not sure if this was changed from 2.2.x)
auto spawnPoint = objectGroup->objectNamed("SpawnPoint");

auto tileCoord = tileCoordFromTMXObject(tileMap, spawnPoint)
auto mapLayer = tileMap->getLayer("my_object_layer_name");
auto p = mapLayer->getPositionAt(tileCoord);
spriteForObject->setPosition(p);

Edit: added code similar to what we use, you may have to modify it for you needs.
Edit2: fixed dumb wrong code, wrote it too hastily
Edit3: fixed again, but posted the code in a later reply

@stevetranby where does height came from? is that map size height or tile size height?
and objectHeight is not used

this topic is exactly what my problem is…
ive been searching algebraic expressions, matrices and stuff but its too difficult to understand…
may be because its math :persevere:

Thanks for the reply, the problem is I couldn’t find getPositionAt function in cocos2dx 2.2.x. how can I get the position of the tile using Its coordinates?

I was wrong (deleted that reply) I forgot how much that class changed.

It’s layer-> positionForIsoAt ( tileCoord )

sir @stevetranby tileY doesnt seem to give the correct value…
its higher than the value it should be…
i place my object at tile 0,0 and its position is at 60,60 given my tiles are 100X60 and my map size is 5x5…

but the tileY gives me somewhere 15 or higher… is should be 0 right?
so when i pass it to the positionForIsoAt() it position the object differently… might want to recheck it… :smile:

Well cocos2d’s TMX parser essentially flips the Y coords of objects. So that’s what my code is attempting to do, but I did write it quickly off the top of my head. I’ll go pull out our game code and confirm the exact setup we use.

Here you can see how when it parses and object it does the y = mapheight * tileheight - y - tileheight which is in pixel units, and my code above was essentially transposing that into tile units.
https://github.com/cocos2d/cocos2d-x/blob/v2/cocos2dx/tilemap_parallax_nodes/CCTMXXMLParser.cpp#L545

Edit:
Here’s one way we get this. We only use the Rectangle objects, so this may not apply to ellipses and definitely not to polygons. For an isometric diamond map this will give you the origin as the Top point on the object’s diamond-shaped rectangle.

Rect tileRectFromObject(STTMXTileMap* tileMap, const ValueMap& obj)
{
    float mapHeight = tileMap->getMapSize().height;
    float tileHeight = tileMap->getTileSize().height;

    float x = obj.at("x").asFloat();
    float y = obj.at("y").asFloat();
    float w = obj.at("width").asFloat();
    float h = obj.at("height").asFloat();

    // height - object's height in # of tiles along axis
    float objTileWidth = w / tileHeight - 1.f;
    float objTileHeight = h / tileHeight - 1.f;
    float objTileX = x / tileHeight;
    // Cocos2d flips Y ("top left" corner becomes "bottom left", same with right)
    float objTileY = mapHeight - y / tileHeight - h / tileHeight;

    auto type = obj.at("type").asString();
    auto name = obj.at("name").asString();
    return Rect( objTileX, objTileY, objTileWidth, objTileHeight );
}

For 2.x you just extract properties differently.

// v2.2.x
Vec2 tileRectFromObject(STTMXTileMap* tileMap, const CCDictionary* objMap)
// v2.2.x
float x = ((CCString*)objMap->objectForKey("x"))->floatValue();