|
|
|
 |
Reply From: |
a0kami |
TL;DR:
- Use a
TextureRect
for crosshair
Range
such as ProgressBar
/TextureProgress
for health bars
RichTextLabel
for digit cooldowns
- (or
TextureProgress
for radial icon progression)
#UI requirements:
You probably are the only one to know which design suits best your project and your workflow.
What I mean by that is UI is not just a generic interface, it’s part of the gameplay and should fit the artistic direction you’re aiming toward.
That said godot built a nice abstraction with convenient classes for UI quick prototyping but also more complex and in-depth interfaces by instancing UI scenes.
Pretty much all UI nodes inherit from Control
which works a lot like Node2D
.
There is no “main” UI node as all nodes share the same capabilities thanks to the inheritance. Rather, your visual UI nodes will be shaped, controlled, contained via parent helper UI nodes.
For example in my projects, to import UI in the main scene, I instantiate a separate specific UI scene which is based on a generic Control
node.
This allow to list all related UI visuals as children and to have a “root-level” script which controls the initialisations and can be used as a proxy in case the different UI parts ever need to interact with each other. But this is not required and could be confusing depending on your workflow/code logic.
An other possibility is having each game element have its own UI elements, for example enemies in a 2D shooter could have their own health bars above their sprites.
Nodes
The main visuals element are summarized here and are basically:
- Text (
Label
, RichTextLabel
, LineEdit
, TextEdit
): different way to display text
Button
s (LinkButton
, ColorPickerButton
, CheckBox
/ButtonGroup
, CheckButton
, OptionButton
, MenuButton
): different ways to handle user input
Tabs
/TabsContainer
- Sliders/Bars (
Range
) : everything related to ranges whether it is to display or set a value/progression
TextureRect
: Probably the most interesting one, a way to display a 2D image along with NineRectPatch
to easily display a scalable image (by tiling the centre but preserving the corners).
For further fine-tuned control such as placement, those can be instantiated as children of a Container
. There are many specific containers but to name a few,
HSplitContainer
/VSplitContainer
will offload the calculation to equally place (or stack) respectively horizontally and vertically your nodes.
ScrollContainer
will offload the scrolling logic for your scrollable elements such as lists.
ViewportContainer
will allow you to display a sub-view, a texture, shader, camera, its own 3D space, you name it.
- And the
MarginContainer
you’re naming is meant to add a margin (spacing toward the exterior of the element) to all children, instead of having to manually add a margin to all your children.
Finally the CanvasLayer
you mentioned is used in case you don’t want to have all the 2D related elements to draw on the same “layer”, given the rendering order, some elements could be overwritten/superimposed. For example It allows you to draw a 2D background on the farthest plane, draw the 2D player over it on another layer above it, then draw the UI on yet another layer above the last, and yet a new layer above it for special effects, and so on…
Crosshair
Where you want to instantiate your crosshair is up to you. If it’s closely linked to other UI then maybe a generic Control
node as a parent which holds the rest of the UI element makes sense. Or maybe it can be part of your player Node if you plan to have the crosshair react to player input or gameplay logic.
But I can only see 2 convenient solutions to draw your crosshair:
TextureRect
: loading a image of a crosshair to which you can scale (make it bigger when player moves and have less accuracy or smaller when the player stops and crouch and have better accuracy), you can also change its tint/color depending on what you’re aiming at (by overriding the Material
of CanvasItem
within the TextureRect
with a custom shader).
There is a crosshair in the godot 3D example demo. Here, it is used to aim where we shoot but also as a 2D origin point from which to shoot a ray projected in 3D space and spawn a projectile (same script, line 140).
When you aim, the visibility is controlled via an Animation. The TextureRect
“visibility” properties are controlled via curves for the given key in the Animation
node when either “far” or “shoot” animation is played .
- Draw it yourself. Whether for
Node2D
or Control
, the Nodes inheriting from CanvasItem
let you use a whole set of 2D drawing primitives:
draw_line()
: draws a line of specified color and width from point A to point B
draw_rect()
: draws a rectangle at point A of size (x,y) with specified color, filled or not, etc…
draw_circle()
: draws a circle of origin point C and radius R with specified color, filled or not, etc…
draw_
etc…
You could then manually draw the 4 characteristic rectangles that compose a regular popular crosshair of any size/color you want, solid color or fill color different from border color…
It depends how you want those to look like. Is there text next to a bar ? Is there a numerical value ? Is only filled/empty icons ? Is it a regular colored bar or should it be a texture ?
In your first version you could probably have a ProgressBar
, a gauge filled based on a value. You need to somehow connect the health value change in the gameplay to this UI element.
But you can make more detailed version with an image using a TextureProgress
.
But basically you can do pretty much any crazy look combining textures and shaders, for example, you could make a spiral or round texture with decreasing alpha along the spiral, and add an alpha cut-off in the shader based on a uniform which represent the health value. (Think Kingdom Hearts style rounded health bar.)
Cooldown
Again, how does the cool down look like ?
-
Is it a simply a filling bar ?
-
ProgressBar
/TextureProgress
-
Is it a digit countdown ?
-
Label
/RichTextLabel
which text value is constantly updated
-
Is it a skill icon ?
-
TextureRect
as a background “disabled” icon and either another TextureRect
or a TextureProgress
with the FILL_CLOCKWISE
flag set, on top for a “enabled” icon.
Nice answer!
Yuminous | 2021-08-13 02:54