STARK: Use the mouse cursor as a hitbox when testing small world items

Fixes #1506.
This commit is contained in:
Bastien Bouclet 2018-11-21 17:24:10 +01:00
parent c5185ee753
commit 4edb8a7add
7 changed files with 41 additions and 6 deletions

View File

@ -127,7 +127,7 @@ bool RenderEntry::compare(const RenderEntry *x, const RenderEntry *y) {
}
}
bool RenderEntry::containsPoint(const Common::Point &position, Common::Point &relativePosition) const {
bool RenderEntry::containsPoint(const Common::Point &position, Common::Point &relativePosition, const Common::Rect &cursorRect) const {
if (!_visual || !_clickable) {
return false;
}
@ -143,6 +143,16 @@ bool RenderEntry::containsPoint(const Common::Point &position, Common::Point &re
if (imageRect.contains(position) && image->isPointSolid(relativePosition)) {
return true;
}
if (imageRect.width() < 32 && imageRect.height() < 32
&& !cursorRect.isEmpty() && cursorRect.intersects(imageRect)) {
// If the item in the scene is way smaller than the cursor,
// use the whole cursor as a hit rectangle.
relativePosition.x = 1 - image->getHotspot().x;
relativePosition.y = 1 - image->getHotspot().y;
return true;
}
}
VisualSmacker *smacker = _visual->get<VisualSmacker>();

View File

@ -95,9 +95,10 @@ public:
*
* @param position game window coordinates to test
* @param relativePosition successful hit item relative coordinates
* @param cursorRect cursor rectangle to be used to test small world items
* @return successful hit
*/
bool containsPoint(const Common::Point &position, Common::Point &relativePosition) const;
bool containsPoint(const Common::Point &position, Common::Point &relativePosition, const Common::Rect &cursorRect) const;
/** Mouse picking test for 3D items */
bool intersectRay(const Math::Ray &ray) const;

View File

@ -159,4 +159,19 @@ void Cursor::setMouseHint(const Common::String &hint) {
}
}
Common::Rect Cursor::getHotRectangle() const {
if (!_cursorImage) {
return Common::Rect();
} else {
Common::Point hotSpot = _cursorImage->getHotspot();
Common::Rect hotRectangle;
hotRectangle.setWidth(_cursorImage->getWidth());
hotRectangle.setHeight(_cursorImage->getHeight());
hotRectangle.translate(-hotSpot.x, -hotSpot.y);
return hotRectangle;
}
}
} // End of namespace Stark

View File

@ -57,6 +57,9 @@ public:
Common::Point getMousePosition(bool unscaled = false) const;
/** Rectangle at the mouse position to consider to hit test small world items */
Common::Rect getHotRectangle() const;
enum CursorType {
kImage = -1,
kDefault = 0,

View File

@ -176,7 +176,7 @@ bool StaticLocationWidget::isMouseInside(const Common::Point &mousePos) const {
if (!_renderEntry) return false;
Common::Point relativePosition;
return _renderEntry->containsPoint(mousePos, relativePosition);
return _renderEntry->containsPoint(mousePos, relativePosition, Common::Rect());
}
void StaticLocationWidget::onClick() {

View File

@ -220,17 +220,23 @@ void GameWindow::onDoubleClick(const Common::Point &pos) {
}
}
void GameWindow::checkObjectAtPos(Common::Point pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction) {
void GameWindow::checkObjectAtPos(const Common::Point &pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction) {
_objectUnderCursor = nullptr;
singlePossibleAction = -1;
isDefaultAction = false;
Math::Ray ray = StarkScene->makeRayFromMouse(_cursor->getMousePosition(true));
Common::Rect cursorRect;
if (selectedInventoryItem != -1) {
cursorRect = _cursor->getHotRectangle();
cursorRect.translate(pos.x, pos.y);
}
// Render entries are sorted from the farthest to the camera to the nearest
// Loop in reverse order
for (int i = _renderEntries.size() - 1; i >= 0; i--) {
if (_renderEntries[i]->containsPoint(pos, _objectRelativePosition)
if (_renderEntries[i]->containsPoint(pos, _objectRelativePosition, cursorRect)
|| _renderEntries[i]->intersectRay(ray)) {
_objectUnderCursor = _renderEntries[i]->getOwner();
break;

View File

@ -58,7 +58,7 @@ protected:
void onDoubleClick(const Common::Point &pos) override;
void onRender() override;
void checkObjectAtPos(Common::Point pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction);
void checkObjectAtPos(const Common::Point &pos, int16 selectedInventoryItem, int16 &singlePossibleAction, bool &isDefaultAction);
ActionMenu *_actionMenu;
InventoryWindow *_inventory;