Slide controls:
Input | Action |
---|---|
Arrow keys | Change slide |
F | Fullscreen (you may first need to click to focus) |
S | Presenter view |
O/Escape | Overview mode |
UUserWidget
in the editor
using C++? For example imagine you want to create a gallery widget and you need
20 buttons with correct names. You could create them by hand, but it's slow and
error-prone.
The example below shows how to create widgets inside a User Widget blueprint, from C++, and correctly update the widget tree so the new widgets can be selected.
Huge thanks to @Sharundaar for sharing how to do this in my Discord, and allowing me to share it here.
Edit: It's worth mentioning that if you're trying to fill out a list, tree or grid in the editor, to give designers an idea of how it will look, you should consider using ListView.
First, we'll need to add "UMGEditor"
and "UnrealEd"
to your dependencies in
your Build.cs
file.
We're doing something a little weird here, we're going to be adding some
editor-specific code to a non-editor class. In order to use the editor
functions, we need to add UnrealEd
and UMGEditor
to our list of modules in
MyProject.Build.cs
, but only when building the editor.
TMap
entries with the key and the value
in the same row. For example TMap
with keys that are FString
, FName
,
int32
, even UTexture
will all be displayed with the key and value together.
However FGameplayTag
and custom structs will be displayed with the key and
value on separate lines. Yuck.
Is there a way we can force them to be shown on the same line? Yes! There are two ways.
The meta UPROPERTY()
tag ForceInlineRow
does exactly what you expect, it forces keys and values to be displayed inline on the same row.
That's all you need to add!
This is a lot more involved, but it will let us show any sort of data structure in a key-value TMap-style way.
Imagine we want to let designers specify the contents of a store. There will be an array of items and how many of them there will be.
USTRUCT()
struct FShopEntry
{
GENERATED_BODY()
UPROPERTY(EditAnywhere)
TSoftObjectPtr<UItemDataAsset> ItemDataAsset;
UPROPERTY(EditAnywhere, meta=(UIMin=1, ClampMin=1, UIMax=20))
int32 Count = 1;
};
We want to show this in tabular form, like ForceInlineRow
, but for whatever
reason, ForceInlineRow
doesn't work for the class we're using as a Key.
Here's how you do that.
StartupModule()
function, register the
customization.Now here's how we register the details customization.
Hopefully between ForceInlineRow
and the example above, you should have an
idea of how to do key-value style display
UEnemyDataAsset
- BP_EnemyBase // Blueprint subclass
- BP_WolfBase // Blueprint subclass
- BP_SpiderBase
You could define the stats for each enemy type with a simple
TMap<FGameplayTag, int32>
and then override the values in child classes.
BP_EnemyBase
TMap<FGameplayTag, int32> Stats
hp = 10
legs = 2
BP_WolfBase:
TMap<FGameplayTag, int32> Stats (Modified)
hp = 8
legs = 4
BP_SpiderBase:
TMap<FGameplayTag, int32> Stats (Modified)
hp = 4
legs = 8
Notice in the example above that the stats
variable has been marked as
modified in BP_WolfBase
and BP_SpiderBase
, because we changed the number of
legs and hp. Once you have changed the TMap in a child class, any changes
made to the parent will no longer be reflected in the child!
Look what happens if we add a new vision
property to the BP_EnemyBase
, the
property does not appear either child Blueprint.
BP_EnemyBase
TMap<FGameplayTag, int32> Stats
hp = 10
legs = 2
vision = 5 // NEW!
BP_WolfBase:
TMap<FGameplayTag, int32> Stats (Modified)
hp = 8
legs = 4
// <= No vision!
BP_SpiderBase:
TMap<FGameplayTag, int32> Stats (Modified)
hp = 4
legs = 8
// <= No vision!
How can we make a data structure that lets us:
Huge thanks to Bohdon Sayre for this one. After
describing my problem he said that FInheritedTagContainer
in the
GameplayAbilities module had a solution for this.
The engine example is a bit more complicated for adding and removing tags, this just allows you to override values and not remove any tags added by the parent. It also works with Data Assets, not just Blueprint subclasses.
tl;dr: I'm kind of stupid, I get stuff wrong a lot.
Verse is an as-yet unreleased language from Epic. It was first announced in December 2020, and not much was known about it until last week one of the authors Simon Peyton-Jones gave a talk at a Haskell convention, so now we have a lot more information!
If you have an advanced degree in programming language design, check out their paper The Verse Calculus: a core calculus for functional logic programming. The slides from the talk are a bit easier to understand, but it was aimed at people with a lot of Haskell experience.
My aim here is to try to translate the slides into something a bit more familiar to C++ programmers.
Hearing about Verse, a lot of people have the same concerns:
The answer to all of these is no.
As far as I can tell, Verse is not intended as a replacement for Blueprints or C++. It's being described as a "programming language for the Metaverse". In more concrete terms it's a new language designed to work at scale and make it easier for players to add user-generated content to games. As we've seen from a December 2020 Tweet, it's already being tested out with Fortnite's user-created game modes.
I've divided this into two parts:
Let's start with the basics of syntax. In Verse, there are two different ways to declare a variable and assign it a value.
Declaring a variable and assigning it a value uses :=
Verse | C++ |
---|---|
Like C++, you can separate declaring a variable, and giving it a value. In this
case you can "bind" x to the value of 5 with just x = 5
.
Verse | C++ |
---|---|
But unlike C++, all variables are effectively const
(once given a value).
This is an important feature of the language both from a philosophical and
practical standpoint.
Edit: The December 2022 slides mention that there might be a way to make some variables mutable, so maybe this isn't a hard-and-fast rule.
Verse | C++ |
---|---|
Verse supports tuples/arrays that look a lot like C++ arrays.
Verse | C++ |
---|---|
A core feature of Verse are "choices".
A variable is only ever bound to a single value. Although that value could be a tuple
Verse | C++ |
---|---|
More complex things are possible by mixing choices and tuples:
Verse | C++ |
---|---|
The slides for the talk show conditionals all on the same line, but from other talks it seems that they are going for a Python-like syntax.
Verse | C++ |
---|---|
Confusingly, or interestingly, depending on your position, x=5
can be used to
say that x is equal to the value "5", and also be used in a conditional:
Verse | C++ |
---|---|
It's also possible to compare against multiple numbers.
Verse | C++ |
---|---|
One core philosophical difference between Verse and C++ is that Verse tries to be way closer to Math.
In C++, when you write x = 5;
you are telling the computer "take the value
5 and store it in the space that we named x".
In Verse, when you write x := 5;
you are telling the computer that for
all uses of x
, it should be treated as equal to 5. Note that this applies
for all uses of x
, not just subsequent values of x
.
Which brings us neatly to the next point.
The following is completely valid Verse:
Verse | C++ |
---|---|
As mentioned previously, it's important to remember that Verse is designed not to be a series of instructions that you give the computer, but more like a series of conditions or relationships that you are telling the computer hold true.
First we tell the computer that "y is equal to the value of x, plus one".
Then we tell it x is equal to 3.
This is possible because once the value of a variable has been defined, it
cannot be changed. We know for the rest of that scope that x = 3
This is more of a clickbait title but it got you here.
In Verse, which branch of a conditional is run depends on whether the expression succeeds or fails.
Failure has a shorthand of false?
, which we use later.
Why does this matter?
Taking the example of using choices and expanding them out, we can see that the example below executes statement e1 because the conditional returns one or more values:
Verse | C++ |
---|---|
Logical OR in verse uses the choice operator |
. Remember that branches are
executed if the if condition succeeds, with success being defined as having one
or more values.
So it would make sense that the choice operator, where every part of it is evaluated, would work as an OR. So long as one of them returns non-null, then the conditional would evaluate to success.
Verse | C++ |
---|---|
Logical AND in Verse uses the tuple comma. This is not quite as clear as with the choice operator being used like OR.
As shown on slide 25, a tuple with any failures is itself evaluated as a failure.
Verse | |
---|---|
This is just kind of a weird feature of the language and feeds in to why you can write some complex conditionals.
Verse | C++ |
---|---|
This was dropped at the end and details were kind of scant but it seemed to imply that it was easy to define new types.
int
is a function that returns the value for values that pass the test of
being an integer, and fail otherwise.
Verse | |
---|---|
So you could define a new type called isPositive
, I have no idea what the
syntax would be to do that, but it would let you set up rules for valid uses of
that type.
Verse | |
---|---|
This might explain why there's a bool
type in the old Fortnite example Verse
we saw in 2020. Or maybe that's just an old feature of the language that was
removed.
It's still way too early to tell much about Verse (but that doesn't stop us wildly speculating and getting ourselves worked up!). So far we have a work-in-progress academic paper that talks about some very cool but unusual language features, and some screenshots of more "normal"-looking code.
I'm wondering if some of the more "odd" features are things that will not get used much in day-to-day programming. For example a language like Perl has some horrendous features that could be described at length, but to write "good Perl" you just avoid those features.
Being able to "use" variables before they are defined, and those definitions being far away in the code could be something that we try to avoid as programmers, just to avoid the cognitive load.
I hope they release a prototype version of the language soon so we can mess around with it.
]]>I think that Mastodon has a lot of potential for building an online Unreal Engine community. So far I've found it a really different vibe to Twitter, a lot more small and cozy. A lot of fellow devs have expressed interest but found Mastodon hard to get into, so hopefully this will help anyone interested in trying it out.
Mastodon is often mis-characterized as "Twitter but there are lots of different servers", and that's not quite accurate:
So an instance is just a copy of Mastodon installed on a server. What's the deal with that?
For me, it was a pretty easy decision to join mastodon.gamedev.place. It has a large number of active users and is moderated by Aras of Unity fame.
At the time of writing this, there are also peoplemaking.games and gamedev.lgbt that are major gamedev-related instances.
One of the kind of weird things about Mastodon is that you are associated with a particular instance, but you can talk to anyone. There are a few factors to consider when choosing an instance:
Mastodon has existed since since 2016 and has built up its own culture. Here are some of the things I've learned that differ from Twitter.
Try to avoid uploading videos as message attachments. Most instances are relatively small and short on funding and videos can take up a big chunk of storage. Upload longer videos to a separate video host and link them if you can.
It seems to be OK to use the Content Warning (CW) preview feature not just for things that might negatively affect people, but for filtering out off-topic discussions. For instance I usually talk about Unreal Engine but I've used the CW header/body formatting to show that a post is about something outside what I usually talk about.
Mastodon has four different privacy settings for posts:
Technically there is the concept of a "Direct Message" but as previously documented server admins can see the message content and if you mention someone in a Direct Message, they can see the message. So I wouldn't use DMs much to be honest.
It is not possible to search for public messages just by using plain-text search. Only hashtags are searchable. So if you want your posts to be discovered, make sure to add a few hashtags to them.
I used this to set up a single column in the Mastodon web client that shows all messages with any of the many Unreal-related hashtags that people use.
Profiles in Mastodon let you show multiple links that you are associated with. There is also the concept of verification where you can prove that you are the owner of the linked website. It doesn't even cost $8!
Just add a link back to your Mastodon page rel="me"
somewhere on your site, and you will get a green check next the link. The snippet is shown on the Profile Settings page.
<a rel="me" href="https://mastodon.gamedev.place/@_benui">Mastodon</a>
I really like the Local Timeline at mastodon.gamedev.place. There's always interesting projects that people are sharing and everyone is super friendly. I can see myself continuing to use Twitter but I'm glad that there is an alternative for if or when it goes down.
Come join and say hi @_benui@mastodon.gamedev.place!
Update: I moved to my own instance because I'm weird like that.
]]>Slide controls:
Input | Action |
---|---|
Arrow keys | Change slide |
F | Fullscreen (you may first need to click to focus) |
S | Presenter view |
O/Escape | Overview mode |
This page has a list of UI elements, sorted by their complexity. The idea is that you try to implement them and gradually learn by doing.
First, download the Unreal Project from GitHub. It contains some code for easily testing out your widgets, and some placeholders to get you started. Look at the Readme file for more details on the Unreal implementation.
Share your solutions on GitHub, and tag them with the keyword
unreal-ui-challenges
That way others can learn from your example!
Difficulty easy
Showing the player score can be as simple as a text box with some numbers in it. It's a great place to start your UI journey!
Difficulty easy
Health bars are a great something
However there are some plugins that make editing Blueprints a lot faster.
If you have to spend more than 5 minutes a day using Blueprints, you have to get Blueprint Assist.
Some of the features include:
It has a huge number of shortcuts but here are some of my favourites.
Shortcut | Effect |
---|---|
Ctrl+G | Go to the symbol in the graph |
Tab | Open "add node" window. If node selected, append to exec |
Shift+F | Formats everything downstream of the selected node |
Ctrl+Shift+A | Quick-add (variable, function) |
Arrow keys | Change selected pin |
Ctrl+Arrow keys | Change selected node |
Shift+Arrow keys | Pan view |
Ctrl+Shift+Arrow | Swap order of selected node |
Ctrl+E | Edit value of selected pin, cycle to next editable value |
D | Delete wire for hovered pin/wire |
Alt+O | Swap between Designer/Graph view when editing User Widget Blueprints |
For the full list of shortcuts and how to customize them, search "Assist" in Editor Preferences > General > Keyboard Shortcuts
Make sure that you share your settings with the team so everyone has the same formatting.
Node Graph Assistant is another must-have plugin. It fixes a bunch of UX nightmares with Blueprints, and works well with Blueprint Assist.
Some of the things it fixes:
My favourite shortcuts:
Shortcut | Effect |
---|---|
Alt+C | Connect pins on selected nodes |
Alt+X | Remove node and re-route pins ahead |
If you have any other suggestions for built-in keyboard shortcuts or other plugins that help, send me a message on Twitter.
]]>