Welcome to Part 1 of the guided tutorial series for the Pro Networked Combat System (PNCS) for Unreal Engine 4.25. The PNCS is not so much a combat system as it is a Combat Framework. It is designed in such a way that it should be possible to implement any combat system you desire. For this reason the totality of the tutorials on how to use the PNCS will be broken up into several smaller tutorials. This tutorial will be the first and it’s primary goal is to setup the project as a starting point for the other tutorials. To follow along you will need to have purchased the plugin from the Unreal Marketplace. You can create a new project and follow along from scratch but I suggest downloading the example starting project to follow along as it contains animations required that are already setup and ready to go.
Get the plugin at: UE4 Marketplace
Starting Project Download
Finished Project Download
The PNCS system was built using S.O.L.I.D. principles with the primary mechanism being Dependency Inversion and Dependency Injection. This is what allows the PNCS system to be implemented across any game with no reliance on pre-built Characters and Actors or the need for a long and confusing chain of inherited blueprints or CPP classes.
The Finished Project
In time the finished project will become more and more robust allowing you to preview various methods of implementing the combat system and supporting systems along with it such as some advanced animation techniques or different types of games. Because this is the initial launch of the combat system it will only contain the finished tutorials, but over time you will be able to see more complicated systems and will be free to leverage those implementations however you desire. In such examples I always provided a built in Blueprint Tutorial that accompanies each additional example.
Through out this tutorial series we will be developing a total of 4 demos to get you up and running with the Combat system and hopefully in a way you come to understand all the various parts of the combat system. This initial tutorial is geared towards getting the project setup and preparing it for the other example demo systems we will be working through. Through this tutorial series we will develop a basic combat system that allows you to equip weapons, attack an opponent, defend from an incoming attack, and deflect blocked attacks that stun the attacker. In each of the four demos we will be building on this combat system.
As noted the first tutorial is an intro and will setup our work space to develop the other four by establishing some common code each will leverage.
The Second tutorial will focus completely on using the Weapon Manager and the Weapon Actors without leveraging the Action Manager. We will get a taste of what is needed to build a combat system without utilizing the Action Manager and how we can implement the features of Attack, Guard, and Stun. Some games may not need the sophistication of the Action Manager which is why it is an optional but powerful component of the combat system. However, because the action manager is a powerful tool this is the only tutorial that will not leverage it. This will be a Melee weapon only tutorial as well and will introduce the Sword Pickup object.
The Third tutorial focuses on the Action Manager and how to implement the various actions such as Attacking, Guarding, and the Stunned State which is an action in of itself. This will also be a Melee only tutorial and utilize the sword pickup object.
The Fourth tutorial will implement ranged attacks using the Action Manager. We'll add a Bow and arrow pickup, implement ammo loading and display, as well as ammo management. These will be simplified examples but you or your developer should be able to extrapolate how to perform more advanced operations such as querying specific ammo in your inventory rather than a generic catch all ammo that we will be utilizing.
The fifth and final tutorial will swap out both our unarmed and sword weapons for precision weapons. Weapons that perform tracing along with the animation to give as realistic a hit result as possible.
Table of Contents
1.0 Project Tour
The Finished project starts with a built in Blueprint Tutorial to get you familiar with the project and projects. I highly suggest you click on them and read through them to get an idea of where everything is and what it does.
For the starting project itself, it is much more stripped down and bare bones. But I will go over some of the key things you need to know about.
1.1 Templates and Content
You'll notice the project includes the Unreal Engine Third Person Blueprint Template. Most of this tutorial will be leveraging the Third Person Template and because we will in some instances be editing the input it is easier to use the Blueprint version of that template over the C++ version. We will also be leveraging the Third Person Map, but this is less important than the ThirdPersonBP itself. You can use any map you want.
I always leverage the ExampleContent and the "StarterContent" because it is useful for prototyping. The Mannequin folder is required as we will be working with the UE4 Mannequin and it's animations.
1.2 The Common Folder
In the starting project there is a folder under "ExampleContent" called "Common" Here you will find some of the globally useful things we will need for all projects. Two important folders are found here. The "Animation" folder and the "Props" folder.
The "Props" folder holds all the visual assets for the various weapons the combat system comes with for testing. This includes a Sword, Shield, Knife, Great Sword, Bow, and Arrow meshes and materials.
The "Animations" Folder holds all the custom build animations I have provided with the combat system. They are not the best as I am not a professional animator nor did I bother to use motion capture. I simply built assets using blender that gave an approximation of what I would need. The Animations folder breaks down into "Bow", "H2H', and "Melee" sub folders. Bow holds all the animations relevant to using the bow weapon, "H2H" is the animations for unarmed combat, and "Melee" holds all animations for the sword weapon and is used for all other melee based weapon assets such as the dagger and great sword. One day I may develop animations for these for demonstration but right now it gets the job done.
2.0 Basic Setup
In this section we will be setting up our project for development by creating the folders for our project. Each of our four demos we develop will have their own folder and be for the most part self contained. As a note this is how I setup all my projects and it does wonders keeping things organized.
Start by creating the root folder for all the tutorials we will be leveraging. We'll call it "DemoContent".
Next create a "Core" folder under the "DemoContent" folder. This folder is where we will put most of the shared data that will be leveraged by all of the demos.
Next create a "Blueprints" folder under the "Core" folder. This folder is where we will put all Blueprints we will use to build out the global logic for the demo. This will also be the main folder we use for this demo.
Next create the "Data" folder under the "Core" folder. This folder is where we will be holding any Data related assets for our demos. This includes Data Assets, Data Tables, and String Tables (if you are using them).
Next create a "Character" Folder under the "Blueprints" folder. This is where our Gameplay character we control will reside along with any additional Blueprints that will belong specifically to the character object.
Now create the "DataTypes" folder under the "Blueprints" folder. This is a special folder we will be using for blueprints that define the Data Assets we will be specializing for our combat system.
Now create the "Interfaces" folder under the "Blueprints" folder. This is where the interfaces the four projects will all use will be stored. Some projects will also have their own specialized interface functions that will be in their specific project subfolder.
Now create the "Pickups" folder under "Blueprints". This is where we will create our Pickup items that will give weapons to our character while playing. It also will provide you with the understanding of how easy it can be to set weapons using the combat.
Now create the "Player" folder under the "Blueprints" folder. This is where we will hold any "Player" related blueprints, specifically the PlayerController. This folder can also hold other player related info such as custom PlayerStates, but in our tutorials we will only be working with the PlayerController. I leave the rest up to you for your own development.
2.1 Anim Blueprint
Before going too far we will duplicate the current animation blueprint for the Mannequin so we can work on with without disrupting the original ThirdPerson_AnimBP.
Right click on the ThirdPerson_AnimBP and select "Duplicate". Renamed the new Anim Blueprint to "ABP_DemoCharacter". That is all for now we will be coming back to this Anim Blueprint in the future to do some modifications.
2.2 Prepare the Skeleton
Now we will prepare our character's skeleton with the proper sockets so that we can attach and detach weapons to the hands and holster locations.
Go to "Mannequin/Character/Meshes" and open up the "UE4_Mannequin_Skeleton". We will be adding several new sockets to the Skeleton.
Find the bone called "hand_l". Right click on "hand_l" and select "Add Socket".
This will create a socket with a name "hand_ISocket" Select the socket and rename it to "s_OffHand". This will be the off hand socket we use for weapons attached to the off hand. I use the "s_" as my own personal naming scheme to indicate that this is a socket and not a bone. Feel free to use what ever naming scheme you desire.
In the Details panel you can change the properties of this socket. Here we'll be setting the Location and Rotation of the socket to the following properties. As a special note, you can copy everything including the parentheses and just paste them into the properties.
Socket Name: s_OffHand
Repeat this process for the following Bones:
Socket Name: s_OffArm
Socket Name: s_MainHand
Socket Name: s_MainArm
Socket Name: s_BackHolster
Socket Name: s_RightSideHolster
Socket Name: s_LeftSideHolster
3.0 Add Core Classes
In this section we will add the Core classes we will need which will be leveraged by the other projects. We will start with some basic UE4 classes that will be needed later.
First lets create the base character we will be using for the game. Go to the "DemoContent/Core/Blueprints/Character" folder and right click and choose to create a new Blueprint. In the "All Classes" search block search for "ThirdPersonCharacter". Click on the "ThirdPersonCharacter" class and click select. Name the new blueprint "BP_DemoCharacterBase".
Go to "DemoContent/Core/Blueprints/Player" and create a new Player Controller. Name it "BP_DemoPlayerController".
3.1 Weapon Objects
Next we will create our core managers and weapon actors.
Under "DemoContent/Core/Blueprints/Character" right click and under "Create Basic Asset" select "Blueprints". Under the "All Classes" section search for "PncsStandardWeaponManager". We will be leveraging the "Standard Weapon Manager" because it is already setup to handle characters with two hands.
Still under "DemoContent/Core/Blueprints/Character" right click and under "Create Basic Asset" select "Blueprints". Under the "All Classes" section search for "PncsStandardWeaponActor". We will be leveraging the "Standard Weapon Actor" because it has functions to easily determine it's weapon type.
3.2 Data Objects
We are now getting to get into the major parts of the combat system. The Combat system runs on Data and we need to start defining what data we will be using for our combat system. We will be creating the specialized data classes for our combat system. This will include creating blueprints for our Weapon Data, Weapon Animation Data, Animation Set, the Weapon Manager, and the Weapon Actor.
Go to "DemoContent/Core/Blueprints/DataTypes", right click and under "Create Basic Assets" select "Blueprints". Under the "All Classes" section search for "PncsAnimationSetBase" and select it. Name the new Blueprint "BP_DemoAnimationSet". This blueprint object will hold all the animations we need for the currently equipped weapon. The Animation system will leverage this object to play the specific weapon animations for the weapon and the Character Blueprint will leverage it to determine what Montages to play for attacking and blocking.
Still under "DemoContent/Core/Blueprints/DataTypes", right click and under "Create Basic Assets" select "Blueprints". Under the "All Classes" section search for "PncsBaseWeaponData" and select it. Name the new Blueprint "BP_DemoWeaponData". This blueprint object is a Data Asset referenced by the data table we created earlier. This Data Asset will be loaded dynamically when needed to display weapons during game play. It has the advantage of being asynchronously loaded so it does not cause your game to hitch or slow down.
Again under "DemoContent/Core/Blueprints/DataTypes", right click and under "Create Basic Assets" select "Blueprints". Under the "All Classes" section search for "PncsBaseWeaponAnimationData" and select it. Name the new Blueprint "BP_DemoWeaponAnimationData". This Data Asset's job is to hold all possible animations that a weapon could utilize. For instance you may have different types of races in your game that use different sets of animations. This Object would hold those animations as well. All the default functions take the Actor as a parameter so that you can perform switches on their gender, race, or other criteria for your game and leverage different animations for each type of character.
4.0 Setup Data Service
Now we will setup the "Weapon Data Service". The Weapon Data Service is used by the Weapon Actors that represent your weapons in the game to load the appearance of the weapons.
This needs to be a globally accessible object and preferably one that is globally accessible in multiplayer games. This limits our choices to: "GameInstance", "GameState", or the "GameSingletonClass". Newer developers maybe tempted to use "GameMode", but if you are building a multiplayer game do not use this to hold your global game data. The GameMode object does not exist on connected clients for multiplayer games, only the GameState. For this demo we will use the "GameSingletonClass" as this is my preferred object to leverage for globally accessible data storage.
Go to "DemoContent/Core/Data" and create a new DataTable by right clicking in the folder and selecting: "Miscellaneous/DataTable" from the menu.
Now you need to select the PncsWeaponDataRow as the table structure to use.
Finally name the Weapon Table as" DT_WeaponData". For now we are done fiddling with the Data Row and will come back to this table to fill it in later.
Now we will go to "DemoContent/Core/Blueprints/DataTypes" to create the GameSingleton Object. Create a new UObject by right clicking and choosing to create a new blueprint. In the "All Classes" list select "Object". Name the new Blueprint "BP_GameDataService".
Open up the new BP_DataService blueprint. Click on "Class Settings" at the top. In the "Details" panel find "Interfaces". Click the "Add" Drop down and type in "PncsWeaponDataService" to add that interface to this object.
Now in the "MyBlueprint" panel go down until you see "Variables" and click the "+" button to add a new Variable. Rename it to "WeaponDataTable" and make it a "DataTable" type. Hit the Compile button. Now Set the Default Value of the Table to the DT_WeaponData table we created earlier.
Now we will implement the IPncsWeaponDataTable function "GetWeaponDataTable". This will simply return the "WeaponDataTable" variable we had created.
Finally we will implement the IPnjcsWeaponDataTable function "GetAmmoDataTable". For this demo we will simply be using the same table for both data. So return the "WeaponDataTable" variable.
4.1 Assign Game Singleton
Now we need to implement the GameSingleton Object in Unreal Engine. This is a very simple step.
Go up to "File" and select "Project Settings"
Scroll down to "Engine" and find "General Settings"
Under "General Settings" scroll down to "Default Classes"
Assign the BP_GameDataService object to the "Game Singleton Class".
5.0 Core Interfaces
Interfaces make your development life easier all around, casting to specific types in Unreal Engine can cause assets to load when they are not necessarily needed. This is especially true when the object you are casting to is not of that type and can get messy when you need to cast to different types should a cast fail. Interfaces are the proper way to handle the question "Is this object of type X and can I call function Y". We will setup four Interfaces for our demo and they will not be the last. They will represent the Core Interfaces that all 4 demo examples will leverage. These interfaces are how we specialize the Combat System for any games need.
In the "DemoContent/Core/Blueprints/Interfaces" folder, right click and in the "Create Advanced Asset" list choose "blueprints" then select "Blueprint Interface". Name the new interface "BPI_DemoAnimationData".
Then create three other new interfaces and name them "BPI_DemoAnimationSet", "BPI_DemoCharacter", and "BPI_StandardWeaponActorData".
BPI_DemoCharacter represents the specialized functions for the character that the combat system will use.
BPI_DemoAnimationData represents the specialized functions we will use to fetch animations from the Animation Data Asset. It is also used on the specialized UObject called the "Animation Set" which is a UObject designed to hold the current set of animations for a weapon which is leveraged by the Animation Blueprint and other systems. We'll get more into the use and function of the "Animation Set" object later.
BPI_DemoAnimationSet represents the specialized functions we will use to "Set" animations to the current "Animation Set" object. This will allow the Animation Set to blend weapon animations together based on your own logic so that you may have animations for a sword and shield configuration as well as a duel sword configuration.
BPI_StandardWeaponActorData is a specialization for Weapon Actors. This interface leverages the "Standard" Enums to get and Set some properties of the APncsWeaponActor object. This interface does not come standard with the Plugin simply because the plugin allows you to specify your own "Weapon Types" and Grip Types". We'll discuss more on that later.
With the stubs of our Interfaces finished we'll come back to implement what interfaces we need later.
6.0 Define Weapon Data
In this section we will be defining what data we will be needing for our combat system. This includes a weapon's visual appearance and the animations for that weapon. There are two Data Assets that the combat system leverages for Weapons and Animations which we created stubs for earlier. The first is the UPncsBaseWeaponData and the second is UPncsBaseWeaponAnimationData. The information for weapons is stored in a DataAsset because it allows that data to be easily streamed in from disk asynchronously if it is not loaded thus making your game run faster and load faster overall.
The UPncsBaseWeaponData object is unique to each weapon, defining the visual properties of the weapon, how it will be positioned on the character, and any other properties you may want to add such as damage. The UPncsBaseWeaponAnimationData is specifically meant to contain what animations need to be played for the weapon. The Animation Data object is also meant to be a shared asset across multiple weapons because most swords in your game will likely use the same set of animations but could use different animations for daggers and great swords. Each UPncsBaseWeaponData object has a reference to a UPncsBaseWeaponAnimationData object for easy loading and streaming.
Before we get into it lets take a moment to speak about an important concept of the Combat System. Each weapon contains properties for "Weapon Type" and "Grip Type". The Weapon Type is fairly straight forward it is an value indicating the type of weapon being represented. As an Example the PNCS system comes with the EPncsStandardWeaponType that has the following values:
- Melee - weapon is a melee weapon
- Shield - weapon is a shield
- Ranged - weapon is a ranged weapon
- Ammo - object represents an ammo type. Not really used by the weapon actor itself but for ammo supporting systems.
The Grip Type is used to indicate how the weapon is handled. For example the PNCS system comes with the EPncsStandardGripType that has the following values:
- One Handed - Weapon can be placed in the main hand or off hand
- Main Hand - Weapon can only be equipped to the main hand
- Off Hand - Weapon can only be equipped to the off hand
- Two Handed - No Off Hand weapon can be equipped as it requires both hands to wield.
Use of the EPncsStandardGripType and EPncsStandardWeaponType is completely optional as the Combat System allows you to define your own enum for weapon types and grip types. The variables that represent these values are uint8 which is the type Unreal Engine uses for it's enums allowing you in blueprint to pass your custom enums into functions with little effort.
6.1 Setup Socket Types
While building the PNCS system I discovered a very useful method of defining how weapons attach to what socket in a configurable way on the UPncsBaseWeaponData object. We'll define the Enum we need to do this and implement how the attachments work late when we build out our custom Weapon Manager.
First we will create a custom Blueprint Enum for the sockets available for our weapons to attach to. This allows us to configure how our weapons attach to holsters and hands much easier and without using FNames that can lead to future errors. Right click in "DemoContent/Core/Blueprints/DataTypes" and under "Create Advanced Asset" choose "Blueprints" and "Enumeration". Name this Enum "EDemoSocketTypes".
Create new Sockets by hitting the "New" button. Create the following Enum Values and optionally descriptions:
- None - Default No Socket Selected, Invalid
- MainHand - Main Hand Socket
- OffHand - Off Hand Socket
- MainArm - Main Arm Socket
- OffArm - Off Arm Socket
- Back - Socket on the Back
- RightHolster - Right side holster socket
- LeftHolster - Left side holster socket
6.2 Setup Interfaces
We'll start by setting up the Weapon Data Interfaces as this plays a major role in defining the properties our weapon data will require. All Weapon Actors have properties describing their "Grip Type" and "Weapon Type".
Start by opening the BPI_StandardWeaponActorData Interface. As noted before this interface will put on our Custom Weapon Actor. The Weapon Actor will define a "Grip Type", "Weapon Type", "Socket Type", and "Power".
With the BPI_StandardWeaponActorData interface open click the "+" sign in the "functions" section. Create the following functions with the category "BPI Standard Weapon Actor Data":
|Get Grip Type||Output||float||GripType|
We'll use this interface to fetch some useful info about our weapon.
Now open up the BPI_DemoAnimationData blueprint interface. You'll need to create the following functions.
|GetIdleAnimationSequence||Output||Anim Sequence Base||Idle Sequence|
|GetMovementBlendSpace||Output||Blend Space Base||Movement Blend Space|
|Output||Anim Montage Base||Ready Montage|
|Output||Anim Montage Base||Relax Montage|
|GetJumpStartSequence||Output||Anim Sequence Base||Jump Start|
|GetJumpLoopSequence||Output||Anim Sequence Base||Jump Loop|
|GetJumpEndSequence||Output||Anim Sequence Base||Jump End|
|GetAttackMontage||Output||Anim Montage Base||Attack Montage|
|GetGuardMontage||Output||Anim Montage Base||Guard Montage|
|GetDeflectionMontage||Output||Anim Montage Base||Deflect Montage|