Monster Hunter World Mount Mechanic
The last course of The Game Assembly allows the student to find a subject they are interested in and make a project that is related to that subject. We are given 5 weeks half time but in this case we were given about 1 and a half week part time and 2 weeks full time to complete this project. We have a planning phase where we make a goals for every day of the project.
On this page I'll explain the progress of my project and the result.
Project and goal
I am very interested in gameplay programming. I love making features and polish them if I have enough time. For this project i wanted to try to learn a new engine from scratch. The engine I choose to learn was Unreal Engine 4. I had never used this engine before and I wanted to see if I would be able to learn how to use it in 5 weeks and make a mechanic with it.
Using unreal engine 4 I choose to recreate the mount mechanic from Monster Hunter World.
The mount mechanic consist of 5 main features.
Movement: The player is able to jump between 2 - 3 points on the monster for example the tail, the back and the head. The player will use this to damage the monster and avoid being dismounted.
Attack: The player is able to attack the monster by left clicking and moving between bodyparts of the monster.
Dismount: The monster is able to detect which bodypart the player is currently on and execute behaviors based on this information in an attempt to dismount the player. For example shake its tail if the player is on the tail and bash its head against a object if the player is on the head.
This clip shows the movement in the mount mechanic, how the player attacks the monster and it also shows the monster trying to dismount the player
Attack Sequence: After dealing enough damage the player enters a sequence where the monster wont try to dismount and the player will deal a higher amount of damage. After a certain amount of damage has been dealt the sequence ends and the monster continue its attempt to dismount the player.
This clip shows the attack sequence in Monster hunter world and how the camera view changes when it starts.
Camera: Lastly we have the camera. The camera is a third person camera that changes view on 3 diffrent occasions. The camera is focused on the player when the player is not currently mounting the monster. When mounting the monster the camera is focused on the monster and is placed further away so the player can see more. When entering the attack sequence the camera is focused on the player and is located really close to the player.
Third person camera and movement
As a start I decided to learn how to use unreals blueprints before diving into C++. I decided that making a third person camera instead of using unreals own third person template was a good way to learn the basics.
After some research I managed to setup a third person camera and make simple player movement. I looked at monster hunter's camera and movement as reference and tried to adjust my camera components distance and movement to match the one in the real game.
I had originally made the mistake of adjusting the camera itself instead of the springarms camera offset that it was childed to. This caused the camera to clip through objects and walls.
I added animations to match the player characters actions but it turned out I didn't do enough research on what the best way was for blending animations. During the last week of the project I had to redo the player animations. I made the animation blueprint decide which animation to blend to using floats and a bunch of bools.
I ended up using a statemachine for the animations which was a lot less complicated then my previous attempt to blend the animations. My statemachine also used bools to decide which animation was going to play but there was less risk for errors.
This is the final result. I use a statemachine for the animations when the player is mounted because it consists of a lot more animations and I use a blend when the player is walking on the ground. I had some trouble with making it switch using a bool so i had to use a float which i set to either 0 or 1 depending on if the player is mounted or not.
Binding player to a joint on the monsters mesh
Now that I had gotten a hang of the basics of unreal blueprints I decided to start learning how to use C++ in unreal. I decided to do most of the mounting features in C++. I started of with trying to manipulate the player using C++ code and get a grasp of how to access blueprints and components. I was able to get a reference to the actor by finding all actors with the tag "Monster" and with this I was able to get the monsters component. I accessed the monsters meshcomponent and was able to get the location and rotation of joints in the mesh.
I could now set the players location and rotation to the current joint every frame. The player was inside the monsters body now because the joints were inside the mesh. I created new joints that were children to the joints I had previously used. This way I could still get the right location and rotation but were able to offset the player so it was above the mesh.
Now I wanted to make the player move between 2 joints. At first I made a function that gets a target location which in this case was the other joints location and made the player move towards that location until it reached the location. I made the player move by adding a value to x y z until the location was reached. This looked bad and didn't work very well so I scrapped this method.
I decided on using a spline instead. I added a spline component to my monsters blueprint and make the blueprint set the spline points locations to the joints I had created every frame.
It now looked more smooth and was a lot more stable.
It still didn't look as good as I wanted so i decided to add a arc when moving between joints. I did this by adding 2 more joints that were located between the already existing joints. This joint was placed a bit higher which caused the spline to arc.
Dismount and UI
The monster needed to detect which bodypart the player was on and which state the player was in. I did this by using 2 enum classes.
MountBodypart has 3 body parts and two extra joints. The reason for this
is because when the player is accessing a splinepoint location it has to use a
index that indicates which splinepoint its on. I'm using the enum as indexes
and because i added 2 extra points to make the spline arc I had to add 2 more
to the enum.
The player has 5 states: Idle, moving, bracing, attacking and superattackmode.
Superattackmode is my attack sequence which I will talk about later.
The monster checks what bodypart the player is currently on. It runs a
behavior in its behavior tree. When the dismount function is executed it will
check if the player is Idle or bracing. If the player is located on the head or the
torso of the monster the player has to move to a different part to avoid getting
dismounted. If the player is located on
the tail of the monster the player can brace instead of moving. If the player doesn't do one of these things
it will be dismounted.
When the monster is starting its dismount behavior a widget appears that consist of a red fullscreen vignette to warn the player and it disappear when the player is safe from getting dismounted.
The player needed a way to kill the monster. I made it so that when the player left clicks it switches state to attack state and it also switches a bool that is exposed to blueprints to true. The players animation blueprint plays a attack animation and the player can't do anything until the animation is finished. I did this by adding notifiers to the animation. I reuse the damage notifier every time the player deals damage and run a script that subtract health from the monster and shows a damage indicator.
As seen on the image with script the damage event runs when it hits the notifier in the animation. It spawns a number which displays the damage dealt. It also subtract health using the damage variable. The damage variable is set every time the player enters a attack state. When the player moves the value is set to 4, when the player enters attack sequence it is set to 7 and when the player attacks normally it is set to 1.
Attack sequence is when the player enters a sequence where it deals more damage and the monster is unable to do anything. It does this once it has dealt enough damage to the monster.
I did this the same way i have been doing with the normal attack except i pause the monsters behavior tree while the player is in this state. I also display a yellow vignette widget so the player knows they have entered this state. I also change the camera view to be closer to the player.
Once the player has dealt enough damage it exits this sequence and the monsters AI resumes.
I decided I wanted to add AI to the monster. I did this by using unreals behavior tree and a bit of C++ code to choose which behavior was gonna be executed. It have 3 behaviors: bash, shake and wander.
Bash is when the player is on its back. The monster walks up to a target location that I have placed in the world next to a tree and then rotates to face a separate target which I have placed inside the tree. It then plays a animation where it slams the tree. After this it goes back to wander.
Wander is a idle stance, it walks to a random location and waits 1 second before walking to a different location.
Shake is when the player is on its tail. It plays a animation where it shakes its head and tail and if the player does not brace or move it will be dismounted.
If the player is located on the head there is a 50% chance it will either bash or shake.
Image of my behavior tree.
Result and thoughts
This is the finished result. I'm not entirely happy with the result, I had some problems when I rotated the player to the joints rotation in the monsters skeleton and didn't have time to fix it. If i had more time I would do more research on how to handle rotation in unreal and find a better way to match the player to the joints rotation. If I had done this without the intention of learning I would probably make it entirely in blueprint or entirely in c++, not a mix between both. It got pretty complicated at times because 50% was made in C++ and 50% in blueprints. If I could redo this I would probably do more research before starting, I had to redo a lot of things because I found a better way to do them later on in the project.