Welcome.
In this video, we're going to make an actor that can change our attributes.
We'll often want some sort of object in our world that we can pick up that will affect our attributes
in some way.
So I'd like to have an actor that's sort of generic all purpose that we can use that has the inherent
capability of changing attributes.
Now we already know that the preferred way to change an attribute is through a gameplay effect, but
we haven't learned how to create and use gameplay effects just yet.
So we're going to make an actor that will change an attribute directly and we'll see the limitations
of doing it that way and we'll create a sort of to do basically add a comment that says we plan on changing
our system to use gameplay effects in the near future.
So let's make a new actor class.
I'm going to go ahead and launch the editor.
And we'll make a new C plus plus class.
So I'm going to go into C plus plus classes, Aura public and right click and make a new C plus plus
class.
And this is going to simply be an actor.
I'm going to click next and I'll put this in its own folder called Actor.
Now, this will be a sort of generic class that will apply some sort of effect.
So I'm going to call this aura effect actor and create the class.
I'll go ahead and close the editor and open up my new actor here in Writer.
So here's aura effect actor wkRP.
And I'll go ahead and open up the header file as well.
Here we go.
And I'll drag them over to the left here.
Now, aura effect actor is going to be pretty simple.
We'll make this much more versatile in the future, but for now I just want to be able to overlap with
or affect actor and apply some kind of attribute change.
So for now I'm going to remove the tick function.
I'm going to remove the comments that we get here by default and in the CPP file, I'll remove the tick
function here and remove these comments as well.
And because we don't need to tick, I'm going to set this to false primary actor.
Tick B can never tick.
No ticking behavior, at least so far.
Now, aura effect actor needs some kind of overlap volume.
I'm going to opt for a sphere and this will be a private variable.
So I'll make a private section and add a T object pointer of type use sphere component.
We'll go ahead and add a forward declaration for that.
Thanks to writer for the shorthand and this will be called simply Sphere and I'll give it a new property
with visible anywhere.
And that's all we need for now.
Let's go ahead and construct it.
So here in the constructor we'll say sphere equals.
I'll use create default Subobject specifying use sphere component and thanks writer for the auto include
there and the native name will be simply sphere and we can make the sphere the root component or we
can attach it to the root.
Either one is fine.
I think what I'd like to do is have a static mesh as the root and attach the sphere to it.
So we can go back to the header file and we can add a static mesh component.
This can be a T object pointer of type use, static mesh component and we'll call this simply mesh and
make this also visible anywhere so we can go back and construct our mesh.
Since I'd like to make the mesh the root, I'm going to put it above the sphere.
So I'll say mesh equals and we'll use create default subobject with use static mesh component this time
and call this simply mesh and we'll set the mesh as the root.
So we'll say set root component mesh and we'll attach the sphere to the root.
So we'll say sphere setup attachment, get root component.
That way, if the mesh moves, the sphere moves with it.
Now we just need a overlap function to call when Sphere overlaps with some other actor and we'll go
ahead and make an end overlap function as well.
And this is all stuff you should be familiar with.
We'll make the overlap functions and they can be public.
We're going to make a virtual function.
It's going to be void.
We'll call it simply on overlap.
Now, the on overlap function signature needs to have a number of input parameters to make this function
bindable to on component begin overlap on the sphere and I'll quickly show you how to figure out what
those input parameters should be.
But first we're going to add them.
We're going to say you primitive component.
That's the first one.
That's a pointer called overlapped component.
We have an a actor called other actor, another you primitive component.
Called other comp and in 32 called other body index.
A bool called B from sweep and a const F hit result.
Reference called sweep result.
And this must be a new function.
So we'll add the new function there.
And this is a function we can bind to on component began overlap.
So we'll generate the function.
Here's the definition and we'll bind this to on component began overlap on our sphere which we must
do in begin play.
So we're going to say sphere on component begin overlap.
Dot add dynamic as this is a dynamic multicast delegate.
We pass in the user object and the callback function which will be the address of a or effect actor
on overlap.
So this is the basic way to have a callback function fired off in response to something overlapping
with our sphere component.
And I mentioned I'd tell you how I knew this function signature.
If you don't know how to figure that out on some kind of delegate, you can right click and go to the
definition of that delegate we see here on component began overlap belongs to primitive component and
this is its type.
We can go to the definition of this.
And we see that it's created here with declared dynamic multicast, sparse delegate and this delegate
of type F component began overlap signature is defined using this macro.
And here we see the input parameters required for any callback that will be bound to this delegate.
And here's F component end overlap signature the delegate for end overlap events.
If we want to bind a function to that, then here's the list of input parameters that a callback must
have to bind to.
This type of delegate and primitive component has one called on component end overlap.
So we can copy these parameters and we can make our end overlap function here in effect.
Actor So we're going to make a virtual void function called end overlap.
And I'm going to paste in those input parameters.
Now in the declared delegate macro, the type is separated from the variable name and the first two
here are you primitive component and on component end overlap.
That's going to be the name of the delegate itself.
We're going to remove those two.
The syntax may change from version to version in older versions of the engine.
We didn't have these first two there, but the function signature begins with a primitive component
pointer called overlapped component.
So removing the comma between type and name.
There.
For each of these, we can see what that signature should be.
So this is kind of a little trick that you can use if you want to know the function signature for any
function that can be bound to a given delegate.
And throughout this course, we're going to be making lots of our own custom delegates.
So we'll be seeing more and more of the inner workings of how these relationships work between delegates
and callbacks.
But for now, we're just binding a pair of callbacks to delegates on the primitive component type from
which sphere is derived.
So let's go ahead and generate the end overlap function definition and we'll go ahead and bind end overlap
to the sphere.
So we'll say sphere on component end overlap.
We can hover over it and see that this is a component end overlap signature delegate and we can bind
with add dynamic.
We can bind to this object and it's going to be the callback.
Aura effect actor end overlap like so.
So for actors that have overlap volumes that you want to trigger off some kind of function call in response
to overlaps.
This is all very much boilerplate, right?
We call this boilerplate because it has to be done.
If you want an actor that can overlap something.
Now for actually defining what to do when we overlap, that's what we really want to figure out here
is what do we do when we overlap with something?
Now we'd like to change the value of one of the attributes in the attribute set for Aura.
But we know that to do that, we should be really applying gameplay effects and that's why we call this
effect actor.
But until we learn how to do that, we're just going to change a value such as the health attribute
on Aura, and that will give us the opportunity to learn how we can access auras, attribute set and
her attributes.
But we'll also learn how this is a very limited approach that restricts us in a lot of ways.
We don't have a lot of freedom and flexibility.
So first let's learn how we can access the other actors ability system component on overlap since we
have access to the other actor, the actor that overlapped with this particular sphere component, We
can see if that other actor has an ability system component.
Remember in the owner actors where we constructed our ability system component, we made sure to implement
a specific interface related to the ability system.
If we go to say, the player folder in the public folder here or a player state, we see that we made
sure the Aura player state is derived from AI ability system interface and that interface has a pure
virtual function get ability system component.
Now this is very nice because we can take any actor and see if it implements this interface.
And if it does, we can get the ability system component that belongs to that actor.
So we really don't have to care what type that actor is, whether it's a character, a pawn or just
an actor.
If it implements the interface, we can call get ability system component on it.
So here in on Overlap, what I'd like to do is take the other actor and cast it to an AI ability system
interface.
So I'm going to make a local AI ability system.
Interface pointer called ASC interface for lack of a better name.
And I'm going to cast to I ability system interface.
The other actor itself.
And I can wrap this in an if statement.
I can say if this doesn't return a null pointer, then ASC interface will exist within the scope of
this if statement.
And what I can do here since I have the interface is I can find the attribute set.
Now I know that aura attribute set has a health attribute, so I can find an attribute set on this ability
system component of that type if it has one.
Now this is a very limited approach.
Again, once we use gameplay effects, we won't have to care what the type of the attribute set is.
If we want to change some sort of value of an attribute.
But for now, until we learn better ways to do it, we're going to learn how to get that attribute set
from the ability system.
So what we do first is we take the interface which we know implements.
The pure virtual function get ability system component.
Now we can assume that that ability system component will be a valid pointer.
So far in our game we haven't implemented this function on any actors.
That should return a null pointer if we call it.
So I'm not going to bother checking it to see if it's null and from the ability system component I'm
going to call get attribute set.
Now get attribute set is a function that requires a subclass of based on you attribute set.
A subclass of is a new class that we can specify so that the ability system component knows which type
of attribute set to look for if it has one.
So we want to search for you or a attribute set.
That's the class of the attribute set so we can use you or a attribute set static class which will satisfy
this input of type T subclass of.
So this whole expression here is going to return an object of type you attribute set.
So because this returns a you attribute set we are going to want to cast to you or a attribute set.
So I'm going to wrap this all in a cast.
We're going to say cast to you or a attribute set and we'll wrap this up and we can store all of this
in a local you or attribute set pointer called ora attribute set.
And this has to be const because get attribute set returns a const you attribute set.
So we'll add const to this.
And now we have the other actors ora attribute set if it has one.
Now in our game, all of our actors that implement the ability system interface have an Ora attribute
set.
So we know that this should be a valid pointer.
In this case, I'm not going to bother checking if that is null.
I'm just going to take Ora attribute set and we're going to do something.
Now notice we have access to health mana, get health, get mana.
We have these attributes which are public and those attribute accessors thanks to the boilerplate attribute
accessors macro so we can set these values I'm going to call set health and set health requires a float.
Well, I can get the Ora attribute set and call get health and I can add some value.
I'm just going to hardcode a value, say 25.5.
Now we see the red squiggles here because, well, this is a const you ora attribute set.
So we can't really change things if it's a const pointer and that's for our protection.
This is something that the ability system enforces.
We shouldn't be setting the health directly on the Ora attribute set like this.
The Ora attribute set should either set its own attribute values or have those attributes changed in
response to gameplay effects.
So already we're doing something that we shouldn't be.
But since this is for learning purposes only, before we fix this up to have a better design, we're
going to break the rules a bit just so we can set that health value and see it change.
So I'm going to go ahead and give myself a semicolon here that I was missing for this line and ora attribute
set since it's const, well, I'm going to cast away the const ness of Ora attribute set.
Now this is kind of a big no no in programming.
It's not something that you want to be in the habit of doing, but we're going to do this with a big
fat to do, to change this to a better system.
So before I break the rules, I'm going to add a to do comment here that says change this to apply a
gameplay effect for now using const cast as a hack.
So we got this big fat comment telling us that we're doing something we shouldn't be doing and that
we have a to do to change it.
So what we're going to do is create a U or a attribute set and set it equal to the result of a const
cast where const casting to type u or attribute set.
And because we're using const cast, we need the asterisk here and what we're casting is ora attribute
set and we're going to call this mutable ora attribute set and we're going to use mutable ora attribute
set to call set health.
So.
We have a const pointer.
You're not supposed to change const pointers, but if you want to break that rule, we have the power
in C plus plus to do that.
This is something you should use extreme caution with.
All we're doing is breaking encapsulation here and throughout this course we're going to make sure to
maintain proper encapsulation and good coding practices.
But as we would like to simply see the value change, we're going to cast away the consciousness of
this pointer so that we can mutate it.
And of course, once we learn about gameplay effects, which is going to be very soon, we're going
to instead have this function, apply a gameplay effect and we'll see the benefits of that.
So we now have a function for on overlap that will take the health on the attribute set of the actor
that overlapped with it and set it equal to its own health plus 25 and we won't bother with an end overlap
implementation just yet.
All we're going to do here is if we do this, we'll go ahead and destroy the effect actor itself.
So we're just going to call destroy here and now we just want to test this out and overlap with it in
the world and see our health value change.
And that's going to be your quest.
I would like you to create a health potion.
So create a blueprint based on or an effect actor.
You can call it BP Health potion, if you like, and set its static mesh.
Look for the potion bottle static mesh in our assets folder and you can set that and then test the attribute
changes.
Place one in the world, overlap with it and with show debug ability system.
See if you can see that health value change.
So pause the video and conquer this quest now.
Okay.
I'd like to make a blueprint, so I'm going to go ahead and run this.
I'll go ahead and run in debug mode.
And here in the editor, I'm going to go to my blueprints folder and make a new folder here.
I'll go ahead and call this actor.
So we'll place our actors in here and I'll make a new blueprint class and I'll search for aura effect
actor and choose that.
And this will be called BP Health Potion.
And I can open this and I can set the mesh.
I'm going to search for potion bottle.
Here it is.
And there's my potion bottle and I can see that it looks a bit too big.
I'm going to drag one into the world and see how big.
Yes, it is too big.
So I'm just going to scale it down here.
I'm going to multiply the mesh by 0.2 for the scale.
Now that's of course going to scale the sphere down.
So I just need to increase that sphere radius there.
And now that I have a health potion, I can test this out in the world.
I'm going to save all first and press play and hitting the tilde key.
I can type show debug ability system to see the value of my health and if I run up to the potion, I
pick it up and my health is now 125.
So our health potion is increasing our health by 25 as expected.
Perfect.
So we now know how we can access the ability system for any actor and we can access the attribute set
of an actor with get attribute set.
If we pass in the subclass of or the U class for the type of attribute set we'd like to find on that
ability system component and get attribute set returns a const pointer to that attribute set.
And we learned that we could sort of bludgeon our way past that Constness by casting it away with const
cast.
Now you should know that const cast is not something you want to use as a matter of habit.
It's something that you can use if you don't quite know yet how you're going to do what you want to
do, but you're trying to figure out ways to make things work.
It's one of those ways that you can break the rules to get things working, but seeing this in your
code should be a reason to sit and kind of try to think of a different solution that can allow you to
not violate the consciousness of your code base.
And in our case, we made a very blaring comment to tell us that we do plan on removing the requirement
to const cast.
In fact, that's not really the biggest problem here.
The biggest problem is that our aura effect actor is very, very specific.
It changes the health by 25.
Something like effect actor should be able to apply any effect to any attribute in any number of ways.
It should be versatile and reusable and shouldn't have to violate the const ness of any pointers, and
that's going to be what we end up doing here.
So that's why we have the to do for now.
We know that we can access and change attributes for our health and so far we can only see that change
by showing the debug information for our ability system.
But in an actual game we're going to want some HUD elements.
We want a UI with health bars and icons and things that show us what's going on.
And so we're going to want to set up a nice system for seeing our health, and we'll do that in the
next section.
So great job and I'll see you soon.