UI is it's own beast especially when you start adding gamepad support lol. Now I know no one reading this knows me but I'm gonna share this here anyway, I've had to go through these same struggles with my projects and I've had to create my own solutions for them, and I'm extremely proud to be able to say that I've been able to overcome these difficulties without the need of any video tutorials, hell even a year ago I wouldn't even know where to start with this lol.
That’s really awesome. I’m currently working through UI for a project because I know it’s my weak spot and whew… Getting the art, the logic, and navigation with Input all working together might as well be an entirely separate project on it’s own. I’d actually prefer implementing the math logic behind movement and things in the 3D parts than having to deal with the logic in UI. Especially with Unity’s new UI toolkit garbage. It looks so nice and helpful at first glance, but when you really dive into it it’s so restricted and difficult for like… no reason.
Overall great stuff! You could use the new Input System to detect when a controller takes control of the input to reselect the last selected object by using the OnControlsChanged method in your Input Manager or another component that is in the same component of the Player Input. You could also use the Selectable navigation system on the button component so you don't need to manually control the selected button when pressing the directions (the arrows at 1:43 in the scene view show how the navigation would be).
This is quality stuff. After years of watching tutorials and even having a degree in Computer Science, I can confidently say this is the sort of thing every dev should learn and many of these programming concepts are being put into our upcoming project No Time Left
Video couldn't have come at a better time. We were just about to start adding menus and UI to our prototype. We really want to support gamepads and kbm from the start, thanks for this!
I saved this video for future reference, which is not something I do very often. I learnt something today - this was a really awesome video. Thank you and great work.
As someone who has published dozens of games on xbox360 and steam but never had a huge success (360 I had a games with 100,000 downloads, and on steam as many as 5k sales for a single game), this is the kind of content I need to help understand how commercial developers think about the little things that take your game to the next level. Thank you!🎉
Such a refreshing video in the unity tutorial space of youtube! I find that a majority of the videos are made by unity/programming hobbyists and therefore disregard basic coding principles and background knowledge that you displayed here :) thank you
4:15 using lerp without a fixed starting point, will make it never reach the actual end-value. either store your start values before the while loop or use MoveTowards or something like that 5:35 instead of right-click > quick actions you should also be able to just hit [alt]+[return] 5:55 null it only if the current selected value is the current object. 7:20 singleton is really unnecessary here since you know you will have a parent/child relationship between the objects anyways. so you're just polluting the project with a unnecessary singleton, with all the drawbacks they have. 10:50 if(! Mathf.Approximately(InputManager.instance.NavigationInput, 0)) { HandleNextCardSelection(Mathf.Sign(InputManager.instance.NavigationInput)); } would be a more compact version of the update method that does the same I guess that you need to wait a frame, because the children are not always setup yet, when the code goes through this.
Also at quick glance, I believe there is nothing stopping you from infinitely growing the scale of the cards. If you move your mouse on/off the card extremely quickly, you will have several Coroutine calls that overlap each other, so you need to set up some sort of cancel before starting a new routine. Also going off what you said, there needs to be something at the end of the routine that sets the scale / pos to the desired position, because as you said, it will always stop just short of the end value. This is especially noticeable at very low framerates.
I was actually trying to solve this same problem for my game UI. I eventually deleted mouse navigation because I don't need it for gameplay but this tutorial might be very helpful for a future project. Thanks a lot.
As always, great video! Thanks a lot. I was preparing the ui for a small project, and the video has made me rethink some things which I hadn't forgotten to keep in mind. Thanks, so helpful.
Hmm, it's not really that up-to-date. Tweens are smoother and can be made more interesting than lerps and using the interfaces isn't as good as using the new input system, which handles switching between input schemes far easier. Also, using UniTask instead of coroutines is more performant, while also allowing for cancellation tokens.
Thanks for the great tutorial! I was just implementing something similar in a project I'm working on and my solution was very sloppy. Looking forward to trying it this way!
your race condition is based on script execution order + Awake. Since OnEnable is also called when Awake is invoked, if your script executes before EventSystem's Awake is invoked, then your script will crash. A simple way around this I've found is just setting a flag in your script that gets set to true on awake, and short circuit OnEnable if that flag isn't met. It's technically safer and more correct than using a coroutine to wait one frame, though it accomplishes the same thing
Thank you-this has been incredibly helpful! I really enjoy your videos, so I just subscribed. I’m a bit surprised you don’t have a Patreon or something similar, but I imagine your game development projects keep you pretty busy. If you ever create one, let me know-I’d be happy to support it! I know a lot of people have moved to UI Toolkit, but I haven’t explored it enough to make the switch yet. For now, I’m sticking with the "old school" approach. lol. I do have a question about this system: if the mouse stays hovered over a card while using the gamepad/keyboard, wouldn’t that cause a bug? It seems like the mouse would still report it’s hovering, which could prevent the gamepad from properly advancing to the next selection (or it might advance, but then jump back to the mouse hover). How would you handle this? Would you add a `currentInput` state to your global UI manager that switches based on the active input device? I’ve done something similar and also hide the mouse when the gamepad is active, as that seems common in professional UI systems. Your video really connected the missing pieces for me, so thank you again!
If you'd like to do everything he did but in a must faster, more efficient way, look into a tweening library. It gives you so many tools to make animations for both UI and objects. Once you get familiar with a tweening library and you understand how it works, it's benefit really starts to shine through
I hate to say it, but I think there is a huge difference in which kind of quality one would typically be aiming for. For example: is it AAA, or is it stylized? Is it indie dev or a huge team? The code is without debate, but this core situation is about everyone doing nothing good for UI. Hell, even I struggle. It is just so difficult to make UI look good when you can definitely make UI functional.
i've been loving these "like a commercial game" tutorials, but i have a question, why would you replace the navigation controls of the default input with your own?
This does not appear to work if the element being animated is on any layout group. It will just move to the bottom left corner and then behaves fine after that but in the wrong location. And each UI element will then stack on top of each other. This is fine if the element is not in a layout group.
I feel like there must be another way than reimplementing navigation "manually" in Update. I'm almost sure there's some callback when unity switches control from the mouse to keyboard/gamepad, and we could somehow intercept the event and set EventSystem.current.SetSelectedGameObject() before that event is handled?
It can be made simpler, if it is okay that the ui-object stays selected. I made myself a "UiKeepControlSelected" script that keeps a ui-object in menu selected when using the mouse on a scrollbar, because mouseover and scrolling deselects the prev. object but does not select a new one. private void Update() { if (EventSystem.current.currentSelectedGameObject == null) { if (this.lastSelected != null) { EventSystem.current.SetSelectedGameObject(this.lastSelected); } } else { this.lastSelected = this.eventSystem.currentSelectedGameObject; } }
Can you please make a tutorial on “new input system” And how to use it properly like in commercial game. I tried multiple times to digest it, but with no effect. These docs are very vage and tutorials are as you said, suitable only for game jam type of games, but in this case easier to stick with the old one
can you do like that all card are overlap each other and when we move pointer on card it will select as you did but will be in front like slay the spire
Ok but what is this 'f' unit type and what are these variable types "SerializeField" and "Range" and how can you have 2 variable types for one variable?
Awesome tutorial, really nice! Ps: am I the only one that is mildly annoyed that people use startPos, and not position, but don't use startSca instead of startScale? Might be my perfectionism haha
Why am the only one getting all the ui elements collapsed in one place, even after 3 times; edit: after much much much time later found problem transform.localPosition = lerpedScale; fix transform.localScale = lerpedScale; 😥😥
Hey, thats some high quality tutorial. I have a question though: When I got multiple elements which listen to the same event, how do you manage, which script should handle the event? Example: the three cards get selected with the arrow keys but the game camera moves with the arrow keys too.
Guess that depends on the situation. You could have a gameState manager that will trigger certain events based on what 'state' your game is in for more complex things. For the simpler example you gave, since I would consider scrolling through cards UI - I would split my controls into 2 action maps, 1 being the game, 2 being the UI. You can disable the game controls and enable the UI controls whenever dealing with UI
Hi I am a software engineer in college for IT but I want to also learn game development but I do not not where to start i want to learn python for apps and softwares and C# for games and pc softwares as well I want to start with C# first because i know python is easy and not hard to learn if you know a language already but I want to learn C# for game development and software apps I wanted to know if anyone knew any update courses or tutorials for beginners I do software engineering and also want to do indie game development solo i know that’s hard but I want to try it I really want to be a software engineer and a indie game developer but I don’t know where to start with game design or programming
If you want to use Unity/C# for game development, Check out Codemonkey's channel. He has a 10 hour free course aimed at beginners (it's one video) and I've heard nothing but great things about it
Product level code 😂. Even Junior developer level developer will be fired for this) Main idea of product level code creation of flexible reusable and extendable code for systems. There are a lot of situations when on prod you will have hacks, but not in core systems
YES! please make a series called (Like a Commercial Game) THIS IS SOOO HELPFUL!
This should be pinned
Please do
Exactly!!!!
UI is it's own beast especially when you start adding gamepad support lol. Now I know no one reading this knows me but I'm gonna share this here anyway, I've had to go through these same struggles with my projects and I've had to create my own solutions for them, and I'm extremely proud to be able to say that I've been able to overcome these difficulties without the need of any video tutorials, hell even a year ago I wouldn't even know where to start with this lol.
Nice, good job
That’s really awesome. I’m currently working through UI for a project because I know it’s my weak spot and whew… Getting the art, the logic, and navigation with Input all working together might as well be an entirely separate project on it’s own. I’d actually prefer implementing the math logic behind movement and things in the 3D parts than having to deal with the logic in UI. Especially with Unity’s new UI toolkit garbage. It looks so nice and helpful at first glance, but when you really dive into it it’s so restricted and difficult for like… no reason.
Fantastic tutorial. Fast paced but easily understandable. Thank you!
Overall great stuff! You could use the new Input System to detect when a controller takes control of the input to reselect the last selected object by using the OnControlsChanged method in your Input Manager or another component that is in the same component of the Player Input. You could also use the Selectable navigation system on the button component so you don't need to manually control the selected button when pressing the directions (the arrows at 1:43 in the scene view show how the navigation would be).
This is quality stuff.
After years of watching tutorials and even having a degree in Computer Science, I can confidently say this is the sort of thing every dev should learn and many of these programming concepts are being put into our upcoming project No Time Left
Video couldn't have come at a better time. We were just about to start adding menus and UI to our prototype. We really want to support gamepads and kbm from the start, thanks for this!
literally getting back into unity and this was exactly what i needed, thanks man.
I saved this video for future reference, which is not something I do very often. I learnt something today - this was a really awesome video. Thank you and great work.
As someone who has published dozens of games on xbox360 and steam but never had a huge success (360 I had a games with 100,000 downloads, and on steam as many as 5k sales for a single game), this is the kind of content I need to help understand how commercial developers think about the little things that take your game to the next level. Thank you!🎉
Such a refreshing video in the unity tutorial space of youtube! I find that a majority of the videos are made by unity/programming hobbyists and therefore disregard basic coding principles and background knowledge that you displayed here :) thank you
Wow I've been waiting for that video for years !
4:15 using lerp without a fixed starting point, will make it never reach the actual end-value. either store your start values before the while loop or use MoveTowards or something like that
5:35 instead of right-click > quick actions you should also be able to just hit [alt]+[return]
5:55 null it only if the current selected value is the current object.
7:20 singleton is really unnecessary here since you know you will have a parent/child relationship between the objects anyways. so you're just polluting the project with a unnecessary singleton, with all the drawbacks they have.
10:50 if(! Mathf.Approximately(InputManager.instance.NavigationInput, 0)) { HandleNextCardSelection(Mathf.Sign(InputManager.instance.NavigationInput)); } would be a more compact version of the update method that does the same
I guess that you need to wait a frame, because the children are not always setup yet, when the code goes through this.
Also at quick glance, I believe there is nothing stopping you from infinitely growing the scale of the cards. If you move your mouse on/off the card extremely quickly, you will have several Coroutine calls that overlap each other, so you need to set up some sort of cancel before starting a new routine.
Also going off what you said, there needs to be something at the end of the routine that sets the scale / pos to the desired position, because as you said, it will always stop just short of the end value. This is especially noticeable at very low framerates.
Wow! This is the best tutorial in its category!
Thanks, so helpful. Oh, and great channel, btw!
I was actually trying to solve this same problem for my game UI. I eventually deleted mouse navigation because I don't need it for gameplay but this tutorial might be very helpful for a future project. Thanks a lot.
As always, great video! Thanks a lot.
I was preparing the ui for a small project, and the video has made me rethink some things which I hadn't forgotten to keep in mind.
Thanks, so helpful.
The quality of this tutorials is astonishing
Hmm, it's not really that up-to-date. Tweens are smoother and can be made more interesting than lerps and using the interfaces isn't as good as using the new input system, which handles switching between input schemes far easier. Also, using UniTask instead of coroutines is more performant, while also allowing for cancellation tokens.
You just earned yourself a new sub. Really liked the video.
Keep up the good work.
19 seconds in the video I already liked and followed you. Just that one sentence resonated so hard :,D
Thanks for the great tutorial! I was just implementing something similar in a project I'm working on and my solution was very sloppy. Looking forward to trying it this way!
Your videos are really helpful bro! +1 sub
Nice work sir, please keep keeping on!
your race condition is based on script execution order + Awake. Since OnEnable is also called when Awake is invoked, if your script executes before EventSystem's Awake is invoked, then your script will crash. A simple way around this I've found is just setting a flag in your script that gets set to true on awake, and short circuit OnEnable if that flag isn't met. It's technically safer and more correct than using a coroutine to wait one frame, though it accomplishes the same thing
Excellent info. Thank you!
Mind blowing!!! awesome content to say the least
Superbly done Brandon!
Great tutorial, subscribed!
im just getting into coding and damn man the way your just throwing this code together is wild.
yeah he is super fast, comes with experience
Great tutorial and to the point, thank you!
Awesome tutorial :)!
Fantastic tutorial!
OMG, more like this please!
Glad you liked it!
Thank you-this has been incredibly helpful! I really enjoy your videos, so I just subscribed. I’m a bit surprised you don’t have a Patreon or something similar, but I imagine your game development projects keep you pretty busy. If you ever create one, let me know-I’d be happy to support it!
I know a lot of people have moved to UI Toolkit, but I haven’t explored it enough to make the switch yet. For now, I’m sticking with the "old school" approach. lol.
I do have a question about this system: if the mouse stays hovered over a card while using the gamepad/keyboard, wouldn’t that cause a bug? It seems like the mouse would still report it’s hovering, which could prevent the gamepad from properly advancing to the next selection (or it might advance, but then jump back to the mouse hover). How would you handle this? Would you add a `currentInput` state to your global UI manager that switches based on the active input device? I’ve done something similar and also hide the mouse when the gamepad is active, as that seems common in professional UI systems.
Your video really connected the missing pieces for me, so thank you again!
If you'd like to do everything he did but in a must faster, more efficient way, look into a tweening library. It gives you so many tools to make animations for both UI and objects. Once you get familiar with a tweening library and you understand how it works, it's benefit really starts to shine through
any links to the library? Thanks!
I hate to say it, but I think there is a huge difference in which kind of quality one would typically be aiming for. For example: is it AAA, or is it stylized? Is it indie dev or a huge team? The code is without debate, but this core situation is about everyone doing nothing good for UI. Hell, even I struggle. It is just so difficult to make UI look good when you can definitely make UI functional.
i've been loving these "like a commercial game" tutorials, but i have a question, why would you replace the navigation controls of the default input with your own?
Can we attach this script to our canvas instead of the cards?
awesome tutorial!
Amazing thanks a lot !
This is great video!
This does not appear to work if the element being animated is on any layout group. It will just move to the bottom left corner and then behaves fine after that but in the wrong location. And each UI element will then stack on top of each other. This is fine if the element is not in a layout group.
This is really good, even for a professional mobile game dev :P
I feel like there must be another way than reimplementing navigation "manually" in Update. I'm almost sure there's some callback when unity switches control from the mouse to keyboard/gamepad, and we could somehow intercept the event and set EventSystem.current.SetSelectedGameObject() before that event is handled?
It can be made simpler, if it is okay that the ui-object stays selected. I made myself a "UiKeepControlSelected" script that keeps a ui-object in menu selected when using the mouse on a scrollbar, because mouseover and scrolling deselects the prev. object but does not select a new one.
private void Update() {
if (EventSystem.current.currentSelectedGameObject == null) {
if (this.lastSelected != null) {
EventSystem.current.SetSelectedGameObject(this.lastSelected);
}
}
else {
this.lastSelected = this.eventSystem.currentSelectedGameObject;
}
}
Really awesome content.
Hi. I have an issue where the UI seems to glitch and just continuously repeat the animation when hovering over it
same to me
Fixed it. Use this.
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
public class CardSelectionHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
[SerializeField] private float _verticalMoveAmt = 30f;
[SerializeField] private float _moveTime = 0.1f;
[Range(0f, 3f), SerializeField] private float _scaleAmt = 1.1f;
private Vector3 _positionStart;
private Vector3 _scaleStart;
private Coroutine _currentCoroutine;
void Start()
{
_positionStart = transform.localPosition;
_scaleStart = transform.localScale;
}
private IEnumerator MoveCard(bool startAnim)
{
Vector3 _positionEnd = startAnim ? _positionStart + new Vector3(0f, _verticalMoveAmt, 0f) : _positionStart;
Vector3 _scaleEnd = startAnim ? _scaleStart * _scaleAmt : _scaleStart;
float elapsedTime = 0f;
while (elapsedTime < _moveTime)
{
elapsedTime += Time.deltaTime;
// Calculate interpolated values for position and scale
Vector3 posLerp = Vector3.Lerp(transform.localPosition, _positionEnd, elapsedTime / _moveTime);
Vector3 scaleLerp = Vector3.Lerp(transform.localScale, _scaleEnd, elapsedTime / _moveTime);
// Apply the interpolated values
transform.localPosition = posLerp;
transform.localScale = scaleLerp;
yield return null;
}
// Ensure final values are set exactly
transform.localPosition = _positionEnd;
transform.localScale = _scaleEnd;
}
public void OnPointerEnter(PointerEventData eventData)
{
// Stop any existing animation, then start a new one for scaling up
if (_currentCoroutine != null) StopCoroutine(_currentCoroutine);
_currentCoroutine = StartCoroutine(MoveCard(true));
}
public void OnPointerExit(PointerEventData eventData)
{
// Stop any existing animation, then start a new one for scaling back to original
if (_currentCoroutine != null) StopCoroutine(_currentCoroutine);
_currentCoroutine = StartCoroutine(MoveCard(false));
}
}
you really type that fast? daym!
No. It is sped up and you can hear it by the pitch of the keyboard clicks.
Can you please make a tutorial on “new input system”
And how to use it properly like in commercial game. I tried multiple times to digest it, but with no effect.
These docs are very vage and tutorials are as you said, suitable only for game jam type of games, but in this case easier to stick with the old one
can you do like that all card are overlap each other and when we move pointer on card it will select as you did but will be in front like slay the spire
My VsCode doesnt show the error when the interface methods are not implemented. kinda annoying
Nice video! Is it only me that if your mouse is still hovering over a card that it stays highlighted but the selection of an other card does happen?
3:00 Coroutines are your friend 😂
The waiting for one frame thing could be because of script execution order?
Ok but what is this 'f' unit type and what are these variable types "SerializeField" and "Range" and how can you have 2 variable types for one variable?
I really hope you follow up on this tut. I want to make a card game in unity and really need some more help.
Good vid, but using Update instead of a Coroutine is more performant if you have many btn elements. Something to keep in mind.
how about dynamic scroll items?
Great video!
So, I get the concept of singleton. but what actually makes it that? The code looks the exact same.
Why do we need the empty game object?
can we achieve
same by using unity new UI Toolkit
Good stuff!
Awesome video but if we use class inheritance that will be more appropriate.
My UI element is glitchy. idk what the problem is. Any help is appreciated.
I fixed it with below code.
using System.Collections;
using UnityEngine;
using UnityEngine.EventSystems;
public class CardSelectionHandler : MonoBehaviour, IPointerEnterHandler, IPointerExitHandler
{
[SerializeField] private float _verticalMoveAmt = 30f;
[SerializeField] private float _moveTime = 0.1f;
[Range(0f, 3f), SerializeField] private float _scaleAmt = 1.1f;
private Vector3 _positionStart;
private Vector3 _scaleStart;
private Coroutine _currentCoroutine;
void Start()
{
_positionStart = transform.localPosition;
_scaleStart = transform.localScale;
}
private IEnumerator MoveCard(bool startAnim)
{
Vector3 _positionEnd = startAnim ? _positionStart + new Vector3(0f, _verticalMoveAmt, 0f) : _positionStart;
Vector3 _scaleEnd = startAnim ? _scaleStart * _scaleAmt : _scaleStart;
float elapsedTime = 0f;
while (elapsedTime < _moveTime)
{
elapsedTime += Time.deltaTime;
// Calculate interpolated values for position and scale
Vector3 posLerp = Vector3.Lerp(transform.localPosition, _positionEnd, elapsedTime / _moveTime);
Vector3 scaleLerp = Vector3.Lerp(transform.localScale, _scaleEnd, elapsedTime / _moveTime);
// Apply the interpolated values
transform.localPosition = posLerp;
transform.localScale = scaleLerp;
yield return null;
}
// Ensure final values are set exactly
transform.localPosition = _positionEnd;
transform.localScale = _scaleEnd;
}
public void OnPointerEnter(PointerEventData eventData)
{
// Stop any existing animation, then start a new one for scaling up
if (_currentCoroutine != null) StopCoroutine(_currentCoroutine);
_currentCoroutine = StartCoroutine(MoveCard(true));
}
public void OnPointerExit(PointerEventData eventData)
{
// Stop any existing animation, then start a new one for scaling back to original
if (_currentCoroutine != null) StopCoroutine(_currentCoroutine);
_currentCoroutine = StartCoroutine(MoveCard(false));
}
}
Sweet!
Awesome tutorial, really nice!
Ps: am I the only one that is mildly annoyed that people use startPos, and not position, but don't use startSca instead of startScale? Might be my perfectionism haha
To me it seems like pos is more obviously referring to position but sca isn’t as obvious immediately that it is referring to scale?
Lol! I'm sure you aren't the only one. Doesn't bother me though :D
Why am the only one getting all the ui elements collapsed in one place,
even after 3 times;
edit: after much much much time later
found problem
transform.localPosition = lerpedScale;
fix
transform.localScale = lerpedScale;
😥😥
Hey, thats some high quality tutorial. I have a question though: When I got multiple elements which listen to the same event, how do you manage, which script should handle the event? Example: the three cards get selected with the arrow keys but the game camera moves with the arrow keys too.
Guess that depends on the situation. You could have a gameState manager that will trigger certain events based on what 'state' your game is in for more complex things.
For the simpler example you gave, since I would consider scrolling through cards UI - I would split my controls into 2 action maps, 1 being the game, 2 being the UI. You can disable the game controls and enable the UI controls whenever dealing with UI
One word - Dotween
why not just use dotween for the animations instead of doing lerps etc, much easier lol tf
Often times Unity tutorials don't use plugins to keep things simple. I'm sure Dotween would work great
Hi I am a software engineer in college for IT but I want to also learn game development but I do not not where to start i want to learn python for apps and softwares and C# for games and pc softwares as well I want to start with C# first because i know python is easy and not hard to learn if you know a language already but I want to learn C# for game development and software apps I wanted to know if anyone knew any update courses or tutorials for beginners I do software engineering and also want to do indie game development solo i know that’s hard but I want to try it I really want to be a software engineer and a indie game developer but I don’t know where to start with game design or programming
If you want to use Unity/C# for game development, Check out Codemonkey's channel. He has a 10 hour free course aimed at beginners (it's one video) and I've heard nothing but great things about it
I'd like to send anyone here who wonders why it takes so long to make a video game.
If you are not familiar with code, skip this video
Product level code 😂. Even Junior developer level developer will be fired for this) Main idea of product level code creation of flexible reusable and extendable code for systems. There are a lot of situations when on prod you will have hacks, but not in core systems
"Handle UI Like a Commercial Game " is pretty bald statement coming from "Me and my wife studio".
No offense.
The actual content of the video is good though.
If he's making a commercial game, it's an UI just like in a commercial game.
First
That typing sound is so damn irritating