Don’t know much about writing own tutorials, so I decided to simply share my sources. Haven’t found if anybody already did it, but anyway.
This way you can make button’s shape to be watever you want to.
Here goes a short video, what could be done using this button (in Russian, sorry):Unreal Engine Custom Shape Button (Custom Hit Box) - YouTube
To make it work - just copy 2 sources files (or folder with em) into your project’s source folder.
Check #include “YourProjectName.h” in cpp file and two occurences of YOURPROJECTNAME_API in header file.
Compile and you’ll be able to use new “Common” item in UMG palette - Ovodus Button.
Add any texture with alpha channel into Advenced Hit Texture property, it’s Alpha channel will be used to determine desired button’s shape.
This texture will allways be “stretched” to button’s dimentions, so be careful with paddings and so on.
PS: You can also use same method to make different behaviour depending on the button’s area pressed. Just check for texture’s color, not just alpha, under the mouse cursor. It could be “Pizza Slices, for instance, and so on”.
Please leave your comments and bug reports here or in comments. You can also contact me by email: firstname.lastname@example.org.
Thanks so much Ovodus and Yakim ! This feature should be in the base engine. I tested the plugin and the Ovodus button work in pc but not on mobile. How to make compatible on mobile ? (with ovodus code or plugin)
That’s cool man. I never even bothered to consider this given the way my buttons are used. Basically in my case I do have an alpha around my buttons text so it looks like just text but highlights and has the down state etc. The only difference being the mouse will change the state while over the alpha area. This is fine in something like a main menu or whatever where it doesn’t matter if the button highlights this way. But if you want a rounded or odd shaped button that only highlights while the mouse is over the visible areas this works for sure.
Thanks for this! I thought about how someone could achive that but that solution is more than simple and multipurpose.
When testing it is not working properly for me. Here is my test texture. I checked the calculated image coordinates, looks good. I gues there is an issue with the lookup of the pixel in the texture using the calculated image coordinate. Can someone please check that image on their end?
Solved it for me.
Use this texture to test on your end, should not work.
Change the code to look like this:
FReply OvodusButton::OnMouseMove(const FGeometry& MyGeometry, const FPointerEvent& MouseEvent)
LocalPosition.X *= ImageWidth;
LocalPosition.Y *= AdvancedHitTexture->PlatformData->SizeY;
LocalPosition.X = floor(LocalPosition.X); // ADD THIS LINE
LocalPosition.Y = floor(LocalPosition.Y); // ADD THIS LINE
int BufferPosition = (LocalPosition.Y * ImageWidth) + LocalPosition.X;
FColor* ImageData = static_cast<FColor*>((AdvancedHitTexture->PlatformData->Mips).BulkData.Lock(LOCK_READ_ONLY));
First of all, great job both Ovodus and Yakim!
After using these custom buttons for a while now, I stumbled upon an issue. If you place a button (call it button A) behind the alpha of another button (button b), it won’t detect a hit on the overlapping part of button A.
Looking forward to any solutions for this and thanks in advance!
My apologies but I actually meant hover instead of hit. When I hover over B (part that isn’t transparent) it changes to it’s hovered color, ovodus button works like a charm on this. Now, I want to achieve the same effect for A, but when I hover the part of A that is behind B, it won’t detect the cursor because B is on top of A.
And about the reference to the other button. The end goal for me using this, is to create a circular menu with different pieces that change dynamically according to the amount of buttons needed.
As u can see in the image attached, there are 6 buttons here. Each button has an image of 1/6 of a circle (in this case) which is also placed in the advanced hit texture slot.
But since each image has a large part (rest of the circle (second image attached)) of transparency, they all overlap with each other. So in this case I can only hover/press button 6, since that’s the last one added and thus the on that’s on top.
So I don’t think I can reference to a specific button, since it could be any of the others…
Only the top widget gets the hover, thats what I was saying and what you were confirming.
With “hit” I was refering to the hit testing that is happening in this button.
For your needs: never did a round menu like this, but as many others showed this is possible. However I gues they just implement it in another way. You can lay a material on top of it, or use overlay widget to place multiple images. When hovering you calculate the angle of the mouse to the center of the button and highlight the according part manually. At least that is what I would do.
Or just spend some bugs on a already finished one. Search the marketplace for “pie menu”
Yeah, that’s what I do for my VR version of this menu, calculating the position of the thumb to the center of the trackpad (vive). I hoped a PC version would be more simple since ue4 has a automatic hover/pressed system for buttons.
I’ll give it a try, thank you!
Not sure if you’ve figured it out, but I have a workaround that fixes this. This only works for your kind of buttons that are in that circular shape. The collision detection will always hit the button with the highest z-order, so just write a check that gets the angle your mouse is at compared to the center of the circle buttons and compare that to an angle range you’ve set for each button. When you go over a button’s angle range, set that button’s z-order higher than the rest of the buttons.
I did find one bug in your code btw. It results in randomly incorrect alpha values when moving the mouse around the widget.
You are calling “floor” on the X and Y values of the FVector2D before dividing it by the “local size” of the geometry. This can produce a vector with fractional values, which causes problems later on when you use this to find “buffer position”.
I floored the values to integers to be safe ( you can’t have a fraction of a pixel), and did so right before calculating “buffer position”. This fixed the issue.