Part 23: Objects - Part 3: Picking up and dropping objects
Downloads
Objects graphics
<?xml version="1.0" encoding="utf-8"?>
<items>
<!-- ======================== Weapons ======================== -->
<!-- EYE OF TIME -->
<item name="ITEM001">
<category>Weapon</category>
<floor_image>00W_Ring.png</floor_image>
<image_file>Items0.png</image_file>
<image_num>17</image_num>
</item>
<!-- STORMRING -->
<item name="ITEM002">
<category>Weapon</category>
<floor_image>00W_Ring.png</floor_image>
<image_file>Items0.png</image_file>
<image_num>19</image_num>
</item>
[...]
</items>
We'll see later that some objects have more than one image, but for now we will only display one.
Mouse areas
enum EMouseAreaTypes
{
eMouseArea_None = 0,
// interface areas
[...]
// game areas
eMouseAreaG_Champion,
eMouseAreaG_DoorButton,
eMouseAreaG_PickObject,
eMouseAreaG_DropObject
};
class CMouse
{
public:
[...]
CObject mObjectInHand;
[...]
};
We can only pick objects that are at our feets - that's to say the "back" row of the tile where the player is - and
bool CObjects::isWallInFront()
{
CTile* tile = map.getTile(player.pos);
EWallSide side = player.getWallSide(eWallSideUp);
CWall* wall = &tile->mWalls[side];
return (wall->getType() != eWallNothing);
}
For the "pick up" areas, we only have to add an area to each object while we draw them in CObjects::drawObjectsStack:
// draw the object on screen
pos -= CVec2(scaledObject.size().width() / 2, scaledObject.size().height() - 1);
graph2D.drawImage(image, pos, scaledObject, 0, false, QRect(0, 33, MAINVIEW_WIDTH, MAINVIEW_HEIGHT));
// add the mouse area
if (mouse.mObjectInHand.getType() == 0)
{
if (tablePos.x >= WALL_TABLE_WIDTH - 1 && tablePos.x <= WALL_TABLE_WIDTH)
{
if (tablePos.y == (WALL_TABLE_HEIGHT - 1) * 2 ||
(tablePos.y == (WALL_TABLE_HEIGHT - 2) * 2 + 1 && isWallInFront() == false))
{
CRect mouseRect(pos, CVec2(pos.x + scaledObject.width() - 1, pos.y + scaledObject.height() - 1));
mouse.addArea(eMouseAreaG_PickObject, mouseRect, eCursor_Hand, (void*)stack, (void*)i);
}
}
}
Here we check tablePos.x to see if the object is in front of us - not on the left or on the right.
void CObjects::drawBackRow(QImage* image, CVec2 mapPos, CVec2 tablePos)
{
[...]
CVec2 mapLeft = mapPos * 2 + pos1;
CVec2 mapRight = mapPos * 2 + pos2;
drawObjectsStack(image, mapLeft, tablePos * 2 + CVec2(0, 0));
drawObjectsStack(image, mapRight, tablePos * 2 + CVec2(1, 0));
// mouse areas to drop object
if (mouse.mObjectInHand.getType() != 0)
{
if (tablePos.x == WALL_TABLE_WIDTH / 2 &&
tablePos.y == WALL_TABLE_HEIGHT - 1)
{
CRect rectLeft(CVec2(31, 153), CVec2(111, 168));
mouse.addArea(eMouseAreaG_DropObject, rectLeft, eCursor_Hand, (void*)mapLeft.x, (void*)mapLeft.y);
CRect rectRight(CVec2(112, 153), CVec2(192, 168));
mouse.addArea(eMouseAreaG_DropObject, rectRight, eCursor_Hand, (void*)mapRight.x, (void*)mapRight.y);
}
}
}
The coordinates of the areas are the same that we saw on the picture above.
void CObjects::drawFrontRow(QImage* image, CVec2 mapPos, CVec2 tablePos)
{
[...]
CVec2 mapLeft = mapPos * 2 + pos1;
CVec2 mapRight = mapPos * 2 + pos2;
drawObjectsStack(image, mapLeft, tablePos * 2 + CVec2(0, 1));
drawObjectsStack(image, mapRight, tablePos * 2 + CVec2(1, 1));
// mouse areas to drop object
if (mouse.mObjectInHand.getType() != 0)
{
if (tablePos.x == WALL_TABLE_WIDTH / 2 &&
tablePos.y == WALL_TABLE_HEIGHT - 2 &&
isWallInFront() == false)
{
CRect rectLeft(CVec2(46, 138), CVec2(111, 152));
mouse.addArea(eMouseAreaG_DropObject, rectLeft, eCursor_Hand, (void*)mapLeft.x, (void*)mapLeft.y);
CRect rectRight(CVec2(112, 138), CVec2(177, 152));
mouse.addArea(eMouseAreaG_DropObject, rectRight, eCursor_Hand, (void*)mapRight.x, (void*)mapRight.y);
}
}
}
In parameters for the drop areas we pass the coordinates of the stack where we will put the object.
Checking the areas
void CGame::update(SMouseArea* clickedArea)
{
[...]
if (clickedArea != NULL)
{
if (mouse.mButtonPressing == true)
{
if (clickedArea->type == eMouseAreaG_Champion)
{
[...]
}
else if (clickedArea->type == eMouseAreaG_DoorButton)
{
[...]
}
else if (clickedArea->type == eMouseAreaG_PickObject)
{
CObjectStack* stack = (CObjectStack*)clickedArea->param1;
int index = (int)clickedArea->param2;
mouse.mObjectInHand = stack->getObject(index);
stack->removeObject(index);
if (stack->getSize() == 0)
map.removeObjectsStack(stack->mPos);
}
else if (clickedArea->type == eMouseAreaG_DropObject)
{
CVec2 pos = CVec2((int)clickedArea->param1, (int)clickedArea->param2);
CObjectStack* stack = map.addObjectsStack(pos);
stack->addObject(mouse.mObjectInHand);
mouse.mObjectInHand.setType(0);
}
}
}
}
In the case of picking up an object, we copy it in mObjectInHand, then remove it from the stack, and finally
Object as a cursor
SMouseArea* CMouse::clickedArea(QImage* image)
{
[...]
if (area == NULL || area->cursor != eCursor_None)
{
if (area == NULL)
{
[...]
}
else if (area->cursor == eCursor_Arrow)
{
[...]
}
else
{
if (mObjectInHand.getType() == 0)
{
QImage cursor = fileCache.getImage("gfx/interface/CursorHand.png");
graph2D.drawImage(image, mPos, cursor);
}
else
{
CObjects::CObjectInfo object = objects.mObjectInfos[mObjectInHand.getType() - 1];
QImage cursor = fileCache.getImage(object.imageFile.toLocal8Bit().constData());
CRect rect = interface.getItemRect(object.imageNum);
graph2D.drawImageAtlas(image, mPos - CVec2(ITEM_WIDTH / 2, ITEM_HEIGHT / 2), cursor, rect);
}
}
}
[...]
}
We get the type of the object in mObjectInHand and if it is not 0 we get the corresponding sprite sheet
Drawing the object's name
void CInterface::drawObjectName(QImage* image)
{
int type = mouse.mObjectInHand.getType();
if (type != 0)
{
std::string& name = objects.mObjectInfos[type - 1].name;
drawText(image, CVec2(233, 33), eFontStandard, name.c_str(), MAIN_INTERFACE_COLOR);
}
}