I created a class template named PlayField<T>
, where T
is the type of the GridObject
. I wrote this class using Cocos2d-x.
The point of this class is to make it easy for me to create a grid for games like "Tetris", "Bejeweled" or "Minesweeper". One of the main goals for this class is to place it anywhere by a position offset. At the time of creation, each GridObject
will position itself according to this offset. This way, I could make the grid center align perfectly, or adjust the position horizontally or vertically depending on the layout.
I am able to do this easily with SFML, since the coordinate system there is top-left. The coordinates system in Cocos2d-x is bottom-left, which has given me a challenge, writing up a simple framework for creating the grid.
One of the key functions of my class is the ability to convert the pixel position of the mouse or touch input into a grid position. For example, 245 x 245 returns grid position of 4 x 4.
Clicking on each GridObject
should only return positive coordinates, so I can use this to access them via a 2D vector. However, clicking on the bottom-most part of the grid returns a negative coordinate for the Y-axis. I think I made some wrong calculations, since I am new to programming bottom-left coordinates, and having a difficult time doing so.
Why does selecting a tile return a negative coordinate?
Here is my template class:
(...)
template<class T>
PlayField<T>::PlayField(const cocos2d::Vec2 & position, const cocos2d::Size & gridSize,
int offset) : mGridSize(gridSize), mOffset(offset), mGridPositionOffset(position),
mDrawNode(nullptr)
{
mGridPositionOffset.y = mGridPositionOffset.y - (gridSize.height * offset);
}
template<class T>
PlayField<T>::~PlayField()
{
}
template<class T>
void PlayField<T>::initialize(cocos2d::Scene * scene)
{
for (int y = 0; y < mGridSize.height; ++y)
{
mGrid.push_back(vector<unique_ptr<T>>());
for (int x = 0; x < mGridSize.width; ++x)
{
cocos2d::Vec2 actualPosition;
actualPosition.x = (x * mOffset) + mGridPositionOffset.x + (mOffset / 2.0f);
actualPosition.y
= mGridPositionOffset.y + ((y + 1) * mOffset) + (mOffset / 2.0f);
T * gridObject = createGridObject(cocos2d::Vec2(x , y), scene);
mGrid[y].push_back(unique_ptr<T>(gridObject));
onGridObjectCreated(gridObject, actualPosition , cocos2d::Vec2(x , y));
}
}
onGridCreationFinished(mGrid);
}
template<class T>
bool PlayField<T>::isWithinBounds(const cocos2d::Vec2 & position)
{
if ((position.x >= 0 && position.x < mGridSize.width)
&& (position.y >= 0 && position.y < mGridSize.height))
return true;
return false;
}
template<class T>
cocos2d::Vec2 PlayField<T>::convertToGridPosition(const cocos2d::Vec2 & position)
{
cocos2d::Size gridPixelSize
= cocos2d::Size(mGridSize.width * mOffset, (mGridSize.height-1) * mOffset);
cocos2d::Vec2 ipos;
ipos.x = (mGridPositionOffset.x + gridPixelSize.width) - position.x;
ipos.y = (mGridPositionOffset.y + gridPixelSize.height) - position.y;
cocos2d::Vec2 gpos;
gpos.x = static_cast<int>(ipos.x / mOffset);
gpos.y = static_cast<int>(ipos.y / mOffset);
//gpos = cocos2d::Vec2(mGridSize.width - 1 , mGridSize.height - 1) - gpos;
gpos.x = (mGridSize.width - 1) - gpos.x;
return gpos;
}
template<class T>
int PlayField<T>::getOffset() const
{
return mOffset;
}
(...)
This is how I initialize the grid; I set a small size so that I can simplify testing:
mScreenSize = cocos2d::Director::getInstance()->getOpenGLView()->getFrameSize();
cocos2d::Size gridSize = cocos2d::Size(3, 3);
cocos2d::Vec2 actualPosition;
actualPosition.x = (mScreenSize.width / 2.0f) - ((gridSize.width * 50) / 2.0f);
actualPosition.y
= ((mScreenSize.height / 2.0f) + (((gridSize.height-1) * 50) / 2.0f) - 74.0f);
mJewelBoard.reset(new JewelBoard(actualPosition, this));
The JewelBoard
constructor automatically sets the grid into a size of 3 x 3. with a tile size of 50 x 50 pixels in its constructor. The size of the game screen is 600 x 550. I set the position of the JewelBoard
to the center using the actualPosition
variable. Notice that I subtracted 74.0f
, so it goes little bit downward to match the background borders.
That is where I notice that the grid coordinates being returned are negative, on the y-axis. I must have missed something, in calculation. Also take note that getting the position of the touch and mouse location is starting at the top-left. Also note that I prefer my 0 x 0 to start at the bottom-most part. as well. to keep it aligned with my other code. That way, I don't have to do flip-axis conversions.
Here is the picture to better understand my situation:
What has gone wrong? Why does selecting a tile return a negative coordinate?