Today I'd like to talk about the process that I used to create a fully fledge rpg boss fight simiulation inside Unreal Engine 4. Before I start though there are a few disclaimers I'd like to make first which are:
- I use a Framework here for basic mechanics like shooting, collision, and actions or animation triggers
- This project was built inside unreal engine and all additional programming code was done by me
- Sample screenshots can be found at on my CakeResume page, the project code on my Github (since the project is large I only have the executable on here for now), and the video can be found here on YouTube
- I will only be covering some of the most important aspects of the code here because the project is simply too large for me to cover everything, as such a lot of additional details will be skipped for simplicity
With that out of the way, I'll go ahead and begin the process I used to create this project, particularly the boss itself and the experience that i wanted it to be.
Here is a overview of the things I wanted in the boss fight:
Dragon flight (at least a few determined paths).
Fire projectiles since he's a dragon why not XD
Bite grab animation
Smaller allies which come in to replace him until they are beaten
Knockdown section when it takes too much elemental damage
Pushback particularly when screaming
All of these I was able to achieve to at least some degree if not completely. Below I'll go over some of the challenges that I faced and how I overcame them with some programming thrown into the mix.
1. Dragon
• Bite grab
The dragon bite grab functionality is maintained inside the action called bite grab under the notable point reached event. The notable point reached event is a point inside the animation that I placed myself. It is the point where the dragon closes its mouth, so only during this one specific instance will it have a chance to grab the player. If it fails, nothing happens. If the player is invincible, specifically dodging or blocking it will fail to grab them as well. The bite grab action plays the grab animation and if the player is within a certain radius of the dragon’s mouth (a distance of about 2000 including z), then the players movement is disabled and a variable inside of it called sent flying is set to true. This variable is referenced inside the main game modes tick event which basically handles the animation for the player. If the player is ascending then a twist animation is playing, if the player is descending or falling then a fall animation is played until they reach the ground. Once they reach the ground, a final animation plays which recovers their stance.
• Attacks
Most actions are easily executed using the ACF framework. It works similar to the normal workflow inside the engine where it allows you to handle attacks and collisions in certain places if you’d like. In this project, I set up the collision components mostly on the dragons’ claws since it doesn’t use any other elements for attacks. No tail swipe unfortunately. The collision component is also set up for the player and damage is also handled by the system. Nothing special goes on inside the actions with the exception of the bite grab
• Flying (detailed)
When the dragon’s health goes below 50%, it has a chance to activate its flying actions. This is done with a function called Initiate Flight path. In summary what it does is use a timeline to interpolate along a specific path. The path chosen is determined basically randomly using integer values and I set up a function that takes care of this for me when this event is called. Using a random integer, it determines a spline and then stores it into a variable called ActiveSpline. The timeline is only using a basic float value of 1, but the duration is reduced by a tenth so it’s longer. Once this timeline has fully executed it resets the dragons normal moveset (since at the start of this it’s changed to flight after it moves to a specified spot), and the target (player) is reinitialized because it is disabled when it moves to fly. This isn’t a full description but this picture shows the workflow of this function:
• Knockdown
This knockdown portion utilizes the ACF framework itself. All it does is when the amount of damage sustained is greater than a certain amount (200), then the dragon is knocked down for a sustained period of time, about 15 to 30 seconds. During this point he is wide open to do anything to him. Afterwards he gets up and recovers, then he pushes you back if you’re close enough. This is done with a recovery action.
• Fire breaths (detailed)
Fireballs are broken into 4 separate types which are the spread fire normal, spread fire (ground), shoot fire ball air, and shoot fire ball. All of these are actions that are executed normally with the exception of the air shot. The shoot fire ball ones are pretty self-explanatory. They shoot fire balls at the player. The only thing that is done during the process is the direction is adjusted to accurately match the player. The air shot however only occurs once the dragon has taken one of the two pre-determined flight paths and is done after the dragon’s health has gone down by about 25% or a little less. The spread fire normal one shoots fire from the mouth and is different from a ball. It spreads fire from its mouth in a normal left to right spray burst. As such there are traces that are spawned in so that it appears that sparks from the mouth leave small residues that can damage the player on impact. They fade after about a few seconds however. Finally, the last type is spread fire (close). This one only occurs when the player is in close proximity of the dragon itself and as such spreads fire more closely to the ground. It works similar to the regular spread but the range of fire is much smaller and focused.
• Minion Spawn
How the minion spawn works is after the dragon’s health drops below a certain threshold, it has a chance to trigger an action known as the CallAllies action. The call allies action immediately makes the dragon levitate off the ground from wherever it is over a set period of time, about 10 seconds. There after that it moves towards a pre-determined spot on the side of the area. It is simple a scene component. Once it reaches this scene component, it disappears from view and five dragon minions spawn from that location and come flying down. The camera transitions so the player sees it from that perspective and they land in after a while. I did some simple programming using other scene components so that they all land good distances around from each other onto the scene. These actors spawn in though inside the dragon from a custom event known as callallies movement. It is proceeded by a function first though called CallAllies Sequence which initializes the basic things such as the count and gets things ready. The CallAllies Movement function simply takes care of the heavy lifting such as the spawning and making sure that the number of acts matches the limit of five in this case. Once they have all finished spawning, I created a function inside of them that is called shortly after their creation which handles their flight path to the ground. Once they have all been defeated the main dragon reappears from the spot it disappeared in and then proceeds to land back onto the field.
2. Player
• Grab response (bite)
This is mostly handled and started by the dragon itself. When the dragon’s action is executed and succeeds, it disables all movement from the player until they get up and recover, which is near 8 seconds when it finally touches the ground. It gets very messy, but the code that handles this specific portion is inside the bottom portion of the Main Character Falling Handler which is inside the active game mode. Actually, the entire function itself handles the process from when the character is grabbed to flying and then recovering. There is a sequence of events that goes from one to the other until it reaches the bottom portion which I described. It’s big so I’m only going to specifically show the recovery code:
• Abilities (fire, block, dodge)
The player has an array of abilities in this simulation including a cloth swap, wolf summon, projectile fire shot, dash, block and dodge. With the exception of block and dodge, everything else applies damage in some way to an enemy. The wolves are an array of allies that I made that spawn near both sides of the player. There are about 8 of them total. All they do is play jumping animations and make a sound effect. Their collision zone is wide to account for the short distance they actually jump. They do a set amount of damage each when they connect so it isn’t a full-on application when one hits. The dash ability is what it sounds like in that it’s a magical dash burst over a short distance. The cloth swap simply changes the skeletal mesh to a different one along with a sample animation that I picked. The projectile fire shot shoots out a fire projectile in a linear straight line from the center of the sword (the body actually so it looks like it is, along with a spacing gap so it’s not coming out of the character body per say). As for blocking and dodging, they have custom animations as well, however they both have invincibility frames in between the animations so that damage can’t be applied to the character. I did this by adding substates (custom notify points) inside the animations themselves that once passed and exited, this feature is enabled and then disabled respectively.
3. Environment
• Invisible walls
Most of the collisions that contain the player are controlled by one actor called WallV2_Bp. This blueprint is customized to specifically fit this area perfectly. It is composed of a series of box collisions that can be customized to fit any scene. I only added the ones I needed but more can be added as well. How this blueprint works is that it casts references to check if the incoming player reference is a player or not. If it is a player, then the collision is enabled. Once off the wall they are disabled. Why you ask? This is because I want the dragon as well as his minions to pass through this unaffected but also to contain the player until the dragon is defeated. Once defeated, these barriers become inactive.
This is inside the level itself:
And this is the Blueprint itself:
• Portal
This portal only spawns once the dragon is defeated. Once it is defeated it disables it’s dragon boss widget from the viewport, stops the boss music from playing, and finally gets a player reference to call LookAtPortal. LookAtPortal is a special function inside the player that handles the spawning of both the final portal as well as the camera placement which interpolates to a static spot where it can be seen, specifically using set view target with blender. Finally, it zooms back into the player.
• Dragon paths
Dragon Flight paths are actors with spline components attached to them. They are placed in the level and are all static and customized. They are referenced by the dragon AI controller in the beginning by using GetAllActors of class and are stored for easy reference. This variable specifically is called SplineReferences. There are some filters though, such as the entrance spline which is the one the dragon uses to come into the level. This spline is excluded from the list because it is only used once which is at the beginning. Here is a picture of some of them placed inside the level and it being reference by the AI controller:
These two are inside the AI controller:
• Start Zone
I’ve called this DragonSpawnTrigger. It is simply an actor with a overlap component. When the game begins it simply gets a reference to the level sequencer event that are placed inside the level. Then when the player overlaps them, it plays the event and spawns the dragon from the start of the entrance spline of the dragon. When this short sequence is finished this actor is destroyed as this only needs to happen once. A special event was created inside the dragon actor itself to handle this special instance since normal spawning doesn’t account for this. It uses a timeline to bring it to the ground.
• Level Sequencer
The level sequencer is merely a reference that is used in the start zone. After this it serves no purpose. I use a cinecameraactor that is placed at a specific location so that the angle zooms in from there (which is on the side) and a reference to the entrance spline itself. Here is an image of the sequence itself:
4. Miscellaneous
• Menus (Pause, Credits, Death screen)
All menus used in this project are simply widgets that were created by me with different specifications. The pause menu pauses the simulation and allows you to quit, exit, and selection the options menu which lays out the controls. It is activated by pressing the 1 key. The Death widget appears when you are destroyed and then respawns or terminates the application depending on the user selection.
Post Mortem:
I actually learned quite a lot from this project about both Unreal as well as the Framework that I used here. While I'm not ashamed per say about how things turned out, I did learn that there are better ways to do things and alternatives. One instance is the player recovery process. It uses tick from the main game mode, but looking back on it now, it would simply be better for me to attach this to the animation itself and add notifies that take care of this since it will only be called at the end of the animation. Not to mention I use float values that are hardcore for the recovery time as well as handlers which both of these would be unnecssary if I'd just done it in the animation itself which has the information I need. The entire process lead basically to more organizational structure code wise to make it neater and tricks here and there. My projects now aren't nearly this messy anymore XD.
At any rate I'd like to thank you for reading this if you made it to the end. As I said you can find this project on my CakeResume page, on YouTube, and on my github if you'd like to play it for yourself. Till next time.
Christian Banks
Top comments (0)