A Guided Tour of Gameplay Abilities | Inside Unreal

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
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.
Info
Channel: Unreal Engine
Views: 157,285
Rating: 4.8991594 out of 5
Keywords: Unreal Engine, Epic Games, UE4, Unreal, Game Engine, Game Dev, Game Development, GAS, Gameplay Ability System
Id: YvXvWa6vbAA
Channel Id: undefined
Length: 201min 27sec (12087 seconds)
Published: Thu Jan 14 2021
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.