Tile Position
by Chris · in Torque Game Builder · 11/28/2005 (2:11 pm) · 10 replies
Hello readers,
For my pathing code to work I need to figure out the current position of a tile. Since the world position is really just relitive I cant determine the location of a tile before hand and expect it to be there when it comes for the object to move to that position. I have started looking at the pick code in an attempt to figure out a way on finding the position of a tile. What I am thinking is having the function return the left top right bottom position of the square. What I am currently thinking is if I know the position of the object on a tilelayer I can then determine the tile it is currently on. From there I could use the tile size to determine how many pixels away the next tile is. The problem here is world position and pixel size arnt the same thing. I am now thinking that it might be possible to go through and pretend that I am going and updating the tile layer. From there just keep going though the layer pretending to place update the layer and once I reach the tile I need to find its position it wouldn't be hard at all, but I am not to sure how to go about that.
The main problem is finding a way to get the area a tile occupies in world position. The area being defined as the "left top right bottom" world position of the tile. If anyone has done work on something like this or has any ideas please post them it would be very helpful.
Lux
For my pathing code to work I need to figure out the current position of a tile. Since the world position is really just relitive I cant determine the location of a tile before hand and expect it to be there when it comes for the object to move to that position. I have started looking at the pick code in an attempt to figure out a way on finding the position of a tile. What I am thinking is having the function return the left top right bottom position of the square. What I am currently thinking is if I know the position of the object on a tilelayer I can then determine the tile it is currently on. From there I could use the tile size to determine how many pixels away the next tile is. The problem here is world position and pixel size arnt the same thing. I am now thinking that it might be possible to go through and pretend that I am going and updating the tile layer. From there just keep going though the layer pretending to place update the layer and once I reach the tile I need to find its position it wouldn't be hard at all, but I am not to sure how to go about that.
The main problem is finding a way to get the area a tile occupies in world position. The area being defined as the "left top right bottom" world position of the tile. If anyone has done work on something like this or has any ideas please post them it would be very helpful.
Lux
About the author
#2
Absolute tile-positions are relatively complex to calculate as there are a number of factors that change the position of any one tile such as tile-layer orientation, tile-size, tile-scrolling. There's also the potential for a physical tile to appear more than once in the world when "wrapping" is active which therefore leads to an ambiguous situation and the need to return multiple positions.
Historically I've avoided calls that only work under "special" circumstances as it confuses lots of people and then requests come in to make the command work for all circumstances which, sometimes, is extremely difficult.
With that said, I think it's probably about time that I added something that will work (when wrapping is not active) that returns the position of a tile. I believe that the best way to return the tile-position would be to return its "area". If the centroid (or any other spatial reference) is needed then it can be calculated.
I've posted this as a new feature-request in our database (#0000855).
- Melv.
11/30/2005 (1:48 am)
Christopher,Absolute tile-positions are relatively complex to calculate as there are a number of factors that change the position of any one tile such as tile-layer orientation, tile-size, tile-scrolling. There's also the potential for a physical tile to appear more than once in the world when "wrapping" is active which therefore leads to an ambiguous situation and the need to return multiple positions.
Historically I've avoided calls that only work under "special" circumstances as it confuses lots of people and then requests come in to make the command work for all circumstances which, sometimes, is extremely difficult.
With that said, I think it's probably about time that I added something that will work (when wrapping is not active) that returns the position of a tile. I believe that the best way to return the tile-position would be to return its "area". If the centroid (or any other spatial reference) is needed then it can be calculated.
I've posted this as a new feature-request in our database (#0000855).
- Melv.
#3
This deals with all the issues I described above but because it approaches the problem from a world-position, wrapped-tile ambiguity isn't an issue.
This code however would serve as a great start to solving your problem.
Hope this helps,
- Melv.
11/30/2005 (1:50 am)
I'll just add that if you want to attempt this in the meantime, the best example code in the SDK is in...bool t2dTileLayer::pickTile( const t2dVector& worldPosition, Point2I& logicalTile )
This deals with all the issues I described above but because it approaches the problem from a world-position, wrapped-tile ambiguity isn't an issue.
This code however would serve as a great start to solving your problem.
Hope this helps,
- Melv.
#4
t2dTileMap.cc -> deleteTileObject function
I was looking at that and was woundering what wasn't good. I know that for most of my dynamic matrixes I do I use the same setup. Based off x and y count I create a single array of size x*y. I just cant seem to figure out what is "not good".
11/30/2005 (12:36 pm)
I was looking at the code, I am going to make a function that gets the world position of a tile. Anyway like I was saying I was looking at the code when I came across this:t2dTileMap.cc -> deleteTileObject function
// Reset Tile Obj.
// NOTE: - This is not good!
mppTileObjectArray[tileX + (tileY*mTileCountX)] = NULL;I was looking at that and was woundering what wasn't good. I know that for most of my dynamic matrixes I do I use the same setup. Based off x and y count I create a single array of size x*y. I just cant seem to figure out what is "not good".
#5
"I believe that the best way to return the tile-position would be to return its "area". If the centroid (or any other spatial reference) is needed then it can be calculated."
Do you mean return a coord list? I'm not sure what the most desireable return for me (selfishly) would be, but I'm having trouble seeing how I'd use a coord list. Mostly I think I'd want the centroid, or maybe a pivot offset from the tileLayer (like linkpoints). In the use-cases I can think of, I'd just want to place an object at that tile location.
So I guess I'm lobbying for at least a cheap way to get the centroid. Perhaps you could have an optional parameter as an offest coord ("-1, -1" to "1, 1"), that would return the world coord as an offset within the tile.
That sounded weird maybe. I mean treat it like link points... getTileWorldPos( tileX/tileY, [offsetX/offestY] )
eg:
just my 2 cents
(Edit for clarification)
11/30/2005 (10:47 pm)
@Melv"I believe that the best way to return the tile-position would be to return its "area". If the centroid (or any other spatial reference) is needed then it can be calculated."
Do you mean return a coord list? I'm not sure what the most desireable return for me (selfishly) would be, but I'm having trouble seeing how I'd use a coord list. Mostly I think I'd want the centroid, or maybe a pivot offset from the tileLayer (like linkpoints). In the use-cases I can think of, I'd just want to place an object at that tile location.
So I guess I'm lobbying for at least a cheap way to get the centroid. Perhaps you could have an optional parameter as an offest coord ("-1, -1" to "1, 1"), that would return the world coord as an offset within the tile.
That sounded weird maybe. I mean treat it like link points... getTileWorldPos( tileX/tileY, [offsetX/offestY] )
eg:
%tileWorldPos = $tLayer.getTileWorldPos( "10 10", "-1 -1" ); // would return the world position of the upper left corner of the tile at idex 10,10 %tileWorldPos = $tLayer.getTileWorldPos( "10 10" ); // would return the world position of the center of the tile at idex 10, 10 // etc
just my 2 cents
(Edit for clarification)
#6
I've added your comments to the issue database and I'll have a look at it when I get to it. You idea sounds fine with me.
- Melv.
12/01/2005 (5:05 am)
Phil,I've added your comments to the issue database and I'll have a look at it when I get to it. You idea sounds fine with me.
- Melv.
#7
www.garagegames.com/mg/forums/result.thread.php?qt=28676
I know this is already being looked at, especially from the C/C++ side. While I'm tempted to attempt a fix at that end, I haven't done much diving into the C code or modding the T2D engine. It seems, however, that there is a definite need for this sort of thing, so perhaps this will help.
This is a partial solution using TorqueScript, derived from a function I developed for a recent puzzle game that uses TileMaps. It calculates the world position (central) of any tile within a tilemap, taking tilemap position and rotation into account, as well as tile size.
This function does NOT address any wrapping or panning issues. Those issues really should be addressed in C/C++, so I'll leave that to Melv and company. Or maybe, if I get bored enough, I'll look into it a little more myself.
EDITS: A couple of code fixes. Never tried it with a rotated tilemap, and certain lines weren't quite right. But after the fixed lines, it pinpoints tile positions like a champ. :)
01/26/2006 (5:10 pm)
This issue is addressed in another thread as well, under Torque 2D Private Forums >> Tiles.www.garagegames.com/mg/forums/result.thread.php?qt=28676
I know this is already being looked at, especially from the C/C++ side. While I'm tempted to attempt a fix at that end, I haven't done much diving into the C code or modding the T2D engine. It seems, however, that there is a definite need for this sort of thing, so perhaps this will help.
This is a partial solution using TorqueScript, derived from a function I developed for a recent puzzle game that uses TileMaps. It calculates the world position (central) of any tile within a tilemap, taking tilemap position and rotation into account, as well as tile size.
This function does NOT address any wrapping or panning issues. Those issues really should be addressed in C/C++, so I'll leave that to Melv and company. Or maybe, if I get bored enough, I'll look into it a little more myself.
EDITS: A couple of code fixes. Never tried it with a rotated tilemap, and certain lines weren't quite right. But after the fixed lines, it pinpoints tile positions like a champ. :)
// ************************************************************************
// Calculates a tile's world position
// - Assumes tilemap is not wrapped or panned, and tiles do not overlap
// - Usage: getTilePosition( fxTileLayer2D, int tileX / int tileY )
// - Author: Ben Amos, Jan 26, 2006
// ************************************************************************
function getTilePosition( %tileLayer, %tile )
{
// Offset the tile index based on tilemap dimensions
%offset = vectorSub2D( %tileLayer.getTileCount(), "1 1" );
%offset = vectorScale2D( %offset, 0.5 );
%tilePos = vectorSub2D( %tile, %offset);
// Scale the tile position based on tile size
%tileX = getWord( %tilePos, 0 );
%tileY = getWord( %tilePos, 1 );
%tileSizeX = getWord( %tileLayer.getTileSize(), 0 );
%tileSizeY = getWord( %tileLayer.getTileSize(), 1 );
%tilePos = (%tileX * %tileSizeX) SPC (%tileY * %tileSizeY);
// Adjust position based on tilemap's rotation, if any
if (%tileLayer.getRotation() != 0) {
%temp = xyToPolar( %tilePos );
%tempAngle = getWord(%temp, 0);
%tempDist = getWord(%temp, 1);
%tempAngle += %tileLayer.getRotation();
%tilePos = polarToXY( %tempAngle SPC %tempDist );
}
// Offset by the tile layer's world position
%tilePos = vectorAdd2D( %tilePos, %tileLayer.getPosition() );
return %tilePos;
} // end getTilePosition
// *******************************************************************************
// Converts polar coordinates to X/Y coordinates
// - Usage: polarToXY( int angle / int distance )
// - Author: Ben Amos, Jan 26, 2006
// *******************************************************************************
function polarToXY( %vect )
{
// Break polar coordinates apart
%angle = getWord( %vect, 0 );
%dist = getWord( %vect, 1 );
// Standardize the angle (0 <= %angle <= 360)
while (%angle < 0) %angle += 360;
while (%angle > 360) %angle -= 360;
// Convert polar to rectangular
return ( (mCos(mDegToRad(%angle)) * %dist) SPC (mSin(mDegToRad(%angle)) * %dist) );
} // end polarToXY
// *******************************************************************************
// Converts X/Y coordinates to polar coordinates
// - Usage: xyToPolar( int x / int y )
// - Author: Ben Amos, Jan 26, 2006
// *******************************************************************************
function xyToPolar( %vect )
{
// Calculate the angle
%angle = mRadToDeg( mAtan( getWord(%vect, 1), getWord(%vect, 0) ) );
// Standardize the angle (0 <= %angle <= 360)
while (%angle < 0) %angle += 360;
while (%angle > 360) %angle -= 360;
// Calculate the distance
%dist = vectorLength2D( %vect );
return %angle SPC %dist;
} // end xyToPolar
#8
02/03/2006 (8:30 pm)
@ben - thanks for the code, got it working on the alpha by using the new naming convention://functions.cs
// ************************************************************************
// Calculates a tile's world position
// - Assumes tilemap is not wrapped or panned, and tiles do not overlap
// - Usage: getTilePosition( fxTileLayer2D, int tileX / int tileY )
// - Author: Ben Amos, Jan 26, 2006
// ************************************************************************
function getTilePosition( %tileLayer, %tile )
{
// Offset the tile index based on tilemap dimensions
%offset = t2dVectorSub( %tileLayer.getTileCount(), "1 1" );
%offset = t2dVectorScale( %offset, 0.5 );
%tilePos = t2dVectorSub( %tile, %offset);
// Scale the tile position based on tile size
%tileX = getWord( %tilePos, 0 );
%tileY = getWord( %tilePos, 1 );
%tileSizeX = getWord( %tileLayer.getTileSize(), 0 );
%tileSizeY = getWord( %tileLayer.getTileSize(), 1 );
%tilePos = (%tileX * %tileSizeX) SPC (%tileY * %tileSizeY);
// Adjust position based on tilemap's rotation, if any
if (%tileLayer.getRotation() != 0) {
%temp = xyToPolar( %tilePos );
%tempAngle = getWord(%temp, 0);
%tempDist = getWord(%temp, 1);
%tempAngle += %tileLayer.getRotation();
%tilePos = polarToXY( %tempAngle SPC %tempDist );
}
// Offset by the tile layer's world position
%tilePos = t2dVectorAdd( %tilePos, %tileLayer.getPosition() );
return %tilePos;
} // end getTilePosition
// *******************************************************************************
// Converts polar coordinates to X/Y coordinates
// - Usage: polarToXY( int angle / int distance )
// - Author: Ben Amos, Jan 26, 2006
// *******************************************************************************
function polarToXY( %vect )
{
// Break polar coordinates apart
%angle = getWord( %vect, 0 );
%dist = getWord( %vect, 1 );
// Standardize the angle (0 <= %angle <= 360)
while (%angle < 0) %angle += 360;
while (%angle > 360) %angle -= 360;
// Convert polar to rectangular
return ( (mCos(mDegToRad(%angle)) * %dist) SPC (mSin(mDegToRad(%angle)) * %dist) );
} // end polarToXY
// *******************************************************************************
// Converts X/Y coordinates to polar coordinates
// - Usage: xyToPolar( int x / int y )
// - Author: Ben Amos, Jan 26, 2006
// *******************************************************************************
function xyToPolar( %vect )
{
// Calculate the angle
%angle = mRadToDeg( mAtan( getWord(%vect, 1), getWord(%vect, 0) ) );
// Standardize the angle (0 <= %angle <= 360)
while (%angle < 0) %angle += 360;
while (%angle > 360) %angle -= 360;
// Calculate the distance
%dist = t2dVectorLength( %vect );
return %angle SPC %dist;
} // end xyToPolar
#9
02/04/2006 (1:04 pm)
@Jaybill: Good deal. I'm still toying around with the latest pre-alpha version, so yeah ... the code I wrote works for pre-alpha versions of T2D. Looks like not much had to change from older to alpha, though. I hope others find this useful as well. I know it's already come in VERY handy for my current project, Circuit Breaker.
#10
" solution worked right out of the box!
02/10/2009 (7:15 pm)
Hay Jaybill.. this is probably super old but I just wanted to give you props.. your "getTilePosition( %tileLayer, %tile )" solution worked right out of the box!
Torque Owner Chris
void t2dTileLayer::updateLayer( void ) { // Finish if we've not got a tile array. if ( !mppTileObjectArray ) return; // Calculate Total Tile Count. U32 tileCount = mTileCountX * mTileCountY; // Calculate Tile Size. t2dVector tileSize( mTileSizeX, mTileSizeY ); // Fetch Tile Pointer. tTileObject** ppTileArray = mppTileObjectArray; // Step through all tiles. for ( U32 n = 0; n < tileCount; n++, ppTileArray++ ) if ( (*ppTileArray) ) (*ppTileArray)->mpPhysics->setSize( tileSize ); }Based off that I figure I might be able to do (*ppTileArray)->mpPhysics->getPosition(); but I am unsure as to where this position is located or even if it is something that I can use. If it is something I can use is the position of this tile based off a center location? the left top?