I am building a tower defence game, where the player can freely use their mouse to click actors on screen (e.g. to click on a tower to see it’s stats, or click a rock to collect stone). Sometimes, I want widgets that the user can click, but then I want this mouse click to be “consumed” so they do not interact with the world behind the widget.
My setup so far is a “WBP_UI” widget which holds all of the UI widgets (e.g. showing resources, buttons to start wave, health, game speed, etc). The canvas panel of this base UI widget is Visible and hit-testable. It overrides the “Mouse Down” event and calls some C++ functions which handle my actual game logic, for example to collect a resource on the ground under the cursor. (simplified BP below)
I then have some “WBP_TowerCard” widgets which are widgets to act as the buttons for the user to select what type of tower to place down. These are created by the WBP_UI on event construct and placed in a HorizontalBox. These tower cards should have their own logic for handling a user clicking them, and so are also Visible/hit-testable and override the “Mouse Down” event. They also have some logic to animate when the mouse is over them and so implement animations on the “On Mouse Enter” and “On Mouse Leave” events. For example, these tower cards might become larger when hovered, and stay larger when clicked to indicate they are selected, and set the player mode to “placing” so the next click in the world attempts to place the selected tower down. In this instance, I do NOT want the click to propagate to the WBP_UI widget. (simplified BP below)
This is because I get issues such as selecting a tower and placing the tower on the ground behind the card in the same click, instead of 1 click to select the tower, and then a second click to place the tower. How can I get the click to be “consumed” by the WBP_TowerCard so the logic in the WBP_UI::OnMouseDown does not run?
I also have an issue where on clicking the TowerCard, it also calls the OnMouseLeave event when clicking down and OnMouseEnter event when releasing the click, which should not be happening as the cursor does not actually leave the edges of the card (which is what I want these events for, as they are meant to handle hover animations). In my blueprint, these events play animations to raise the card up and down to indicate they are the card being hovered over. However, when clicking the card they lower briefly before coming back up, which is not intended. I am not sure if this is something that is caused by the click propagation but it causes annoying unintended visual effects.
These are the output strings printed from the above blueprints when I start the game, move the mouse over my WBP_TowerCard, and then click once without moving my mouse.
The two logs with the green dots are expected, the logs with the red dots are not expected and cause unintended effects.
Thanks for any help!
NOTE:
I noticed that when using generic Button widgets instead of a custom WBP_TowerCard, the button is able to consume the click and perform it’s own logic without calling the WBP_UI OnMouseButtonDown function. What is the button actually doing to do this? I suppose one workaround would be to make my WBP_Towercard a child of a “Button Widget” instead of a “User Widget” and handle my logic in the Button::OnClicked event instead of overriding the UserWidget::OnMouseDown function, but I want to know how it actually works so I can implement it without changing my widget inheritance heirarchy.