>>Sjoerd De Jong: Welcome to
my Blueprint marathon. It is only two hours long.
It will be fine. Two hours of hardcore
Blueprints. My name is still the same.
I am still Sjoerd. I am the evangelist for Europe, been doing this now
for I think four or five years. I have been using
Unreal Engine for 20 years, started with Blueprint
in particular in 2013 I think before
Unreal Engine 4 went public. I know that what I started with
was we had one single page of documentation on Blueprint
when I started. That was, how do I make a door?
I started with a tutorial, how do I make a door,
and that is it. Then I just started
clicking around and experimenting with it
and seeing where it takes me. That is usually
how I learn things. I just click around,
see what happens. It takes a much longer time
than if I just read something. But on the other hand,
by doing that, I also learn
what not to do. I learn to fail.
I learn all the things that a tutorial would not
tell you necessarily. What we are going to do is we are going to talk
about Blueprint in depth. I have made a beautiful
little graph here where it says dive
into Blueprint and learn stuff and then print string, hooray.
That is kind of the conclusion. The idea is to give you an
in-depth insight and knowledge of Blueprint
beyond the usual topics. This is not about you click here
and this is how you script it. It is a little bit about
the bigger problems that you can fix in Blueprint. It goes in terms
of collaboration, how does that balance with C++, things like performance,
what is cost in performance, how do you then counter that?
Those kinds of things. That is really
the focus of this talk. I am not a programmer.
I am an artist designer. I am going to get back
to that a few times as well. You need to look at this talk
in that perspective. This is not me
as a programmer saying, you should do this,
this and this. This is me as a designer saying,
I went terribly wrong here, here, and here and here,
and then a lot of programs got pissed at me here
and here and here. Probably do not do that.
That is how I am going to speak. What we really want to do
is we want to use Blueprint in an advised, scalable, performant,
and future proof way. It is not just about
making it work. It is about doing as well. Before I start, just for myself
to have a little bit of an idea
of who is in the audience, who of you uses Blueprint daily
or weekly, often? What is the average degree
of experience? Who has been using Blueprint
for more than three years? How many of you are programmers?
That is scary. How many of you are artists? Designers, or similar?
We will see how this goes. It is always scary
when you do one of these talks. What does the audience
already know? Maybe everything
is totally obvious. I do not know.
It probably is not, I hope. I did this one at Unreal Academy
in December for the first time. Halfway in, there is a break. There are a couple of slides
halfway in. That is the break point. I might not make it
to that break point in time, so it might happen that I will
just stop at a certain point, we take the break,
and we come back with the rest. Because I just guessed
where the break would be. I might have completely
guessed it wrong. Let us get started. Before we start for real, there
are two introductory chapters. In fact, I had an overview slide
somewhere that is going to come
in a second that shows
you the general layout. But we have an introduction,
just refreshing your mind what kinds of systems
and features we have in Blueprint.
Just so everyone is aware, these are our building blocks
we are working with. Then I also want to formalize
a little bit of the problem that we have that you might face
with Blueprint. We have those two
out of the way. We are going to go in depth
technical and performance, compiling, etc. I think getting started
with Blueprint is easy. For me as well,
I just clicked around as I explained in the beginning. It is not that difficult
to figure out. It is kind of like a flowchart
and it kind of just works. Obviously,
you have got to learn this. It took me a few months as well, but it is relatively
straightforward. You can learn that. The real difficulty
comes in doing this correctly. Even the way
we design Blueprint, it is kind of similar to - it makes programming concepts
easier to understand as well. All of this is visual scripting. It is designed to make
ii accessible. It is really about
how to use it correctly. We want to do this
for three reasons. We want to have it future proof
so you can extend it. Again, you will see some of
the mistakes I make with that. I am sure you have all done
the same stuff. Collaboration is a topic
that comes back often. How do we work in Blueprint,
the binary Assets, how do we merge stuff together,
what is the advice way forward? Performance is a typical
one as well. But because that is
maybe not ideal. There is actually a website -- I now forgot the name,
but you can Google it. There is a website
someone set up in a community where you can post
Blueprint spaghetti pictures. It is a website
that is dedicated to just that. I took these pictures
from there. Credit goes to whoever
posted it on there. For example, you could do that. I really like this long,
long blue line. That line here, it goes up.
You have no idea what is there. But it might be a lot worse. It is kind of
like these paintings where you see something
on the edge of the screen and your imagination
takes over with the rest. It is really well done.
That is not that bad. It is just a lot
of copy pasting. At least it is clean. I like that every
single part of it is commented. That is not that bad.
It is just very compressed. It could be worse.
You can actually frame it. [Laughter] I really like this one
as well. This curl here
I really nicely artistic. Google that website
and have some fun. Just before we start,
just to make it clear, BP means Blueprint. Obviously, Classes means either
Blueprint or C++ entities. Native is equal to C++. We are going to switch
those terms around, so everyone is aware. Lines mean break of subject.
This is what we have got. I hope to get here by the break,
have performance covered. But again, the break
might be somewhere halfway into performance.
We will see how that goes. We start off with these
two introduction parts. Performance is a big one.
This is technical. Compilation is technical. Runtime cost, ticking,
profiling, memory loading, garbage collection
with compilation overview and the impact of it,
compiled times, casting, recommended workflow,
race conditions -- although I only have
a little bit on that. Some on C++.
It could be longer there, but we are definitely
going to cover that. Again, I am not a programmer,
so I am going to cover C++ from a designer’s perspective. Then we have
some miscellaneous tips. This is mostly here as backup
in case I am done early. I need to manage my time,
so it is just some random tips. Let us start with just
refreshing everyone’s mind. A lot of this is discussable. There are a lot
of different ways you can often approach
the same problem. You could say C++
is not a feature. You could reasonably say so. But for the sake of trying
to give a schematic overview of what we are dealing with
from a Blueprint perspective, in a way C++ is a feature that helps
the Blueprint workflow. Let us just take that mindset
for a second. You can discuss this
for a few years if you want to, but bear with me.
You have C++. All of this feeds into
the system that is Blueprint. You have got Data Tables
and Curves. You have got Data Assets. You have got Child Actors,
Interfaces, Libraries, Framework,
Components, Inheritance. Those are kind of the things
you are working with, the building blocks. I am just going to step
through those to quickly again refresh your mind. C++ could be smoothly
combined with Blueprint. We can smoothly
balance functionality back and forth between the two. It is obviously
a faster performance which we will get back
to later on. In larger projects, obviously
better for collaboration. I think most of this
is obvious for everyone. Inheritance meaning it inherits
from a parent Class. You can do this
within Blueprint as well. Again, this is so fundamental
to the Engine. Everyone who has been using
the Engine for a while
will understand this. You have got
the framework Classes which means the standard Classes
such as GameMode, PlayerController,
those kinds of Classes. Those are present
within the Unreal Engine. It is a tool in your toolkit
as well to work with. We have got Components,
and when I say Components, I specifically mean
a Blueprint Component. I do not mean a light
or anything else. Let us just focus purely
on Blueprint right now. You could have a Component that holds some
Blueprint functionality or C++ functionality that is added to the Object
and to the Actor and it gives
some specific results. For example,
this is from my own game that I did a few years ago.
We had a temperature system, so some items and some Meshes
had to offset the temperature. For example,
the crystals were cold, so we made a Component
called TemperatureComponent which added essentially
an offset to the temperature that you can set to a range,
and we did that. That is kind of what we use
Components for. Again, a lot of this
is discussable. You could argue, yes,
but we use it a lot more, or you can have this
kind of workflow, etc. But ideally,
Components in Unreal Engine tend to be used
for specific solutions. They do not tend to be used
I am going to have 50 different Components where the Unity approach, that
would be more their workflow. It is not typically what we do.
You have got Child Actors. It is literally
another Actor Class that has been added as a child
Actor in another one. For example, this flashlight, the volumetric light
beam thing itself and the Light Actors,
that is a Child Actor that got added
to the flashlight. We will get back to this later
on as well with a few examples. It is not that commonly used,
I think. Typically again,
specific purpose only. Libraries meaning
like a Blueprint library or it could be done
in C++ as well. That is another one you can use. You have got interfaces,
of course, within Blueprint. You have got data tables
and curves so you can specify a curve and then read
from that Blueprint. You can make a data table read
from that Blueprint. I think most of you I hope have
done this before, all of this. Otherwise, the rest is probably
going to get a little bit hard. Data Assets exist as well. To make a Data Asset
is basically just holding a couple of properties
and read from that. The tire system
uses this by default. Interface I am missing here,
which is intentional. Again, you can argue this
for the remainder of Unreal Fest if this is correct or not, but it is one way
of looking at it. I am trying to just structure it
a little bit just to give you a little bit of a feeling
what you are dealing with, and you could therefore
argue obviously C++ and Inheritance
is the absolute foundation. Framework would have
a supporting role, Libraries as well.
Components, Child Actors tend to be
more optional in light of what we just saw, etc. Just trying to structure it
a little bit. Let us talk a little bit
about the main issue. Once you are past
the initial hurdle of learning how to work with Blueprint, you are going to hit
very specific problems, especially if you
are not a programmer. Because you have never had
to do that before. I hit those issues too.
If you are a programmer, you are probably more likely
to think of the bigger picture and what is my architecture
going to be like, where does
my certain functionality live? How would that scale
in the future? How do I make sure
I can keep that as buck-free as possible
and how can I maintain it? You are going to start
thinking of that. But if you are an artist so you
have never done this before, you will not
think that probably. You will only start thinking
that after you have failed
a couple of times or someone screamed at you
in the office. That is where.
I have this example of a door. At some point,
I got this sent to me. They built all of that.
I did this. It is a super simple example, but you have been
in these situations before. How do you make it easy
to understand? How do you make it clean
but still powerful? How do you get
that balance right? I had a number of steps here. Did I do everything as clean
and as few steps as possible? Those are kind of the questions you should ask yourself
if you look at this. If someone else
would take over your work, would they understand
it reasonably fast? Do I have
a logical distribution? Does it simply make sense,
what you have done, or is it just bizarre? Did it take casting and memory
and performance consideration into account that we are
going to discuss later? If ever you want to grow this, is that doable
in a reasonable way? Those kinds of questions
you should ask when you build a system. Again, especially I know
from a designer’s background, I never asked those questions
until it went wrong. I had this Swedish door.
I live in Sweden. Classical Swedish yellow door. This is a very
theoretical example. Just bear with me,
but it illustrates the point. You are going to say,
I want to make a door. Make a Blueprint_
RegularDoor. You have a door. Easy, right?
There is a trigger, you walk into the trigger,
the door opens. We made a door. We start
placing it in the Level. Then someone comes to
the conclusion, actually, there should be
a double door too. We duplicate
the first Blueprint. Now we have two Blueprints.
They are exactly the same. They are duplicate,
but in the second one, we make two door halves,
but it is still the same figure. It is only two doors, right? What could possible go wrong?
It starts fine. Then the problem is,
someone wants revolving door and a garage door
and an elevator door. We start duplicating it again. Now we have five duplicate
Blueprints with some changes to it.
It is maybe not ideal. Someone comes to the conclusion,
let us make a parent Class in Blueprint
called EnvironmentObject or whatever we are going
to call it, Doors, anything you want, which has
the main trigger functionality. Then there are child Classes
under it which would be the actual doors,
the variations on that. Maybe the door
has to be destructible, so we have a Component in there
just to handle that, perhaps. The problem is,
as the game goes along -- because this is what you do
in your first prototype. This is a few months in,
and it gets worse. Then someone, for reasons
we will get back to later on, there probably should
be some C++ Classes above it. Now we have more locations
where functionality could reside that has to do
with opening the door. Then perhaps you do not just
want to walk into the trigger. Perhaps you want to get close and then play an animation
or press a button or something more than
just walking the trigger, right? You have got the whole player
and player control of things comes in and has functionality
for the door too. You want to have an Animation
Blueprint that is related to it because you need to play
some animation for opening the door
or whatever, right? There is more stuff.
You need a HUD Because you need to display
something about yes, you can open this door or not.
We have that coming in. It gets worse, because
someone wants to have achievements, how many doors
you want to open and stuff, so that has to keep
track of it too. Then there are a lot
of different Levels with a lot of different doors. All the Level Blueprints
might have references or some functionality related
to opening doors. For example,
if you open this door, a monster should spawn there
or something. Somehow, you need to link
that together. Then there is AI. Then you need
all of those Classes, and then there is probably
NPC, humanoid, enemy, and then there is a solider
or something, etc. Again, it is
a very theoretical example, but it kind of paints
the picture of what happens over the course
of game development. It gets worse because
someone has weapons, you need to be able
to shoot the door as well. Eventually,
you have got all of this that could potentially
hold functionality relating to you opening a door. If you started this idea with,
I am going to do this, probably you had an issue.
That is exactly what an artist and a designer
is going to do, typically. I would have done that too.
I would have done that. That is the goal of this talk. You want to keep things
as simple as possible by having enough complexity. If you can manage that,
you are good. There is a very
golden line somewhere between keep everything
as simple as possible. Otherwise, it is too difficult
to maintain and understand. But do not skip out
on using advanced features. But do not use advanced features
for the sake of using them. There is this very fine line
between them. Do not over-complicate
when you do not have to, but do use advanced features
when it simplifies things. The functionality
has to be scalable. Try to be as agnostic
and as justifiable. Of course, sometimes
it does not make sense. You just do it.
But it depends case to case. Performance and stability should be taken into account
from day one. You have got collaboration
on Blueprints is also a challenge
sometimes, and that is helped tremendously
by designing it with the right architecture
from day one. We have got a merge tool, but it is not meant
for day to day usage. Having the right hierarchy and
distribution of functionality is going to help
you there too. This would be a theoretical
example of what a car
could be like and what the distribution
of functionality could be like. Obviously, we have got
an Actor at the top. You have got a Pawn. There is a Wheeled Vehicle,
standard Class, but then you would have
maybe your vehicle Class, your particular car Class. There is a Blueprint Class
that comes directly from that. We are going to get back to why
specifically I am advising that, and then a Blueprint Sedan. The headlights should probably
be a Child Actor perhaps, because it is a set
of different components together that are going to be
used across different vehicles. CarEngineValues
might be a data table, so you can easily
tweak that stuff. There are probably
some general libraries in use
somewhere in there. The VehicleMovementComponent
is a standard Component, but that would be
a Component. There is a Data Asset
for the tires. That is also a standard
part of the Engine. But this kind of
gives you the idea. Build up that architecture. Let us start doing
Editor things. I will switch to the Editor
back and forth as I am doing this
to demonstrate some of it. Again, a lot of the examples I built in the Editor
are very strange by themselves. They are kind of just there
to illustrate what I am saying. Obviously, the best case
scenario would be if I have a full game that we worked on
for two or three years. In a realistic scenario, that is
kind of difficult to simulate. We will have some
theoretical ones in Editor. In general, I think performance
is really important even if for whatever reason
you do not feel it is going to be an issue.
Working cleanly is good anyway. It is going to help
the performance. It is going to help
with other things too. Blueprint is slower than C++.
It is not slow at all. The most common reason
that we see that people move from Blueprint
to C++ is not speed. It is typically workflow
and collaboration much more so than performance itself. There are of course exceptions
to everything I am saying, but in general. Nonetheless, there is a bit
of an impact of Blueprints. Kind of they are
10 times slower-ish, but it really depends a lot
on what you are doing. It is difficult
to put a number on it. It depends on the project,
it depends the hardware. As Nick mentioned
in a keynote yesterday, we are looking
into experimenting with different virtual machines
for Blueprint. We are expecting
a further speedup of Blueprint performance
in the future. I have got a graph that compares
the different performances of Blueprint,
a couple of different states I am going to get to
in a second. But before we go there,
a couple of reasons. The first reason -- not necessarily
in the right order -- but the first reason you could
say why Blueprint could be slow is simply executing
large networks of nodes. Because performance cost comes
from the connection between nodes,
not what the nodes actually do. There is a cost to them, but it is not necessarily
Blueprint-related. Anything that is node heavy
or logic heavy is for that reason expensive because it is
a lot of connections. If you have got this example
over here, it is very simple. Print String,
all this does the line trace. This is 100 percent
equal in performance in terms of Blueprint. It is not 100 percent equal
in performance across the board, because this essentially
triggers functionality in C++. But the act of triggering
that via Blueprint is a line. It is equal, and that
is really important to note. Related to that, anything
that is related to quick loops tends to be
relatively expensive. With quick loops, you have a lot
of connections looping, simply. Anything related to quick loops
is on the expensive side. Anything that requires iteration
of large numbers of Actors is on the expensive side. I have seen many examples
of where someone does, on every time
they press a button, they do Get all Actors of Class
or something. Please do not do that. Please cache the result
or something. That is expensive too.
Then of course, ticking. We are going to look into
ticking extensively. That is typically the most
common cause of performance loss, extensive use of ticking.
For everyday usage, you are not likely
to experience any slowdowns. I am not telling you,
please never do a wire loop. You have to judge
this case by case. But eventually,
if it is a long project, large team, etc.,
over time, it might add up. Blueprint is always executed
single threaded. It has a default of a million, which translate to 250,000
in reality, instruction execution
limit per tick and for all Blueprints combined. You can set this
in the project setting. You can actually set it
to maximum loop iteration count. I do not think
you should change it. I am just saying it is there. You cannot hit that limit unless
you are really doing stuff in very sub-optimal ways. For that reason, you probably
really should not change it. You probably really should
not hit the limit either. If you hit the limit,
you will just get an error that says infinite
loop detected or similar. A Blueprint in itself does not
give any significant overhead. Just making a prefab essentially with Static Mesh Components
in there, it does not give a measurable
impact on performance. You would have to go very far for that to eventually
start impacting you. Generally, that is okay. Also, we are going to look
at the comparison now. Before we look
at the comparison, note that there are three
different ways of doing this. You have got Play in Editor,
you have Dev Play. Dev Play is my improvised name
for meaning you start the game but without packaging it. Shipping Play is you package it
and you play it. Let us take those
three different States. We have got a very simple test
Blueprint which again is theoretical. It is not necessarily always
representative of real life, but it does a random calculation and loops
that around very quickly. On a timer,
every one second or whatever, it does a lot
of calculations looped. Trying to string the Blueprint. That is what we had
in this particular test. It is a slight difference
between red and blue. In C++ to Blueprint, you can see Blueprint
gets a little bit expensive. Blueprint is the red line,
confusingly enough. I am sorry. It gets a little bit
more expensive than the blue line
here at the bottom. But this is both in Play
in Editor. Because the next one
gets more interesting. This is without C++,
pure Blueprint, shipping compared
to Play in Editor, compared to
just running the game. You can see Play in Editor
is way more expensive. When you ship the project,
when you package it, it is half the cost of that one
in the worst case scenario. Again, this is
a theoretical test. It does not necessarily
reflect on reality. But it gives an idea
of what you are looking at. If you were to then
compare this to C++ here, you can see this would have been
Blueprint, the blue line here. C++ would have been here
at the bottom, not suitable for this scale.
There is a difference. It is slower,
but as mentioned before, it is not necessarily slow,
just slower. Again, when you profile this,
really pay attention to just how slow Play in Editor
really is performance-wise. Let us really look at ticking, before there is a lot to say
about ticking. It is typically the number
one reason for performance loss. Tick itself is not
the only thing ticking. A timeline would be ticking
while it runs. Stuff like Mouse X
or one of those kinds of things, those kinds of inputs
that are ticking. In Animation Blueprints, the update animation
is essentially ticking as long as that thing is active.
In UMG, if you bind something, it is ticking
with a couple more of them. Now the obvious advice first,
please do not do it much. That is the simplest advice,
but it is true. If you are going to use ticking,
make it a deliberate decision. Do not just do it
because it happened. You have to think this through.
In 80 to 90 percent of the cases,
you do not need to use ticking. You can also disable ticking
on a Blueprint by default, by the way.
In the Project Settings -- I forgot now what to type here.
I think you can do, Can Blueprints Tick
by Default -- you might want to disable that
just to make it even more deliberate.
If you have people in your team and they actually have to enable
ticking for that Blueprint, so it is a conscious decision,
do I really need it? Yes, I am going to say yes. Now, timers and events can
take care of almost everything. Simple example, we have a timer,
it loops this print string. You can do a lot with that. You can offset the time
with a random float in range if you have a lot of instances
of this Blueprint to distribute the cost. Instead of having,
for example, in my game, I had 100 different items
or so per Level. All of those 100 items
are on a timer, a couple of different times. I do not want all those
100 items to loop at the same time, because you have got a spike
at the same time. Random float in range
could help distribute the load a little bit. If you do it Event
based as much as possible -- here is a simple UMG example. Instead of doing bind,
we did a bind on a text field. This is essentially ticking. Make sure the text in UMG
only updates on an Event. You can do this
across the Blueprints. Event based is always the best. You can turn off ticking
in a Blueprint itself as well, or you can change the tick
frequency, the interval. If a Blueprint does not actually
use ticking in its graph, having this enabled or disabled
does not make a difference, is what I have been told. But some other people
would contend that. If you leave it enabled, it does
show up in the ticking list, but it does not seem
to bear a performance cost. I will show you later
on how to display all the Actors in the Level that are ticking. This would pollute
that list a little bit, because it would just crowd
the list with random stuff. To be good,
you might turn it off. You can have building conditions
that limit how often when ticking
is active. For example, you could do One
Player Pawn, Get Distance To, so you only do ticking
if the player is closer than X number of units
to the Actor. You can simply do that
and it might be a benefit. Similarly so in the next one, you can reduce the tick
frequency on distance as well. Go to Distance To and gradually reduce
the update rate of that Actor, of that Blueprint
the further away you get. It is just those
couple of nodes. You could obviously automate
some of this in C++ as well via function in there. When you face away, you have
this thing called in Blueprint, Was Recently Rendered,
that you claim number figure out if you are seeing
an Actor or not. If you know you can see it
or not with that thing, if false,
then turn off the ticking or slow it down
or whatever you want. That is another simple one. Again, it is really just
a few nodes every single time. Often, you can split the logic
from the visual effects. This was my game
from a few years ago that some of you
might remember, Solace. We had an ocean in there
with a bunch of islands, so every island is obviously
surrounded by an ocean. The ocean had rising tides. The ocean was made
by essentially a Blueprint, and the Blueprint
was a giant Mesh plane, which is the water surface
and a couple of particles and other random things
that touched. Then there was a box underneath, a collision box
which acts like a Water Volume and a Post Process Volume
and such. The surface, the Mesh itself continuously
looked at a float value for the time or the tide. It read a value,
and based on the value, it would change its position. You looped between A and B,
and you would set that. That was really, really,
really, really slow, because it turned out that
moving a gigantic trigger box across the entire Level and doing an overlap check
on everything in the Level is not super fast.
My solution was, often there is a very
particular thing that is heavy. Ticking itself
is not necessarily bad. My point is, sometimes it is
just one particular part of it, so take that one
particular part out of it. I did the updating Volumes,
I put that on a timer. That is the logic
from the Volumes, so I just set Actor location.
That is the timer now, but the visual functionality
remained unticked because there was barely
any cost to that. Again, judge it case to case and
try to split it where possible. The same goes for anything
that is animated in general. It is a bit of a simple example, but I have got
this rotating Mesh. There was a code on here, 06.
It rotates. It is a simple one. You would not probably have
done this in Blueprint anyway. But the point is, if you want
to animate a basic animation, if you can do this
in the Material, then it is done on the GPU,
not on the CPU. It is not done in Blueprint, and it almost always
executes faster. This is faster
than the equivalent of doing that in Blueprint,
almost always. Whatever you can pull off doing via
World Position Offset in the Material, do that.
Obviously, it is not going to help
with collision or other things, so there are limitations
to this. But what you can,
please do that. In fact, the next step is 07,
which is what we have over here. In fact, I can just
show you in the Editor. I have got this little
Blueprint here with a cube. If we play this,
the cube goes from red to green. But if I change the option here,
Use Parameter -- I will show you in a second
what I actually did - and I play this again,
it also goes from red to green. It is the exact same thing. One of them is driven
by Blueprint. The other one is not. Here is the Blueprint.
This is your parameter switch. If it is true, it makes
the Dynamic Material Instance, and it has a timeline. This is ticking, and it changes
this with the timeline. Instead of doing that,
you could have done that. It does not do this at all. It just makes the Dynamic
Material Instance and then the Material
takes care of the rest without even being triggered
by Blueprint. It simplifies
your Blueprint too. In the Material
that we have over here, if parameter this,
it simply does that. There is a time,
I divide the time, and it just runs. It handles it.
The moment it enters the world, the time starts being taken
into account and it automatically fades
from that to that. That is it. You can use this
for footsteps or something. For anything
that has a set length of time, that simply will play
its animation, its fate,
or whatever it is meant to do without you having to do this
for your Blueprint. Again, that is almost always
faster than stripping that. Or again, very simple advice,
just do it in C++, which is true. But before you do that,
please profile it first and really justify it.
Why are you really doing it? Because often again, it is not
necessary to move it in C++. Now we have got a couple
of different ways for profiling and debugging. There is actually a lot
to say about this. This is a relatively
short chapter, so I will just skip through
a couple of these. I will start
with the obvious one. I think the Visual Logger
and those kinds of features, which I will get back to
in a second, I do not think they are maybe that well-known
or that much used. I never used them
in production either. I knew it was there, but I did
not see the use for it. But I think it is really cool.
I want to just highlight that. First of all, as you have
probably all figured out, you can visualize Blueprint
as it runs. If you are playing in a game,
you can see that happen. I am sure you have
done this before. As you are playing, you could
do, no debug object selected, third-person Character,
and I can see this happen. I can watch values as well,
which is the next slide. If I right-click something,
on this one, watch this value. It will print it above it,
and I can see it as it happens. This is really nice
to debug your logic and have an idea
of where the flow goes to. When you watch the values, in the Blueprint
debugger window, you can watch all of them at the
same time, which is quite nice. You can have a general output of
everything you are doing there. You have a Window,
Developer Tools, Blueprint Debugger. In the Watches, you would see
all of the watches combined. You have a general view
of the whole thing. That is quite nice.
Again, I knew it was there, but I never think of it
while working. It was actually
a very useful tool. You have got a Visual Logger. How many of you are using
the Visual Logger at least once a year? That is about 8 percent
or so of the audience. That is what I mean.
This is a nice tool. I like this one. I always forget about it
when I am working. It is a nice tool nonetheless.
This is in performance 8. The way it works is that
you have to make a Blueprint or within an existing Blueprint. You have to enable
Visual Logging. On begin play,
Enable VisLog Recording, yes. Then on tick, you would have
this set that records it. There are a couple
of random tests. But I take a Health variable. It is just a variable,
and I append it with text so I can understand
in the Visual Logger what it is. Health is X.
I do a VisLog Text action. There is a VisLog Box Shape, VisLog Location,
and a VisLog Segment. Those are the different
ones you have got, so you add those to it and essentially
populate the properties. That is the text
it is going to be logging. You can log a shape. This is a box shape based on
that location with this shape. This is the VisLog Location. It simply stores
the location itself directly and will automatically
give that a marker. We have got a couple
of other things here. That is it. You can add this
in any Blueprint you want, and then when you run the game,
you can go to Visual Logger. Again, Developer Tools,
Visual Logger, that window there, play. As you can see,
it is recording that. Let me just jump a few times. Let me stop that and stop that.
What happened now is you have the Actor
you were recording in here. This might be hard
for you to read, but there is says health is 998, so you can see over time
the health is now 587. It made the health tick
gradually goes to 0. You can store the variables
and see them over time, and you can see where the
position was as this happened. That is debug.
That is my simple little test, but that was my player
running through the world. For example, you can enable this
on all of your AI and see how your AI
was navigating the world as they were trying
to locate the player or whatever they are
trying to do. You can have
a visual representation of all the variables you marked
and the positions of things, which is quite nice to get
an idea for what is happening. You have got the Stat window. Obviously you just type
"Stat Game." This also tells you
how many things are ticking. You have got
a few things in there. Blueprint time is interesting.
The tick time also shows you there are
19 things here ticking, and the ticking cost
of a lot of things. In fact, with the ticking, what you can do is you have
a command, dumpticks, and that will give you an output
of everything in the World that is ticking.
That is very good to do. If you type that every now
and then, you keep track of what in
the world is actually ticking. You can then go look into that
and see, okay, is that justified or not? Literally, just type in here
“dumpticks." In this very simple Level,
it is not going to do much. But it just outputs you.
It is this one here. This is the ticking group
it uses, etc. You have that idea.
Then you can go look them up. You have the regular profiler,
of course, which is quite precise
in the sense that it can really show you, look,
it is this particular Blueprint, and we have got these Blueprint
functions or things in there, and they take this much
performance per. I use this one a lot
in development. You can actually
run automated tests, which again is a thing that
is not necessarily well-known. It is also rather
strangely implemented, requiring a very specific
naming convention. But if you do everything right,
it will automatically appear. You can do a functional test
in code, of course. But you can actually have
a Blueprint functional test and have that be
automatically recognized by the automated test window if you name it
in a particular way. I have done that. It was 09.
I have made this thing here. I made first of all
just a test Object. Here is the test Blueprint.
It does not do anything. It is meant to be a door.
There is a trigger box. There is a door.
It is for a test. There is nothing in here. It just says, if the trigger box
is overlapped, it says bool is through.
It is just for a test. What we are trying
to do an automated test on are my triggers of my doors, can they be activated
by the player? It is a very basic test,
but it illustrates it. Then you have
a second Blueprint, which is the functional
test example. That is Parent Class
Functional Test. By having it as functional test,
you get two unique events. One is called
Event Prepare Test, and the other one is called
Event Start Test. Event Prepare Test
is whatever is has to do before it does a test,
obviously. I am spawning the door
Blueprint at this location. I remember which one it is.
Then I spawn a Character, just a regular Character,
at this location, which happens to be inside
the trigger box of that one. Then I run the test,
Event Start Test, and it is going to check,
does the door, the bool of that door,
is that true? If yes, then the door is being
triggered, the trigger works, and we finish the test. I can output a string here
that says, Test successful - Door activation status is true. Otherwise, it will fail,
Test Result failed. Doing it like that,
then very strangely, you have to make a Level called
FTEST_ or it does not work. You put the Blueprint
in that Level and you save that. If you then go to
Developer Tools, Session Frontend -- in automation,
we would then have projects, and we see our functional test
that we made. That is all Blueprint.
We can then enable that and we can say,
please start a test. That automatically
runs to that Level, and it says the test
was successful. You can see here too the test
is successful. You can have a series of these
Blueprints or one Blueprint that does a lot of different
things in the same step. A little bit of a weird setup,
but again, I just wanted to highlight that, because I have not seen
anyone do this. Let us go back to the Level
we had. One second. Then we have got memory
and loading. This is a really,
really big one. There is a really
fundamental thing in there that I realized way too late. I really wish someone told me
this the day I started, and I took years. Blueprint is fundamentally
different than C++ when it comes
to loading and memory. Blueprint is content.
C++ is C++. It is completely different, and you really have
to understand that
or things are going to go wrong. When you have C++, all the C++ code
will be loaded on boot. You start the project,
it loads all the Classes in C++. Blueprint is only loaded
when it is used. I have a slide here.
It is crucial to understand. C++ loaded on project boot,
but content, which includes all the Assets
including Blueprints is only loaded
on an as-needed basis. If C++ references content, that content is loaded
on boot as well. Here is an example. There are
two different Levels here. Both of those Levels reference
Blueprints. We are running the reference
check on the Blueprint. There are two Levels
referencing the Blueprint. That means this Blueprint
will only be loaded if the Level is loaded. That Blueprint, in turn,
references a Mesh, which references
a physical Material, a Material, and a bunch of Textures. If this one is loaded,
that one is loaded, that one is loaded,
that one is loaded. That is content.
It loads it as it needs it. I did not know that,
so I did that. This the reference view. Just to make sure everyone
is on the same page here. If you have anything, you can
right-click Reference Viewer, and then you see
what reference it is. This was a kind of bad example because it is not showing
a reference. It is my basic Blueprint.
Let us find something else. Let us take
the performance test one, because it is going to say it is going
to be referenced by the Level. You can see that references
the door on that side, but on that side,
it is referenced by the Level. You can change the search depth, which is not going
to do anything here, because nothing else uses it. But you can bump up
the search depth and see the whole network
of what is -- that one uses also a cube. That will probably use
a Material. That uses a Material. That uses a Texture, then,
I assume. Yeah. You can kind of see how the path
is going to flow on. Now, this one is not even
the full view. I had to span it over
my two monitors. One is above the other one.
I had a giant resolution, I zoomed out
as much as possible, and I think I Photoshopped, because I think
somewhere in here, if you see here, the grid point here
is messed up. That is the Photoshop copy paste
of two pieces together. You can see this
is the center point. That is the center Asset. You can imagine
what is above it, and you can also see how
the line continues at the bottom.
It is terrible. Do not do this. I figured I can just reference
everything, right? So I did that. Any form of referencing between
Blueprint and another Blueprint will also load
all the content with it and will also load
the other Blueprint. Super, super important. If you do not control this,
it is going to get out of hand, especially towards the end
of the project. If you cast,
it is going to get out of hand, because the casts
are also references. We are going to get back
extensively to casting in a bit. It ends up like that. This is site map,
just to make sure again everyone is aware
of what we are doing here. Right-click not reference
viewer, but Site Map. Site Map shows you
what is loaded. You see all the things
that are referenced and loaded for that Asset.
The functional door test example takes 660 kilobytes total
information including the Mesh - oh, that is the Blueprint,
sorry. The Mesh is somewhere. The Static Mesh
took 487 kilobytes, etc., for the total sum of it. I did that on that above
giant Blueprint, and it kind of looked like
that I love how optimistic it is or it tries to manage
your feelings, because here in the top, it says Item Standard,
which is my Blueprint, at least 1.1 gigabytes.
I like that it says at least. It just gave up. Again, kind of do not do that,
maybe. Let me get back to this
in a second as we go over that slide, because it is a very applied
example of that too. You need to plan ahead
in how you will organize and manage the references.
Please think of this stuff. Prevent Blueprints
that reference a huge number
of especially large Assets. Try to split it up, have Child
Blueprint Classes under it, for example. Here, this is how
I started my project. I said in my project, I am going
to have a pipe you can pick up, I am going to have a rock
you can pick up, a plant, and I think it was a can. Four things.
What could possibly go wrong? Let us make a single Blueprint
that we call item. In that one item,
let us make a function that sets a bunch of variables.
Essentially, if this is set, what we do is we say,
it is this heavy, it has this name,
it has this whatever. Then we reset
a couple of things. It was a couple
of pivot point things. That is not the right term,
but you get the idea. Reset a few things, and then
I set the new Static Mesh. That is it.
I did that for 4 things. I did that arm 4 times. The problem is,
by the end of the project, I ended up not having 4 items.
I ended up having 40 or so. I ended up having
this giant switch, and the whole thing
got out of balance. I ended up referencing every
single one of those Materials, Textures,
all the particles, all the sounds that were unique
for every item, which looked like that as well,
as you have seen. Here is what you should do.
This is the advice way forward. The best technique is to create
a clear hierarchy with rules in place for where
the Asset references live, which should look like this. You have every key Class
is defined in C++, all of them almost.
There is always a Blueprint that is then
inheriting from C++ Class, and potentially
another Blueprint in turn where it makes sense. Content is ideally referenced
primarily in the third step. It looks like this.
I have this overview. There is always a Parent Class.
That is the C++ one. There is then
the Blueprint Class, which in my item example
would have been C++ InteractiveItem,
Blueprint Interactive_Item, and then the specific ones,
Item_Pipe, Item_Bucket, Flashlight, etc. That would have been what I
should have done in retrospect. By doing so, and by making
the C++ Class above it, you always have that present. Even if there is nothing
in there yet, at least you have got
the architectures in place. It is going to make it
easier later on to move things to C++ if needed. That is a topic
we will get back to later on. By having the content references
in here in separate Child Blueprints,
if a Level needs a pipe, it will only load
this Blueprint. The functionality
might still be here, but the content references,
the Materials, the Meshes, they are only in this Blueprint.
They are only going to be loaded when the Level needs
that particular item. Right now, when I load
a Level in my game, it loads every single item
you could possibly have and all the Assets
along with it. Libraries. If you have function libraries
or macro libraries, any kind of Blueprint library, we have got a similar
kind of challenge there. If a single function
of the library is used, the entire library is loaded.
Please be aware of that. If you have a reference
in any one of the functions within the library,
that reference is brought along. I have seen an example
about a year or so ago where there was --
you have a main menu, and then the main menu was completely separate
from the game, as it should be
for these reasons. But it was one
particular function that was used from
a Blueprint function library. It just loaded something
related to the menu. There was something
in that function library, like I do not know, find sound
for menu or something. Whatever. But somewhere else
in that same function library, there was a reference
to another Class, which had the reference
to another Class, to another Class,
to the entire game. Eventually, it would load
the whole thing. The moment you would load
that main menu, it would load one gigabyte
of extra data for the act of doing that because of that one reference
to that function library. You really want
to pay attention for that. For example, in this example,
this is not optimal. But it could be. It depends again
how critical it is. To be entirely clean
is not optimal. A very basic one where it says,
here is a function, Get Components by Class,
get all Static Mesh Components, find all the sockets
with this name in there -- that is kind of a weird one,
I know. Ignore that. Then spawn emitters
at that socket. I do not know
why I want to do that. But ignore that.
The point is, there is a reference
here to an emitter. That means that emitter
will always be loaded whenever any function in that
entire function library is used. This would be more correct, where the particle is a variable
that is brought in. Because then you specify
what particle to use where you use the function
and not in the function itself. Those kinds of things. Game Modes help
for this as well. The whole point of Game Modes is to kind of help you separate
the two, to make a clear break. Okay, so this is all of that,
and this is all of this. We do not have the references
going back and forth. There is dynamic Asset loading, which you can also do
in Blueprints. I can just show you
in the Editor. This is 11. Here is
all this stuff here first. You have got this, for example. That would be the normal way
of doing it, you just do, Set Static Mesh.
That is now a hard reference. You could do
an Async Load Asset. Then you have the reference
to the Mesh there. You cast it to a Static Mesh,
in this case. Then you set the Static Mesh from that thing you got
from the Async Load Asset. That will load the Asset
on the fly as you need it. There might be
a small hitch there. That is something
to be aware of. If you then look
in the reference viewer, you see what happens there.
You get this pink line. That is the soft reference line. It also distinguishes it
in the reference viewer. When you have soft references -
and it is the only way forward when you have
a lot of configurable parts, so different parts -
you can use maps. Again, that was the one
we had underneath here. We have a soft reference
example. Full screen here. Essentially,
you can have a string that is touched to the Asset. Therefore, you can
always find something. Essentially, it is like a table.
You can say, find me the bucket. You just say, look for bucket, and it finds you the Mesh
associated with the bucket instead of having to look
for the actual bucket itself. That makes it more configurable.
It makes it easy to manage. If ever you change the bucket,
the Mesh itself, maybe assign
a different Asset to it, you would not have to change
some of the logic either, because it would have to try
to find that Asset in there. It does not even work. This is the better way forward.
You can look for a keyword, and it will return you
the Mesh associated with that. That is a map Asset. Also, just to point out
a different topic kind of, but loading times in the Editor
are way different from the final package project.
Again, you cannot look at that. Also, in the Editor, there is
actually in the Config file, I think it is the game
.ini file, I think. I am not 100 percent sure
now. You can say recompile on load.
You can actually turn that off. Because by default,
when you start the Editor, it is also going
to compile the Blueprints. In some cases -- this is rare,
but I have had a case like that where something got corrupted
in the Blueprint, it will crash the Editor
the moment you load it, because the crash happens
on compile of Blueprint, and the Editor compiles
the Blueprints on load, so the Editor
does not start anymore. This would fix that.
It might also speed up Editor boot times
depending on project setup. I will do this one quickly and then we will end part one,
move to part two. Garbage collection
is not a very long -- there is a lot
to say about this. I am keeping it fairly
straightforward. It is obviously
the process of collecting and removing any Objects
that are no longer required. We have got a test
Level of that. Because whenever you destroy
something in game, it is not immediately
removed yet. It is simply hidden
from the world. It is simply marked as,
this should no longer be there, but it is not actually removed
from the game just yet. In order to do that, we would have to iterate
through everything in the world, and then say, yeah,
that one should be gone. We cannot do that all the time.
That is expensive. That is the garbage
collection process. At regular intervals, the Engine is going to look
through everything and say, that, that,
and then that, let us move that. That is garbage collection. It is somewhat expensive because
of the iteration it has to do. Often, there is no need
to think about it, but I just want to explain
a little bit. Again, if you are not
from an engineering or programming background, you might not have considered
this all too much. What you can do here is there is
a stat called stat garbage. In fact, I have a Level here.
Simple setup. These are going to spawn things,
a lot of it. Worst case scenario,
a lot of it. You could use this
to see what the impact is going to be
on garbage collection. Every now and then,
it is going to hitch, because it has spawned a lot, and it is remembering
all of these cubes still. It eventually has to remove
all of the cubes. You can change this
and you can use the stats to see what the cost is. But you can change it just
to test it in Project Settings. You probably should not
if you do not know really exactly
why you want to do it, but just for the sake
of demonstration. In Garbage Collection,
which I forgot what it is named. You can change the time. Because by default,
it is every 61 seconds, I think. Engine - Garbage Collection, Time Between Purging Pending
Kill Objects. Let us do that.
Let us look for purging, because nothing else
is probably called purging. There we are.
61 seconds. If I make this say 10 seconds
and you run the game, you can clearly see
what would happen. At some point in 10 seconds,
we should get a hitch. But the computer
might be too powerful. There. That was a hitch there.
That was garbage collection. You can tweak it.
If you are doing non-games, there have been
quite a few cases that we have noticed where it
makes sense to tweak this value. If you are in games, I think you should be
much more cautious. For example,
if you work in film, you do not necessarily want this
to happen every one minute. You might be okay
just to let it run for an hour or so,
depending on the memory and what you are doing.
Also, you can cluster. In Blueprint there is a setting.
Every Blueprint, there is a setting that says,
Can be in Cluster. But in general,
everything related to garbage collection is complicated, so if you are running into
problems with this, if you are doing a lot
of spawning and destroying, you should probably
really involve a programmer and look through this properly. That is it. Let us take a break.
Everyone good? Thank you. [Applause] ♫ Unreal logo music ♫
Its great video, however beware of the pitfalls if you EVER intend on making a multiplayer game or making your existing game multiplayer supported.
Some of his callouts to wrap-up logic from C++ into blueprintPure functions out of brevity is dangerous because it can cause you to rely on singletons or the dreaded "GetFirstOf" paradigm which is a bad practice for multiplayer.
Be sure to think carefully about what you're doing if your game supports multiple players, as the context can vary what is done based on if its multiple local players, one single player + multiple remote players, dedicated server vs listen server.
Nice. Thanks !
These videos/talks were all really good.
Good old Hourences. Dude's been making good content since UE 2.0. Very concise and to the point.