Home page button below.
Introduction to Unreal Engine
The start screen is called the splash screen. When creating a project you are asked if you want starter content which adds pre-set content to the project. Here are some pre-sets for game creation, first person, third person, top down, VR, AR and vehicle.
In the project the area where file, edit window etc. are located is called the top bar. Under the top bar is the tool bar where you can press play and stop play and also quickly add actors and content. At the bottom you have the content draw which stores all assets in the project. In the right hand side you have the outliner which holds all actors. Actors are all objects within a scene.
Unreal engine so far
Key binds
Basic controls:
R- scale
E - rotate
W - Move
Q- Select
F- focus
Delete object- DEL
Blue Print Short Cuts:
Pan- Right Mouse Button
Zoom- scroll wheel
Zoom smaller- ctrl scroll wheel
Marquee select add- shift hold right click
Marquee select remove- ctrl hold right click
Find node in blueprint- ctrl F
Compile blueprint- f7
Get variable- ctrl left click drag
Set variable- alt left click drag
Edit comment- f2
Cut selected nodes- ctrl x
Copy- ctrl c
paste- ctrl v
duplicate- ctrl d
add comment around selection- c
break all connections- alt click pin
move all connections- ctrl lmb drag
branch node- b left click pin
delay node- d left click pin
sequence node- s left click pin
gate node- g left click pin
for each loop node- f left click pin
multi gate node - m left click pin
do n times node- n left click pin
do once node - o left click pin
begin play event node- p left click pin
Blueprints
The event graph (the middle area) is the location for all blueprint information or nodes. To the left you have the graphs, functions, macros, variables and event dispatches. Function is code/nodes that can receive inputs and/or gives outputs. Variables store information.
Boolean variables are true or false statements. There are two types get or set. Set is where you set a value of true or false, get is where you obtain it from other nodes.
Integers are any whole number. Floats are numbers with decimal places. Name variables are for naming things. String is for text/characters not shown in game. Text is for text displayed on screen. Vector is position/direction. Rotator is to rotate an asset on loop. Transform is a combination of location rotation and scale. To the left are a couple examples of variables.
Event Begin Play is triggered when the blueprint is spawned in. Events are the very starting nodes for blueprints.
A branch is a true or false statement influenced by a Boolean variable. Branches output either true or false depending on the input variable.
This example shows that if the Boolean is true then print string, "hello", which will then be printed in the debug.
A trigger box is a box shaped trigger used to generate overlap events in the level, in other words triggers are used to cause an event when they are interacted with.
Open Door Blueprint
On actor begin overlap is to reference when an actor interacts with the selected object, the cast to "actor" references the actor for further code, then destroy actor destroys the target actor.
You can do the same as before yet reference another actor as the target actor, this way when the first actor interacts with the trigger box the new actor is the only actor destroyed.
Replacing the Destroy actor node with Set Actor Rotation node, rotates the target actor by the set amount on each axis when the trigger box is overlapped.
Lerp node affects a variable/value over time. The A value is starting value and B value is the max/end value.
Timeline is a length of time (graph) we can use to affect other nodes.
Double clicking the timeline node opens the time line where you can add a float timeline, which you can then add key frames and set when on the timeline they are and the value they hold. After, you can plug the node using the branch with the name of the timeline into the alpha of the Lerp node.
Health Bar design
Instructions for creating the UI:
Right click content drawer, select UI, then select widget blue print.
Name all Widgets, W_"......". Open the Widget BP.
Search Border in Pallete and drag it onto the layer W_HealthBar in the Hierarchy.
Right click border, select wrap with, size box, then in the details tab change width/length override to suitable size i.e. 400 width and 50 height. In the top right of the graph, next to details, change fill screen to desired on screen.
Finally add a progress bar under W_HealthBar, by searching it in the Pallete.
What is a Progress bar? Progress bars are bars which can fill and deplete. Set the colour of the Progress Bar.
Setting health system
Instructions:
Open the BP third person character, add new variables name them current health and max health, setting the type to float.
Set current health to 0 and max health to 100.
Then drag Event begin play from the Add Input System blueprint area and add set current health and get max health, inputting max health into set current health, therefore making current health at the start of the blue print 100.
Add event tick, add get current health and get max health then add a divide, dividing current health by max health then dragging from the divide node create promote to variable and name the new variable Health Percentage.
Health percentage from health system to health bar
Open the Graph INSIDE the widget, delete all nodes except Event Tick. Drag progress bar from the variable tab, add cast to ThirdPersonCharacter, from object input drag Get Okayer Character and from As BP ThirdPersonCharacter drag HealthPercentage. Then Drag From PB_HealthBar Set Percent, and plug HealthPercentage into InPercent and Cast to Third Person Character into the white arrow.
Go back to the character blue print and add create widget by dragging from health percentage. Add Get player controller dragging from create widget. Set the class in create widget to the widget(W_HealthBar). Drag add to viewport from Create Widget plugging both the white arrow(Exec) and the blue link into the Add to Viewport node and connecting that to the Add Input System, cast to BP ThirdPersonCharacter.
Tags
What are they?
Tags Can be used to reference specific actors and/or components and reference them in blueprints.
How to create a tag:
Create a tag by typing tag in the details tab, whilst the actor you wish to tag is selected. Then if the object selected is an actor click the plus icon under the Actor-Tags section and name the new tag (trigger in this case).
How to make find out if the Actor has a specific tag:
Open the event graph of the Third Person Character Blue Print, then add Create Event Actor Begin Overlap, then drag actor has tag from the event node via the other actor section, type the tag for testing. Then from the return value drag out the branch node and from that, print string. make sure Event Begin Over Lap is plugged into the branch as well. In this case once the third person character interacts with the trigger box which has the tag trigger, it will print the string "TriggerBox", this way it has referenced the trigger box without needing to input the trigger box into the blueprints.
How to create a loop check for tagged actors:
Create a tag for multiple actors, in this case all four walls, naming the tag "walls". Open the Level Blueprint and Create a new Variable, change the type to Name, calling it Tag. Then Change the Tag variable type to array in the details tab. Add EventBeginPlay and drag Get all actors with tag from it. Then from Get All actors with Tag drag a for each loop node, plugging both the exec and blue link into the for each loop. Then from the for each loop drag print string from completed, and for the string drag a length node from the Get all actors with Tag node and plug it into the string. This Blueprint should when, played, print a string with the number of actors with the tag "walls", this way should one of these actors be destroyed we can reference that there are now only 3 actors with the tag walls etc.
When R key is pressed, prints location of character. R key node detects when the R key is pressed and or released. The set Location variable is a vector so it has 3 float values (x y and z), and the get actor location sets the location to the 3rd person character, then the print string prints the location of the character.
The same as the location, except for all three transform values. Switched R key for E key, Set vector to Set transform and Get Actor Location to Get Actor Transform.
Door Open and Close (Followed Basic Blueprint course)
First I created a new blueprint (actor class), then added a SM_DoorFrame, SM_Door and Collision Box and aligned them in the viewport.
Next I created a On Component Begin overlap (Box) event and On Component End Overlap (Box), these begin and end the blueprint when something is overlapped with the collision box. Bost begin and end overlap are then connected to the cast to third person character node. This means that when the character overlaps with the collision the begin overlap is activated, and when the character leaves the collision box, the end overlap is activated. Then the cast to character (on begin overlap) is connected to Enable input and the cast to character (on end overlap) is connected to disable input, which both take the get player controller as the player controller. All this blue print means that when the character is in the collision box inputs from the player are enabled, and when the character leaves, inputs are disabled.
For the opening and closing of the door, I started out by adding a E key, this just means that when the E key is pressed and or released the output happens. Then the E key is connected to a Flip Flop, which essentially means that when the E key is pressed once output A happens and when it is pressed again output B happens. The Flip Flop is connected to a TimeLine where the A value (first press) is connected to the Play from Start and the B value (second press) is connected to the Reverse from End. The Play from start, starts the timeline when the input is received (E key is pressed) and the Reverse from End just means the time line values go backwards. The time line is connected to a Set Relative Rotation (Connected to the SM_Door) and A Make Rotator (which splits the rotation axis into separate values. The timeline goes from 0 to 2 seconds and from a value of 0 to 90, as this is connected to the rotation of the z axis this means that over time the value on the z axis will go from 0 to 90 and in reverse from 90 to 0. The points on the curve are also set to auto so it's a smooth curve.
I also added a collision box to the door so the character can't walk through the door mesh.
Hat Equip Blueprint(Following same Basic Blueprint course)
First I opened the BP_thirdpersoncharacter added a static mesh to the capsule component called HatMesh.
Then I created a Custom Event called EquipHat (to be referenced later in a new blueprint). I then took the static mesh (Hat Mesh) and dragged it into the event graph connecting it to a Set static mesh node (which basically sets the input mesh as a new mesh) and connected the New mesh to the Custom event. The set static mesh is then connected to an Attach component to component node (which attaches a component to a parent component) and connected the Hat mesh as the child and character mesh as the parent. I also named the socket HatSocket (to be referenced later) and set the location, rotation and scale rules to snap to target.
I then created a new blue print called BP_HatPickup, which has the same Enable and Disable input node network as the open and close door BP except the collision box is now a sphere. Then from the On component Begin Overlap (sphere) a cast to third person character is connected to the referenced Equip Hat custom event, where the New Mesh is set to a Model called SM_Hat ( a hat model downloaded from the blueprint course). And finally the cast to third person character has the input key (E).
I then, entered the skeletal mesh (of the character model) and right clicked on the Head bone creating a socket and naming it the same as the socket in the Blueprint. I then previewed the hat asset on the socket and adjusted the location and rotation to fit the head.
Finally, I added a text over the Static hat, so the key bind is clear. And added a destroy actor for the static hat.
Health and Damage box
First I created a blue print widget called WBP_HealthBar and added a canvas and progress bar. I then reshaped and coloured the progress bar to fit the theme of health.
In the Character Blueprint, I added a new float variable called health and set its default value to 100.0, then I created a damaging system by using the event AnyDamage. I then, subtracted the Any Damage from the Health variable and set the output as the new value for health.
Then I opened the widget blue print graph and added a cast to third person character to access the health variable, as the object I used the Get owning Player Pawn to reference the ThirdPersonCharacter and then multiplied the Health by 0.01, as the value of health at max is 100.0 and the max value on a progress bar is 1.0.
Finally, in order to show the widget I created a custom event called Create Health Bar Event, linked to the created widget node with the WBP_HealthBar set as the widget, the owning player set to the player controller and then the widget linked to add to viewport. I also added a sequence to the event begin play node this way I can connect both the character input node network and also a new node called create health bar event.
Then I created a new blueprint called damage box and added a cube collision box to the viewport. Then I added a On component begin overlap (damage box) node so when the character overlaps with the damage box the blue print runs starts. Then I added a cast to third person character node and promoted it to a variable, which was then linked to a Set timer by Event and promoted that to a variable too. I then set the time of the timer to one and clicked true for looping and created a custom event called Damage Player for the event. The event was also connected to the built in Apply Damage node with the damaged actor selected to Get BP third Person Character and the damage was set to ten. To stop the damage after the character leaves the collision box I added an On component End overlap (damage box) cast it to the third person character and added a clear and invalidate timer by handle node (stops and clears the timer) with the handle being set to the Damage Timer variable.
Then, to create the health box I created a new blueprint and added a box collision to the viewport. Then I added On component begin overlap connected to the cast to character which was then promoted to a variable. Then similar to before I added a Set timer event and promoted that to a variable except this time the custom event is called Heal Player. The event is then branched into a print string which says MaxHealth and a set health variable. The condition for the branch is that the health is equal to 100 so using the As third person character variable and health variable I connected the health into the == node which allowed me to check whether the health variable is in fact equal to 100.0 and if this is true it prints max health and if it is false it sets the new health. The new health is set by adding 10 to the health variable and the As third person character as the target. And finally I did the same as before to end the timer when the player is not in the box collision.
Finally, I downloaded a free FX asset pack and added these two FX systems to the blue print viewports for both the damage and heal respectively.
Later, I thought that if I can make it print string when the health reaches 100, then I could possibly destroy the actor when health reaches 0. So I decided to test it out and it works, the same method branching off the custom event, except changing the == node to 0 and adding a destroy actor(thirdpersoncharacter) after the string.
This was added much later after the last blueprint following this first part of the blueprint series, it envolves the same nodes except for the damage box so when the character dies he ragdolls instead of just standing around with 0 health.
Football and goal
When the football overlaps with the collision box of the goal, spawns emmitter particle at location of goal and destroys football, then spawn actor at vector location. New nodes include, break and make vector, spawn emitter at location and spawn actor. Make vector allows three values (x y and z) to form into one (vector). Break Vector splits a vector in to the three values (x y and z). Spawn Emitter at location, spawns an emitter particle system at a certain location rotation and scale. Spawn actor, spawns an actor at a transform location rotation and scale, allowing the actor to spawn anywhere you want.
When the blueprint starts, Is valid checks to see if the Football is Valid(exists) then it sets the variable "Spawn Transform Location" to the Actor location so that in the previous node tree the spawn actor can use the original location of the football to respawn the football after it is destroyed. This also means you can move the football and it will change the location.
Yellow Mesh is called Hit Actor, added capsule collider to Hit Actor with arrow component to show direction of spin and Rotating Movement component to make the mesh spin.
When character Overlaps with HitActor calls hit actor and sets the Hit Location to the Arrow's forward vector.
When custom Event is called, and is Knocked Down is true it does nothing, However when Is Knocked down is false It sets Is knocked down to true and Set Simulate Physics, which essentially activates the simulated physics of the third person character, which I now set the collision to the preset Ragdoll. Then after the simulation of physics is activated an impulse is added to the character so it goes flying after being hit. The Hit Location is set to 50000 times the x and y axis whilst the z is just set to 50000. Finally after the impulse happens the character movement is disabled.
Here when R key is pressed set Boolean variable "RKeyPressed" to True, then connect both the RkeyPressed and Is knocked down into an And boolean which means that both booleans have to be true to output true. Then branch of so if both are true delay for 2 seconds and set simulate physics to non simulate this way it stops simulating i.e. ragdolling. Then attach the mesh back to the capsule and set the relative rotation and location to the default for the character mesh. Then set the movement mode back to walking and set is knocked down to false and health to 100. Health to 100 is actually for the damage box blue print earlier.
AI Blueprint
Following AI series
Start out by creating a Blueprint character class and a Blueprint Ai controller.
Then add the skeletal mesh of the character and change the animation class to the correct animations.
As I'm using a pre made animation and the movement animation requires the player controller, we had to check if the player is controlling it or not. So I added a get pawn owner and Is player controlled and connected it to the select index. This means that it will check to see if it is player controlled this way if it is controlled then it will still move when controlled but it will also move if it is false.
Then I changed the pawn settings so the AI controller class is the AI_NPC blueprint I created and the Auto posses AI is set to place in world. This means it will use my AI controller and will only work when place in the world (this can be changed later to let AI spawn in). Then I deselected use controller rotation yaw and in the character movement(rotation) settings selected Use controller desired rotation. This give more dynamic movement as it isn't just rotating to align with the character in one movement.
Next in the AI character blueprint on Event Begin Play, to add simple movement I added an AI move to node selected its self as the pawn and the target as the player character.
Lastly I added a Nav Mesh Volume and scaled it up to the playable area, this can be previewed with P.
The last AI movement is fairly simple so to make more complex AI you have to create a Behaviour tree and for it to communicate with the AI controls a Blackboard is necessary as well.
In the Behaviour tree there are three basic composites, a selector, sequence and simple parallel. The sequence has a series of tasks attached to it and if the first task is successful it will do the next task etc. The selector is similar to the sequence however it used the nodes, so if the first branch to the left succeeds it will stop and consider the whole thing a success, whereas if it fails it go to the next branch to the right. Simple parallel works differently as it splits into two paths, the purple one is a single task that can be added, the other one can be anything a selector, sequence etc. and it will loop these whilst the purple task is being done.
After, I created a new task called Random Movement. Then, in the task graph, I added an Event receive execute AI, which is essentially the same as event begin play except for AI. Then I added a Get Random Reachable Point Radius node, which essentially gets all reachable points in the playable area highlighted in light green. Then the Origin is set to the AI's location and The radius was promoted to a variable and made instance editable. Then the Random Location is set to the AI Move To node, where the pawn is the controlled pawn and the Acceptance Radius is again promoted to a variable and instance editable. Finally, On success, I added a Finish Execute node set to success and on Fail another Finish Execute node is set to not success. Effectively this takes the AI location then Gets a random location the AI can reach to and makes the AI move to that location. Finally, I added the new task to the sequence and changed the Radius and Acceptance Radius values. Lastly to make the behaviour tree run, in the AI controller on Event Begin Play, I added a simple node called Run behaviour tree.
In the AI controller I added an AI Perception this will be used to give the AI vision.
Then In the AI Perception settings I added a new Ai sight Config in the senses config, changed the peripheral vision to 50 to limit the sight and selected detect enemies, neutrals and friendlies just so now issues occur. Finally, I added 200 to the POV backward offset and Clipping Radius to 200. The POV backward offset moves the vision cone backwards from the character origin so the AI doesn't have a thin vision when viewing from directly in front.
I then added a On Target Perception Updated, which updates whether or not something is in or out of its vision. I then also broke the AI Stimulus in to its separate pins.
Then I created a new function called Handle sight, I added two inputs, Actor set to an actor and Stimulus set to the AI Stimulus from the Event Graph. Then from AI stimulus I linked a Get Sense Class into a Branch and equal node. This checks that the AI Sight Config is being used and then branches into true or false. If it is false then it will return, essentially doing nothing, however if it is true it will go into another branch. The condition for the second branch is that the Actor is equal to the player character, if it is false it will again return. However if it is true, then it will set the Value of the Blackboard as an object with the name Target Actor. The object value input is a Select object node which selects the A value if true and the B value if false. The A value is the Get Player Character node so If the Boolean is true it will select the object value to the player character. The Boolean is linked to the Stimulus broken down, and it uses the stimulus successfully selected as the condition. The stimulus successfully sensed is also lined to a new branch which is executed from the set value as object node, and if that is false it sets the value of the blackboard as a vector, where the vector is the stimulus location.
In summary, this function checks to see if the right sight config is being used and if it is, it continues. Then it checks if the Actor variable is the Player character and again if it is, it continues. If it was true then it sets the value of the Blackboard to the player character but only if the stimulus has been sensed, it also gives it a key name called Target Actor. Then it branches off again so that if the stimulus has been sensed its sets the value of the Blackboard to vector using the stimulus location and gives it the name Last Known Location. So if the sight is being used and the Actor is the player it will name the player target actor, and if the stimulus is no longer sensed it will mark its location as the last known location.
Then I added the new function to the target perception updated. After, I made sure to add the Target Actor, Actor Location and Last Known Location to the black board and changed the Target Actor Base class to actor. I then went back into the behavior tree and added a Blackboard decorator to the sequence, changing the Blackboard key to Target Actor and Key query to Is not set. Lastly, I branched of a new sequence and added a move to task and again set the Blackboard key to Target Actor. This means that first it will run the function and next it will move to the Target Actor. Finally, I connected the previous move to sequence into a selector and added a new move to for the Last Known Location, I also changed the abort setting to both.
Decorators are like gates which allow or block information to flow through the behaviour tree. Blackboard decorator takes keys from the black board and allows you to check if they are or are not set, you can also abort the operation if the Blackboard key is not correct. Cooldown based condition, blocks the node from being used after certain amount of time. Is at location, determines whether or not something is within range. Keep an actor within view of another actors cone vision. Loop detects whether the loop has been exeeded.
I created a new Decorator called check scale and added a Perform condition check function. This function checks the condition to see whether it will allow it and continue the code.
Then I created a new Blackboard variable called Actor and a get Blackboard value as Actor, then to check whether it is valid an is Valid node so when it is not valid it returns false. Then also out of the value as actor I added a get actor scale and vector length into a less than node. I then promoted the bottom value to a variable so I can set the Maximum acceptable scale and finally that goes into the return value when the value as actor is valid. This checks the scale of the Actor and checks if its is less than the Acceptable Scale and if it is then it will return true.
Hearing Sense
Hear I added AI Hearing Config to the AI Perception and set the hearing range to 3000.
Here I created the hearing handle, it is the same as the sound handle except after the first branch its sets the value of the blackboard to vector using the Stimulus Location as the vector value. Then In the behaviour tree I replaced the sequence for the random movement with a selector with a new sequence to the left of the task, this sequence is to stop the AI when it arrives at the Actor Location and wait for three seconds before clearing the code and continuing like before. I then went into the animation editor for the landing animation and at the frame where the character lands added a new notify. Then in the Animation blueprint for the AI I called the Notify Land, and linked it to a branch. The condition for the branch is that the pawn actor is the player character, and if true it will report noise event. The noise location is the pawn actor location and the instigator is the pawn owner. This means that when in range of the AI perception, if the landing animation plays it will detect the player location and walk towards it.
Patrol Path
First I added an Enumeration blueprint and added three enumerator, I named them Loop, Return and None. Then I added a new Actor blueprint called Patrol Path and I added a cylinder and arrow for visualisation of the points where the AI will walk to. Then I created a new task called Patrol and added four new Variables, Patrol Path, Current Path, Patrol Path Outcome and Path Direction. I also added the Patrol Path and Patrol Path Outcome into the AI Behaviour component. The Patrol Path Outcome uses the Enumerator a its class and the patrol path is set to a float map type and is an in built class called AI Object Patrol Path. Also the variables in the Behaviour Component are set to instance editable.
I then started the Patrol task with Receive execute AI and set the controlled Pawn and checked if Is valid using the get component by class (AI Behaviour Component) as the Input object. Then if the Controlled pawn is valid then it sets the patrol path outcome to the return value of the component by class. If it was not valid then it finishes as a a fail. Continuing from the Set patrol Path Outcome, I added a branch with the condition that the Patrol Path's length is greater than 0. If it is greater than 0 it will set the patrol path equal to the patrol path from the AI Behaviour Class and moves to the Patrol Point. If it is false then it finishes as a fail.
So, what this does is it checks that the Controlled Pawn is valid with the component by class from the AI Behaviour Component. Then from the AI behaviour Component it takes the Patrol Path Outcome enumerators and has it set. It then also takes the Patrol Path and checks the length to see if it is greater than 0 and if this is true it will either Set the Patrol Path to the Patrol Path from the AI Beahavior component and then move to the patrol point, or finish as a failure. So later on I will be able to select the Patrol Path blueprint as the Patrol Paths so it will Move to these blueprints.
Next I added a custom event called Move To Patrol Point in the Patrol Task. I then got the Keys of the Patrol Path, which Outputs an array of all the keys in the map. Then from the keys I added an AI move to node with the Pawn being the Controlled Pawn and the destination being the Actor location in which the target its the Get keys node with the Current Path as an Input. Then from the Ai move to, On success I added another Keys from the Patrol Path Into another Get and Current Path this time going into a Find node and into a Max set to 0.1 which then goes into a set time by event as the time value. The event for the timer is set to a custom Event called On End Waiting, from this custom event I set the Current Path to the Current Path plus the Path Direction and checked if the Map index was valid, this was then used as a condition. If the Map index is valid then it will move to patrol point, if not then it will Switch On the E Patrol Path Outcome. Then for Loop enumerator, I set the Current Path and added a move to patrol point. For the Return Enumerator, I set the Path Direction to the Path direction multiplied by negative one and then set the Current Path to the Current Path plus the Path Direction and move to patrol point. And finally for the None I added a decrement for the current path. Finally, I went back to the Patrol path blueprint and created a custom event called On Patroller Entered, then added an input called character set to character class, and got the controller of the character and set the control rotation to the arrow's world rotation. I also added a call on point met as a Event Dispatcher in case I wanted to add other events later. Then back in the Patrol task I called the Patroller Entered from a cast to character node, where the target is the get keys from patrol path.
To explain what all this means, essentially It starts out by moving the AI to the next patrol point using the current path as reference for which patrol point to go to. Then it sets a timer by event, where the timer is set to a maximum of 0.1 which actually means the minimum it will output is 0.1 as it takes the highest value from both the patrol path and 0.1. This is to prevent it from being 0 and just stopping the timer. Then the Event for the timer sets the current path to the current path plus the path direction where the path directions default value is set to 1. so if the current path is 0 it will set the current path to 1 etc. Then it checks to see if the Current path has a valid map index and if it does it will move to the patrol point, in other words if the value is already valid it will continue to move to its next patrol point. But if it isnt valid then it will call the Enumerator Patrol Path Outcome, which has the three options Loop, Return and None. So for loop it sets the current path to 0 effectively making it start all over again and have the AI move back to the first selected patrol point. If however, it is set to Return then the AI will set the path direction to its opposite value as it multiplies the path direction by negative one, so if the path direction is one it will be negative one, and if it is negative one it will become positive one. Then it sets the current path to the current path plus the Path direction and moves to the next patrol point. This effectively reverses the path direction so when it reaches the end it will return back throught the route going the opposite way. Finally, for the None category, it will simply take one away from the Current path which will make the AI stop once it reaches the end of the path.
In the behaviour tree I added the new Task using a Selector where the Patrol task is to the left of the Random Location task.
Finally, I added the AI, to the view port and also some Patrol Path blueprint objects, in a path and selected them in order and gave different times for them to wait at each patrol point.
Video of AI for demonstration purposes.
Touch Sense
I added a new sense to the AI Perception called Touch Sense config, and added a new Function called Handle Touch, I then copied the exact same as the Handle Sight function except from the Last Known Location part and I also changed the AI Sight Sense to AI Touch Sense. I then went into the AI Character Blueprint and added an Event Hit which essentially gets called when the actor is hit by another actor. Then I added a report touch event where the receiver is itself and the other actor is set to other actor, with the location set to Hit location. Finally, I added the Touch sense to the AI Control event graph (for testing purposes only the handle touch is executed.
Nav Mesh Modifiers
Nav mesh modifiers affect the Nav mesh in various ways, there are four pre-set modifiers, Default which is the normal nav mesh, LowHeight, which means if the AI is small enough it can entere the area, Null which means no matter what the AI can not enter this area and finally, obstacle which means if the AI has to it can go through. The nav mesh has different values, the default value is set to one and the default obstacle is set to one million. So the AI will take the cheapest (smallest valued) area as the path to take should it need to go through. You can also create custom modifiers using Nav Area blueprint, where you can change things like the default value and how much it costs when you are in the area. You can also add Nav mesh to blueprints with collision objects, such as a particle system, so the AI cant go through the particles. In order for this to work you have to change the nav mesh runtime settings from static generation to dynamic modifiers only.
EQS systems
They can be used to make the AI behave in various ways, such as to run away from the player, find advantageous postions and even hide from the player.
Here I added a simple environment query and and EQS test blueprint. Then In the environment query I added a points grid node. Then in the details panel of the EQST blueprint I changed the Query template to the Environment query and dragged it into the viewport. Then after the points are set up you can add tests for the points. Some common tests include distance, dot and trace.
Distance allows you to set some test purposes, the tests include, filter, score and filter and score. Test mode changes the distance settings these include Distance, 3D, 2D, Z and Z(absolute). Z refers to the height. Then you have distance to the query which means which query are you measuring the distance to. Then you have the filter settings which the type can be changed from range to minimum or maximum. Score settings change how the points are scored, so linear means the further away from the query the higher the score.
Then I created a new Query Context Blueprint base, this is to make the player a query so that instead of the stationary query from before the query settings follow the player around. As there is only one actor I added a new Function override called provide single actor. I then added a Get actor of class Player Start, this way it will get the player whilst the game is running. I then also set the score settings to the type square so the further from the query the higher the value.
Then I added the trace test and changed it to filter with the context player. So if the AI is to hide from the player only the points with values are areas where they can hide.
I also changed the vertical offset of the projection data to 80 this way the spots which are supposed to be hiding spaces but are clearly visible are not no longer visible.
Then I added another distance test this time set to inverse linear and score, so the score is higher the closer the point is to the player however also being out of "sight".
I added a new sequence in between the Roaming sequence and the Chase sequence called Hide sequence. Then to the left I added a run EQS query and changed the Query template to the EQS_NPC and the Blackboard key to Actor Location. Finally, I added a move to Actor Location. So now whenever the AI sees the player it will move to the player and then to the highest valued point in the area surrounding the player.
More EQS tests
Next I added a new points grid and move the old one to the side. I then added a dot test, which essentially draws two lines, one goes from the query, checking its rotation and the other goes from the query itself to an item in a the query. So if the two lines have the same direction and rotation then it will equal a value of one, if they are opposite each other then it will have a value of negative one and if they're perpendicular then it will have a value of zero. So for example If we set the Test purpose to just filter, set the filter type to minimum and the value to zero, it will filter out all the points behind the EQS test pawn as the minimum value is zero. This is because the points behind the EQS test pawn are facing away from the query so they have a value of negative one which is less than zero. So changing the settings and values put in you can allow for certain points to have value and others to not.
Next there's gameplay tags, this takes gameplay tags and gives a certain value based on the gameplay tag. Gameplay tags are essentially conceptual hierarchy labels, so for example a Family and children, the Family is the tag and Children are items within that tag. So gameplay tags are usually better of set up on individual items. The gameplay tag EQS test will allow for certain items within the query to fall under a particular tag and then if you want to call certain tags maybe all items with a tag etc. then you can. This works like usual with Filter, Score and Filter and Score. So if you want to filter certain items with a tag you can or if you want to score an item with a tag etc.
Then there's overlap, you can set up extents of x y and z which are half values of the value. For now I set it to Filter Only and the extents to a value of 50. What this does is when items are close to static objects like a wall it will filter them out. However, one thing I forgot to change was the post projection vertical offset of the grid points itself back to 80, which led to the test not working as seen in the first viewport picture. But once I changed that setting it worked like normal. This is useful for finding cover places behind walls etc. Or the inverse to stay away from walls.
Then there's Path finding and Path finding batch, they both function in the exact same way just the batch version is slightly more accurate. Essentially the path finding just checks whether or not the AI can reach this point so point which are not reachable get filtered out, this can help stop bugs from happening by filtering out all unreachable spots so the AI simply will never try to reach them.
There is also project, which helps points which would collide with other objects or even sometimes be inside objects to projects and show outside those objects. By default this is set to use the nav mesh, which means that items that would not be within the nav mesh get pushed back into the nav mesh, this is useful for items next to the walls of objects where the nav mesh cuts off. However, certain objects still have the nav mesh inside the object as the floor is technically within the nav mesh so these items will still appear inside of objects. To stop this from happening we can change it from Navigation mode to Geometry by channel.
Finally, you have volume, this is similar to the overlap except you can set the source volume itself. So you can change the shape of the volume.
AI Find cover
First I added to cubes scaled and placed them for the cover. Then I created a new Environment query called find cover and added a grid points node. Then I added a trace with context to the player and I changed this to filter only. Then I increased the post projection vertical offset to 50. I added an overlap box where x and y extents are 100 and is set to filter only. And finally I added two distance tests one for the querier and the other for the context player both set to score only and inverse linear. This means that the closer to the player whilst also not being visible at the vertical offset of 50 will be higher valued then the rest and it will filter out any points not close to objects walls. Then I created a new behaviour tree called Find cover and added the Run EQS query, set to actor location and a move to Actor location. Then for testing purpose I changed the EQS in the AI controller from the NPC to Find Cover.
Then I created a new AI Blueprint Interface and added four functions, Attack, Retreat, Advance and Cover. I then went to the class settings for the BP_NPC and applied the new Interface. Then I added the Event Cover to the Event graph by double clicking it in the Interfaces section and dragged of the crouch node, I also had to change the character movement setting, can crouch from false to true. Then for the other three events I added the Un crouch node so it will no longer crouch. Then in the Find cover BT, I created a new task called Enter Cover, and from the Execute AI, I called the cover event for the controlled pawn and finish execute success. Finally, I added the task to the end of the find cover behaviour tree, and at the very end a wait node with three seconds and a random deviation of two seconds.
Crouch animation
First I added a free asset pack called Animation starter pack then took the animation couch idle holding rifle and retargeted the animation from the UE4 mesh to UE5 Manny mesh. Then in the ABP Manny blueprint, on the end of the falling animation I added the movement component and is crouching node and set it to a new variable, Is Crouching. And finally, in the Anim graph in the locomotion state machine and in the idle animation I added a Blend poses by bool with the condition being the Is Crouching, the true pose as the new crouch rifle idle and the false pose as the Manny idle. So now whenever the AI is behind cover it will crouch and then play the crouch animation.
AI take cover continued
First I added a new Environment query called Find Attack and changed the post projection vertical offset in the grid points to 120 so the points appear above the cover. Then I added the test trace with context player and set it to filter only and I also added a distance to querier set to inverse linear. Then in the find cover behaviour tree I added a new sequence with the run Attack EQS and move to Actor Location. This way when the AI enters attack mode, it will exit the cover and into the visibility of the player. Like the crouch I created a new task for entering attack mode, where on Event Execute AI, I called the Attack interface and execute as success. Finally, I added the attack task onto the end of the behaviour tree. I then, for testing purposes, added a print sting after the event Attack is called, this can then be replaced with things like shooting etc.
Then, in order for the attack code to even run, I added a new blackboard key called Is Attacking set to bool, and to the crouching sequence I added a blackboard decorator, with the key set to the new bool key, and is not set with both abort. Then in the Enter Attack task I added a set timer by event, with a custom event called Back into cover and the time is set to a random float range of one to two. Then from the custom event I added a set blackboard value as bool with the key being the make blackboard key selector and the key name being Is Attacking, I also added a finish execute success.
Finally I went into the crouch task and added a Boolean with weight into a branch. What this means is that if it is set to 0.25 there's is a 25% chance of the Booleans being true. If it is true it will set the black board value as bool to the Is Attacking key and finish execute, if not then just finish execute. And lastly I re added the wait after the crouch so it stays crouched for at least three seconds before entering attack mode.
Then to make the AI look at the player whilst in attack mode I added a simple rotate to face BB entry and selected the Target Actor as the key. Then in the AI controller I linked the player character for both selections, this way even when in cover he will remember the player characters position.
AI Smart Objects
First I turned on two plugins, the first is AI behaviours and second is smart objects.
Then I created two new blueprints a Gameplay behaviour and a behaviour config. I then applied the behaviour config blueprint as the behaviour class in the gameplay behaviour. I also added a new Data asset (found in miscellaneous section) and selected the smart object definition. Then in the gameplay behaviour blueprint I added a new function override Event On triggered character. This means that when the character triggers the smart object this will run. The avatar is the character interacting with the smart object, the config is the behaviour config and the smart object owner is the actor which the smart object belongs to.
Then I created a simple animation montage of the Manny sitting, this was done using the sequencer and the inbuilt rig for the Manny mesh. After that I went back to the gameplay behaviour and promoted the avatar to a variable and played the montage using the Manny mesh as the skeletal mesh component then On completed and interrupted it ends the behaviour. Then I installed another plugin called Gameplay behaviour smart objects. Then I entered the test definition and added a new slot, changing the default behaviour definition to the gameplay behaviour smart object behaviour definition and under that I selected the test config. Then I created a new BP actor, added a cube and a smart object gameplay. In the smart object settings I changed the definition to the test definition, then I aligned the objects so the smart object is accessible.
AI Sit Down
Next I created a new behaviour tree with a blackboard and added the new key type, SO Claim Handle Key. Then I added two new tasks one for finding the smart object and the other for using it.
In the find smart object task, the above blueprint checks to see if there are smart objects within the given area and if there isnt it will finish execute and if there is it will continue. If there is a smart object within the area then it will mark it as claimed checking if it is valid and if it isnt then it will execute as a fail. If it is valid then it will set the blackboard value as SO Claim Handle with the blackboard key set to SO Claim Handle Key and finally it will finish as a success.
So the Find smart objects node finds smart objects using the Smart object subsystem and a requester. The make smart object request node allows you to set the requester using a filter and a query box. The filter allows it to be filtered using gameplay tags and behaviour definition classes, in this case I just used the gameplay behaviour class. The query box takes the controlled pawns location, in this case the AI, and makes the box with the minimum values set to the actor location subtract 2000 on all three axis and the maximum being the actor location add 2000 on all three axis. So it will find smart objects within a 2000 radius of the AI.
After it finds the smart objects it promotes the array results to a variable to be used later. Then it checks if the results are valid, if not then it executes as a fail. If they are valid then it marks the smart object as claimed using the array results > random > break smart object request result. Then it promotes this to a variable too, called Claim handle and it checks if it is valid. If not then it will execute as a fail, if it is valid then it will set the Claim handle as the black board key SO Claim Handle Key and execute as success.
The use smart object task is easier, we get the Blackboard, gets the SO Claim Handle the key name is make literal name SO Claim Handle Key. Then a move to and use smart object with gameplay behaviour node, using the return value of the SO claim handle and the owner controller as controller. Finally on succeeded finish execute as success.
So it gets the SO Claim Handle makes using the SO Claim Handle Key, and moves to and uses the smart object.
Then in the behaviour tree I added a selector with a sequence, then under the sequence I added the Find and Use smart object tasks along with a wait, and if this succeeds or fails it will wait one second and then run again. Finally, in the AI controller I set the run behaviour tree to the BT Sit Down.
Then I enabled Motion warping in the plugins and created an Idle sitting animation to go along with the regular sitting animation. Then in the animation montage used for sitting I added a new notify state motion warping at the beginning. Then in the settings change the warp target name to Chair and open the animation asset, then in the asset details enable root motion. Then in the BP NPC I added the motion warping as a component. Finally In the smart object behaviour I added a get component by class, with the class being motion warping component, and from that an add or update warp target from transform. The Warp target name is the chair as named in the animation and the transform is the smart object actor transform.
Then in the animation to stop them from standing I disabled auto blend out in the montage. And to make the AI sit properly in the chair I set the chair collision to false so the AI can reach the smart object within the chair so when the animation plays it actually sits in the chair.
Smart Enemy AI
The following is me learning how to make smart enemy AI using the youtube series by Ali Elzoheiry
First I made a quick sword model to be used as a weapon and also a quick sword slashing animation. To create the animation I downloaded the X bot model from Maximo and made a rig using unreal engines built in rigging tools.
To make control rig, simply right click skeletal mesh, new, control rig. Then in the control rig create controls for the bones that should be controlled, by right clicking the bones, new and add controls for selected. Then create two new item arrays one for all the controls and one for the bones, this is done by dragging and dropping the selection into the graph and selecting create item array. Then add a for each node selecting the bones item array as the array, then from the element pin add a set transform bones. From the index of the for each node, add an "at" node and select the controlls array as the array. Then from the "at" node get the transforms and connect the output to the value of the set transform node. Finally, change the shape rotation size etc. for each of the controls.
Then for IK controls select the hand bones create new controls and unparent them and change the shape to a box. Then for the elbow, select the fore arm bone and add new control this time keeping the parent and offsetting the control out from the elbow (this will be where the elbow is facing and is called the pole vector). Do the same as the arms for the legs. Then in the graph make new basic IK where item A is the upper arm/leg bones, item b is the middle/elbow/knee bones and item c is the hand/feet bones. Then the effector is the hand IK controls and Feet IK controls. Then the primary axis depends on the axis direction the upper bones are facing towards the lower bones, so if the direction from the upper left arm to the left hand is negative y then the primary axis is -1 in the y this is the local axis of the upper bones. Then for the Secondary axis it is the same as the primary axis except of the middle bones towards the corresponding pole vectors. Then I replaced the item arrays by setting them as variables and connecting them to the construction event.
Then in order to make a switch for IK and FK controls, I created a blank control called IK FK Switch and changed the value type to float so now when the control has a minimum and maximum value on the x axis. To impliment the switch I created a branch from the forwards solve with the condition that the switch control is remapped with a target minimum of 0 and maximum of 1 and is nearly equal to 0 with a tolerance of 0.1. So depending whether or not it is true or false it will hide the FK or IK controls.
I decided to scrap the rigging myself and go with the inbuilt mannequins rig as it is easier to setup and animate, I also downloaded a free weapon asset pack for a better looking sword.
Then like previous AI I created a Behaviour tree, blackboard, character blueprint and AI controller blueprint. Changed the pawn settings and rotation settings to work with the AI controller and use controller oriented rotation.
I then created this simple combat state using a few tasks. First I added a blackboard key of type object (actor) called Attack Target. Then from the sequence I added a Move to, then base attack task then wait. Then I added in-between those, the focus player task and clear focus at the beginning. Before the attack sequence I also added a task for equipping the sword, so it won't just run the equip sword task over and over again I also added a blackboard decorator.
The Focus and Clear focus tasks are fairly simple as their is an inbuild function for each, I just had to specify that the focus is set to the Attack Target.
Then for the attacking task I called the attack event which I made in the enemy AI character blueprint, then bind event to on attack end (an event dispatcher) with the new event called Finished Attacking. The attack event itself is simple as it simply plays an animation montage I created using the unreal engine control rig for slashing sword animation. Then on completed or interrupted it calls on attack end which was binded to the new event in the attack task.
Then for the equip sword task I called the equip sword event from the AI character blueprint. I then created a blueprint for the sword with just a simple static mesh. Then under the custom event equipped sword I spawned the new sword blueprint as an actor. In order to spawn the actor it needed a transform so I just used get actor transform. Then I attached the actor to the component which is the enemy AI mesh under the socket name Grip_Point, changing the settings to snap to target. I then also set a new Boolean variable called Is wielding sword to true. I quickly added the new socket under the same name Grip_Point, to the right hand of the enemy AI skeletal mesh. Then I created the new decorator for the equip sword task, which performs a condition check is wielding weapons, which basically means if the return value is true then it will run the task and move on. However, the equip sword task should run when the sword is not equipped so I had to change the condition to inverse condition.
Here I created a new blueprint called patrol route of type actor and added a spline. I then created a custom event, setting a new integer variable called patrol index to the patrol index plus direction (another integer variable). The patrol index is representing the point where the AI is along the spline and the direction I set to a value range of negative one to one. Then if the number of spline points minus one is equal to the patrol index then it sets the direction to one, this means the AI is going in towards the end of the spline. If not and the patrol index is equal to 0 (Has reached the end or beginning) then its sets the direction to negative one or in other words going back towards the start.
Here I created a new function for the patrol route where it sets the new value Location to the spline point where the AI is at (patrol index). I then set the patrol route for the AI in the viewport details settings.
Here I created a new interface added an output called patrol route of the type blueprint patrol route and in the Enemy blueprint I set the Patrol route to Patrol Route variable.
Here I created a new task called move along patrol route, then checking to see if the patrol route is valid, then get spline point as world position and AI move to that location and finally incrementing the patrol route. So it gets the patrol route checks to see if it is valid, if it is then it gets the spline point as a world position and makes the AI move to that position and increments the patrol route function.
I then created an enumerator with four enumerators called idle, walk, jog and run. Then in the blueprint interface I added a new function called Set Movement Speed with an input of the enumerator and output of type float. Then the float value is set to the maximum walking speed of the AI which is then set to a either the idle speed (0), walk speed (150), jog speed (300) or run speed (500). I then created a new task to implement the function to be used for the behaviour tree. I then created a new decorator to check if the AI has a patrol route this way if it doesnt I can make it do something else.
Here I added an enumeration for each of the possible AI states (some to be used later). Then I created a new blackboard key called state and in the AI controller set it as value enumerator. I then made two functions one for passive and one for attacking and duplicated the blueprints changing the state to attacking when in the attacking function etc. This way I can switch between attacking and passive states.
I then added blackboard decorators to the behaviour tree for both the passive and combat states. The attacking state also requires a target so I took the black board as object blueprints from the event graph and set the object value to a new input called attack target which is set to actor.
I then added a way to switch between states by pressing the one key. I then also added an abort self to both the passive and combat states. I then added a stop movement when receiving an abort, this way the AI doesnt move when switching states.
Here I added a new custom event for sheathing and changed the equip sword event to play custom animation montages. On completed it calls event dispatchers for wield and sheath and on notify begin when the notification (which I added in the animation montages) plays then it spawns the sword etc. And for the sheath sword it just destroy the actor. And finally For the sheath sword I created a new task so that only when the sheath sword is finished will it execute as a success.
Then I updated the behaviour tree by adding a selector after the passive state so if the AI is wielding a sword (same decorator as before) then it will sheath the sword and then go back to patrolling. Finally I added the ability to changed between states by pressing the one key.
I then added three senses to the enemy AI, sight, hearing and damage (changing some settings like distance and age and stuff). To debug them I created a small blueprint which creates a noise when the player presses the R key as well as spawning an explosion particles and playing sound. And for the damage I did the same just reporting a damage event instead of noise.
Then I created a new function for handling the senses with two inputs, Actor (set to type actor) and Sense (set to a new enumerator with four options, none, sight, hearing and damage). Then I got the Actor perception from the AI Perception and broke the Actor Perception Info. Then for each of the Last sensed stimuli I got sense class for stimulus then, if the sense class is equal to the enumerators with a sense class for each of them then the stimuli is successfully sensed and also has an output for the AI Stimulus.
Essentially it gets the perceptions of from the AI Perception and for each of them gets the sense class. If that sense class is equal to the sense class given in the select node for each of the enumerators then it outputs true. Then its sets the Boolean values of Sensed to the Successfully sensed Boolean from the AI stimulus. And it also outputs the AI Stimulus as Stimulus to be used later.
Here I Implemented the Handle sense function so when the AI Perception is updated for the updated actors it handles sight hearing and damage and prints a string depending on what sense is used. (I also added the handle sensed sight function which is explained later).
Here I created a new function to get the current state the AI is in.
I then created a new function for handling sight, so if the current state is passive or investigating and the actor is a player it will set the state to attacking. So now when the player is seen by the AI it will enter attacking state. I then created another function to set the state as investigating and setting a vector called Location as a new blackboard key called PointOfInterest. And I created another function this time to handle hearing and to set the state to investigating.
I then updated the event graph to include handle hearing with the location set to the stimulus location. I then created a new task to set the state as passive and updated the behaviour tree to move to the point of interest if the state is equal to investigating and wait then set the state back to passive. I also rearanged the states so the priority goes from combat state, to investigating state to passive state. I also changed the investigating state to abort its self so if it sees the player it can still enter attacking stated even when investigating.
EQS:
Strafe EQS:
I started by making a blend space for walking forward, left, right and backwards as well as a new idle animation to setup a strafe system. I set the blend space up so that on the horizontal axis is direction from -180 to 180 and on the vertical axis is speed from 0 to 100. The far left and far right at the top are walk backwards animation, at the middle top is walk forwards, to the left is walk left and to the right is walk right and at the bottom is all the idle animation. Then in the event graph i set up a new Boolean variable called Is Focusing Target so for the walk/run animations if Is Focusing Target is true it chooses the new blend space with Direction and Ground speed plugged in, if not then it chooses the original walk run blend space. I also set this up for Idle animation.
I then created the environment query and environment query context where the context gets a new variable, which was promoted from the AI controller set state as attacking function, is used as the resulting actor. This means that the querier is set to the attack target or in this case the player, as I want the AI to strafe around the player when attacking. I then set up the behaviour tree to focus the target, set movement speed to jog, run the EQS query (the blackboard key is set to Point Of Interest as it needs a vector value) and then Move to Point Of Interest. I then set up the query system to use points in a circle of radius 350 and space of 50 with 5 points and the spacing method set to by number of points, this way only 5 points are generated, it also uses the context attack target created earlier. I then set up a path finding test so that only the points that are reachable have value. So now when the AI enters combat state (Currently the Chase/Attack sequence is unplugged) the AI will wield the sword and strafe the attack target whilst staying focused on the attack target. I then set up a distance test to filter and score points within a range of 100 to 500 so that the AI doesn't cross the circle to get to another point and will only move to points which are next to the one its already at (so essentially strafe). I then reattached the attacking sequence and added a cooldown of 10 seconds (a decorator called cooldown), this way it will attack every 10 seconds and then strafe).
I then created two new blackboard keys of type float called Attack Range and Defend Range, I then also created a new function in the blue print interface with two outputs of the same name and type as the blackboard keys. Then in the AI character blueprint I changed the interface so attack range is 150 and defend range is 350, this is so the AI wont enter strafe mode even when it is no where near the player. Then in the AI controller I set the new attack and defend ranges as their blackboard keys.
I created a new decorator, which takes the distance between the attack target (a blackboard key as actor) and the controlled pawn(AI) and checks if it is less than or equal to (in range) of a new blackboard key selector called Ideal Range. It also subtracts a margin of error variable which is equal to 50, in case of any errors.
I then created a custom move to ideal range task with the target actor as Attack Target (actor) and the acceptance radius as Ideal range (Float).
I then added a selector before the strafe sequence, then a new selector called Move To Ideal Range holds the new decorator with the ideal range set to defend range and attack target as attack target, and the condition is set to inverse as it is checking it is not within defend range. If it isn't then it will clear focus, set movement speed to run and execute the new task move to ideal range. I also implemented the new move to ideal range task into the attack sequence.
I also found out I was using a selector for the move to ideal range section which messed up the behavior tree so I changed it to a sequence as it should be.
EQS- Find Cover
I made a simple get cover sequence using a new EQS. It uses grid points with a half radius of 1000 and 150 between each point. Then I added a path finding test to discard unreachable points as well as a path tracing test with the context attack target and the item height offset set to 180. I also added a distance test set to score only and inverse linear so the AI stays closer to the Attack Target. I then implemented it into the behavior tree as a quick test, getting rid of the attack and strafe sequences, so it clears focus, sets movement speed to running, runs the EQS with the result set to point of interest, then a move to point of interest, wait a few seconds, move to ideal range (attack range) and then run the default attack task. So the AI runs from the players sight then after a few seconds runs back to the player and attacks them.
Enemy types (Ranged, Melee):
I first downloaded some sounds, a rifle model, some rifle animations from mixamo and also installed an asset pack which contained some effects. With the two sounds I mixed them together in a cue, and created a blend space for walking and running with the rifle. (I also changed the sword animations from custom made to better pre made). The sound and gun model were acquired from the Lyra Game free unreal project. And the effects were from the Paragon Sparrow asset pack. Finally I duplicated the materials from Manny and changed the tint in the base colour to an orange gold colour to change the look of the new enemy.
First I created a child blueprint class from the enemy base blue print, called Enemy Ranged. I then applied the new materials to the enemy ranged class.
I then duplicated the animation blueprint (ABP Manny) and called it ABP Ranged Manny, I then also disabled the foot IK blueprints which were in the previous animation blueprint (the float node is just to make clear that the foot IK is being disabled), this is done as I'm using all custom animations. I then changed the idle animation and run walk locomotion states to the new rifle idle animation and rifle directional blendspace. I also added a new socket for the rifle.
I then created a montage from the fire rifle animation and added a notification when the animation trigger finger is pulled. I added an animation to be used for triggering a damage event (Fire Shot), as well as the rifle fire sound effect, and a flash effect, each on their own notify track.
Then in the BPI (for the enemy base) I created two new functions one for equipping weapon and the other for unequipping a weapon. This is because the base enemy currently uses an equip sword event rather than being generic with an equip weapon event. I also renamed the event dispatches for equip and unequip sword to their more generic counterpart and I also replaced the equip and sheath sword events with the equip and unequip weapon interfaces and I also renamed the tasks for equipping and unequipping sword to weapon. I then changed the equip sword and unequip sword tasks to fit the new equip weapon and unequip weapon interfaces. I then changed the variable names for Is Wielding Sword and sword actor to weapon. I also changed the name of the BP weapon sword to BP weapon base, removing the sword and renaming the sword mesh to just mesh. I then made a child blueprint from the base weapon, called weapon sword, where the mesh is set to the sword and back in the enemy base I changed the spawn actor to the new child blueprint for sword.
In the enemy ranged blueprint, I called the Equip Weapon Interface and spawned the bp weapon rifle, setting it as weapon actor (a variable of type bp base weapon base), then I attached it to the ranged enemy mesh snapping to the rifle socket, then I set has equipped weapon to true and called equip weapon event dispatcher. Lastly I called Equip sword as a function on event begin play.
I then also quickly set up a new child blueprint off the enemy base, this time for melee enemy, copying the base enemy event graph to the melee enemy and getting rid of all the blueprints inside of the base enemy. I also added a new function to the BPI for attacking and repaces the attack event with the new interface function.
Here I created a new folder for behavior trees and a new behaviour tree called sub tree investigating and copied the investigating state into the new behaviour tree. Then in base enemy behaviour tree I added a run behaviour node with the new behaviour tree for investigating applied (along with the black board condition from the old sequence). This is done because most enemy AI will likely need an investigating state. I then created another "sub" behavior tree for the passive state, excluding the unequip weapon task as the ranged enemy, and maybe other, wont need to unequip their weapon. And I again run the behavior tree. I then duplicated the enemy base behavior tree calling it enemy melee (the original enemy base behavior tree is already programmed for the melee enemy type). I then deleted all of the combat state nodes, leaving only the Combat state sequence, Investigating state sequence and subtree, and finally the passive state with its subtree. The base enemy behavior tree is now just to get an initial structure for other enemy types and wont be used in any actual AI.
I also found out that in order to see all the variables in the child blueprint that the parent has, in the my blueprint section click the cogwheel and tick inherited variables.
Then In the enemy base blueprint I created a new variable called behavior tree of type behavior tree(object), and I then changed the default value to the enemy base behavior tree. I then changed the default value for the melee and ranged enemy to their respected behavior trees, (I already duplicated the base enemy tree and called it ranged).
Then in the AI controller I cast to the enemy base and get the behavior tree variable (converted to validated get) and plug the behavior tree into the Run behavior tree node.
Then I set up the ranged EQS so that points further away are scored higher (so its keeps a range of around 600), the player is visible to the AI and that it will not go to the points directly next to it (so it has to move a decent distance).
For testing purposes I placed the testing pawn and applied the new EQS to visualize where the AI can go.
Then I made the Evade and attack sequence for the ranged enemy, it focuses the target sets movement speed to jogging (300) runs the new EQS choosing a single random item within the best 25% (the selected key is point of interest), it then moves to the point of interest and plays the default attack task ( which calls the attack function provides by the BPI). I then took the attack function in the ranged enemy blueprint and played a shooting animation, in that shooting animation when the notification (made earlier) is played then it gets the attack target. It then traces a line, setting the weapon actor as the start point and the attack target as the end point, if the line hits then it prints a string (temporarily).
Here I created a new decorator called can see target, which traces a line from the controlled pawn(ranged enemy) to the attack target(blackboard key/player), it ignores the controlled pawn so the trace doesn't collide with itself. Finally i returned a Not Boolean of the return value from the line trace, so if the line hits the player then it can see the player if it hits something else along the way then it can not see the player.
I then added the decorator to the Evade and Attack sequence (set to abort both) and created a new sequence so that when the player isn't visible it moves to the single best item in the EQS and it sets the speed to run instead.
In the first person character, I previously made a report damage event for the AI, now after that it spawns an explosion particle at the AI (base) and then applies 10 damage to the AI (base).
Then in the enemy base I set up a quick health system with max health and current health default set to 100, then from event any damage it subtracts the damage from the current health and clamps it so that it has to be within the min an max of 0 to max health, it then sets the current health to its new value and if that is less than or equal to 0 its sets a Boolean value Is Dead? to true. I then set up two new interface functions one for getting current health and one for max health both return a float value called health.
I then made a new decorator, that gets the current health and divides it by the max health and if that is less than or equal to a new variable health threshold then it will return the value. The health threshold has a slider range of 0 to 1 and a value range of 0 to 1, this is for easier percentages. So for example if the current health is 70, max health is 100 so the outcome of the division is 0.7 so if the health threshold is set to 0.3 then it will not return a value. I then copied the find cover sequence from the melee enemy and removed the attack parts so now it will find cover when current health is below 30 percent, so if its is above 30% it will abort what its doing and go back to attacking but if its below 30% it will stop attacking and run for cover. I also added a focus target at the end so once it is in cover it stays focused on the player.
I then created a new function in the BPI called heal with an input float heal percentage, it then multiplies the heal percentage by the max health and it to the current health and if it is between 0 and max health it will return the value as current health. So it takes a new variable heal percentage takes the percentage from the max health and adds the health onto the current health. I then created a task to call this function with the heal percentage set to a variable between 0 and 1. So after going to cover they will now heal by 5% and wait 1 second.
Damage System:
I started by creating a new BPI for damage with four new functions, get current health, max health, heal and take damage. Get current health has an output of current health (float), max health has max health output, heal has amount in and new health output and damage has a lot so I created a structure to store all the variables. I then created an enumerator for the different damage types with none, melee projectile etc. I then created another enumerator for responding to damage. In the structure I added the two enumerator types, a damage amount, should damage invincible (should damage even if the player is in an invincible state), can be blocked, can be parried, damage causer, and should force interrupt (interrupt anything happening). The take damage function also returns a Boolean value, was damaged.
I then created a new Actor component blueprint to implement the functions as a generic damage system. I added these new variables to the left where health is (current health) and is set to 100 as well as max health set to 100.
In BP enemy base I implemented the new interface and changed the max and current health to get the max and health from the BPC Damage system.
Then back in BPC damage system I created a new function called heal which takes health and adds it to the amount (of health healed) and sets the outcome as health and returns that as new health. It is effectively the exact same as what I did earlier except more generic and can be used for multiple actors. And finally I added a branch so if Is dead is not true then it will heal otherwise it wont. Then I implemented the function into the enemy base.
Here I created a take damage function for the actor component with the input and output being the same as the interface function. It uses a macro "can be damaged" to determine whether damage was taken or not. The macro checks if is not dead and is invincible or should damage invincible, then if that is true and can be blocked and is blocking are both true then it block damage if i cant be block or isn't blocking then it will do damage other wise if all conditions are false so, is dead, or is invincible or shouldn't damage invincible then it will output no damage. Then in the function damage amount is subtracted from health and if do damage is true then health is set as that new value, (if block damage or no damage is true it just returns was damaged as false. If it has applied damage and health is now less than or equal to zero it sets is dead as true and returns was damaged as true, otherwise it just returns was damaged as true. I then replaced the print strings with new event dispatchers, one for after is dead is set to true, another for damage response and the last for can be blocked, with an input of can be parried.
Finally in the construction script, I binded the event dispatchers to new custom events.
I also forgot to create this is dead function and so I implemented it like so.
I forgot to plug the false into the return node.
Health Bar:
I set size to custom of 200 by 20 added a canvas panel and progress bar, selected anchor type to fill, and changed the off set settings to 0.
Then I created a binding for the percentage, which takes a new variable of type BPI Damage System and takes the current health and divides it by the max health.
Back to Enemy AI:
First, I downloaded two hit animations for rifle and sword. Then I implimented the functions of the damage system into the player as well.
After implementing the functions and also changing deleting the old functions and replacing them with the new ones, I also removed the event any damage. I then used the take damage after the spawn emitter node to test the damage system. For the heal task I took the maximum health and multiplied by the health percentage to get the exact amount of health healed which is what's required for the heal health function.
Here I implemented the widget into the enemy base, I also added a widget as a component called health bar. I also had to call parent event begin play for the other AI children.
Here I implemented the take damage into the melee enemy by having a notification on the montage, then when that notification plays a sphere trace occurs with the actor location as the start and for the end, a actor as forward vector x 200 added on to the actor location. For the object types make array, pawns. Then if it returns a value (hits a pawn) it will get the hit actor from the out hit, then take damage as usual.
I then promoted the AIC enemy base controller to a variable. Then from the Death event, I set simulate physics to be true, and set collision enabled (query and physics) and then from the AIC I got the brain component and stop logic. This means when the enemy dies it ragdolls and stops all its code. I then set up a new function in the AIC called set state as dead which i then set after stopping the logic.
I then set up a service in the ranged behavior tree and applied it to the combat state. Then I set up a blackboard key selector for the attack target and an event receive tick AI, so this service will happen in loop, it then checks if Is Dead is true for the attack target and if it is it sets the state as passive so the AI stops attacking a dead target.
I duplicated the healthbar and made one for the player which fits in the bottom left of the screen and then added it to the event graph on begin play, setting health and max health to 100. I also set up the event dispatchers in the construction scrip of the player.
Then in the bp first person character, under the dead event (from the bind on death), it sets the physics and collision enabled (would do something if the player could see it), and then disables the input so the player stops moving.
Then on damage response in the enemy base, i stop movement, set state as frozen and play a montage, the montage is a variable so each enemy type has their own montage which is set as the variable default value. The montages have the curve disable leg IK with a key with values 0 to 1.
IMPORTANT: I forgot to change the default value of Is interruptible in the actor component which resulted in the animation not playing (and me scratching my head for two hours), this was due to the fact that it would only call on Damage Response when interruptible or force interruptible was true.
I then created a new subtree for frozen, which clears focus (as previously it would play the animation be frozen and still turning to face the attack target), then sets movement speed to idle and waits (this wait is so it doesn't immediately loop the behavior and gives time to interrupt the frozen state).
I then also made a subtree for find cover just in case it is needed at another time. I also implemented the frozen subtree into the melee behavior as higher priority than all the other states etc. I also did this for the ranged and base enemy.
Here I changed the set state as attacking function (AIC), to add a new Boolean input (Use Last Known Attack Target), to set a new local variable called New Attack Target, if the Boolean is true and the variable attack target is valid then it will set the variable attack target as the new attack target, if not it will use the input attack target for the function. It also sets the black board object value as the new attack target and also the attack target variable as the new attack target. It also checks if the new attack target is valid and if it isn't then it sets the state as passive. And in the base enemy after the hit animations play, set state as attacking with use last known attack target checked. So now once it is hit it will play the animation then once its done it will start attacking again. I also forgot to add the service to the combat state in the melee enemy which caused it to keep attacking even when the ranged enemy died. I also set it so that once the melee attack animation happens is interruptible is set to false so the melee enemy can attack without interruption.
Magic/Stances
First I got some animations for magic walking left right etc. and a magic attack, then created a blend space with the walking animations. Then I created an Enum for stances (default, magic, gun), and I created a variable in BP first person to hold the Enum values.
I added events to set the stance as magic or default and a input key to change between them. Then I duplicated the abp Manny to make one for the player only, removing some of the AI related nodes such as the is focusing target and validating whether the controlled pawn is a player or not.
I then promoted the stance variable to be used in the animation blueprint.
I then changed the animation blueprint to swap the is focusing conditions with stance equal to magic. As well as the sword animations to the magic animations.
I then set max walk speed using the character movement after the magic stance and default stance functions, promoting the values to a variable.
Here I set up a new widget, with an image anchored to the center, (the image is a cross hair with transparent background from lyra unreal file), and I set the positions to 0 and alignment to 0.5 each and finally checked size to content.
I then created two new functions in the graph editor for showing and hiding the cross hair. And I created a custom event for displaying the player HUD, I created a new variable of type widget player HUD, and got it as a validated variable, where if it is valid it sets the visibility to visible, if not it creates the the widget and adds it to the viewport. Along the event begin play blueprints at the end I added display HUD, and in the widget blue print I set the default value of visibility to hidden and after the magic stance is set I set the variable visibility to visible.
Projectiles
I first downloaded some asset packs called paragon gideon, and infinity blades effects.
Here I created a new blue print of type actor for a projectile base. With a box collision(drag and drop onto the root), an arror(to tell which direction its going), a static mesh (with sphere for initial visiuals) and a projectile movement component. In the projectile movement component there are values for speed and gravity which I created two new float variables to be used in replacement, this way different projectiles can have their own speed and gravity. In the construction scrip I set the projectile movement speeds to the new variable and the projectile gravity scale to the new variable, I also made the variables instance editable and exposed on spawn. I then set collision (on the collision box) to block all dynamic so it doesn't pass through objects and on the static mesh I set collision to no collision.
Here I added on component hit (from the collision box) and created an event dispatcher with two inputs other actor (actor) and hit (hit result) and finally it destroys itself.
I then created a child blueprint of the projectile, removed the static mesh and added a particle system with the particles from the Gideon asset pack. I also changed the box size.
Back in the projectile base I spawned an emitter at the hit result location (emitter template is promoted to a variable). I also did the same for sounds. I then created another one this time of a fire arrow and also an ice shard.
Attack System
I created a new actor component blueprint, created a custom event and spawned the dark energy projectile I made earlier, the transform is an input, along with target ( I added two new variables to the projectile system and made them instance editable), the owner is from the get owner node. Then i assigned an event to on projectile impact, after I called take damage, where damage info is an input, then I made a report damage event and assigned the correct inputs. Lastly called an event dispatcher called on attack finished.
I also created an event to shoot bullet (intended to replace part of the ranged enemies code and can also be used for other actors which need to trace a line to a target). It uses line trace for objects where the objects is a make array with the type pawns. The start and end points are an input. Then If the trace hits a pawn then it calls take damage on the hit actor, then reports a damage event, where the hit actor is the damaged actor and the instigator is the owner, (rest of info is from the structure and the owner actor location).
I then assigned the attacking component to the enemy base and replaced the line trace of the ranged enemy with the new function.
I forgot to ignore the owner actor when the box collision is moving so it would damage the player (fixed in the projectile base).
Here I made the shoot magic spell event, where it plays the magic shooting montage (which has notifications for sound some effects and the regular notification). Then once the notification begins it calls the magic spell function, using the hand socket location for location, then for the rotation it uses the firs person camera world location plus the the forward vector multiplied by 10000 (high number so it can travel long distance whilst maintaining rotation). So now it will get he direction the camera is facing and shoot in that direction from the hand socket. I then made this custom event play when the left click is pressed and a new Boolean variable is true, is in magic stance, this variable is set after enter magic stance is called.
Here I made a new variable can move and when the shoot function is called its sets it to false and once the montage is complete or interrupted it sets can move back to true and if can move is true then in the movement blueprints I set a branch so it can move. I also deleted the boolean variable and instead just checked if the stance is equal to magic then if it is then it will continue. I also called ignore actor when moving in the attack system itself (its more reliable because sometimes it would still damage the player even though it was done in the base projectile).
Also I added some Boolean conditions so only when can move is true will it play the animation and the animation can only interrupted if should interrupt is true, now the animation cant be repeatedly played before finishing.
I then made this blocking blue print in the melee enemy, if is blocking, play montage of blocking, then on blocked play block impact montage and then when ending block set is blocking back to false. I then created a blocking state enumeration, where the enumerators are, None, Blocking or Blocked Successfully and I then created a variable to store this enumerator. Then before the first montage I set it to blocking, then after on complete end block or on interrupt if blocking state is equal to blocked successfully. Then after on blocked I set it to blocked successfully and after the montage I called end block. Finally after end block I set blocking state to none.
In the BPI damage system I added a new function called is attacking. Then in the player blueprint I made a new variable and set that to the input for the Attacking, I then set attacking to be true before the montage (and after set magic stance) and also set it to false after the montage is completed.
I also did this for the base enemy (without the implementation and I had to name the vairable slightly different due to same name). Then in the ranged enemy after the attacking functions I set it the variable to true and after the montage was completed set back to false.
I then made a new decorator which checks if the attack target is attacking. I then created a task to start and then finish execute once stopped blocking (using an event dispatcher at the end block in the melee enemy). Finally I implemented them into the melee behavior just before attacking, set speed to idle so it doesn't move whilst in animation and focus target.
I also set the stance change button to be hold right click, I also set the is attacking variable to true only after notification (so its like its reacting to the attack rather than predicting it).
Bug Fixes
First Idle animations weren't looping so in the animation blueprints I selected the idle animations and set them to loop.
I deleted the damage causer variable from the structure (didn't make sense to have it there when I needs to be an input. Then on the take damage function and on damage response event dispatcher I added damage causer. I then added it to the BPI (had to add a space between name due to conflicts). I then refreshed all the damage info nodes, and added damage causer to the damage response events in the first person character and enemy base.
Then in the attack system I used get owner as the damage causer for both the fire bullet and magic spell. Finally, in the enemy base under the attack response event, I linked the damage causer to the attack target for the set state as attacking.
Then in the shoot spell event, I added a do once node instead of checking to see if the player can move, then in the reset execution pin I created a new custom event reset magic spell which is then called at the end when attacking is set to false.
Then in the AIC in the set state as attacking function, after checking if it is valid, it now checks if is dead (this is because previously if you attacked the enemy just before dying it would be confused and switch between attacking and passive state before going back to passive state), then if they are dead it sets state to passive, if not then it continues what it did before.
In the melee behavior tree I set movement speed to idle just before calling the attack function so it doesn't slide if the player moves out of the way.
And just after the start block event (melee) is called I added a stop movement immediately, as before there was a small chance it would slide a tiny bit just after blocking.
I then changed the health bar to fit on the same widget blueprint as the cross hair.
Here I changed the projectile aiming system (and bullet shooting), so that it traces a line and if the line hits an object it sets that point as the target (previously it would set the center of the screen as the target, but only at a distance of 10000, so it would eventually end up in the center of the screen but you aimed at an object it wouldn't hit the object where the cross hair is.
Updating perception
First I created a variable called known seen actors ( an array of type actor), and in the handle sight I added an add unique node plugging in the actor and known seen actors.
I then created an event which checks the length of the known seen actors and if it is not equal to the length of get known perceived actors (in other words if there's a change in the perceived actors, like one is forgotten). Then if that is true, for each(known seen actors), find in the known perceived actors known seen actors and if that is equal to -1 then something has been forgotten as the number of known perceived actors is less than the number of known seen actors.
For now on possess, it loops a timer by the forgotten event. I also promoted this timer (return value) to a variable. Then on Un Possess I cleared the timer.
I then created a new function for handling forgot actor, removing the known seen actors, then if the forgotten actor is the attack target then it sets state as passive. Then it calls the new function after checking if there has been change in the array.
Here I created a handle for losing sight where if the actor is the attack target then it gets the current state and if it is attacking, investigating or frozen it will set the state as seeking using the attack target location. The seeking state is another function duplicated from the investigating state and changed the enumerator to a new enumerator called seeking.
I then modified the focus target task to check if the attack target is a valid actor or if it isn't is it a vector, if it is a vector then it sets a focal point instead of setting focus.
Then I created a new subtree, clearing focus, setting the movement speed to run (as theyve just lost sight of the target they want to get back to them as soon as possible), then move to the point of interest and then call the new focus task with the target point of interest. So if the player is out of sight it will run over to where the player was last seen then focus on that point.
Here I made a query system to see points which are not visible to the AI in a cone with 180 degrees and I set the path find to use path cost instead, this way even if it is close if it takes too long to get to it will filter it out.
Here I added a sequence which takes the old sequence (higher priority) so it goes to last seen location, then clears focus sets movement speed to jogging and runs the query, this loops five times using the in built decorator loop, and finally after finishing seeking it clears focus and sets state as passive. I also changed the handle sight so that if the AI is seeking it can still switch back to attacking, (aswell as handle sense sound). I also added a noise event after shooting the spell, using the location as the trace start.
Nav Links (Jumpin AI)
First I created a blueprint of type Nav link and deleted the simple link (simple link doesn't have event capability). I then created a function in the BPI enemy for jumping, where it takes a vector input, breaks it into x y and z, then suggests the projectile velocity in an arc with the start being the actor location and the end being the x and y values of the destination (vector input) and z being offset by 250 (this is because it wouldn't gain enough height otherwise).
In the AIC, I created a custom event called seek attack target which just sets state as seeking. Then in the lost sight function I added a set timer by event and used create event to select the custom event, and set the time to three seconds. Then In the handle sight function when attacking and the current seen target is the attack target then it clears the timer. I also cleared timer just before setting the time, to make sure there isnt already a timer running and lastly I cleared it when the state is set to seeking.
Important bug/weird behaviour fix, in the behaviour tree there are multiple move to tasks, so if it plays these whilst in the air then it struggles to understand what to do. To fix it we cast to character(controlled pawn), check if it is falling, if it isn't then finish execute, if it is then bind event to landed delegate (once landed) then on the event finish execute.
I also edited the animation blueprint and switch stance blueprint to make a way to use both magic stance and gun stance. Using has equipped weapon As a condition to enter the gun state and has not equipped weapon as a condition to got back to locomotion.
Token System/Team combat system
First I created two new functions in the damage system BPI.
The Reserve attack token, takes an amount and outputs whether it was successful, and the return attack token just takes an amount.
Then in the damage system component, I created functions copying the two from the BPI, and created a new variable called attack token count. Then in the reserve attack token function, if the count is greater than or equal to the amount then it sets the attack count to the attack count subtract the input amount and returns success, if not it returns success as false.
Then in the return attack token function I just added the input amount to the attack tokens and set that as the attack tokens count.
I then implemented them into the bp player (I renamed the first person character to player), and into the enemy base. I also set the default value of attack tokens count to 1 and in the player construction script set the attack tokens count to 1 as well.
Then in the BPI enemy, I added an input to the attack function for the attack target. Then in the melee enemy I called the reserve attack token, from BPI, and if it succeeds, then it plays the montage etc. If not then it calls on attack end with a delay until next tick (this is so the default attack has time to run before ending). In the default attack I set the attack target to a blackboard key selector of type actor and finally on attack end return token. Also set the defult attack target in the behaviour trees.
I then created three new functions in the BPI enemy, attack start (attack target and tokens needed), Attack end (attack target), and Store attack tokens (attack target and amount).
Here I created a new variable in the enemy base, of type actor (map, integer). Then in the enemy base event stor attack tokens, if there are already attack tokens in the reserved attack tokens then it will add the amount to the number of already reserved attack tokens and then adds it to the reserved attack tokens, if not then it will just select the amount input and add it to the reserved attack tokens.
I then implemented the attack start in the enemy base, if the reserve attack token returns true it stores attack tokes and sets a new variable tokens used in current attack to the amount and outputs success, if not then it outputs false.
Then on event attack end, it now returns attack token with the tokens used in current attack as the amount and then it stores the attack tokens as the negative of the tokens used in current attack. Then it calls on attack end and sets attacking to false, so it doesn't have to do this every time it is attacking we can just call the attack end function. Then for the event attack, it sets attacking to true.
Then I replaced the start of event attack with the parent attack node and replaced the on attack end and return token nodes with the attack end. Also I forgot to add is interruptible to after the attack ends and I then did the same for the ranged enemy.
In the enemy ranged I also replaced the validated attack target variable as we now know the attack target is valid and I also got rid of the get AIC and cast to AIC Enemy, because they were only needed to get the validated variable.
I then took all of the tasks from the melee attack sequence and moved all their functionality into one task as when we implement the token system it would have had to check if it already has a token for each individual task which would require a selector for each task.
Here is the finished task. It calls start attack with the attack target being a blackboard key selector and the tokens needed being an integer variable (instance editable), then if that succeeds it sets the movement speed to run (if not it finishes as failure), clears focus, moves to the attack target with the ideal radius as the radius, then on fail attack ends and finishes false, on success it sets focus and calls the attack function, then it casts to enemy base and binds on attack end to an event, which then finishes execute as success.
Then I deleted all the previous tasks and replaced them with the new one, setting the blackboard key values and the tokens needed and also moving the cooldown to the attack task itself, so now if the attack itself fails it will just move on to strafing.
I also changed the AI controller parent class to the detour crowd AI controller which means the AI should avoid each other now.
Here I did the same for the ranged attack and then implemented it into the behaviour tree. I kept the strafing sequence and removed the default attack task. I moved the decorator to a new selector, the selector now first checks if it is attacking (with a cooldown of 2 seconds) then waits and goes back to strafing.
Here I also made it so after setting state as dead the attack tokens are returned.
Main Menu
First make a widget blueprint, add a canvas panel and vertical box, set the anchor of the vertical box to the centre and set the alignments to 0.5. Then add three or however many buttons needed, and add padding in the details panel (for me 100 at the top and bottom).
I then made a new level and new game mode for the main menu, and I added the game mode to the new level using the world settings and in the game mode blueprint I changed the default pawn class to none.
In the level blueprint on begin play I added the new widget blueprint. Then In the widget blueprint on the play button I added the on clicked function (details panel) which then opens the regular level.
Finally I added an image of the enemy AI as a temporary background, selecting anchor to fill (set offsets to 0) and selecting the brush to the image and z order to -1 for it to appear behind.
The final thing I added was for the mouse to stay when in the main menu and disappear when playing. So on event construct, It sets show mouse cursor to true, and set input mode UI only and on start button clicked after starting it sets show mouse cursor to false and input mode as game only.