Afrikaans
Akan
Albanian
Amharic
Arabic
Armenian
Azerbaijani
Basque
Belarusian
Bemba
Bengali
Bihari
Bosnian
Breton
Bulgarian
Cambodian
Catalan
Cebuano
Cherokee
Chichewa
Chinese (Simplified)
Chinese (Traditional)
Corsican
Croatian
Czech
Danish
Dutch
English
Esperanto
Estonian
Ewe
Faroese
Filipino
Finnish
French
Frisian
Ga
Galician
Georgian
German
Greek
Guarani
Gujarati
Haitian Creole
Hausa
Hawaiian
Hebrew
Hindi
Hmong
Hungarian
Icelandic
Igbo
Indonesian
Interlingua
Irish
Italian
Japanese
Javanese
Kannada
Kazakh
Kinyarwanda
Kirundi
Kongo
Korean
Krio (Sierra Leone)
Kurdish
Kurdish (Soranรฎ)
Kyrgyz
Laothian
Latin
Latvian
Lingala
Lithuanian
Lozi
Luganda
Luo
Luxembourgish
Macedonian
Malagasy
Malay
Malayalam
Maltese
Maori
Marathi
Mauritian Creole
Moldavian
Mongolian
Myanmar (Burmese)
Montenegrin
Nepali
Nigerian Pidgin
Northern Sotho
Norwegian
Norwegian (Nynorsk)
Occitan
Oriya
Oromo
Pashto
Polish
Portuguese (Brazil)
Portuguese (Portugal)
Punjabi
Quechua
Romanian
Romansh
Runyakitara
Russian
Samoan
Scots Gaelic
Serbian
Serbo-Croatian
Sesotho
Setswana
Seychellois Creole
Shona
Sindhi
Sinhalese
Slovak
Slovenian
Somali
Spanish
Spanish (Latin American)
Sundanese
Swahili
Swedish
Tajik
Tamil
Tatar
Telugu
Thai
Tigrinya
Tonga
Tshiluba
Tumbuka
Turkish
Turkmen
Twi
Uighur
Ukrainian
Urdu
Uzbek
Vietnamese
Welsh
Wolof
Xhosa
Yiddish
Yoruba
Zulu
In this video we're going to create the charge shot ability.
And things do get a little bit more complicated here.
So if you find it hard to follow along, please make sure to use the controls on the video to maybe
play a 0.5 speed and slowly follow along.
But everything you're learning here is going to be very important and going to set you up to create
your own abilities in the future.
And it's also going to show you the kind of problems that can come up in the edge cases, and how we
fix these in these Mega man clones, a charge shot ability is a staple, and you can hold the button
to charge up your shot.
And if you wait a set amount of time, if you let go, you get a stronger version of the projectile.
Before we get into making the projectile itself, let's just first go into the player and see how we
can even detect if we hold the button and when we let go of the button.
So in the player we can see the IA shoot event.
If we look for it, we have the Beginplay I jump, I move and IA shoot right?
So if we let go of the button we then want to decide do we shoot the irregular projectile here or do
we shoot the.
Or do we shoot the charged projectile which we're going to create later?
And if we open this up, you can see that we have a lot of different things here, like elapsed seconds
and ongoing and triggered seconds.
There's a lot of things here we can use.
However, to enable these we need to change the input action for the shooting a little bit.
So in the content drawer we can go to content go to Input and Actions.
And we have our IA shoot.
But actually what we change is not in the action itself.
It is in the IMC action the binding.
So in here where we go to the IA shoot, there is a trigger which we want to implement.
And in here if we click we have a bunch of options here like down hold, hold and release pressed and
all of these different things.
But the one that we want to use is released because we want to check when did we release the button,
and if enough time expired for us to be able to use the charged shot or not.
And here make sure to save.
And now in the BP player, well, we can just close all of these things down.
Let's just open up the BP player.
Nothing else.
And here we now have access to the elapsed seconds.
So now on completed which happens if we let go of the button we can just print string.
And we can look for the elapsed seconds.
And let's try this out.
I can still shoot normally, right?
But now I'm holding the button and I let go now.
And you can see we held the button for 2.5 seconds and I hold it again.
I let go and you can see like how long I'm holding the button.
So let's say for example we want the charge projectile to work after two seconds.
Then we simply check for this number and then decide if we are allowed to spawn the charge projectile
or not.
So this is the first step.
This is working.
But now we have to actually create these projectiles.
And the good thing is that we already thought ahead with our inheritance pattern, right.
So so far we only created the base, we created the player base and we created the regular one.
But now what we want to create is the partially charged shot and the fully charged shot based on the
player projectile base.
And then if we let go of the button, we simply have to decide to respawn.
Nothing.
Do we spawn the partially charged shot or do we spawn the fully charged shot?
So back in the content drawer, let's go to blueprints.
Go to projectiles.
And here in the player we have the BP player projectile base.
Right click this and create Child Blueprint class.
And let's do the partially one first.
So BP player projectile.
Partial charge.
In here.
We don't really want to do much.
Just open it up and we want to just change the color.
I don't have a different animation.
I don't have a different flipbook for this one because there was none in the assets.
But we can easily make this look different from the basic one by going to the sprite color here and
just making it purple.
And this is just so we know that this is the partially charged shot.
It's different than the regular shot.
And if you wanted to you could go here on the right side and you could adjust the projectile damage
to maybe two instead of one.
But this depends on what you want to do.
I believe in the original games, it actually has only the same damage as the regular projectile, so
I'm just going to keep this as one.
The fully charged one is going to be three damage.
So if you wanted, you could actually set this to two damage.
And this is all we're going to do for the partial charge shot.
So just go out here.
And now again from the BP player projectile base right click Create Child.
And let's create the BP player projectile.
Full charge.
And open it up here.
We actually want to change a couple of things.
Well, the first thing is we want it to deal three damage.
So projectile damage three it should deal more damage.
This is going to be used if you have to fight airborne enemies and you need to time your shots.
It is going to be beneficial from a gameplay perspective to use the charge shot.
The next thing we want to change is the paper flipbook.
So here for the source flipbook we can just look for shoot charge, right?
We have the player shoot charge one and you can see this is it.
Right.
And we might want to adjust the sprite location a little bit.
Just move it backwards a little bit to make it a bit more accurate.
And this is again everything we have to do for this fully charged shot.
And why is this so easy?
Because we have been using inheritance.
We have been thinking about our pattern from the beginning, and it makes it very easy to just create
variants like this.
And now that I think about just to give the charge shot a little bit of more utility, we can also just
change the speed, make it feel even more powerful.
So let's just go for 1300.
We don't want it to change too much, but just make it a little bit faster.
Make it a little bit more snappier to make it feel even more powerful.
Let's go back to the player blueprint.
You can just close this down and yeah.
So now here after completed, we want to decide if we actually want to spawn a projectile or not.
But we will also keep this code on start right because we want to shoot a projectile anyway on start.
And we want to make all of this reusable, because now if we just copy paste all of this, it's going
to be a little bit of a mess.
And we just want to be able to just pass the class in here, the pseudonym, the duration, everything
is going to stay the same.
So we just want to create a function where we can pass the shot energy and where we can pass the class,
and we can then just give it different parameters for the partial shot, for the fully charged and all
of these things.
But all of the things we are doing here on started, like shooting the regular projectile.
We're still going to use this as it is, but we want to reuse some of these things so we can then use
them at the bottom here when we shoot a projectile.
And the first thing I want to do is take care of the shoot animation.
So we have the is shooting to true and we have the delay for the shoot em duration.
And then the is shooting here.
So I actually want to separate this from here.
So we can use alt here.
Go up here and just move it around.
And also take this out here.
And now this is just going to be about the shooting animation, the shooting logic.
Uh, not about the spawning projectile.
Right.
So we can just connect this.
So this is now separate.
This cares about spawning projectiles and the shot energy, and this cares about the shoot anim duration.
So here we can just make another custom event.
And call it trigger.
Shoot Annam like this.
And now, instead of having all this here, we can just call trigger shoot anim here.
And all of this is going to happen during the same frame.
So you might think we want to play the animation first and then shoot the projectile.
But everything happens during the same frame.
So there's really not a difference in this case.
And now we just want to take this and move it to a different place where it's a little bit less crowded.
Yeah.
Down here.
And again, just to show that the shooting still works, right?
Everything still works the same.
But we just made it a little bit cleaner, a little bit more reusable.
The next thing we want to do is to make the part where we spawn the projectile, where we have the shot
energy being subtracted and the projectile being shot.
We now want to make this more modular, so instead of just doing minus, minus, we want to be able
to decide do we want to subtract one for a regular shot or three for the charge shot?
And also do we want to spawn the charged projectile, the partial charge projectile.
So it's best to just collapse all of this into a function.
So if we have all of this selected, we can just right click and collapse to function.
And just call it spawn projectile.
Like this and move it here.
Right.
So the conditions this is fine.
And in here we just, uh, clean this up a little bit.
And what we want to do now here is we want to be able to pass this class in here so we can just drag
off the class here.
And it creates a new input node.
And I just want to compile and save.
And I want to change the name to from class to projectile class.
And this works fine, but it's not so nice to have this line here, right?
Uh, so there's actually a shortcut we can do.
And for this, it's very important that we compile save.
Otherwise, not gonna work.
We can just write the same name here, just drag off here and just write projectile class.
And it's going to show up here because this is basically a local variable.
And we just use this and just shortcut it to here.
So it's just cleaner.
But it's the same thing as just connecting it here.
And the longer your function is the easier this becomes to use.
Because otherwise you would just have to drag off here, here, here, here.
And it's just going to become a mess.
But one thing with this is that if we rename this input, this reference is going to be corrupted.
So we actually need to refresh this reference in that case.
So just be careful with that.
So now let's just have a look at how this works.
Right.
I can go back to the event graph where we shoot the IA shoot.
And here the projectile class.
Now I can just select a projectile.
Well actually the problem is I can select everything.
So in the function or if we just select the function here we see the class right.
So the projectile class is the input here.
And right now it is an actor.
But we actually want to make this more specific.
So we can only pick projectiles.
So we can just go here and type in projectile.
And we have the BP projectile base, but only the player uses this function, right.
So it could be a BP player projectile base and not an object reference, but a class reference.
And just compile and save.
And we might get an error here.
Now this is fine, but now we can only select player projectiles here so we cannot pick something else
on accident.
And let's just try the fully charged shot for now.
And let's look at the error.
So projectile class.
Yeah.
So this just because the type changed we just have to right click and refresh.
No actually we can't refresh.
We just have to get rid of this.
Now just compile and save.
And here drag off again and just right the projectile class again.
And this is what I meant with the reference can become corrupted.
And we just have to like retype the thing so it understands it's of the same type.
So now let's just try this out.
And here, if I shoot now, I shoot the charged projectile.
Right.
So this works.
We can then only here in the van graph.
Right.
We can simply select which projectile we want to shoot.
So this is a reusable.
Now we can use this for all of the different projectiles.
However one problem we still have in here is the shot energy.
So in the case that the projectile is a fully charged projectile, we want to subtract three.
If it's a regular or a partially charged one, just one is fine.
So we need to actually update this here.
So instead of doing minus minus we have to do it a little bit differently.
And we can get the shot energy.
Where is it here.
And we set shot energy.
So how do we set this right.
We have the current shot energy minus subtract the value that we want to get rid of.
So -1 or -3 and disconnect this back here.
But how does this function know if we want to do -1 or -3?
Because we cannot simply drag this projector and it doesn't know, we need to create a mapping to tell
it.
Hey, if it's this projectile, just subtract one.
If it's this projectile, subtract three.
And mappings can be very useful for these kind of things.
So how do we create a mapping.
We can create it as a new variable.
Can just go here and just call it projectile.
To.
Energy.
And compile and save.
And here on the right side it should be of variable type.
Again the projectile which we used before right.
The BP player projectile base class reference and compile and save.
And here we want to change this from a regular variable to a map variable.
And this basically just lets us connect two different types together.
So we can say if this is the case then use this.
If this is the case, use the other one.
And here yes, we want to have a mapping from the player projectile to an integer.
But here we could also have like anything else we could have one class to another.
You could have to a boolean all of these things right.
And we just compile save.
And here in the default value we can now set our mapping.
So this plus here and the first one we want to look at is the full charge right.
So if it's a full charge we want to subtract three and press plus again.
Then do the partial charge.
In the partial charge it's just one.
And then also put in the regular projectile.
Regular is also just one.
So we subtract one energy for the regular and the partial and three energy for the fully charged shot.
And again just compile save.
And now we actually have to use this right.
So we can drag it out here get projectile to energy.
And we can find.
And this lets us look inside of the map which we created.
And we can just connect this here.
And it's going to give us right to find.
We have to give it the left value and it's going to output the right value.
So if we give it the fully charged it's going to output three.
If we give it something else it's going to output one.
And here again we can use the projectile class which we get passed in here.
Projectile class.
And this is how easy it is to use a mapping.
And yeah, just clean this up a little bit and this should then work.
But one thing I want to do here is just implement a safety net, because we never want to go below zero
shot energy.
We don't want to have like a bug or something that we go minus shot energy and we just accumulate minus
and minus and we become unable to shoot.
So here I just want to use max max integer and have zero.
So max is just a kind of shortcut for clamping.
And it's just going to make sure that if it goes through here it is going to use the higher value.
It's going to use either this value or the zero if it's higher.
So if this one goes to minus one, it's going to ignore this one and just use the zero.
If this one is higher than zero, it's just going to use the higher one, right returns the maximum
value of A and b.
Just as a safety net.
So now if I go back to the map and I shoot, I can actually only shoot one projectile at the time,
even if I press very fast because we are using three shot energy.
But one thing we also have to do actually have to recover three shot energy if the projectile is being
destroyed.
So in the player we have this function restore shot energy and we can just copy this over this projectile
to enemy projectile class.
Just copy control C and go to the restore shot energy.
And again here we're just using this plus plus which we don't want.
And we can just use this.
Well this one is going to be corrupted.
This is fine.
We just want to use this one here.
And here we can do the same thing.
We're just going to drag into here to create the input.
And I'm just gonna write.
It's already player projectile.
This is fine.
Just call it projectile class.
Just like this.
And again I can disconnect this here, compile and save and then just shortcut here for the projectile
class.
Just make it cleaner.
Right.
So what do we want to do here.
Well instead of plus plus again we can also copy paste some of this right.
We want to get the shot energy and set the shot energy.
So in the restore shot energy right here can just reuse this pattern.
But it's going to be slightly different.
Go here.
And yes.
So we don't want to go minus we want to go plus shot energy.
Right.
Add here and add the shot energy of this projectile type back.
And here we don't want to use Max actually here we want to use min which is the opposite min integer.
And this is going to give us back the smallest value between a and b.
What we want to do here is to just make sure that we cannot recover more shot energy than our maximum.
So the three shot energy is our maximum.
So we can just put this to a variable right.
So promote the variable not local variable variable.
Very important.
And just call it max or just shot energy max like this.
And this is just going to return the smaller one.
Right.
So even if we threw some bug or something get a four here.
It can never be higher than three.
So it's just going to put the three as our shot energy.
And now we just compile and save.
And the restore shot energy is being called on the player projectile.
So we have to go to the player projectile.
Yes.
Projectiles player blueprints projectiles player player projectile base.
And well a simple way to find is just go find results or hit control F, and we can just go for restore.
Right.
And it shows us where the restore shot energy is.
We don't have to look for it ourselves.
And now it takes in this projectile class.
And how do we get this class.
Well we can just get self get a reference to self and then class.
And I think it is here.
Getclass.
So we can get our own class.
When being destroyed and just restore the shot energy.
We just tell the player I am this type of projectile.
I am being destroyed now so you can restore this type of shot energy and just compile and save.
Do this again.
And right now, actually it doesn't work because I forgot one thing.
Sorry about that.
In the max shot energy, we actually need to compile and save and set the max value, right?
So if we have zero then we cannot ever have shot energy.
So just set this to three and compile and save.
And now it should work just fine right.
So here I can shoot again I can shoot again.
And this makes sure we don't have any bugs with the shot energy.
And again I can only have one active at a time.
And this is going to prevent bugs where we maybe don't restore enough energy or restore too much energy.
So now that we have prepared everything with the energy, we can go back to the BP player and again
find our IA shoot.
And yes, for the regular shot, we just want to use the regular shot again.
Right.
So here just select the regular.
We are done testing this.
And now we want to move on to actually using this charge time here.
And again the first thing we don't need to print string anymore.
We again need to check.
Are we not stunned.
And do we have enough shot energy.
Just like this and go here from the completed not the cancelled completed.
Very important.
And just do it like this.
And one thing we have here now is that we just check for shot energy bigger than zero.
And this works fine because charging the shot takes a long time.
So just from a practical perspective, it's not going to happen that we don't have any shot energy ready
when our charge shot is ready.
But if you want to be very strict with this, it actually makes more sense to take this, um, control
X and put it inside of the spawned projectile function.
And here.
We can just do the check in here.
Yes, just go here.
And put it in here and we want to check if the shot energy.
Is not bigger anymore, but bigger or equals than the value which we need.
And here we can just again find our projectile class, which tells us like how much energy do we need?
And just check if we have the energy available to even spawn this projectile, because otherwise it's
just not going to spawn it.
And this just makes sure we don't have any bugs where we can, or the user can probably find out some
weird scenario where they would possibly be able to use a charge shot, even if they don't have the
charge.
So go back to the event graph.
And here we can now get rid of this because it is inside of the spawn projectile.
And the good thing is that it is being reused for this now.
And it's also being reused for our completed.
And the is stunned is not really related to the shooting itself.
So I think it's fine to just have it outside here again.
And now's the part where we want to decide if we can shoot the partially charged projectile or the fully
charged projectile.
So we need to decide on the thresholds for the elapsed seconds.
And what I came up with is that below 0.8 we are not going to spawn anything.
If we have more than 0.8 elapsed seconds, we spawn the partially charged projectile, and if we have
more than 1.8 seconds, we spawn the actually fully charged projectile.
And these are very similar values to the actual games we are basing this off of.
And why do we need to have a threshold for spawning?
Nothing, because if we just press the button well, to ourselves, it feels like we're just pressing
the buttons.
But actually we are holding the button for 0.0 something seconds, so we don't want to just spawn two
projectiles if you just press the button very quickly.
So the first thing you want to do here is to have another branch here.
And we just want to check.
If the elapsed time elapsed seconds.
Bigger or equal.
Then our partial charge time.
So 0.8 is our partial charge time.
If this is not the case, then just nothing happens, right?
We don't want to spawn anything if we let go of the button.
And of course we want to turn this into a variable again.
Right.
The 0.8.
Just promote the variable.
And it's called partial charge time.
And let's say in this case, well, if this is the case, first we can just copy and paste this, the
spawn projectile and we just spawn the partial charge projectile.
Right.
So let's just try this out.
I go like this, I just press the button very quickly and let go.
We don't get a partial projectile.
I hold it, I hold it, I hold it, and now we get the partial.
Right.
You can see it's a little bit purple.
If I let go, the color is different.
I let go and you can see the other projectile is spawning.
But of course we need to add one more branch to.
Then again decide.
Well first we pass this threshold.
If did we pass the next threshold.
But this is going to become a little bit complicated.
So we just want to select the branch the spawn projectile and hold control.
Select these as well.
And we just want to collapse this to a function.
Just right click collapse the function and try charge shot.
Like this and just move this up here.
And this is going to be a little bit easier to deal with this and just yeah, make another reroute node.
And I want to change the name here to elapsed time.
Yes.
Okay.
So now we can go in here, compile and save.
And again I want I like shortcutting these.
So I don't like to have these lines here.
Just elapse time just to write it here.
Get the shortcut.
And here, instead of, uh, spawning this projectile, we actually want to add another branch.
So just copy paste this.
And here we check for, well, elapsed time.
Bigger equals then.
And here we have the fully charged time.
Right.
So we need to make another, uh, variable.
But first we can just type in 1.8, which is the value we talked about before for the full charge and
just promote to variable.
And it's called full charge time.
Move this over here a little bit and compile save.
Make sure it is set to 1.8.
Make sure this one is set to 0.8.
Yes this is fine okay.
So if we have the full charge then copy paste.
We want to use the full charge projectile for true and the partial charge projectile right.
The partial charge for false.
And this is just how we can branch and decide between these projectile based on the time which we pass
in here from our IA shoot event and compile and save.
And let's try this out.
I'm holding the button a little bit, I let go, I get the partial charge.
You can see it's purple.
I hold it longer and longer and longer and I let go and I get the full charge.
So this is how you can make a button hold system and do something else based on the elapsed time.
And all of this is just possible because of the enhanced input system, which became the standard with
5.1.
Before this, it would have been a lot more annoying, even more complicated than this.
Of course, the charging doesn't feel good yet because we don't even see if we are charging, right.
Like, I don't even know if I'm still holding the button.
So for that, we are going to implement a sprite flashing, just like when taking damage, but a different
color to actually show that we are charging.
But that's for another lesson.
What I want to do now is that if I get hit while I'm charging, I get hit, and if I let go, I still
get the full charge shot.
But this is not how it should work.
If I get hit, it should actually cancel my charge and it should reset me.
So back in the player we can make a new boolean and just call.
It was hit during charge.
And this should be a boolean, right.
So we can first, uh, compile and save.
And make this a regular a single variable and set this to a boolean.
Compile and save to get the default value.
Default value should be false right when we spawn in.
We don't care about this.
So now we go to the any damage event right on the player.
Uh not constructed event graph.
And if it's hard to find well it's here, but you can also just.
Right any damage.
And it's gonna zap you to the position, right?
So on any damage before we trigger the invincibility we also want to set was hit during charge.
To true.
Like this, and we then want to actually reset this when we press the button again, right?
So whenever we get hit this gets turned to true.
But we need to reset this before we start holding the button again right.
If we are not stunned.
So here I can then just set wotsit during charge to false because we start pressing the button again.
I want to have this be reset.
If we are not stunned, we're not allowed to press this while we are stunned.
And what can I do then?
Well, in try charge shot, I need to put in a check for this.
I can then just go for was hit during charge.
Get was hit during charge, not boolean.
And again put in a branch.
So if we let go while we were hit during a charge, well, it should just do nothing.
So we're going to take the same branch here, just do nothing and I can just compile and save.
So now I charge.
Normally I don't get hit, I let go, we get the charge shot.
It's all good.
I start charging, I hold, I hold, I get hit, I let go, we get nothing.
Right?
So this is what we need for game balance, for game feel.
If you get hit, if you get stunned, it should reset your charge shot.
And congratulations for coming this far.
This was a quite complicated ability to code, but we went over a lot of very important things that
will help you to actually make abilities that are similar by yourself, not just a charge shot, a charged
attack with a sword maybe, or a charge jump.
Like a lot of different things that you can use this pattern for.
And also in most cases you actually want to cancel that action if you get hit.
So you also we looked at the stun.
We looked at how we can reset something if we get hit during the hold action.
But while setting this up, we actually created a lot of new variables and things are starting to get
a little bit unorganized.
So the next lesson is just a very simple lesson on how to clean up variables.
Can't find what you're looking for?
Get subtitles in any language from opensubtitles.com, and translate them here.