Designing A Responsive Tooltip System in Unity
HTML-код
- Опубликовано: 20 сен 2024
- Tooltips are a fundamental part of Game UI design but it can be tricky to make them look good, let's take a look at how to design a smart and responsive Tooltip system that will resize and position itself on screen relative to its content!
Thanks to Kenney for the Assets! www.kenney.nl/...
Creating A Debug Cheat Console: • Creating a Cheat Conso...
Creating a UI Line Renderer: • Creating a UI Line Ren...
Making UI that Looks Good: • Making UI That Looks G...
--------------------------------------------------------------------------------
Want to support the channel?
▶️ Help fund new episodes by joining the Patreon - / gamedevguide
Use these links to grab some cool assets from the asset store:
Get the Must Have Assets! - assetstore.uni...
Free Unity Assets! - assetstore.uni...
New on the Asset Store! - assetstore.uni...
Top Paid Asset Store Packages - assetstore.uni...
Asset Store Partners - assetstore.uni...
--------------------------------------------------------------------------------
Socials and Other Stuff:
• Subscribe - www.youtube.co...
• Join the Discord - / discord
• Twitter - / gamedevguideyt
• Facebook - / gamedevguideyt
• Instagram - / gamedevguideyt
The UI god, understanding the rectransform class and other ui components has been one of my biggest challanges with unity tbh, and there's very little resource on this, thanks for the tutorials!
me: "huh thats a thumbnail I don't remember --oh new game dev guide video, finally!"
I've binged the others too many times in the last 2 months haha
lol same
Great guide!
I modified a little the logic that sets the pivot of the tooltip in order to position it relative to the mouse cursor depending of the screen quadrant.
private void Update()
{
var position = Input.mousePosition;
var normalizedPosition = new Vector2(position.x / Screen.width, position.y / Screen.height);
var pivot = CalculatePivot(normalizedPosition);
_rectTransform.pivot = pivot;
transform.position = position;
}
private Vector2 CalculatePivot(Vector2 normalizedPosition)
{
var pivotTopLeft = new Vector2(-0.05f, 1.05f);
var pivotTopRight = new Vector2(1.05f, 1.05f);
var pivotBottomLeft = new Vector2(-0.05f, -0.05f);
var pivotBottomRight = new Vector2(1.05f, -0.05f);
if (normalizedPosition.x < 0.5f && normalizedPosition.y >= 0.5f)
{
return pivotTopLeft;
}
else if (normalizedPosition.x > 0.5f && normalizedPosition.y >= 0.5f)
{
return pivotTopRight;
}
else if (normalizedPosition.x
I gotta say, toggling on and off a layout element to handle sizes smaller than your max size is just genius. So many projects at work I have written complicated code to do the same thing, but this is just so much easier.
I didn’t actually care about the tooltip system when watching this, (I’ve coded up similar systems a lot) but it is gems like the layout element trick that made me want to check this out. Great problem solving there.
If I'm not mistaken the 3:54 layoutElement.enabled trick requires manually matching your chosen characterWrapLimit to your chosed preferredWidth in the Layout Element. An easy way to avoid this is using "layoutElement.enabled = Math.Max(headerfield.preferredWidth, contentField.preferredWidth) >= layoutElement.preferredWidth;
" instead
Goated comment for saving me some time thinking about something slightly annoying, but not annoying enough to deal with later
I couldn't track how those 9 minutes passed, the explanation was so smooth! Great video, thanks for sharing 😊
„It‘s LEANTWEEN time“ 😂
Great video as always! Hope to see a new video soon
Great tutorial! I learnt a lot. If anyone is looking to get this a bit more 'mouse snaps to corners of cursor to stay on screen' rather than have be based on screen position average, the below might be helpful to you in place of the rectTransform positioning bit of the tutorial:
Vector2 position = Input.mousePosition;
float pivotX = position.x / Screen.width;
float pivotY = position.y / Screen.height;
float finalPivotX = 0f;
float finalPivotY = 0f;
if (pivotX < 0.5) //If mouse on left of screen move tooltip to right of cursor and vice vera
{
finalPivotX = -0.1f;
}
else
{
finalPivotX = 1.01f;
}
if (pivotY < 0.5) //If mouse on lower half of screen move tooltip above cursor and vice versa
{
finalPivotY = 0;
}
else
{
finalPivotY = 1;
}
tooltip.rectTransform.pivot = new Vector2(finalPivotX, finalPivotY);
tooltip.transform.position = position;
----------------------------------------------------------------------------------
SMOOTH TWEENING IN UPDATE:
If you want the above to move smoothly rather than completely snap you can call a DoTween sequence to position it in the Tooltip's update (just be sure if you do this, to kill the tween sequence if already running and then again on hide or you'll get wonky behaviour). Sorry, I don't know LeanTween but I'm sure you can do the same with it.
So in the update of the tooltip itself I replace the "tooltip.rectTransform.pivot = new Vector2(finalPivotX, finalPivotY)" bit with:
finalPivot = new Vector2 (finalPivotX, finalPivotY);
if (rectTransform.pivot != finalPivot)
{
moveSequence.Kill();
moveSequence = DOTween.Sequence()
.Join(DOTween.To(() => rectTransform.pivot, x => rectTransform.pivot = x, new Vector2(finalPivotX, finalPivotY), .5f))
.Join(DOTween.To(() => rectTransform.pivot, y => rectTransform.pivot = y, new Vector2(finalPivotX, finalPivotY), 1f))
.SetRelative(false)
.Play();
}
moveSequence is a DoTween Sequence variable I declared at the top of my code
Hope that helps someone!
Thanks for the solution, great topping on the original version.
Exactly what I was looking for, thank you!
thanks i was thinking the exact same thing and this code worked perfect for it
3:54 another way of doing line 24 is to just set the layoutElement.enabled to the condition to be true (since if the conditions are true, then it sets to true and the opposite happens too), like:
layoutElement.enabled = (headerLength > characterWrapLimit || contentLength > characterWrapLimit);
That actually bothered me too.
I paused the video there to find this comment. It annoyed me too much.
Or layoutElement.enabled = Math.Max(headerfield.preferredWidth, contentField.preferredWidth) >= layoutElement.preferredWidth;
This has the advantage of obviating the "characterWrapLimit" parameter, which is annoying to calibrate. Instead it just uses the LayoutElement's preferred width you set.
Agreed. no need of using ternary operator here
@@zoltan9498 need, becouse if component disabled all responce from him is null.
Hello,
How to use LeanTween.delayedCall when game is paused (Time.timeScale = 0f)? Because tooltip is not appearing when the game is paused.
Great guide!
Something you didnt touch on that i used myself:
If you want to add the tooltip to objects at runtime (e.g. for inventory items instantiated from a base of Scriptable Objects), you can use AddComponent and set the title, content, etc afterwards with info from the SO.
The wait is always worth it. Thank you very much for all these GREAT Game Dev Guide tutorials!
Thanks for the tutorial. This might be personal preference but the visual cuts are a biiiit fast for me. Stopped counting how often i had to stop the video just to see what was happening. I like that it doesn't waste a lot of time but especially the drag and drop stuff is hella fast.
I had to slow it down to half speed. Makes it more entertaining also since it sounds like a drunk person is explaining programming to you. (due to slow speech) :P
Came here for ToolTips... stayed for all the layout element tricks.
Finding this video made my week!
Hey, I doubt you'll see this but I just wanted to say this is by far my favourite game dev channel on RUclips. You make everything so clear and easy to understand, and cover so many bases and edge-cases that others usually wouldn't. Thank you so much for this, you've helped me a ton.
Thank you so much for the kind words! I'm glad you find the videos useful. ❤️
This is a huge puzzle piece for the project I'm working on, with such a clear and concise explanation. Thank you so much!
Honestly though, how the f*** do you not have a milion subscribers already!? I really don't get it, your videos are much higher quality than Brackeys (in my opinion).
Are you sure you're not just biased because Brackeys mostly targets(/targeted...) total beginners and this channel doesn't?
I developed a custom tooltip system long ago but I was unaware of how to manage its pivot according to the screen width. Your video save me thanks matt.
At 3:57, line 24, it's better to use
layoutElement.enabled = headerField.preferredWidth > layoutElement.preferredWidth || contentField.preferredWidth > layoutElement.preferredWidth;
As you're comparing the preferred size of TMP to the Layout Element preferred size rather than arbitrary text length which does not work for when you use special TMP features such as HTML color or Sprite asset.
Hope this helps.
I'm often blown away by how beautifully made you videos are. Excellent instruction. Thank you!
its LeanTween time - one more useful video! Thanks
This has been incredible! Thank you so much for making it! :D I love how you explain extra things such as doing it for gameobjects or how to get information for what text to display, it's greatly appreciated :)
your UI videos are always fantastic. doubly so because it can be a bit hard to find actually useful UI info sometimes!
I Had developed something similar to this before, but your solution is way more elegant and cleaner.
Great Job!
Fantastic tutorial, super well spoken, edited and the code + explanations are great man! Will be implementing this tonight!
For those whose Tooltip image/text shows on Start, keep the Tooltip canvas active before playing, but turn off the Tooltip GameObject. When you hover over the items, the tooltip will show and hide when you exit. This will stop the Tooltip from showing when you start playing and are not hovering over anything.
Thank you! This came at JUST the right time - I've been putting off implementing tooltips to my game, and this is a MUCH better way than the one I've been using so far. I love it! Thank you! Please keep doing these.
You, my friend, are some kind of sorcerer! Absolutely banging video. great content. Thank you so much! SUBBED.
Sure this will be useful to someone... it sets the pivot of the tool-tip so it is positioned next to the mouse. This keeps it on the outside of the tool-tip at all times, so you can clearly read the text. Similar to how it is displayed at the end of the video.
Vector2 position = Input.mousePosition;
float x = position.x / Screen.width;
float y = position.y / Screen.height;
if (x = 1 - y) //right
Rect.pivot = new Vector2(1.1f, y);
else if (x = 1 - y) //top
Rect.pivot = new Vector2(x, 1.3f);
transform.position = position;
Thank you for your comment. I can confirm it works
Thank you a lot !
Thanks!
this looks great, thank you!
This is exactly what I needed, and your video arrived just in time. Thanks man!
I love you man! Awesome editing, clear explanation, clean coding 5/5 will watch again
This was awesome. I hate UI/UX, so hard to do right, but you make it look simple!
Awesome, awesome, awesome!! Your tutorials are next level, thanks, buddy!
Thank you. Simple, elegant, and useful. Making clear UI is very important for a successful game.
Dynamic pivot was awesome solution, thanks for the truck!
I developed a system with tooltips for a card game that's currently in steam when I worked in it but with all of this I think I'd make a better one using this knowledge, really awesome!
Still a wonderful guide. Thanks a lot!
Great video, I really appreciate your concise editing!
I went through alot of diffrent tutorial and all the features that this one had and boy is this easier Very underaterd
Your Channel is doing the Lords work. ty
Really nice video, will definitely be one I keep referring back to whenever I want tooltips :D
Definitely gonna use it someday! I'm currently building a game for mobile, so it may be unnecessary. Tho I still learned something. I didn't know that you can use content size fitter to adjust the recttransform automatically. Definitely a helpful thing.
Keep up the great work man.
Great as always Matt
4:33 If your copying the code over, be sure to keep the "static" on the Show(), I was getting a CS0120 error for a bit.
Hi, instead of using a ternary operator, you can simplify it like this:
layout.enabled = headerLength > characterWrapLimit || contentLength > characterWrapLimit;
I was having trouble getting the tooltips to show on non-UI objects, eventually discovered this was due to me using unities new input system. The solution was to add a physics raycaster component to the camera. Now pointer events (such as OnPointerEnter/OnPointerExit) can be called on non-UI objects without needing OnMouseOver() and OnMouseExit() in the tooltip trigger script.
Thank you for sharing your solution to this!
Thank you! So crisp and useful!
Amazing work! Thank you for sharing!
I'm actually using this in my current prototype, thank you
Great video - as always!
2:54 tooltip image not adjusting height in my case if disabling header or content object. Any idea why this happening? I watched videos 10+ times, i can't find anything that I missed. 🙏🙏🙏
You need a source image and the image type Sliced in the tooltip.
Love the UI videos
Thank you very much for sharing all these amazing contents.
Great video👍, love the ui series.
as a general programming tip, if you are going to do anything life (statement) ? true : false, the statement itself returns true or false
so the code: layoutElement.enabled = (headerLength > characterWrapLimit || contentLength > characterWrapLimit) ? true : false;
can be: layoutElement.enabled = (headerLength > characterWrapLimit || contentLength > characterWrapLimit);
Thanks this was very helpful!
Hello! Can you make a tutorial in which objects in a layout group move smoothly, and not just jump after removing or adding an element?
This man is a hero we don't deserve
Wow, what a great tutorial. Really well done and thanks a lot :)))
Lovely video, enjoyed this.
Thanks..
one note i found.;
new inputsystem takes 2 lines..
get the inputsystem and read the value ;) ohh and the value is a vector3 not 2.
Using UnityEngine.InputSystems;
get the value as such.
Vector3 position = Mouse.current.position.ReadValue();
Amazing video. Love it!
Very helpful!! Thank you mate!
Lmao, the LeanTween time cracked me up. Btw nice tutorial
This is a good tut. I could use this.
If someone else is using the new input system and trying to OnPointerEnter on a sprite, you have to add a Physics 2D Raycaster to your camera and a collider to the sprite
there are some missing info's in the video, after the pivots / screen, which moves whenever the cursor get close to screen edges, and then at the end of video suddenly the tooltip still in the next cursor ? idk how?
Thanks for the video, it helped a lot!
what a nice tutorial, ty for the great content :D
This is amazing. Thank you!
Just AWSOME
Really excellent videos!
nice easy concise thanks alot great stuff thanks
Also using static means Unity can't serialize it, so if you modify code and have Unity hotswap it while the game is running, you'll lose the tooltip reference. A fix for this is to put current = this inside Update() as well.
Great video. Commenting for the algorithm
Awesome video !
I actually ended up making something very similar for Ludum Dare 50 this week-end. 🤣
Couple issues/thoughts. When my tooltip first enables and shows up on the screen, something looks off about it. Almost like it's enabling first then repositioning which I can notice. The other minor thing is the content/header strings in the TooltipTrigger script should have the [TextArea] header for easier entering and formating of information.
This is awesome!
you deserve more likes.
IMPORTANT: IF YOU HAVE IT LINGER PAST THE OBJECT NOT BEING HOVERED OVER:
In the Tooltip_Trigger script, if the object gets disabled or destroyed before OnPointerExit gets called, it will stay on your screen until you hover over another tooltip trigger.
TO FIX THIS: Simply make an OnDisable() or/and OnDestroy() method in the Tooltip_Trigger to Hide() the Tooltip as well.
Yuh' Know, I was skeptical of LeanTween because I hate using packages that I didn't make. But Between this, and the fade with Leantween.alphaCanvas. It was super easy to do compared to writing my own coroutines or learning invoke etc... Thanks again
excellent tutorial, thank you
Celebrate your success of your tutorial! ;)
If you could do a tutorial about the country lines, like 0:36 , that would be great.
Never saw that kind of like/dislike ratio, well deserved :)
I've followed this and have no errors in my code however the tooltips wont appear? Or if I enable the canvas in the inspector the tool tip is permanently showing. I get errors object reference not set to instance of object, making reference to current.tooltip.gameObject.SetActive(false); in the Tooltipsystem script
[Multiline()] is how he got the bigger text area in the editor, just above public string content; in TooltipTrigger script. You can see it at 8:05 in the video.
When I got to transform.position = position; in the Tooltip script, my tooltip disappeared. What happened was that I was using a camera to put the overlay to fit game screen, so the tooltip was appearing miles away for some reason.
Once I put the Tooltip Canvas -> Canvas component -> Render Mode back to SCreen Space - Overlay, it was fine. I had to reset the transform value on the tooltip too to put it back where it should be.
There's probably a proper way to make it work with a screen space overlay set to camera, but it worked with that little fix anyway.
How is he able to get a margin on the left and right of his text with the Content Size Fitter? I keep trying to rearrange my canvas image but the text is still really close to the edges.
EDIT: He added a padding of "10" to each element in the Vertical Layout Group, just saw that.
amazing, thank you!!
1k likes, 0 dislikes, *visible great content*
I'm so glad I found your videos! Question though... I mainly deal with Mobile games. Is there a solution you'd recommend for Mobile? Would love to see a video on Mobile solutions for common problems like these
simply the best!
Great video! Thx! :)
Dude your great
thank you king
Thanks for your video
Had to watch this in 0.25 speed just to be able to not miss something with how fast those video zooms and mouse movements were.
This is really useful for displaying basic strings but what about referencing variables in the tooltip? At the start of the video you hover over some objects what have more advanced tooltip information...
These videos only serve as a base for people to build on! For your suggested use case, you can use string formatting on the tooltip and pass the info into the formatted string / tooltip from some other component when it's required.
5:53 was just wondering, why does your inspector show a textfield for the content? do you use some special inspector or is there a tag for it? thx
INFORMATIVE!
So Good!
How did you do the fade animation? I've been trying to get it to work with LeanTween, no success yet.
Put a canvas group on the component and use Leantween.alphaCanvas
@@GameDevGuide Thank you
@@martynawasiluk1405 can you help me please? what i have to do?