AMANDA: Hey, folks! Make the big city the backdrop for your next big idea with the latest free environment collection on the Unreal Engine Marketplace--Downtown West. Released in collaboration
with PurePolygons, Epic Games brings easy
modular city creation, complete with shops,
signage, and snack stands to all creators. Download the Downtown West
Environment Collection--now available for free on the
Unreal Engine Marketplace. While there, check out the coolest deals of the year--with hundreds of items at 50%
off during the Winter Sale! Discover hot deals
on frosty items like ice materials or
snow-capped temples. Prefer to avoid the cold? Cozy up inside an
old wooden cottage and warm up with environments
like deserts, grasslands, oceans, and more. Whatever you're looking for,
the Winter Sale has a little sprinkling of everything--shop now through Friday at 11:59 PM EST. Debuting first in the Hummer
EV, you can expect cars
sporting new Unreal Engine-powered
human-machine interfaces to hit the road later this year. Learn about the
Unreal Engine features that enable design-driven
development of HMI demonstrated in our
most recent webinar, now available on-demand on the Unreal Engine YouTube channel. Among the top AEC technology
trends to watch in 2021 are digital twins. Get need-to-know information
on what they are, the technology at their
core, and their impact in the architecture,
engineering, and construction industries
from our in-depth article on the Unreal Engine feed. Earlier this week, innovators from across the globe converged on CES 2021's
virtual event for a glimpse at the latest
cutting-edge products and emerging technologies. Sony invited viewers
into a digital twin of New York's
iconic Sony Hall for a sneak-peek at a
new immersive concert experience featuring Epic
Records artist Madison Beer. Head over to square.Sony.com
to learn more about this collaborative
production. Speaking of trends,
last year was huge for real-time technology
and for the creators who have continued to harness
the power of interactive 3D to transform the way we play,
create, and communicate. Head to the feed and take a look at some of the exciting trends that emerged in 2020 and
what's to come this year in our real-time roundup. On over to this week's
top weekly karma earners. Thank you to: ClockworkOcean, T_Sumisaki,
Alekann01, Shadowriver, Everynone, MaxPower42, Kehel18, Aherys_, and plangton Have you ever wondered what
happens when you start up your Unreal Engine game? In an excellent
tutorial, Alex Forsythe takes viewers on a guided tour of the Engine's initialization process, covering the high-level structure of Unreal and how all the different
parts of the Game Framework fit together. Visit his YouTube channel and
website to learn even more! Here's a first-look
at Within Shadow Veil, a new story-driven
adventure game. The beautiful teaser
was completely rendered in Unreal Engine. Head over to Vladimir's
ArtStation page to offer them your feedback and keep
tabs on Within Shadow Veil at twitter.com/stategravity. Announced at the Game Awards
2020, take to the skies next month in
Century: Age of Ashes, a free-to-play multiplayer
dragon battle game. Compete in fast-paced
aerial combat to become a legendary Dragoneer. Wishlist Century: Age
of Ashes on Steam! Thanks for watching this week's News and Community Spotlight. VICTOR: Hey everyone,
and welcome to Inside Unreal, a weekly show where we
learn, explore, and celebrate everything Unreal. I'm your host Victor
Brodin, and my guest today is technical writer,
Michael Prinke. Welcome back. MICHAEL: Glad to be
here, Victor. VICTOR: We had a
great time last time. We were covering in a little bit of multiplayer fundamentals. But today, we're going to cover the Gameplay Ability System. MICHAEL: Yes. Shall I take it from here, then? VICTOR: Yes. Please, go ahead. The floor is yours. MICHAEL: OK, so the Gameplay Ability System is a system that was
originally built to support the development of Paragon. It is exactly what
it sounds like. It is a powerful and
sophisticated tool set for managing and creating
player-triggered abilities, or mostly player-triggered
abilities. You think of all
the kinds of stuff that like a MOBA or an
action RPG needs to do. Like you've got these very
unique hero characters, and they have all these
bespoke abilities, with very different
types of effects and highly variable execution, different movements they have to make, different kinds of
effects that need to trigger, that sort of thing. They need to be able to support data-driven attributes so that you can fine
tune and tweak it in like a spreadsheet in a way that's very designer friendly, and that makes it
so that you're not tied to diving into a bunch
of hard-coded variables and things inside of your code. And it all has to be able
to run across a network. The Gameplay Ability
System has all of the tools that
you need in order to set up that kind
of thing and support making character-driven
abilities in a game. It is robust enough that it
can support shipped games, but it also comes with
a handful of caveats. For one thing, Blueprint exposure is limited by default. That is to say,
there are a lot of classes and a lot of bits
of functionality that are not immediately
exposed to Blueprint when you get the plugin and
turn it on out of the box. Basically, users are expected
to define their own workflow for organizing abilities
in a way that makes sense for their specific game, right? Like, you need to set up the
way that you want to grant abilities to a character. You need to set up how you want abilities to affect costs. You need to set up your own
sets of attributes and things like that. And so you kind of need
to dive into the C++, set all of that framework
up inside of your character. And then you need to selectively expose functionality at the C++ level that makes sense for your specific project and your team and the way that you
guys work together. With that being said,
I'm going to show you around the Gameplay
Ability System and try to help disambiguate
the relationships between all of the different
classes that support it. Which are not necessarily
self-explanatory as a result of its very
technically-focused implementation. And for our test
subject, we're going to be using our man
Greystone here from Paragon. This is another
little disclaimer. Greystone in this demo
is not implemented in a way that is consistent with his implementation in Paragon. I did not implement the entire Paragon ability framework in this demo. This is a very simplified
demo to demonstrate the basics of the
Gameplay Ability System and how to work with it. And Greystone's attacks
that I've set him up with are not going to
be accurate to how they work in Paragon
either, with apologies to any fans or
developers of Paragon who might be watching this. The reason I picked
Greystone is number one, he is a readily-available
asset on the Unreal Engine Marketplace that you
can get for free. So you can reproduce
all of the stuff that I'm going to
do here yourself. And also he has a melee attack. And I really wanted to create
a couple of melee abilities to show off, and kind of talk
about the principles behind melee. Because the last time I did a
stream, lots of people commented that they wanted
to know how melee works. So this is my opportunity to
kind of share that with you. With all that out of the
way, let's first talk about the theory behind
the Gameplay Ability System and organizing
abilities in a game. So an ability
system for a game-- you could be working on
many, many different types of games that need
something like this, right? Like an action RPG,
or a turn-based RPG, or something like that. The idea is to take abilities
and encompass them inside of one object that is
responsible for all of the bits of functionality
that it has to perform. You want to take on ability as the player would understand it-- an action that an actor
can perform in a game-- and just wrap a class around all of the stuff that has to do. So examples would be like
casting spells, performing melee attacks,
all that sort of thing-- or performing special attacks. Gameplay Abilities as a class, coordinate how those execute and temporarily take over parts of the character who owns them, like movement and
animation, so that you have one spot to go in order
to change that sort of thing. They have a concept
of being activated, of being currently in
progress and executing, of being completed,
and of being canceled. So you can interrupt
them prematurely and tell them to stop. Adopting a design
pattern like this makes it possible to encapsulate every individual ability's functionality in a way that's
intuitive to edit, to iterate on, and to reuse. Your alternative would be
to hardcode your abilities and tie the functionality
directly to like movement states and various
different sets of events, and creating a lot of
spider web code that gets really yucky really fast. You get to the point where you want to add one more attack, and you have to go into a
really big state machine and add a bunch of new
enums and things like that. Here, you make an entity
that represents an ability. It's self-contained. You tell it what to do. You coordinate all of the
stuff the actor has to do. And then you just call it a day and add it to the character and tell it to use it. So it's much, much simpler. To start getting into the
ins and outs of the system, let's talk about the roots
of Gameplay Abilities. First thing that
I need to discuss is actually gameplay tags. And for that, I'll actually bring
this guy back up. So Gameplay Tags are
a separate system from Gameplay Abilities
that is I believe in the Engine by default.
You don't have to turn it on like a plugin. And what it is is it's
a type of variable that wraps itself
around a series of hierarchical tags like this. This would be a good time
to go like full screen on this, if you can. So you can see that
I've got this like tree of different tags that exist, with a parent-child kind of way of being organized. So I've got a bunch of tags for the character's health state, for different kinds of
damage that they can take, and things like that. I've got tags for different
types of abilities that can exist, like casting a spell and doing a melee attack. If I wanted to make like
different energy types, like damageType.energy.fire
or damageType.energy.ice or something like that, then I could do
it like that too. So this is a way of keeping like a library of different tags that can exist
inside of your game and that can potentially
be used in a lot of different types of systems. And all of this exists
inside of a config file that you can edit outside of the Engine as well. So you can populate it
very, very quickly, just opening it up
with a text editor. This is used for a lot of
different things inside of the Gameplay Ability System. It is used for controlling
the types of abilities that can cancel abilities. So when you trigger an
ability, it will automatically look
for the cancel tags, and say if the other abilities that are active right now have this tag, then cancel them. It can block other
abilities from happening that have a certain type of tag while the ability is active. You can make tags
that are required on the character in
order to allow execution in the first place,
all that sort of thing. And then there's
lots of uses of tags in other parts of the system. This is just examples of
things that Gameplay Tags are used for. And I wanted to give
people a primer for these since they're used in so
many different places. In terms of the structure of
the Ability System itself, we need to hop into C++
for a second and go over to the AbilitySystemComponent. So I've got the backing C++ code for my demo character right here. And one of the components
that I've added to it is the AbilitySystemComponent. This is like the brain
for your abilities. It contains a list
of the abilities that have been granted to the actor. It manages them. It is the thing that is
responsible for activating them. And it also contains
gameplay attributes. A lot of the stuff in the
AbilitySystemComponent is not exposed
directly to Blueprint. It is available in C++ if you
attach the component there. And then you can call whatever functions from it you want, and kind of write
UFunctions that expose its functionality
to Blueprint selectively, if you like. So for instance, I have a GrantAbility class here that will add the
ability that you feed into it to the
character, and it will tie it to a specific
InputCode it's called here. It's really just an
index number the way that I've got it
implemented right now. But it will add it to the
AbilitySystemComponent's list of abilities. And then it will be available
for the character to use. And then I can call this
ActivateAbility function, and it will tell it to
perform this InputCode, which will then trigger the ability. There are many
different ways that you can interact with your
ability list inside of AbilitySystemComponenent. So let's see if I can find one of the other ActivateAbility classes here. So TryActivateAbilityByClass
is an example of another function that can be used to activate an ability. Basically,
you can feed it the subclass that the ability belongs
to, and it will try to find an ability
that matches that class and try to use it. There are also tools for
activating gameplay abilities that have certain tags. Which is really, really useful for if
you are writing AI and you don't necessarily want to deal with the AI having to know the exact
ability to activate, but you want it
to find an ability with matching sets of tags. So like you want to make a command,
'Use a Healing Ability', right? Use a healing
ability on yourself, and it will look for an ability that has the healing tag and then try to trigger that. Many of the functions in
the AbilitySystemComponent have multiple alternate
ways of handling them, either with input
codes or with tags or with AbilitySpecHandles,
which are these handles that
you can keep around to keep track of an ability
that you have added. And those are just a couple
of different examples. And this way, I just set it up to
use this InputCode, because I liked the
idea of just giving it an index number from a list. And then, of course, I exposed the
CancelAbility with tags function as well,
so that I can tell it to turn off melee abilities. So let's see, those are the
basics of managing abilities. Those are a couple of
ways you can do that. But the other big important
area of responsibility here is gameplay attributes. Now, let me see here. AttributeSet, there it is. So gameplay attributes
are basically numeric values that have a
concept of a current value and a default value. They are intended to be
accessed through reflection by Gameplay Effects and by other various data-driven types of systems. And basically,
this is the way that you give a character stats. They can be used for a variety of different types of stats that you need for calculations in Gameplay Abilities, including things like
the character's health, if you want to affect their hitpoints and things like that. I've added attributes for
Strength, Endurance, and WeaponDamage for calculating
the damage on hit. And I also added a MaxHealth
variable for reasons that I'll talk about
a little bit later. But basically, this is just how you handle gameplay stats. You can also use it for
transient kinds of stats. Like if you want to keep
a place for the damage that the character
just took this frame, for instance, you could use a gameplay attribute as a temporary place to store that. And then you would use
that to calculate changes to their health as well as trigger other kinds of events. Like let's say you want a damage number to pop up on the HUD when the character takes damage. That would be the sort of thing that you would do with that. These are contained inside
of AttributeSets, which are a class that is just
set aside to wrap itself around a series of attributes. One important piece
of functionality that I want to highlight
is that AttributeSets do have a handful of overridable functions for handling logic that should happen
when attributes change. So PostGameplayEffectExecute,
for example. This is the function
that will happen after you have
changed a variable with a gameplay effect. And you can kind of query it to see which attributes actually got changed, and then execute
some kind of functionality based on that. You could use it to fire off
events in the character that owns the AttributeSet. Here I'm just using it to manually clamp the character's current health so that
it doesn't go below zero and doesn't go above
their max health. Really simple typical example. Another important feature. The AttributeSet class
contains a number of macros that you can use
to quickly define getters and setters for each
of your different gameplay attributes. So
GAMEPLAYATTRIBUTE_VALUE_GETTER is this is just a really
simple inline function that returns the current value. And that makes it easy to
expose in other places, if you need to. VALUE_SETTER, similar thing. It will set the value
for that attribute, and so on and so forth. PROPERTY_GETTER
will get a reference to the specific attribute. And that's what
I'm using over here is the GetHealthAttribute,
which is defined in this PROPERTY_GETTER. One recommendation that
I want to make regarding AttributeSets. You should, number one, avoid directly changing gameplay attributes with code,
if you can possibly help it. That is to say, don't go writing a
bunch of functions that call SetAttribute on
the different attributes that you have defined
in your AttributeSet. What you should do instead is
rely on the Gameplay Effect System. Which is something I'm going
to go over in a little bit. But those are
basically objects that are designed to interact with the system through reflection, and kind of bottleneck
the way that you're interacting with them in
terms of like live gameplay. And the reason that you
would want to do this is so that you don't have a
bunch of hardcoded methods floating around inside of
your code that might be difficult to debug and trace. If you're relying
on Gameplay Effects for changing these
attributes, then that will make it a lot
simpler to know what is responsible for
causing certain changes, if something is
happening by accident or if something seems
a little bit off. Another best practice that
I would personally recommend is don't go attaching
UAttributeSets to everything. Attach it to something that has an AbilitySystemComponent. And likewise, don't go attaching AbilitySystemComponents to everything. AbilitySystemComponents
are intended to be attached to an actor that is like a top-level instigator. So if you understand the
gameplay framework in Unreal Engine,
the instigator is the actor that owns everything and is
responsible for everything. It's usually a player
character, right? So if you fire a
projectile, the projectile will have an instigator. And that's usually
the player that was responsible for
firing the projectile. The Ability System has a concept of, when you use an ability, there is a source
for the ability and a source for the effects
that it triggers, and then a target for the effects
that it triggers. And the source is the
AbilitySystemComponent that owns the ability. And so the best way to condense everything that you're doing and make sure that the
responsibility for what's going on is clear is for
the AbilitySystemComponent to be attached to your character or some other top-level actor that you want to be responsible for triggering this effect. If you want to have attributes fed into it from weapons and things like that,
then you would simply have variables attached
to the weapon in some way, or a data table that's attached to the weapon, that would feed information up to the character and its AttributeSet, and fill out live
attributes that you want to use to keep track of
their current weapon damage and things like that. And that is like the
exception of where I would say it's feasible to
directly set these values. If you are doing some
kind of initialization from equipment or
from a stat set or from leveling up or something like that, or a save state, then that would be a reason
to directly affect your AttributeSets. Getting back to the way that
I've got this all set up, I've got the AttributeSet
declared inside of my character. You could also extend the Gameplay AbilitySystemComponent itself and write custom
functionality in there. This is just a simple demo,
so I kept it with the default AbilitySystemComponent. I have written a getter for it. This is actually
using an interface. There is an
AbilitySystemInterface class that you should
implement alongside the AbilitySystemComponent. You shouldn't just declare
the AbilitySystemComponent and put it here and attach it. You should use this
interface and fill out the
GetAbilitySystemComponent getter here, because then you
can do an interface call. And then you don't
necessarily need to know the class of
the actor that owns the AbilitySystemComponent. You can just ask the
interface to grab it, and it will fail out
if it doesn't have it, and it'll give you the
AbilitySystemComponent that's attached to the
actor if it's got one. And that means that
you can do things a little more freely with
a few less casts and things like that. In terms of initializing
it, it initializes like any other actor
component that you could add, like a movement component. You create the default subobject inside of the constructor and give it a name,
and that's how it will show up when you
go to the Components panel. Is everything following along so far, Victor? VICTOR: Yes. You're speaking at a good
pace, as always. And the screenshare
is looking good too. MICHAEL: OK. Aside from that, I also implemented
a number of getters in the character that
correlate to the getters from the AttributeSet. However, I do not
initialize the AttributeSet inside of the constructor here. You could do that. You could manually
set the attributes to have a bunch of default
values and things like that. But why do that,
when you can have a data table do that for you? I'm going to show you how to populate it from a data table. In the meantime, though,
I do initialize the pointer to the AttributeSet, which is declared
in the header here, inside of BeginPlay. So as long as the AbilitySystemComponent is valid, the AbilitySystemComponent
has its own way of initializing
the AttributeSet. It will do that itself. And then all I'm doing
is getting a reference to the AttributeSet here and
applying it to this pointer. And that's more or less how
I've got this thing set up. And with those couple of
functions and bits of code, this thing is now
ready to add abilities and use them and refer to this AttributeSet in gameplay. We'll hop back over
to the Editor here. And I'll just show
you real quick how I have this set up to
initialise from a data table. So I've got Greystone's
Blueprint here, which is derived from the GASAbility Demo Character class. And if I click on the
AbilitySystemComponent here, you'll notice that it's
got this default starting data list here. And it's a list of
basically data tables that you can use to populate
the character's attributes. You have to pick
the AttributeSet class from this dropdown. And then you have to
pick your data table. And if I go over to
the data table here, you'll notice that I've got
rows that are each named for the AttributeSet's class
name and then a dot and then the name of the attribute, exactly as both of these things appear in C++. As long as you have these
matching, then the base value in
this column will be applied to those attributes when you plug it into-- I keep thinking I've
got multiple Blueprint windows open-- when you plug it into this
default starting table. There is one other requirement. You do need to,
in the AttributeSet, define the gameplay
attributes as UProperties so that they are visible to
the Unreal Reflection System. If you do that,
then they will be recognized. If you forget to do
that, like I might have done in the
process of building this demo a couple of times-- might have, allegedly. If you forget to do that,
then the attribute changes from the table will
not take effect, and you will have
your MaxHealth start as 0 instead of 100,
and things like that. The reason that I have
a MaxHealth set up instead of using
this Max Value column is that the default
implementation of this data table functionality only really applies the base value. You could write your
own version of this to capture the min value
and max value stuff and apply it to the
gameplay attributes. The gameplay attributes
have a concept of a default value and a current value. But as it is, it will really
only look at the base value. So I'm using the MaxHealth
attribute separately as a kind of
workaround for that. Let's see, what did I skip over? All right. To make a data table
like this yourself, you simply go to Miscellaneous, you go to Data Table. And then for your Row Structure, you pick the AttributeMetaData class. Not class, structure actually. Sorry, misspoke. And that is the
structure that correlates to all of this
attribute starting data. And then if you do that-- it's not actually displaying
his health right here. If you do that, then all of the
stats will populate, and it will be able to
use them in calculations. You can potentially set up
multiple different paths for interacting with
this, depending on what your game needs. That is one possible path
for initializing attributes. It is one that I find
very, very convenient, especially for the purpose
of these kinds of demos. Your mileage may vary. Now that I've kind of talked
about all of the stuff that is backing the
abilities, let's actually talk about composing gameplay
abilities themselves. And as a demonstration,
we're first going to talk about
GameplayEffects. GameplayEffects are
an encapsulated class for basically anything that can change a gameplay attribute or that can act on an AbilitySystemComponent
or its owner. Let me see, GameplayEffects. Here we go. So examples would be like a
spell effect, like a buff, right? If you add a buff to a character that increases their movement speed or something, that would be a gameplay effect that you attach
to the character, and then it will enact its stat change to their movement speed, and you should see that impact it live during gameplay. Regeneration. I've got a regen effect
here for the character when they activate a certain spell. Gameplay effects are
able to have a duration, or they're able to be
activated instantaneously, or they're able to be
applied indefinitely. Like you add it and it
just sticks around forever until you manually dismiss
it, which gives it a lot of versatility. You can make
Blueprints of these. Unlike with the
AbilitySystemComponent and the attributes, which don't have
a lot of exposure to Blueprint by
default, these are intended to be edited
inside of Blueprint. And for the most
part, you shouldn't need to add a lot of manual
like execution and code in order to make it work. You simply have a series of
modifiers and calculations that you plug into these
various different dropdowns, and it will know to apply
them based on the settings that you give it. So this Regen effect
has a duration. The duration is a
flat Scalable Float. It will last for 5 seconds. And then it has a
period of 0.1 seconds. So every 0.1 seconds,
it will cause a change to the player's current health. The modifiers here is where I've set it up to modify the health. You can see that
it will allow you to pick any variable that exists inside of an AttributeSet that you've defined. There is nothing special you
need to do to expose this. This is just accessible
through reflection, which is the benefit of
having the AttributeSet. You don't need to know
what type of actor it's on. You don't need to know
what type of class it is in order to
directly access it. You can just tell
it the AttributeSet name and the name
of the attribute, and it will know
which one to effect. And if it's actually got that
attribute, it will change it. For the Modifier Operation,
I've got it set to Add. And for the Modifier Magnitude, it's a Scalable Float set to 1. Alternatively, if I have like a damage effect, then I can set the modifier to be-- melee damage isn't really the one that I want. I want the DamagePickup. There we go. This is another example. This does an
instantaneous duration. So this happens once,
and then it's done. And this one is adding
a value of negative 90 to the character's health. Which means that it
is subtracting 90 from the character's health. In a development
environment, I would probably have a damage taken attribute, instead of directly affecting the health value. This is just a really quickly set up example of an attribute or of a gameplay effect
that affects this attribute for demonstration purposes. And you can see,
I've got this pickup here. And when I run into it,
bam, there goes 90 health. And then for the spell
effect, if I hit the R key, he'll do his spell
casting animation. And then this healing
aura that I totally just grabbed from Infinity
Blade will turn on. And he'll regenerate some
health for 5 seconds. And now we're all
nice and topped off. So that is gameplay effects in a nutshell, at least the basics. Sometimes you might need to
do more sophisticated stuff than apply flat numbers
to the character. So for instance, I have this
MeleeDamage gameplay effect. Sorry if I get tongue
tied by the way when I'm talking about this. There are a ton of classes that are prefixed with the word 'Gameplay'. So it's very easy
to get mixed up when you're trying to talk about it. Gameplay effects, gameplay
cues, gameplay events, you get the idea. Anyway, so the way that the
MeleeDamage gameplay effect works-- where is it? It has a series of executions
down here at the bottom under its Gameplay
Effect settings. Execute. So you can make custom
gameplay effect calculations. They are actually an
encapsulated object in themselves that
you can reuse. And you can see I wrote a custom gameplay effect calculation called MeleeDamageExecution. You can also create custom modifier calculations as well. Let me see, Modifier Magnitude, Custom Calculation Class here. And that'll give you
a custom magnitude. And that uses a
different type of class. The two classes for
gameplay effect calculations that you'll end up using the
most often are going to be-- and I'm just bringing this
up to get a menu of them. They're going to be GameplayEffectExecutionCalculation and GameplayModMagnitudeCalculation. ModMagnitudeCalculation is a
simplified calculation class that just returns a
single value to use as the magnitude for a modifier like this-- for a modifier operation. And that's what slots in here. Executions are more
complicated and involved, and more powerful, potentially. And now is the time when we need to hop back over into C++, because a lot of the information for this is not necessarily exposed to Blueprint. So here I've got the
MeleeDamageExecution class. And it has just arrived from
EffectExecutionCalculation. It has an implementation
function for Execute that will run when it is called. And we have a whole
lot of boilerplate here that is designed to
fetch information about the source of
the gameplay effect and the target of
the gameplay effect, and get the attributes from
them that we need in order to run the calculation. And then it will simply
run the calculation which is down below
this comment here. And the calculation is basically Damage times AttackPower divided by Endurance. So it will take the
endurance from-- let me see. It uses these functions
to capture the attributes from their various
different owners. So this one will capture the
definition for WeaponDamage and add it to this local
BaseDamage variable that I've got it set up here. This is like an out variable. This one will grab
it for endurance. This one will grab
it for strength. And it's actually
applying it to-- OK, yeah. I did something wonky and
named these differently from what they actually are. It will apply it to this
AttackPower local variable. And then finally, here is where we actually do the calculation. I'm setting a floor to it. You can do a minimum damage of 1, when all of this is said and done. Then I multiply
it by negative 1, because damage
should be negative. It should be something that
you subtract rather than add. And then finally,
I call AddOutputModifier, and that is able to output the damage dealt to the target attribute. These target attributes are
defined inside of a struct up here for shorthand purposes. So this FMeleeDamageStatics here is where I'm capturing all
of these different attributes and kind of setting up
whether I'm getting it from the source or the target. And this has just a bunch of
really short macros to set up the attribute capture
functions that are necessary to do
this kind of thing. I'm telling it to
capture it from the AbilityDemoAttributeSet. I'm telling it to get to the
Strength attribute, which is declared up here using
these CAPTUREDEF macros. And then I'm telling
it true or false for whether it
should snapshot it or whether it should get a
reference to the live version of the variable. If you snapshot it, then it will
capture the variable as it exists at
that exact moment when you ask for the variable. So if it changes
for whatever reason in the middle of
running this execution or in the middle of
running an ability, then it won't
capture the change. It will keep whatever
the original value was before it started changing. If you say false,
then it will try to use whatever the most
up-to-date value is. So I'm grabbing strength
from the player that's using the ability,
endurance from the target that I'm using it on,
damage from the source. And the health of the target is what I'm eventually affecting. You can use execution
calculations to potentially output multiple different modifiers at once and encapsulate a lot of
different functionality for a gameplay effect all at once, and make the logic for it very detailed and intricate. Whereas modifier
operation magnitudes are going to be like just
one value that you output, and a little bit simpler. So I could have probably
simplified this just for a magnitude
value, but decided to use this to show
off an execution. And so bearing that in mind, we have this melee
damage effect. It's instantaneous. It plugs in this custom
DamageExecution class. And we know from writing
it that it fetches all of these different
variables from the character and factors them together
by damage to the character's health whenever this
gameplay effect is applied to the character. And when you are applying
a gameplay effect-- let's see. Here it is. There is a function called
ApplyGameplayEffectToTarget. And you can also do
ApplyGameplayEffectToSelf, so that the
AbilitySystemComponent that is responsible for
triggering the ability can also just apply it
to itself as the target. These kinds of
functions are where you specify what effects
to add to what character. And you can see
that the assumption is that you are targeting
the AbilitySystemComponent and not the character
that it belongs to. So you don't need to
know what the character class is to get a reference to the AbilitySystemComponent. You can just use the Ability
System interface call to plug in any actor. So if I wanted to try to get
the AbilitySystemComponent from a cube,
then I could plug that in, and it would try to
get to the component and feed it into this as the target for the gameplay effect. But this is how you specify what effects to apply to whom. And then necessarily,
when you do the ApplyGameplayEffectToTarget implementation,
this first Target refers to the user of the
ability, the person who is responsible as the
source of the effect. This Target variable
down here refers to who you're applying it to. That's a little confusing, but that's basically
how it works. And so to see an example of a
standalone effect in action, we have this pickup
that I built here that explodes when the character touches it and applies damage to them. All it does is it tries to
get an AbilitySystemComponent from the actor that overlaps it. I don't care what the actor is. I don't know what it is. I don't want to know what it is. I just want to know if it has
an AbilitySystemComponent. And then it applies the damage pickup gameplay effect to it. It has a return value. This return value is a
gameplay effect handle. So if you need to keep
a record of an effect that you have added to a character for whatever reason, that's how you
maintain that record. All these various
handles are much, much easier to
pass around in C++. It's a very intuitive
structure, if you've done a lot of
network programming, where handles are
used to keep track of information and asynchronous calls all the time. That's basically
what it's used for. And there are all sorts of
methods for getting gameplay effect handles and getting
gameplay ability handles as well,
so that you can kind of mess with things that
are in progress. And then finally, after applying the
gameplay effect, it will destroy the actor. Now, one thing that
you might notice is that when I hit this thing, I get that hits back effect. And there is nowhere inside
of the gameplay effect that is programmed to cause
that hits back to show up. And there's also nowhere inside of the pickup that causes that hits back to show up. What I am doing there
is using a gameplay cue to trigger the visual
effect that goes alongside this gameplay effect. Almost said gameplay
event there. Gameplay cues are
basically a way to encapsulate a visual
effect or any other type of cosmetic information
that is needed for when a gameplay effect
gets applied to a character. So this example,
I have this regen cue. And that is the visual
effect that shows up when I trigger this regen effect. And what that does-- well, you know what it does. But how does it work
is really the question. If I go to the gameplay
effect for regen and I go down to the
Display Properties here, you'll see that I've got
a list of gameplay cues. And instead of having
a list of objects that I'm plugging in
that it's going to spawn, it has a list of
Gameplay Cue Tags. Here is that Gameplay Tag
System coming back again. And here I have applied the Health.Regeneration tags to it. So what this will do is when it applies this gameplay effect to the character, it will look for a gameplay cue that matches these tags and apply that. And inside of the
gameplay cue itself, if I look at the
Gameplay Cue Tags here, that's where you define that. So I have Health.Regeneration
set up here. And then in the Regen gameplay effect, I have it set up here. And as long as those match,
it will automatically try to match those up and
apply it to the character. Similarly, the hits back for melee damage is looking for
Health.Damage.Melee. And that will apply for
any gameplay effect that uses these gameplay cue tags. This is basically a
really, really useful way of setting up generic visual
effects, auras, and hits backs on a game-- on not just one gameplay effect, but all of the gameplay effects across your game, right? So you don't have to go and do a bunch of bespoke programming to figure out the
exact points that you want to activate all of
these different effects. You can make gameplay cues
for a library of effects that you want to trigger
and then tie them together with these tags, and just keep this
library of tags that cause these cues to show up. In that regard, in terms of the way
that these execute, they function kind
of similarly to sound cues, in that there is a function that happens when they execute, and you can tell it to trigger various bits of
functionality based on information in the
target or parameters that go alongside the gameplay effect that you just fired off. So here I have the
BP_GC_MeleeDamageCue. This is derived from
GameplayCueNotify_Static. This is another
case where there are two different types of gameplay cue classes you can make. So GameplayCueNotify_Static is a one shot effect, basically. It will instantiate
in the world, and then it will fire
off and do its execution, and then it will go away. So if you're doing
like a hits back, that is a typical kind of
use for that type of cue. GameplayCueNotify_Actor
is what I used for the regen effect here. And this is the gameplay effect. I want the gameplay cue. Here's the regen cue. It is an actual actor that
will instantiate in the world and not just a UObject
that exists invisibly. The Notify_Actor
cue basically can be used like a physical
object, and it can keep track of ticking
logic, and it can keep track of
stuff that happens when it is both
executed and removed, as well as when it is active. So you get more sophisticated
stuff you can do. Here all I did was attach
a particle system component to the character, or rather,
attach a particle system component to the gameplay cue. And then in the defaults,
I have the settings set up so that this cue will
attach to the character that owns it basically to the person that the gameplay effect was used on. And I've got it set with a unique instance per instigator, so that different
characters can all have their own copy of this. And that is the way that
it'll kind of pool these. The melee damage is
much, much simpler. I get the target of the
damage that is being applied. And then I spawn an emitter that will just fire and forget. And that's all that happens and I just take the Greystone-- I spelled Greystone wrong. It's with an E. And I just give it the Greystone primary impact visual effect, and it will
just spawn it and forget it. And we can see that happening, unless I accidentally got rid of it. Let's see here, did I pick a different hits back somewhere? VICTOR: I think I
saw a small one. MICHAEL: Yeah, I might have done
something silly. Let's see, Greystone. Primary_Sparks, that's the one. That's the effect I was using. At least I thought it was
the effect I was using. Did I forget to
compile my Blueprint? Take a quick look at this thing, Primary_Sparks, hit Play. That's not the one. Primary_Impact. Primary_Impact, that's the one. I've been accidentally
grabbing the Sparks. Well, it's still not-- that one triggered. So what the heck's going
on with the melee attack? Yes, we run into bugs too. VICTOR: We do. Not the first time,
won't be the last. MICHAEL: Indeed. So melee damage, did I accidentally
remove the tags? BP_GE_MeleeDamage,
Health.Damage.Melee. Yep, OK. I wonder if-- oh, it's not even
triggering the effect. So I broke this ability somehow. Interesting. Well, let's not let it
slow us down too much. Magnitude Attribute. VICTOR: It can sometimes be
good to follow along the way that you would troubleshoot
a problem like this as well. MICHAEL: Yes. Yes, I think that's a good idea. Modifiers. Ah, OK. OK. It's because I accidentally
added this modifier here, I believe. Now if I do it
normally-- there we go. Now it's not trying to interfere with the execution calculation, and it's working as intended. I will walk you
through how I built several of these abilities
from start to finish. But I'm trying to get
everybody acquainted with all of the components
that make this up. Because gameplay abilities
are complex enough, I think you can see,
that you kind of need to know all of the
different components before you can start doing
even really basic things. So I do apologize if it's
maybe a little difficult to follow along with how
some of these are composed. But we will address that here. So that is gameplay cues. You don't necessarily
have to use gameplay cues to trigger all of your visual
effects, by the way. You can do bespoke code
to fire off visual effects and sound effects
and things like that, if you need to in various different places,
in like the abilities and the effects,
and in the characters, and in montages and
things like that. Like, I've got the trail for Greystone's sword set up here, so that that's on
his anim montage. But gameplay cues are a
useful companion class specifically for
gameplay effects that makes it easy to set
up like really, really generic systems for hits
backs and things like that. And now finally,
after showing off the kind of standalone
implementation of a gameplay effect,
this is another thing. You don't necessarily
need a gameplay effect to be associated
with an ability. It needs to have an owner and a target, or at least it needs to have a target. It doesn't necessarily
need to have an owner, unless you are
calculating something that's coming from the owner. When it's a flat value like
this in the damage pickup or in this heal pickup
that I also created-- if it's like that,
then if you're not referencing the owner's
stats, then you don't necessarily need to assign an owner to it in order for it to work. But it is good practice
for it to have an owner, and the easiest way for
an effect to have an owner is for it to be fired off
from inside of an ability. And that finally is
going to bring us to gameplay abilities themselves as they exist inside of the Blueprint editor. So Gameplay Abilities are
themselves a special type of Blueprint that encapsulates the functionality that I described at the start
of this whole rigamarole, when I described the kind
of theory behind abilities and how they work. Sorry, let me go ahead and
close a couple of these tabs, so that I don't have tons
and tons of these open and keep getting confused. So here is the melee ability. And what happens is when
you call the Activate function from the
AbilitySystemComponent, it will trigger the
ActivateAbility event. It will then follow whatever
execution you have from there until you reach EndAbility. And this will tell it the
ability is no longer in use. And that will do
things like free up the AbilitySystemComponent to use other kinds of abilities, if you maybe have different
abilities blocking other abilities, so to speak. The main way that you control
the execution of an ability is through what's called
a gameplay ability task. Ability tasks are
specialized Blueprints-- specialized Blueprint
nodes, I should say-- that rather than representing a single function that you fire off, they represent an object. Ability tasks get added
to an ability task owner. That is the
AbilitySystemComponent which keeps track of all of them. There is an instance
of this task that's attached kind of
invisibly to the component for every single one of these
nodes that you're using. That's why it has a
Task Instance Name, so you can name them,
if you want to look up a task and need to do
something with it. And these, like abilities themselves have a concept of being started,
in progress, and stopped. And they can have the upshot of kind of wrapping a Blueprint node around an object
like this for a task, is that you can have
multiple different execution paths potentially on the
Blueprint node itself. So this one will fire off when the anim montage is completed. It will fire off this pin
when it starts to blend out into the next animation. It will fire off this
pin on interrupt. Or cancel, it'll fire off these
different pins. Likewise,
I have a Wait Gameplay Event. And this is able-- wait for gameplay event is
really what this is called. And it will wait for a
generic gameplay event to come in that has
certain tags applied to it. So this one is waiting
for a melee strike event to be fired off inside of
the character that owns the AbilitySystemComponent. The AbilitySystemComponent
will kind of listen for this when
I create this node. And then any time it receives an event that matches these tags, it will fire off Event Received, and that will give me the signal to start
applying gameplay effects to the target that is included alongside of this payload. Other examples of
different tasks that exist include tasks for applying
root motion to the character. So if you want the character
to move to a location and fire off an
execution pin when they reach their destination, you can do that with this node. And then the character will-- once you trigger this, it will take over
the character's root motion, and normal
movement will be disabled, and it will move along whatever curves you specify here towards this final destination. There are a lot of different
root motion ability tasks, in fact. And what they are
actually doing is-- if you've ever played around
with the anim montage system, sometimes animations
will have what is called root motion in them. And that's where inside
of the animation, you have a root bone that is at the origin for the character. And you move that root bone. And then the animation system
and the character movement component in particular are
able to capture information from that root
component's movement. And instead of applying
it to the model that's attached to the
character, it will apply that to the character itself. And that is how you get things like ledge climbing, right? It's a terrible pain in the
butt to try and interpolate a character up over
a ledge with math, when you could animate the root component-- or the root bone, rather-- and make that move
up over the edge, and then just capture
that inside of gameplay and apply that, and kind of take over the character's movement like that. There is a system built with
Gameplay Abilities in mind called root motion
sources, which is where you manually take
over the root motion system. You kind of hijack it to do
whatever kind of movement you want. So if I want to do
root motion that is consistent with a simulated jump, I would call this node, and it will take
over the root motion. All of the other movement in the character movement component will stop and it
will do this instead. The reason why this
exists is so that you can have root motion that needs to move arbitrarily, right? So you can't
necessarily predict, if you've got a ground pound attack or something like that, where root motion needs to
land, if you're editing the animation
inside of like an animation suite of some kind-- if you're inside Maya or something. You can animate it to follow
exactly this one path. You need it to trace down to the ground, find the ground, and say, however long it takes to get to the ground, go there. That's what this is for. And so you can just
very, very easily control the way
that the character is moving during the
execution of an ability when you're doing
something like this. And that's a really, really good example of the kinds of things that these tasks make intuitive that would otherwise be a real pain in the butt
to do in the tick code for like an actor or something. To edit this kind of
thing, all you have to do is hop into the
code for the task. I have a play montage
and wait for event task that I custom-built.
Actually, I hijacked it from the action RPG
sample, because I wanted to test it out. And here we go. You can see that it's got all of these different delegates that correspond to the
different output pins. And then it has
a static function that is what is referred to
by the Blueprint node itself. This is what is defining
the way that it's going to show up inside of Blueprint. And then it has all of the
different logic structured like an object-- like
a UObject that you would have sitting in the
world and executing code. So it's a fairly straightforward process to kind of understand. And there are all kinds
of different tasks that are ready made
out of the box. You've got tasks for waiting
for different overlaps in the physics system. You've got tasks for
waiting for different types of gameplay effects. Confirming and canceling input. So it is possible-- I didn't do this here. It is possible to bind
gameplay abilities to specific input
per the input system and listen for that
inside of these tasks. So when you get to this
specific step of the ability, while it's active,
you can wait for the player to click that input again. Or you can wait for them
to release that input. So you could hold down the button, execute a bunch of code for Greystone to
leap into the air and hang there for a little bit. And then you could wait for the player to release their input, and then shoot him down
in the direction of where he should land. I have not created an
ability that works like that. I was in the middle of trying to decipher how to do that when I created this ability, which just demonstrates
the principle of doing root motion movement. I'm still kind of
figuring out what all you can do with all
the different root motion tasks that are available. But you can see we
have ActivateAbility. That goes to Apply
Root Motion Jump Force. It will move Greystone
in the direction that he's facing at a
distance of 1,500 centimeters at a height of
2,000 centimeters. When he lands, he's supposed to
play an anim montage, but I've had a little bit of
trouble getting this montage to actually play. And then it does a sphere
trace for any pawns that are in the area and
applies a gameplay effect for melee damage to them. And the
ApplyGameplayEffectToTarget nodes inside of the gameplay
abilities actually don't need you to
supply the owner. They know to get the user
of the ability as the owner, and use that as the source. So that'll save you a
little bit of trouble. And then once it does
that, once it applies this effect
to everybody that is caught inside of this radius, it will end the ability. One neat thing that you can do when you are applying effects to targets, this function
inside of Gameplay Abilities actually takes this
target data structure. And this is a handle
that can contain one target or many targets. So you can kind of
compile a list of actors that you want to hit. And then on completed,
I'm actually taking this Hit Actors array and applying it inside and making target data from this array. There are several
utility functions for creating ability
target data like this, using either hit results or
different source and target locations that-- I'm not really sure
exactly how that works. But it could be useful. Let's see, 'target data from' -- and then from specific
actors or groups of actors. I could probably actually
take this hit result and plug that in, and it would
probably still work. Let's go ahead and
try that and see if that saves me an
extra couple of function calls and a local
variable, because that could be pretty nice. So I get a few meters away. I accidentally trigger
regen, because I'm using the wrong button. I do my leap. I hit him. Pretty sure I hit him. It's hard to tell, because--
no, I didn't hit him. OK. Need to not overshoot. Needs to be-- I should make this the direction where the camera is facing, and I should add a visual effect that shows the radius in order for this to work. Ah. [LAUGHS] OK. Let's take some guesswork out of the equation for just a second. Let's have him jump
500 centimeters so that it is a shorter
jump and depth perception is less of an issue. OK. So if I do it from
right over here. There we go. Yes, the hit result did work. And that just makes
a nice shorthand that can grab it directly from a hit result on like a sphere trace or on an overlap event
or anything else of the sort that you could want to use. And I don't need this
Hit Actors array. And we're good. "Do I have HitActors in use?" No, I don't need
HitActors in use. I don't even need
this For Each Loop. Simplification, how wonderful. Well, I might actually need
to do that from hit results. Yeah, I'm actually
plugging it in from there. Can I do it like-- nope,
I need the for each loop. I need the for each loop. My bad. It's a good thing I'm
finding that out now. But I won't mess with
this too much longer. I'm already being
very, very verbose about how all these are set up. But that is a good
illustration of how you can take ability
tasks and use them to coordinate
an actor's movement and have different events pop up and apply different effects in a very, very specific order. There is also a Wait
Delay task that you can use to just wait an
arbitrary amount of time, if you need to do
something like that. Sometimes you want to tie
things to an anim montage and have like a
specific frame where you want to trigger collision
and things like that. But sometimes you want
to be able to edit the timing for an ability and
the timing for an animation separately from each other,
like if you're casting a spell or something like that. That's how I have the cast
affect ability set up, where it will play
the anim montage and just wait half a
second into the ability to apply the gameplay effect. But that is the gist of how to work with Gameplay Abilities and apply all of
these different tasks. That is the gist of how you can kind of make a custom task and populate it with different bits of functionality. A couple of important
bits of boilerplate to mention here with Gameplay
Abilities in the class defaults, which I have
completely skipped over in talking about the
actual execution. You might notice that there is a function called CommitAbility. CommitAbility is the
function that you call for dealing with the-- for locking in the costs
associated with the ability. This is the thing that
you use to signify the last possible chance to fail out of the ability basically. So there is a cost section. And you can attach a
gameplay effect class that represents a cost, like deducting mana or deducting hitpoints or
something like that. CommitAbility will tell
it to actually apply those costs to the
AbilitySystemComponent. And you won't have to do
that manually yourself. Let's see,
other bits of boilerplate. There is a cool down section. Remembering this was
built for like action RPGs and MOBAs in specific. The cool down effects, basically whenever you fire off an ability effect
that you put in inside of this cool down, that is what's going
to control when you can use the ability again. So it will create
that effect upon use. And then once that effect ends, whatever duration it has, you will be allowed to
use the ability again. It will automatically forbid
it as long as this ability effect is active. And then there's all
of these shenanigans that you can do with tags. Abilities themselves have tags that are applied to them. And this is used mostly
for canceling and denial and blocking of different
abilities being able to fire. So you can tell it,
these are the tags that belong to this ability. You can query the
AbilitySystemComponent to get a list of abilities
that match these tags. And that's what I was
talking about with AI. So you can pick an ability
without necessarily knowing what it is,
and write generic AI. So you could write a
generic melee character AI that knows to look
for melee abilities, or a generic healer
AI that knows to look for healing abilities. You can add tags to track
things like whether or not it targets self, whether or not it targets others, and stuff like that. And this doesn't have
an inherent meaning. But you can script around it. You can check on whether
or not this information is true about an ability
that you're using and use it accordingly. And then Cancel
Abilities with Tag. When you activate the ability, it will automatically try to cancel any other
active abilities that use the tags you specify here. So if I want casting to
cancel melee attacks, I could do that
for this ability. Blocking will explicitly
prevent certain abilities from being activated. Activation Required, this will require a certain tag to be there in order to use
it, and so on and so forth. You can also decide that
if the character and their AbilitySystemComponent
has tags active on it, you can deny or
require those as well. And same with the target. So lots of different
things you can do with this as kind of
a switchboard for when to allow the ability and when
not to allow the ability. Let's see here,
what other things should I cover with
regards to the basics of Gameplay Abilities? That's mostly it. I guess I can-- oops,
not what I wanted to do. That's mostly it. I guess the last thing
that I want to do is go over how these specific
abilities are set up. I kind of went over the
casting and the jump ability that I put together. But the melee system
is what I was really excited about talking about. But before I do, does anyone want to
ask any questions? VICTOR: We've received
a lot of questions. We've been gathering them
up, and I was hoping to ask a couple of them. MICHAEL: Yes. Sorry to keep you
waiting for questions. VICTOR: Oh no, Mike. We do Q&A at the end. Your presentation first, and then we know
what you covered, and then we can tackle some
of the other things that haven't been talked about yet. Do know that we received a
lot of questions in regards to multiplayer. I think it's worth mentioning
that that's something that you're still working
on, and we hope to cover in the future. Now, it is good to know that the Gameplay Ability System is set up for multiplayer, right? It's built for low latency
replication of the values. So by learning how
to use it first, even if it's just
for single player, and you're not just yet
implementing multiplayer, you're already halfway
there, right? MICHAEL: That's more
or less the idea. I wouldn't tell people,
implement your abilities in single player and then
add multiplayer later. If you know your game is
going to need multiplayer, then you should build
for it from the start. But as an example,
this is really just supposed to get people acquainted with
the basics of how to interact with the Gameplay
Ability System and how to set up abilities and
just get them working. Replication, yes,
is something that I am still trying to research the exact
best practices for doing it. There are various
different affordances built into the system for
handling that sort of thing. Root motion is
actually one of them. That is the other
thing that I forgot to mention when I was
going off on my big tangent about root motion sources. The reason you
would want to do it is because the
character movement component can replicate
root motion automatically. And so by going through
and hijacking root motion, you have this ready-made path
for replicating root motion without having to do anything. Other things, you can tell the
GameplayAttributeSet to replicate and have
different values replicate according to
different preferences that you want, and use the
replication notify functions to trigger a bunch
of logic the way you would with any normal
variable that you declare. Those are a couple of
examples of things that you can do to set up replication. I feel reasonably
certain that all of the handles that
get passed around are also useful in
tracking replication. And then of course, the concept of
source and target. Sources for abilities, right? Parallel the instigator
for the actors. And that is intended to
make replication easier. Those are a couple
of little examples of things that I've
picked up on that Help it hook in with replication. But as I say, still researching
how best to apply it. And we will put together
a guide on that. That is another
thing that I meant to bring up that I kind
of skipped over getting into the meat of this We are revising the
documentation for this significantly. We're doing a big expansion
of different reference pages for all of these classes
that I just talked about, and how to work with them,
and different how-to guides for reproducing a lot of the
effects that you see here. So if that's how you prefer to pick up on this sort of thing, within the next
couple of months, those docs are going to go
up, and that material will be available. This is kind of a sneak
preview of all that stuff. That being said,
what other questions came up? VICTOR: All right,
are you ready? MICHAEL: Mhm. VICTOR: KaosSpectrum asked, how would knockback and things like that be executed via GAS? MICHAEL: That depends largely on the specific implementation and needs of your game. So the tasks for root motion
are not necessarily the thing that you would want to use in order to do that kind of thing, because these assume
that you are targeting the owner of the ability, right? What you would
use instead is you would have a gameplay
effect that has-- VICTOR: Sorry, Mike. Seth, can we go full screen? MICHAEL: I apologize. I got ahead of him. I'm supposed to be giving him signals for that sort of thing. Are we at full screen now? VICTOR: Not yet. Let's see if we can get a-- There we go. OK, you're good, Mike. OK MICHAEL: OK, so as I was saying, these root motion
things are really for moving the Character
in highly specific ways that it's really
for how they execute the motion and their abilities. Instead what you would
do is you would maybe apply a gameplay effect
that is built for knockback. Let's actually give
that a try here. Caps lock. So grab this gameplay effect-- BP_GA_Knockback. And then let's say that it has-- let's see. Let's take a look
at the functions. No functions that stand out. No events that stand out. OK, that's probably not the
best way to do that then. Well, actually,
yes, it can work. Here's how. You set up your
knockback effect. Gameplay-- not GA knockback. GE knockback. Getting my prefixes all muddled. You set up this effect. You add a modifier,
and you give it an attribute, or you give it a custom
calculation for how you want knockback to be factored. Maybe it's based on a
damage force variable that you put together. You would define
that damage force variable inside of your
GameplayAttributeSet-- Where have I got it? As like a transient property. And then when you
do your modifiers, you do it based
off of this value. And then when you do
that, you can then go over to the AttributeSet
in the CPP file. Sorry,
I'm kind of word salad-ing as I try to explain this. You can go to the AttributeSet. There it is. There's the CPP I'm looking for. You can go over to PostGameplayEffectExecute
and say if Data.EvaluatedData.Attribute equals GetKnockbackAttribute. So what you're doing is
you have a damage force. You take that and use
that in the calculation to apply to the
Character's knockback. This doesn't represent a stat
that is on the Character. This represents a value
that you're using-- like you're kind of flashing
it with the information that you need, kind of like the
damage you just took. So maybe KnockbackForceTaken is what I'm trying to say here. Get
KnockbackForceTakenAttribute. Make a property getter for it. And then let's see. That should now work. And then you can tell it to
execute code based on this. And then,
whether that is something where you want to actually apply a force using the physics system,
you could do it that way. If you wanted to manually
move the Character by taking over the
movement component, and making a custom
movement state, and having it follow a curve
based on the knockback force, you could do it that way. If you wanted to skip
this step entirely and not mess around
with a gameplay effect, this is a nice way to make
it data driven, right? This is a nice way
to have a calculation that you can grab
from the Character in order to decide
what it should be. So if I wanted to make an
effect calculation based off of the Character's strength and apply knockback based on that. I could do it that way. But you could skip that
completely and go to-- let's see. Hop into the melee attack here. And when you apply the damage
effect, just go ahead and-- not the root motion force,
but grab the target Actor. Apparently I can
target this Actor. Nope, nope. That's a location Actor. That is a target for
it to home in on. Let me just-- let's just
cast it to Character right now so I don't keep
having to drag up from there. There we are. There's all the physics stuff. And you could just make
normal gameplay calls and add forces to it, right? And that could be
your knockback. You could apply an upward
and backward force that way, or if you have some custom
functions in your Character for simulating force that isn't using the physics system, then you could call
those functions directly, and you could do-- you
could do whatever you want. It all depends on
what is the best way to apply that for your
game, and the way you represent knockback force. Some people are going
to be using physics, like if you think about
Unreal Tournament, a lot of explosive
weapons just throw the Character into the air, or set their velocity, at least, instantaneously. In fact, set velocity is
probably a more-- let's see. GetVelocity is there,
but not SetVelocity. Setting the velocity
might even be a more elegant way of doing it, depending on what you're doing. But lots of ways
that you can do that, either simple or detailed. For my money, though,
making a knockback effect and telling it to
apply itself to-- I actually need to compile
it for the knockback taken-- applying it to a
knockback taken attribute, and then doing
calculations based off of that is the way that I would probably try to implement that. What else? VICTOR: Let's go
to the next one. Sorry. I was typing in chat. johnathanharkeriscool asked,
"Any tips on predictively removing gameplay effects? I've seen example projects
predictively apply an additional effect--
removal effect, but an extra gameplay
tag removal tag, but I found this a bit clunky." MICHAEL: So removal,
interesting. So there are a
couple of mechanisms for adding abilities. Gameplay Effects themselves can grant abilities to a Character. So while this effect is ongoing, give the Character this ability is something that you can do. But removal-- so what I've
done here in the Character-- there's GrantAbility, ActivateAbility, CancelAbility. CancelAbility is
not what we want. We're talking about getting-- like pulling an ability
off of a Character. Let's see. Let's see. Remove ability, apply ability-- GrantAbility is the
opposite of what I want. Is it ClearAbility? ClearAbility is the function
that gets rid of an ability. And what it takes is
an AbilitySpecHandle. AbilitySpecHandles
are created when you give an ability
to a Character, and it is a struct
that you can use to just keep track of references to them as you create them, kind of similar to keeping
track of an async callback. As long as you have an AbilitySpecHandle
sitting around, you can call this function
and get rid of it. In terms of creating a more
organized or intuitive way of removing abilities,
let's see if there's one for removing based on classes. There's
TryActivateAbilityByClass. There's
FindAbilitySpecFromClass. So yeah, you can get the
AbilitySpecHandles for-- or you can get the
AbilitySpecs and create AbilitySpecHandles using
FindAbilitySpecFromClass. And if it's got a copy of
that ability laying around, it will find this, and then you can
use that in order to remove a specific ability. Removing abilities
is harder than adding them at the moment due to the way that that's organized. It's not exactly a
user-friendly process, and the exact things that you do to manage removal of abilities is going to be something that
is game specific depending on how you organize it. So like for a lot of games,
when you initialize gameplay, you're going to grant
abilities to a Character, and they're going to
just have the abilities for the duration of the game. And that's, I think, the intended use case that this was originally built for. But if you need to
keep a record of it, if you need to keep
a list of abilities that have been granted-- let's see. VICTOR: I think Jonathan
was specifically referring to Gameplay Effects, not necessarily the ability. But this is, of course,
good information, as well. MICHAEL: Oh, well,
it's similar logic to that. If you are triggering
a gameplay effect, this is actually a little
easier to talk about, because I'm comparatively more familiar with the functions here. VICTOR: Just to provide a
little bit of information, as well, that KaosSpectrum referred to-- for all you who doesn't know
and you're interested in GAS, there's actually
a document that we facilitated with the
help of Dave Ratti last-- two years ago, 2019. It's linked in chat. I'll make sure to put it in the YouTube description and Twitch, as well-- where Dave Ratti explains
that you can't predictively remove them. [INAUDIBLE] will remove
them from the client if the prediction
key gets rejected. MICHAEL: That is good to know, but for gameplay effects, they return a gameplay
effect handle, and that's what you
use to keep track of it if you need to story
reference to the effect. Where you choose to
have these references live is going to
depend on your game and where it makes
sense to make that live. But that is what you would
use in order to-- so let me. So [TYPING] 'remove effect'. Let's see here. There's got to be
a way to do this. Probably just grab
this reference. So that's getting
information from them. That's wait for removed. RemoveGameplayEffectFromOwnerWithHandle. This would be the
function inside of the Gameplay
Abilities to do that, and it will remove however
many instances of the effect that you want. VICTOR: Cool. Yeah, I guess the predictive
option is the tricky part there. I'm sure Dave-- MICHAEL: Yes, he knows comparatively
a lot more than I do. I will give the disclaimer again that I am learning this system right alongside everybody who
I'm trying to teach it to, so there might be a lot
of things that I miss. That is definitely one of them. VICTOR: Let's see. last_devil_ asked, "Are there any workarounds to bind ability activation to UMD buttons?" This is useful for mobile. MICHAEL: To do that specifically built into the
AbilitySystemComponent. Let me see here. So I know that
AbilitySystemComponents have the ability to
bind to input in terms of buttons and key codes. Let's see here. Wait for event. Where is the-- I don't have it open, no wonder. Right, I don't actually have a custom AbilitySystemComponent. Go to the Character. Go back up here. AbilitySystemComponent. Let's see. So that's got LocalInputPressed. That's where you-- so
you can assign the input IDs through that,
but this is not necessarily what you would want in order
to assign it to a button. Basically, if I were to do
it with the way that I have this set up now where the
input codes are really just generic integers,
I would make it so that-- I would make it so that
the input codes that I assign to these abilities-- I didn't actually talk about initializing this in Greystone. So this is a good
time to bring that up. I initialized this
with an ability list. I just made a list of
the ability classes that Greystone has available to him, and I plugged it into-- I plugged the different
abilities into this list. And then there is an
initialization function that grants all
of those abilities and assigns an input code to it. And that is done inside of this GrantAbility function, where it will create an AbilitySpec. And that is one of those
references that floats around that you can use
to get information about the live ability
or delete the ability. The InputCode is just
a 32-bit integer. And when I call ActivateAbility with LocalInputPressed, that's what causes it to go off. However, when I call this
ActivateAbility function inside of the Character, as I do in the melee
system over here, I'm just manually telling it
to use a specific input code. So if you know that
it's going to be bound to a specific button,
what you're really doing is assigning a function
to that UMG widget that will tell it to activate an ability with an assigned input code for that button. And it will just-- that will map it to-- that will map the UMG input
to this ability for you. If there is some way of using the input system itself to map to on screen widgets,
that is something that I'll need to
do more research on. I know that we have plans
to put input mapping in the documentation
that's upcoming, but this is the
simplest way that I could think to do it, at least for the
purposes of just getting it working with the
logic that I've got here. VICTOR: Cool. And if some of you joined
a little bit later, Michael did mention
earlier that there is new and upcoming
documentation for the Gameplay Ability
System that he is working on. MICHAEL: Yes. Are there-- I think
we can do one more question before I
go on to showing this melee functionality. VICTOR: OK. Yeah, we have two more pages,
but to let everyone know-- MICHAEL: Two more pages. [LAUGHTER] VICTOR: Two pages. To let everyone know, in regards to the questions and the amount of time we have here,
I will send them all to Mike, as well as Dave
Ratti, afterwards, and if there are
any they can answer and they think are
important to discuss with the community at
large, they can answer on the
forum announcement post, which is where we announce all of our livestreams every week. You can find that on
forums.unrealengine.com under the Events section. xNaxdy asked, "Are gameplay abilities production ready yet? And if so, what does the
future roadmap look like if you're
able to disclose?" MICHAEL: I do not know what the future roadmap for Gameplay Abilities looks like. There has been interest
among the developers of revising the
system and making it more Blueprint accessible,
and user friendly, and things like that. As it is, as I've illustrated
in multiple different places, the relationships between
a lot of the classes doesn't necessarily just leap out and explain itself to you. There are numerous instances where you have to dive into C++ to work with it,
and things like that. But there are-- I don't of
any schedule specifically to do those revisions. In terms of being
production ready, you can support an entire
shipped game with the system as it exists right here. The only caveat, as I said at the beginning of this session, is that you're going to need to supplement all of the stuff that you need to expose to
designers at the Blueprint level, and you're going
to need to kind of build your own workflow for it. So the underlying
systems all work great. The workflow is something that you have to kind of customize and edit for yourself. VICTOR: Cool. Yeah, please continue,
and then we'll see if we have
time for some more. MICHAEL: And we have
shipped multiple products that use this system. In fact,
the-- off the top my head, I can tell you that the action RPG sample project that you can get in the Unreal launcher
in the Learn tab-- that uses the Ability
System, as well. VICTOR: I think it's
on the Marketplace. MICHAEL: Marketplace--
is it in the Marketplace, or is it in the Learn tab? I think it's in both. I think you can
find it for both. VICTOR: We got them both? We got them both, nice. MICHAEL: Yeah. But anyway about it, so now I will talk
about the theory behind making a melee
attack using this system and show you what I mean
by gameplay specific implementation. So as a disclaimer, this is a really simple prototype version of a melee system. It is not necessarily-- excuse me, hiccups-- how I would want to ship it, for reasons that I think you'll see
once I start showing you the ins and outs of it. But it will get the
idea across of what the starting point would be
for making melee attacks. And to get things started
off, I'm going to click Debug
Melee on Greystone here. Now, the theory
behind a melee attack is basically that
you want to drop a collider, or some kind of overlap component, or a trace-- like a sphere trace
or something-- and then detect all of the targets that are inside of it, especially if you want
it to be able to hit more than one target at a time. And then apply damage to
those, and then add them to a list of
targets that you have hit. And by adding it to that
list of hit targets, you can then forbid
subsequent overlap events from picking up the
same Character twice. To show you what
that looks like, I have an entire event graph set up for handling the melee hits. And on the
PerformMeleeHitboxTrace function here, basically every frame
this is going to fire-- and it is going to do a sphere overlap for Pawn Actors. And it will get
all of those Pawns that it detects inside
of a sphere overlap. And then it will add them
to this melee hit targets. I'm going to clean
this up before making this available
for people to look at, by the way. Sorry about all this spaghetti looking Blueprint code, but this was made on a
fairly short time span, but it will add the-- it will add anybody who has
been detected by this overlap to this list of hit targets. And then if they're
already in that list, it won't try to add them. If they weren't already in that list, if they are new, it will send a gameplay
event saying to trigger the-- saying that I got
a melee strike in. And this is getting
called every frame. Not only is it getting
called every frame, it is getting called on multiple different sphere traces. So to show you what
that looks like, let's go ahead and
swing the sword. And you can see-- if we are in full
screen right now, you can see that, as he swings his blade, frame by frame, it is doing a sphere
trace at different points along the path of the blade. And that is going to be typical in a melee collision system. I don't need to go in here. I need to go into the
melee logic for Greystone. So many windows. Basically, while the Character is swinging their blade, you want to be detecting
collision within that area continuously, because there is
this window that registers in the user's mind
where the blade is crossing this path. And they think that, at any point during that path, they should be able
to hit a target. You want that kind
of sense of tolerance for the blade
hitting the Character within this window of time
that the animation is active. So then you activate
the collider, or you start doing
the sphere traces, or whatever mechanism you're using for detecting collisions. And then you add Actors
to the hit Actors list. And then as long as
they're in that list, they cannot be hit
again is the idea, and you only apply the
hit event to them once. And then when the attack ends, you clear out that list, and that will allow you
to do another attack and hit them more than one time. Alternatively, if you've ever
played fighting games with really,
really cheap boss Characters, you could manually refresh
this by clearing out the hit Actors list at different intervals if you wanted to. And that would be a way
of having the same attack animation hit somebody twice. So you swing,
and you hit them, and then you swing slightly
more, and then you hit them a second time. And it feels really
brutal when you're in a fighting game and
something like that happens. But for the most part,
like 90% of the time, you only want the attack to
be able to hit somebody once. And that's why you
set it up that way. Sorry I keep bringing
up Visual Studio. I keep clicking the
wrong tab to do this. The way that you decide
to set up melee colliders is going to vary a lot. I have a particular
implementation that I'm going to walk
you through in a second that I personally like,
but depending on your game, you might have
something different. I'm going to go into
Greystone's animation assets. I'm going to go to his
primary attack here. And what I've done here is-- actually, the primary
attack is a little messy. Let's use his attack
C, because that one I've got it set up a
little bit more clearly. So you can see in
the anim notifies for this attack I actually
have a series of tracks for detecting melee events. And I have a special
anim notify state. Anim notify states
specify a range of frames in which to
activate functionality and then deactivate
functionality. And here I have a
list of hitboxes that I want to activate while
it is within this range. And you can see, going down this list, I've got the-- let's move around
behind him here so that it's a little
more intuitive. I have the hitbox for his right hand side, a hitbox for center right,
a hitbox for the dead center, a hitbox for the dead
center and another that's a little bit in front of it-- center left, center
left2, and left. So he will swing
from left to right as I go through this,
activating hitbox, after hitbox, after hitbox. And the way that that
is set up to work I created an interface class-- go back up to the
Blueprints here-- called Melee Events Interface. Again, so I don't need to know what specific class of Actor it is that's doing this. I can grab whatever Actor
owns the anim notify and tell it just try to do this
interface function. Add melee hitboxes and
remove melee hitboxes will take the hitbox name that I specified in the anim notify. And on the notify begin,
I add the hitboxes. Go ahead and delete
that crap there. And it will just take the
entire list of melee hitboxes that I defined. You can add variables to your
custom anim notify states by simply adding them to the
Variables panel over here, and then they-- that's how
they get picked up in the-- that's how they get picked up
in the montage editor here. So that's what this
hitboxes list is here. And it will call Add Melee
Hitboxes using this interface on the owner of the mesh that
is playing this animation. I don't know what the
owner of the mesh is. I don't care. As long as it's
got this interface, it'll run this function. And then inside of the
Greystone player Character, it has class settings. It has the Melee Events
Interface implemented. And I have several of these
functions that fire off whenever it gets that name. I also have a data asset that
I created called hitbox data. And what hitbox data is-- this is just a list. This is just a
list of information about where these spheres are going to be positioned relative to Greystone, and what their radius
is going to be, and what their name is. And these names are what
I'm using to reference them. I could probably cut a
lot of the middlemen out of this process by
just making this a-- well, just making this a data
table, right? Because data tables already
have a name applied to them. I was kind of experimenting
when I put this together. So this is a little
bit overkill, but you can see I've got
attack1 center right, attack1 center1, attack2 left, all these different definitions for hitboxes that could
potentially trigger when Greystone does an attack. And I attached a
reference to that to Greystone's Blueprint here inside of the Variables panel. And then when I initialize my
hitboxes, all I'm doing is I am taking a map that includes the name of the hitbox that I'm using
and the definition for the hitbox, the offset
and radius that belong to it. And I'm actually wrapping
that around inside of an active hitbox entry
is what this is called. This includes all of this information from the hit sphere definition, and it also includes a count of the number of times that the hit sphere with
this name has been activated. So what happens-- I go back to
MeleeHits over here. I take Add Melee Hitboxes. And for each name
that I give it, it will try to find the
hitbox entry by name. It will set the Count. It will increment
the Count up 1. So it'll say, hey,
I found attack1 center1. That one needs to
be incremented up. Let's increase its Count by 1. And then if it has a
Count of more than 1 after this is done,
it will add that hitbox entry to a list of Active Hitboxes. And then likewise,
the Remove Melee Hitboxes will find a hitbox by
name, decrement the Count in the ActiveHitboxEntry. And then if it has
a Count of zero, then it will remove it from
the Active Hitboxes list. And then I have another
utility function that is just for clearing out the entire Active Hitboxes list and setting the count of
all my hitboxes to zero And that is my way of
making it easy to edit in the anim montage which hitboxes are going to be active and when. Let me see. Where is the anim Blueprint? There it is. No, that's not the
anim Blueprint. Why do I keep losing the
anim Blueprint for this guy? Let's locate him. That's his model. VICTOR: I think you just
opened the model, right? MICHAEL: Yeah,
probably I should. Well, actually, I'm not sure that
that's the case. No, I don't need
his anim Blueprint. I need the montage. That's all I need. There we go. There's the anim montage. So that condenses--
all that rigmarole serves to condense this
workflow to adding the hitbox entries like this by name. I pre-record what
I think are going to be good hitboxes
for this arc, and then I just list the
names of those hitboxes. And then that's
all I have to do. And if I have
redundant hitbox names, like if center1 is used in
more than one different set of frames here, then it will
increment that count instead of trying to
activate a second copy of it or do a second trace of it. And that keeps it nice
and clean in terms of the way that it is running
these sphere overlap events. And then the hitbox trace-- it looks to see that there's
more than one active hitbox. It will place-- I don't need this
sequence anymore. I don't need that anymore. It will do the
overlap in a location that is offset relative to
the player's own location. And then it will run
the overlap on Pawns, and then it'll output any Actors that have been overlapped, and so on, and so forth. I could use sphere
trace for objects, as well, in which case, I would just feed
this into the start and end position to
have a sphere trace with a length of 0, basically. And that would enable me to
output not just the Actors that have been detected,
but actually a hit result. And that would give me more precise information about where they overlapped and
things like that so that I could maybe place the hit specs a little bit more judiciously when I
trigger the effect. The way that this interacts with the Ability System is through Send Gameplay Event to Actor. This function will
trigger a generic gameplay event that uses a tag. It has Animation.MeleeStrike set up as the tag to fire off. It has this event
data structure, which I can fill with whatever extra metadata that I want to be able to work with
when it fires off this event. So if you want some
sophisticated information about how to apply a hit spec, you could make effect context. Let's see-- [TYPING]
'ability target data'. You could make Ability
Target Data from Hit Result and feed that in. And then when you go back to
the gameplay cue for this, you would go in and-- where the heck is
my gameplay cues. There they are. You'd go into this, and then the parameters
that come out here includes things
like the location and normal of a hit event
and things like that. So there's a lot of
different parameters fed into gameplay cues that let
you handle this sort of thing more precisely. And that event data and
target data structure that we put together
here is where you're going to set
up that information. But once it sends this
gameplay event to the Actor, it doesn't know what
is listening to it. It just is expecting
something is listening to it. We go into the melee
ability itself. We have it-- commit the ability. We have it play the montage for the attack that we are using. That causes all of
these events to fire off with the melee collision system. And then it will wait
for a gameplay event that has the animation melee
strike, like what we set up inside of the Greystone Blueprint right here. And then it will
take the payload. This is the gameplay
event data that we set up, this payload, this package full of
juicy information. Where is it? And then it will
use the target data to apply the gameplay
effect to the target. And you can use any other
information about the target here, as well. And that's more or
less the mechanism for passing target
information up to a gameplay ability
from some component that the Character owns. So in this case, the melee trace system is set up in a way that it is attached
to the Character. It is intrinsically
part of the Character. The Character is triggering
these overlap events. The reason I'm
doing it that way is so that I'm condensing what
has responsibility for doing the melee traces, by the way. So I'm not having
this happen inside of every single
melee ability that needs to do this melee trace. I'm just referencing
this one common spot that does the melee trace for it and then passes information into it. Similarly, if you have a
projectile that lands a hit, then you might send a
gameplay event that-- you might send a gameplay
event that contains the payload of the hit target. And you send it to the
owner of the projectile, because the owner of the
projectile, the instigator of the projectile,
will ideally be the same as the owner of
the AbilitySystemComponent. And that is specifically if you need to calculate something based off of the owner. Or you could just tell it
to trigger a gameplay effect directly. Let's see here. Make gameplay effect. Probably apply gameplay
effect to target, right? Pull this one apart...
Target Data. [TYPING] 'apply
gameplay effect'. Make-- nope. Target Data Has Actor,
Append Target Data Handle. Target data, by the
way, can contain more than one thing at a time. You can actually loop through
a series of target datas and add them all to the same-- I went over that. Sorry, I'm kind of
repeating myself now. Let's see here. Target data... [TYPING] Interesting... [TYPING] OK, ApplyGameplayEffectToTarget. Sorry to kind of fumble around there looking for the function. So many names to
remember-- so many names. So that gets me a Target. That is an Actor
object reference. That is actor Ability
System Component. So I can Get Ability
System Component, and then hand it up to here. And then I can trigger this
gameplay effect directly. And if I have the
instigator for a projectile, then that necessarily means
I can get the Ability System Component with my
handy-dandy interface call and set that as the target. And that would be what you would put inside of a projectile to shorthand this without
sending an event back to an ability that may
or may not be active. But for melee,
we can be reasonably certain that the melee ability will be active because we defined it as being active while
the Character is swinging their weapon here. And we really never
want to cause damage if the melee ability
is not active. Now, with regards to my scheme for doing these hit traces, there are many,
many possible ways that you could set
up a melee system to do collision
checks like this. This is just one. One way that I've
seen people do it-- I've seen them attach
a collider simply to the Character's weapon,
to a bone on the weapon and have that turn on and off. I have seen
implementations where people do what I call a
perpendicular trace, which is where they take the
weapon, and they have the last
position of the weapon and the current
position of the weapon. If you think about it like
hands on a clock moving, it will take the last
position and take a bunch of points
along the weapon, and then trace to
the current position. And it will detect collisions
in between those points to kind of simulate this trail that it's sweeping along. And that's another
common popular model that I've seen in the forums
and inside of the community. I try to stay away from
both of those methods because their reliability varies with basically the frame rate and with the speed with which
the attack crosses the frame rate, right? It seems really
appealing because you can set it and forget it. But the problem is, if you have a collision box that is attached to your sword
and within one frame it jumps almost 180 degrees
across your Character, you are making a situation where here's the previous frame. Here's the current frame. It is picking up
collisions in these spots, but nothing in between. And that is a giant headache. Likewise, when you're
doing perpendicular trace, you can have it
to the point where you are tracing from the
tip of the blade over here and then sweeping the
blade across over here and tracing to the tip
of the blade over here. Instead of getting this arc that you think you're going to get, you end up getting like this. And it just cuts right
across the Character's body, and it's super, super short and not
very useful at all. Stabs are also really awkward to do with perpendicular trace. So that's not
something that I've seen as an implementation
in games that have used this other than the
action RPG project, I think, is actually detecting
an attached collider. Most of the games
that I've worked on where you use something like this it works a little bit more like how I've got it set up
here, where, on a frame by frame
basis, you are controlling a number of active
colliders, or sphere traces, or box traces that kind
of all together try to add detected hit Characters. So they're all kind of
bottlenecking together through the mechanism I showed you into the same list of hit Actors. And you activate them
at different points along the Character's arc. This probably seems to people like it is a little imprecise, because look at the size of those colliders versus the size of Greystone's blade. It's a lot of leeway
that's introduced here. And it looks like a really
big area is being hit, but the thing about it is,
in a lot of melee action games, and action RPGs,
and things like that, you actually want extra leeway. Players, as I demonstrated
with this lovely move, don't always have the best depth perception in the world. And having that little
bit of extra forgiveness in the size of the
colliders can help mitigate a lot of frustration
and make it feel more the way that you think that it
should feel versus the way that it would literally
work if you were running a perfect simulation of a blade crossing a Character's path. Additionally,
you can control things at different points in the-- different points
in the collision. So I could set up
extra data for these where the sphere that is
at the tip of his blade does extra damage or has
a high critical hit chance or something like that. It has a magnitude that it
will apply to critical hit calculations. I can set it so that colliders that are closer to his body are weaker, that sort of thing. There's a lot more
control that you get when you start
controlling it this way instead of hoping
for the computer to automatically do
something for you that fits the path of your attack. And likewise,
if you make really, really fancy visual effects-- lots of melee action
games have very poppy arcade-y visual effects with
like an animated arc that shoots out from your
blade to suggest the path of the swing just going shing, like that. And very oftentimes you
actually want the collision to line up with those visual
effects instead of lining up with where the blade
seems like it should hit. And so that's another
reason why you would want to do that to
control the extra length. The way I have it set up here is not necessarily the best way to build it. This is like a prototype version of that kind of system that you're controlling on a frame by frame basis like this, but it's functional enough to
get your brain kind of going in the right direction. And it is definitely
functional enough to cause damage to the poor
Unreal Engine mannequin here. What else? What else could I go over with regards to melee collisions? VICTOR: You've got
another seven minutes. You think you can do it? MICHAEL: I think probably this is where I will stop for
now, but to summarize that, there's all kinds of different-- oh yeah, I remember
what I was going to say. The thing I was going to say
is, if I go to the Character's data-- so this HitboxData class
that I've got-- this is not necessarily the
best way to maintain a record of this information. The way that I did this
and found these out was I just dropped a copy of the
anim montage into the level. Montage-- and over here
in the Details panel, I can go to the initial
position and scrub it. And that will give
me the timecode that he's at at
certain points in this. And I can just drop sphere
Actors in here and size them. And I just put him at 0, 0, 0, and put these relative
to his position. And I just copied the location and pasted them inside of these vectors here. And that's how I got
that information. That is a clunky way to
work with this information. If you were doing this in
a production environment, you would surely create a custom editor for this sort of thing and try to almost build
it into the montage editor itself or build it in
a special editor that's like a wrapper around
both a montage, and the data for the
attack, and stuff like that. And you would specify timecode and position spheres in here. And that would be a
much more intuitive way of working with
this kind of thing, but as a prototype for that sort of system, this works fine. For your game,
maybe this is appropriate. Maybe you don't need even
this level of precision, and all you need to do
is make one sphere pop up in front of the Character
when they make an attack. Like an MMORPG is
not going to have amazingly precise mechanics
for this kind of thing a lot of the time,
or action RPGs are not going to have very
precise mechanics for the same kind of thing, like if it's a top
down style action RPG. But if you were making
a melee action game, it would look more like
what I'm doing here. That wraps up what I wanted
to say about it, finally. Sorry about that. I wanted to make sure I
had my base covered there and my caveats out of the way. So any other questions? VICTOR: Yeah,
we can do a couple more. Let me quickly-- I have one that I marked here. MICHAEL: There's probably
a lot of good questions. VICTOR: There are. Some of them I know you
won't be able to cover, but that's why we'll have some of the folks from the team-- they said they were interested in chiming in on the forum announcement post
that we've linked in chat a couple of times. o_dz_o asked, "Can we add new stats
from Blueprints?" MICHAEL: Adding new stats from Blueprints-- so right now, the way that you do that is by going into the AttributeSet in C++. That is not
functionality that is exposed to Blueprint directly, and you would need to-- you would need to create
a way of doing it. Yeah, pretty sure of
that, anyway. If there is a way of doing
that, then I will try to capture it and
try to give some information about how to do it. But I don't think
that that's possible. VICTOR: praise_solek asked, "What are the plans to flesh
out attribute mesh debt?" Sorry. "What are the plans to flesh out attribute metadata tables more? I'd love to see those other
properties get some uses." MICHAEL: So that is something-- that is something that I believe you can customize yourself. The implementation
that is in the default AbilitySystemComponent is like placeholder functionality or just a demonstration
of how it should work. I think that, if you override
the AbilitySystemComponent, then you can take that process over and use the minimum and maximum values as you
see fit for your game. Or if you have a completely
different type of data table that you want to use in
order to keep track of that, then you could do that, as well. VICTOR: All right. KaosSpectrum asked
another question. "What would the
benefit and reason be for using states inside a gameplay attribute, I believe-- GA? I find them finicky to use,
and I'm just not using them." MICHAEL: Gameplay
ability, not attribute. Attributes are just numbers. Yeah, using states inside
of a gameplay ability. So tasks are a structure
that is similar to states. Tasks are the things that you want to use rather than states. They have this concept
of executing and then heading along a different execution path to another task. And you can coordinate
them very easily. And if you're thinking about
implementing a state machine inside of a gameplay
ability, that would be useful if you had-- that would be useful if you
had a really complex ability that you want to use,
like where you enter that-- where you enter a certain
state in the ability, and then that gives you a
series of different things you could potentially do
while you are in that state or while this certain
task is active. That would be
something you could do, but I don't think in
like 80% of the abilities that I would put together
that I would use a state machine for organizing it. I think ability tasks work fine. VICTOR: The theseedofjuna
asked, "Can GAS listen to Character
movement attributes?" MICHAEL: Can GAS-- VICTOR: A-T-T-R. I'm fairly certain that one is attributes. "For example, grant an ability when a Character is falling or at a specific feed" -- speed. Jesus. "And if this is the
case, would you grant them inside anim
Blueprint by casting? Thank you." MICHAEL: Oh, very interesting. So grant them inside the
anim Blueprint for velocity? VICTOR: You could
check for it there. I would think the
default way to go would be with an animation notifier. MICHAEL: I would think
that the way that you would do that is-- so what you can
do is you can make a gameplay attribute for your
Character's current velocity, and that would be an implementation where you're not planning to ever apply a change to it with a gameplay effect because that would
be a little bit-- maybe a little bit-- well, yeah,
maybe a little bit silly. But you would use it to read
the player's current movement speed, right? So that's where
you start breaking my rule about using gameplay
effects only to affect these. I would go ahead and
make CurrentVelocity... GAMEPLAYATTRIBUTE_VALUE_SETTER. And then I would obviously
make sure that it's a UPROPERTY,
go into the Character, and define a function. And then I would have that
call SetCurrentVelocity in the AttributeSet. And that would
basically be my way of capturing it
in a way that can be factored into calculations
for gameplay effects. I hope that answers the
question satisfactorily, because there's a lot
of different things that could mean. VICTOR: Yeah, Juna, let us know if that wasn't the case. Alayaki Ireoluwa asked,
"There was talk"-- and I actually have an
answer from Dave here. "There was talk of making GAS work with the Network Prediction plug-in. How soon can we expect the
Network Prediction plug-in to be fully functional for use? And when can we expect
comprehensive documentation?" Dave chimed in there
in the dock and said they're still iterating on
the movement and physics integration and have-- and GAS will come when we
think the base is solid. And there's currently no
ETA when that will be. MICHAEL: Thank you for
that, Dave. VICTOR: Thank you, Dave. Chat, please thank Dave. MICHAEL: You should thank
Dave for a lot of things. VICTOR: Let's see. Danny B asked,
"Can you pass custom values into a custom
calculation class which are not gameplay attributes?" MICHAEL: Let me
take a quick look at the damage execution here. So I actually thought of that
after answering that question about movement. Theoretically, if you have the source actor, yeah, you can. You can do a calculation class, and then fetch the source Actor from the execution parameters
like you see up here, and then get velocity. And then that would
be a different way of getting the
velocity without going through the rigmarole of
getting a gameplay attribute to reference. The advantage of making
it a gameplay attribute that you can kind of update like that is that you could get a hold of that information in
other types of calculations that are simpler,
where you're just picking attributes to use
from a dropdown. And that'll make it
available that way. But you could totally just
do it this way and just grab that information directly. VICTOR: Let's see. polymorrah asked,
"What is the purpose of FGameplayAbilitySpec, FGameplayEffectSpec,
why do we need these?" MICHAEL: So I am not
familiar with why the naming convention for
those is the way that it is, but I do understand the idea behind what purpose they serve. AbilitySpec and
AbilitySpecHandle are structures that
stick around to tell you information about the
ability and where to find it. Most of the low-level like C++ implementation you would use for abilities, if you're not
triggering them directly through input or assigning
them input codes, or things like that, is going to be using
the AbilitySpec. And what the
AbilitySpec contains is not only a reference
to the ability. Otherwise you could just
give it the class, right? You could give ability by class, or activate ability by class, or activate ability with tags. And that would do fine. The AbilitySpec
contains information about the ability's
level and other metadata about the ability in
addition to the reference to the ability itself. And so it is more informative
and potentially more useful to pass around inside of C++, or in Blueprint if you feel like exposing a lot of that stuff. The gameplay effect handle
is similar to that, where gameplay effects can potentially have a level assigned to it and a number of
stats assigned to it. And I believe that
the EffectSpec contains that information. I could be incorrect. So maybe it's best
to double check that. VICTOR: KaosSpectrum
in chat chimed in. "A spec is short
for 'specification' and holds the information. It is what is used
to hold everything about a pre-compiled
specification with all the magnitudes,
targets, et cetera." MICHAEL: Yep,
that's what I thought. That's what I thought. But yeah, that is why-- that is what the specs are for. It's not just for a
reference to the ability. It's all of that data
that's associated with the current
copy of it that's not embedded in the ability itself. The handles are used
to trace its location and get access to them from
various different places asynchronously. VICTOR: Pequeno0 asked, "Is it possible to define new
gameplay effects at runtime? That is, generating new effects basically on the fly." MICHAEL: That is potentially something that is possible. So gameplay effects don't necessarily have any execution code here in Blueprint
that you can override, but you could conceivably
override a gameplay effect at the C++ level,
add some event dispatchers, and then register events to event dispatchers to have those fire off. Likewise,
Construct Object from Class Grab a gameplay effect here. I don't care about the Outer. Likewise, I could construct one that's just a generic gameplay effect,
and I could conceivably-- if it were exposed,
I could conceivably change all of the variables
that are associated with it and do that on the fly. As it is, it doesn't seem
like those are available as-- excuse me. As it is, those don't seem
to be available as variables that you can-- now there's the gets. Yeah, you can get those. You can read those,
but you can't write those. You could write functions
in a custom gameplay effect class that let you
set those manually with a gameplay effect that's
constructed at runtime. And you could do it that way. Alternatively,
you could create a set of tools that reads through a
bunch of data tables or JSON sheets and automatically
populate your content browser with abilities that match those data tables or those JSON sheets. And that would be like
a custom editor feature that you would have to construct yourself, but potentially a useful one for
if designers want to come up with a data
driven way of handling these and just populate the list in a way that is friendly to them outside of the editor. VICTOR: logicalcuber asked, "Best way for attribute
change callback to change client's
UI automatically?" MICHAEL: Attribute
change callback to-- so this is some functionality
that I have not messed with yet, as a disclaimer. VICTOR: Mike is clearly
not afraid of challenges. MICHAEL: I dive
headfirst into anything that is undocumented
or that has relatively limited documentation. So there's this class
called GameplayEffectUIData. I don't really have insight into what it specifically does, but let's take a quick look. GameplayEffectUIData...
select... [TYPING] 'TestUIData'. Open this up. It doesn't have any
relevant details. It doesn't have any events. This is probably something that has a lot of C++ functionality that isn't exposed. My presumption would be
that UI data is something that you can read when you
construct a gameplay effect and that that is the
mechanism that you can use to apply a
widget to your user interface representing
that gameplay effect. So it would be a
holder for information like what the name
of the ability is, or what the localized
text for the ability is, and what icon to use for
it and things like that. And then you would have some
execution in your own UI that says add this
to the list of icons when you add this ability. And when you remove this
ability, get rid of it. That, at least,
is the theory behind how I think that would work. Let me take a look at
the other UI data class. UIData_TextOnly -- this probably is
more filled out. And yes, it has a description. So I would expect that,
when this gets applied-- I'm not sure where that
routes or how to access it, is the thing. So I'll have to get back to you on that at some other time, unless somebody wants to
chime in with the chat with some insight about that. VICTOR: praise_solek said,
"GameplayEffectUIData just has variables to set
and pull from in a UMG. Something like the name and icon to display of a status effect." MICHAEL: Like what
I described then. The only unanswered
question is how UMG accesses that, which is something
that I'll look into. But that's definitely
a good question. VICTOR: ag858 asked,
"How would one bind a double keypress to a
single activation binding?" MICHAEL: Double keypress, OK. So the input code that I
presented here in Greystone-- you can basically
trigger that arbitrarily. It is-- for me, that input code is the index in this list. So I could create a
Greystone super attack and bind it to a double tap
instead, and that would be-- there are a variety
of different ways that you could
detect a double tap. Let's see if there's
anything in the input system. That's not correct. This is editor settings,
project settings. So I'm wondering
if this has action mappings for double tapping,
and I'm not really seeing it. So that's not the way you do it. You would-- let me think here. So depending on
what type of game you're making, and depending on how this ability works, tapping the button once might
cause an ability to go off, and then it'll be in progress. And then maybe you
want double tapping to change the way
the ability executes. So let's say I want
to do it that way. If I hit Wait Input
Press, then that will wait for the input button for the ability's activation to be triggered a second time. If I-- let's see. Another way that you could do it is having an input buffering system. Let's say you have
a combo system. Right now, the combo system
that is implemented here is very, very brute force. It is the default combo system that the Greystone Asset actually comes with,
with a few modifications to activate abilities instead of just playing anim montages. And this is keeping a count
of the number of times that you have hit
the attack input and resetting it after it loops a certain number of times. You could keep track of the
number of counts like that. And so tap once,
count goes up to one. Tap a second time,
if the count is set to one, trigger a different ability. A way that I would
prefer to do it if I were making a
melee action game is I would make an
input buffering system. And that's where
I would keep enums correlating to the different
button inputs on a game pad. And I would-- every time
those inputs are put in, I would record them
inside of a list that periodically clears itself out. And so I would
hit these buttons, and it would record x, y, a,
b, all those things getting pressed in this
sequential list that's in a stack kind of fashion. And what it would
do is it would check a data table that has
a list of these inputs, or a list of abilities
that are activated by certain sequences of inputs. So the double tap is just x, x. So I look down that data table. I look for x, x. I check it against what is
inside of the input buffer. And if I have input matching
x, x right at the start of that input buffer, then-- if those are the two most recent inputs, I should say, then I want it to activate this ability that corresponds to it inside of this data table. And that's how I get
that second attack. The way that you
manage that system-- I've built one of these. I kind of took notes
from a thing on Twitter that I saw where somebody put
together a really cool input buffering system. And the way that
that works is you can control the double
tap tolerance basically by controlling
the period of time that it takes to clear
out the input buffer. So if it takes two
seconds without an input to clear the input buffer,
then you can go x, one, x. But if it takes like half
a second without input, then you do x, x,
and it'll probably work. If you do x, and then x, then it won't look for the x, x. It'll only look for x. I hope that was easy to
follow, because it's a little tricky to talk
about it without showing it. VICTOR: We all know you're
doing your best, Mike. theseedofjuna had
another question. If you're good to continue,
the team's good to continue, so we can just keep going
through the questions if you want to. MICHAEL: Yeah,
I can go through these. VICTOR: All right. All right,
longest stream of the year. Here we go. In what class-- for the year-- I mean, it's a new year. Anyway, "For AI, in what class would you implement the ASC, and how would you call
the gameplay ability inside behavior trees?" MICHAEL: OK,
so that would boil down to-- I don't know if it already
exists, but let's find out. That would boil down
to creating an AI task. Do I make that through the
normal Blueprints editor, or do I do it-- OK, that's behavior trees. The behavior tree system uses
tasks in a similar fashion to the Gameplay Ability System. It's a very similar
theory where the AI has a concept of a task
that is currently active that can be completed. And when it finishes,
it will fall through to the next
task in the list, and that's how you can
get the AI to behave with particular routines. Let's see. [TYPING] 'AITask'... 'Task'. Let's see. BTTaskNode-- that is
for behavior trees. So not a lot of tasks
created by default. You can create a
task in Blueprint. VICTOR: I think we need to
get KaosSpectrum on here. He's providing answers. He said "The ASC for AI would
be on the Character/Pawn, and activating abilities
via task and/or service via gameplay tag" -- that's
what you're doing -- "...triggering the ability. This is one of the
most popular ways." MICHAEL: Yes. That is precisely how I
would recommend to do it. So yeah, you would just
make an ability task. You would get the
Execute function, and then you have
the Owner Actor and then Try Activate
Abilities by Tag. And then you feed
it this gameplay tag container containing what type of ability you want to use. And this would be a way to make it generic so that the AI is-- so that the AI
can kind of use it blindly without knowing
exactly which melee abilities it has at its disposal. In terms of listening for
the ability to be completed, let me see if there's any event dispatchers or anything. Basically, the thing that
you need to do is call-- let's see-- Finish Execute. There it is-- based off of
when this ability finishes. And the frustrating thing about Try Activate Abilities by Tag is that this isn't outputting an AbilitySpecHandle that I can use to keep track of this. That would be the
way I would do it, is I would get an AbilitySpecHandle out of this. And let's see. Try Activate Ability by Class. That's also not giving
me an AbilitySpec. But that is what I would
do, is I would create something
that would output a handle that I could then use to
call Finish Execute based off of an event dispatcher when
this thing gets finished. Or actually, come to think of
it, let's see. That's not what I need. The other thing you could
do is you could probably apply it inside the AbilitySystemComponent, as well. You could make the
AbilitySystemComponent host to an event dispatcher
that could then fire off the Finish Execute here after you kind of do that. I would try to do it
based on the ability itself instead of using
the AbilitySystemComponent, because that could
potentially fire off when anything executes. You want it to fire when this
specific ability executes. VICTOR: Let's see. ak_them provided a question that Dave also gives an answer to. "Can a gameplay cue be--" I need some more caffeine. "Can a gameplay
cue be programmed or linked to a Niagara system?" MICHAEL: Yes. A gameplay cue is
really just a vehicle for having something happen
when a gameplay effect gets applied to an actor. So going to gameplay
cues, damage cue. Yeah,
all you would do is you would tell it to spawn the
emitter at location, and you would feed a
Niagara system into that. And that's all you do. Then it'll fire off the Niagara system like any other particle. The ones here are
all legacy particles because that's what comes
with the Greystone pack, but there's no reason you can't do this with Niagara, as well. If you're asking about having
a gameplay cue fire off based on something that's happening
in a Niagara system-- like the Niagara system
fires the gameplay cue-- that sounds pretty
off label to me. VICTOR: Dave said that
that's specifically not really possible. MICHAEL: Yeah, that doesn't seem like something that I would want to have-- that I would want
to have happen. You basically want the flow of this to be gameplay ability causes effect. Effect causes gameplay cue. And that's how it should go. It should be driven by the-- my dog is poking me
in the leg something fierce while I'm
talking, and it's making it hard to concentrate. Say hello, Douglas. That's a good boy. VICTOR: Hello, Douglas. MICHAEL: He's a good boy. But yeah,
the intended flow of this is ability, effect, and then cue, not ability, effect, cue, then another effect
based on the particle that the cue spawned
and stuff like that. You can-- if the particle
coincides with an area of effect or something
that you want to detect, then you could just make a
completely cosmetic gameplay effect and have that trigger-- add that gameplay
effect to the Character. And then that gameplay
effect will have the cue that you want to use. VICTOR: This could be a follow up question a little bit to the question in regards
to a double tap input. loraesh asked, "How would one go
about recreating the one, two, three melee attack combo that, for instance, Greystone ships with
on the Marketplace with pure Gameplay
Ability System?" MICHAEL: So, well, it is here. I am using the one,
two, three combo that he ships with
on the Marketplace. All I did was I took
the execution here, and I changed the anim
montages that he was playing with Activate Ability. And I feed it the index number of the ability in his ability list as I've initialized it. And that's all I'm
doing to activate these. Likewise, you could use
the input buffering system that I talked about. And an input buffering system-- it compiles a list of different inputs that you've pressed, and then you use-- you create functionality that is like a switchboard that says, if I match this string of
input, if the latest inputs match this string of inputs,
then execute this ability. And so when you do that, if you want to do
a three hit combo, you have an input for x. And that will execute
the first attack. You have an input for x, x. That will execute
the second attack. You have an input for
x, x, x, and that'll execute the third attack. That's a very involved
piece of functionality. That is one that I would love to demonstrate for people maybe at a later time. But that's the way that
I would put it together if I were making a melee action game or a fighting game. If you're doing it using
Gameplay Abilities, it is actually possible to
set up a gameplay ability to encompass all
three hits of a combo. You don't have to make them
separate abilities the way that it's set up here. It just so happens
that Greystone came in with these three anim montages for his melee attacks, and I was able to
use them separately. What you would do instead is,
when you activate the ability and you play the montage, you would give it
a Start Section. And you would give it
Attack1 for one section, Attack2 for another
section, and then Attack3 for another section. And those would all be contained in one continuous anim montage that is divided
up into three sections. So when you're editing it
in the montage editor-- I'll even show you the
animation that's got this. Where is his-- have to
scroll down to him here. Go down to Greystone. Let's see, attack A.
Does he actually have all three attacks at once? It doesn't look like he has all three attacks at once here, but that is a way you
could organize it. You would organize the animation with the complete combo in one anim montage if you wanted to support it that way. And then you would
tell it to trigger the different sections of the
montage based on the input. Maybe not wait
for confirm input. So if it's assigned to
a button press input-- and this can listen
to all the same input events that you
use in Blueprint, but it's better practice to use the one that it's assigned to. So Wait Input Press. I could use this, and then I could create the Count in here. And I could use that every
time it gets pressed, and then Switch on Int. And then this would
go to Attack1. This would go to Attack2. This would go to Attack3. Much like how it worked before, I would make this leap back around to zero after it hits-- whenever it hits three. Set it up like that,
give myself a little space. Space. Didn't want to do that. And probably a sequence
instead so that it's not-- so it's a little more organized. So first I check if it's three. If that's true, select. Count here. And then-- not
actually what I want. That's the node that I
wanted-- was Select Int based on a Boolean. If it is greater
than or equal to 3 is what I should do here
just to be extra, extra safe. If greater than or equal to
3, then pick 0. Otherwise keep the normal count, and then set that value. VICTOR: Do you think
some of these things that you've been
working on as you've been answering questions
might make it up into the [INAUDIBLE]? MICHAEL: Yeah,
I'm not getting rid of it. Of course, I'll keep it around for educational purposes. VICTOR: That's what
we like to hear. MICHAEL: OK,
so this will increment it. And if it turns out to be-- if it turns out to be a
value of 3 or greater, it will loop it
back around to 0. Otherwise it will
keep that value. This is probably a
really clunky way of doing this when I
could have just copied what's going on here. And then it will pick
which montage to play, and basically
while it is active, you probably don't
want to listen to-- listen for Attack1. You probably just
want to keep 1 and 2. And Attack1 is the one
it'll play by default, and then after Attack1
starts playing, you start listening for
wait for input press, and just put it through
the output node here, the output pin here. And then that's where you start evaluating that sort of thing. And then the tricky
part about this is the variable length of
execution, getting to the EndAbility node here. You need to be able to-- you need to be able to
determine the difference between completed
and interrupted. If one of these other
montages is interrupting it, you don't want it to
prematurely complete. So you might wait for a second after each one of these is done, and you might
cancel that wait in order to determine when you
get another input in, is what I'm trying to say. So that's an example
of how you would encapsulate the full combo
inside of one ability. VICTOR: Let's do-- I got two more here. There's more questions
still, but we'll have to try to
tackle some of them. We're over the three hour mark. Good job, Mike. I can even see how it's getting dark in your room over there. MICHAEL: Yes. It's getting dark,
and the dog is hungry. VICTOR: Yeah,
mine needs to go, too. loraesh asked another question. "This was the first time I
saw gameplay attributes get initialised from a data table. Normally,
I saw gameplay effects being used to just grant
you the values and apply them on yourself
at begin play or something. Both work, obviously, but is one of these approaches preferred?" MICHAEL: The data
table is preferable. Using a data table or
some similar method for kind of bottlenecking where the information comes from. If you're using gameplay
effects to initialize it, then you need to edit all those individual gameplay effects in order to change what those
values are every time you want to change them. And it's not necessarily exposed in a designer friendly way. Data tables are
designer friendly. Data tables-- you can import
a data table from Excel. And so you could
have a repository of these either on Google
Sheets, or on a secure drive somewhere,
where designers can edit them willy nilly without ever
having to open the editor. And then you can import
them when you need them. And that just makes
it a lot more flexible to initialize these. VICTOR: It's super easy to
manage all kinds of things using data tables--
just the fact that you can get an entire overview of sort of all of your Characters, the damage the
weapons are doing, the amount of health they have, how much [INAUDIBLE] gives, especially much more convenient to use and work like that when you're sort of trying to
balance instead of opening up each individual class, having to set
[INAUDIBLE] for sort of the producer, et cetera,
to keep track of all of that, as well. MICHAEL: Yeah,
depending on the type of game that you're making,
other initialization methods might be preferable. But if you parameterize it
in a data table like that, or if you find a data driven
way to keep track of it, even if your game
isn't necessarily something like
Paragon, which has this incredibly sophisticated
series of stats that are driving everything,
it just gets easier for you to do your job. VICTOR: All right, and then for our last question, Alexander Flodén asked, "Is it easy to
transfer a prototype ability made in Blueprint with this to C++ later on, or is this system very
Blueprint-centric?" MICHAEL: You are meant
to interact with ability tasks using Blueprint. That is their
intended use cases. You make an ability
Blueprint, and you shuffle around tasks
inside of the graph to figure out how you
want it to execute. It is meant to be very easy
to iterate on an ability, and they're meant to not
be extremely verbose, and they are meant to-- through the task
system, they are meant to have reusable
parts that you can just pull out of a box
of building blocks and put together whatever
ability you want with it. You could theoretically derive a gameplay ability from a-- in a C++ class. In fact, it's not theoretically. You probably should derive a
base gameplay ability class in C++ to add whatever boilerplate functions that you want for designers to be
able to interact with. And you can very likely put
together your ability tasks there, as well, using the status functions that are defined in C++ for each of
those individual tasks. It's just not going to be a very intuitive way of coordinating ability tasks compared to
seeing the node network. And the whole point of this
is to make this less verbose. VICTOR: I said that
was the last one, but I have another one. loraesh asked, "Is there any
official interaction between GAS and
the built in damage feature that's on an Actor?" MICHAEL: No. VICTOR: All right. And with that, thank you so much everyone for hanging out today. I know it's been a long stream. I hope you learned a lot. Mike, big ups to you
for sticking with it and answering all of our
questions in such detail. For some of the other
questions and follow ups, as well,
that we didn't get to, make sure you check out the
forum announcement post. I know Dave said that he
wanted to go ahead and tackle some of them. So hold our thumbs and
toes, and we might be able to see a little
bit more information from him there. Let's go ahead and paste
that in chat again. And then if you stuck around
with us from the start, make sure you hit
that follow on Twitch. We're live every Thursday--
almost every Thursday, I should say. There are a couple of ones
in the year when we're not, but we try to hit all of them. If you new to game
development, and you'd like to get started
with Unreal Engine, make sure you check
out unrealengine.com. You can download the Engine for free through your Launcher. If you already have
Launcher installed, you can just go ahead, and go to the Unreal Engine tab, and get it. Easy peasy. If you are curious about some of the stuff we mentioned, and you weren't sure about how
the word is spelled, what to Google for and look
for, we do transcribe all
of our livestreams on the channel, which means
that, after-- usually within five to seven days after the file goes up on YouTube, we also provide the
file for the transcript. So this also means
that the captions you can turn on
on the stream will be accurate to what was
said in terms of spelling, and not just the automatic
ones that YouTube applies. It's another good way
to go ahead and go hit Control-F, search for a term
you're looking for. And you can also
find the timestamp next to the sentence
that was said. And you can go to that
portion of the video if you wanted to hear what was talked about more in depth over there. We do put timestamps
on the video, as well, now, which is great. If you're curious to find
more like minded people who like working with Unreal
Engine, make sure you check out
communities.unrealengine.com. There are clearly
no in-person meetups going on around the
world-- maybe New Zealand. I haven't actually checked. Probably should. I don't even know if there's
a meetup group over there. But they do organize virtual
hangouts in their Discords and elsewhere, so go ahead and check that out. If there are no
local UE4 communities near to you,
and you're looking forward to being able to host them once we come back from the pandemic, make sure to fill out--
there's a form out there that you can apply to become
a community group leader. We'll go ahead and
get in touch with you. Make sure you let us know
all the cool things you're working on. There are many good
places for that-- Twitter forums,
UnrealSlackers.org. We check them all. We'd love to see what
you're working on, and occasionally we
feature you as part of our community spotlight at the beginning of these streams. We're still looking for
more countdown videos. It is 30 minutes of
development that you record. Fast forward that
into five minutes, and send that to us
coupled with your logo. And then we'll go ahead
and composite the countdown on top of that. So logo, video, separate. If you stream on
Twitch, make sure you use the Unreal Engine tag, as well as the Game Development one. That's the best way for
us, as well as other people in the community, to find you when you're live. And we are going to go ahead
and raid someone today. I think I saw a couple of people that are currently live. As always, make sure you follow us on social media for all news Unreal. And if you're watching
this on YouTube, make sure you hit
the notification bell so they can see all of
our cool videos coming out. I know the evangelism team
are prepping more content coming out in the next couple of months, which is great. If you haven't checked
out the water one from Sjoerd make
sure you do that. Also, Paolo's, what is
it, 25 minute presentation on AI, stealth AI-- it's phenomenal. Just watch it if you're
curious about learning that kind of stuff. MICHAEL: I got to
check that one out. VICTOR: Yeah. It's great. Next week, we are going
to cover the Movie Render Pipeline explicitly. Let me get the topic. Of course I didn't write that. Anyway, Movie Render Pipeline. We're going to have Andy
Blondin, and Matt Hoffman, and Max Chen on the stream. It's going to be great. I'm excited to see them. Going to cover that a little
bit more in depth than we've done previously. And then last but not least,
Mike, thank you so much again for coming on the stream. I know we both have to
take our dogs out now because they're getting antsy. MICHAEL: It is my
absolute pleasure. And I want to give thanks to the other members of the team who helped me wrap my head around
this system to the extent that I have. I want to thank Dave Ratti for chiming in in the comments. And yeah, thanks, everybody. Thank thank you, the audience. VICTOR: Thanks to all of you. And as always,
we'll see you next Thursday again at 2:00 PM Eastern time. I hope you stay safe
over the weekend. And take care. Bye, everyone.