Stealth Mechanics
(Ongoing)
(Ongoing)
Ever since I was a kid, I loved stealth and spy games like Hitman, Nightfire, Splinter cell, Assassin's creed etc. Here is my attempt to recreate some of my favourite stealth mechanics from those games.
In order to create a responsive and reactive stealth and AI system, the first step is to give the players the ability to control their actions and to affect the environment at their will.
This locomotion system gives many options to players to make decisions that would affect the environment.
The players can:
Run, Walk and Roll in any direction [Standing].
Crouch walk, Slow crouch walk, Fast crouch walk and Roll in any direction [Crouching].
Animations Sequences from Mixamo
Root Motion
Launch Character function
Velocity based
Detailed para explanation
(Click to see explanation)
Root motion based movement systems are best used when the required output or behaviour is supposed to give a feel of realism, immersion and life like reaction. This requirement is best suited for immersive story driven open world games as the general design philosophy is to immerse the player in the world.
When looking at a stealth game, the requirement is to have a highly reactive and responsive behaviour towards the player inputs which allows them to quickly dodge to either avoid being detected, or evade after being detected. Another requirement is to allow players to change direction of roll/dodge in between the animation.
As a result, Root Motion based dodge/roll is not suitable for the current problem statement. ❌❌❌
Other factors-
Needs Motion Data in Animations
Hard to customize dodge distance
Summarized bulleted explanation
(Click to see explanation)
Best when design requires realistic/life like movement system.
Mainly required for the purpose of immersing players in the world
Stealth game design requires reactive and responsive input behaviour.
Players should be able to quickly evade/avoid enemy detection.
Conclusion: Root Motion based dodge/roll isn't suitable.
❌❌❌
Other factors-
Needs Motion Data in Animations
Hard to customize dodge distance
(Click to see explanation)
Gives unwanted inconsistent results.
The function by default sets the player to 'Falling' state which we do not want.
This can easily become the root of n number of problems especially in the State Machine while working on a larger project.
Detailed para explanation
(Click to see explanation)
Giving maximum control to the player
I wanted the dodge/roll to be highly reactive and responsive to player input. The player should have the ability to quickly evade to avoid enemy detection. Furthermore, the player should also be able to roll in any direction. Direction of roll should also be modifiable even when the animation is playing.
Why control?
A Stealth game is an experience requiring the players to be patient and slow, as well as, quick and agile with their decisions. Because situations in a stealth game can easily escalate, it is essential that the player has the ability to quickly react to the environment. The player shouldn't have to wait for a sluggish animation to stop playing. Hence, by giving players maximum control results in a much more engaging stealth experience.
Sustainable?
This system allows easy modifications(e.g. Roll Distance) which can be catered to individual animations to give different feel. Highly customizable and scalable to give different Dash/Roll/Dodge functionalities.
Conclusion
Because of the need for a reactive and responsive system, I implemented the 'Velocity Based' Dodge/Roll. This may not give the most Life Like/Realistic/Immersive behaviour like the Root Motion based movement would, but again, that does not solve our current purpose.
✅✅✅✅
Summarized bulleted explanation
(Click to see explanation)
Giving maximum control to the player
Highly Reactive and Responsive to player input
Ability to quickly Evade to avoid Enemy Detection
Ability to Roll in any Direction
Ability to change direction mid-roll
Why control?
Stealth games requires patience as well as high reflexes
Stealth experience works on quick decision making
Essential to have the ability to quickly react to the environment
Giving maximum control results in an engaging stealth experience
Sustainable?
Easily modifiable (e.g. Roll Distance)
Highly customizable & Scalable
Can give several types Dash/Roll/Dodge functionalities
Conclusion
Velocity based movement results in highly responsive behaviour
Comes at a cost of immersive realism that could have been achieved by Root Motion based movement
✅✅✅✅
Using shadows to hide from enemies was one of my favourite stealth mechanics in video games but sadly has slowly faded away from them. Now that a lot of stealth games have huge open world with complex and dynamic lighting systems, building a full proof automated shadow detection system is not viable. Except the Splinter Cell games, the last time I saw this mechanic was in a stealth game Aragami 2 made with Unity.
Here is my attempt to recreate this mechanic in Unreal Engine with dynamic lights.
The system is based on a combination of Sphere colliders and Line Tracing. Instead of constantly checking for light sources by doing a line trace, the system only does a line trace when a player enters an area illuminated by the light. Blocked traces, would mean that the player is hidden in shadows.
The calculation of Sphere Collider radius is done automatically according to the point light radius or cone angle of spot light
Level Designer Friendly - Lights are instance editable i.e. properties can be changed in the level editor (Light color, intensity, attenuation radius etc.).
Colliders are automatically placed and their radius is calculated according to the values set in level (e.g. - Attenuation Radius, Inner Cone Angle etc.).
Works on both Point Lights and Spot Lights.
Use of Interface to trigger Line Tracing. Scalable and Modular
If in future, more light types are to be added (rec light), one only has to call the Interface function.
Constant Line Tracing is only performed when player enters an illuminated area to improve performance. This is also done in C++ instead of Blueprints.
Works well when multiple lights are near each other i.e. the colliders are mixed with each other.
Spot light - There is a slight offset in the location of the collider when the spot light is at a slant position. The light spread becomes oval from the front and hence results in a little offset.
This system does not work when a light is constantly moving in-game with player standing inside the light.
</> Code Snippet with Explanation
The radius of the Sphere Collider is calculated according to the Attenuation Radius of the Light. The construction script lets you customize the Light Intensity, Light Radius and Light color per instance in the scene. According to these values the radius for the collider is calculated.
</> Code Snippet with Explanation
Construction Script 🔼
Calculating the radius of the Sphere collider for Spot Light was a little tricky as we are only given the Angles of inner cone and outer cone. So some Mathematics was needed.
First a Line is cast from the source of the light towards the ground.
This Line Trace acts as the Height of the cone(spot light).
Then we perform TAN function on the inner cone angle and multiply the result with the height to get radius.
The above will get us our desired radius for the sphere collider. But the maximum range of our sphere collider will be limited to the light spread by the inner cone. The outer cone spread will be forgotten. So I made a complex equation for this calculation to get near accurate results.
First we will get the difference between the outer and inner cone angle.
Then we will add half of that difference to the inner cone angle. Let's call this new value - Complex Inner Cone Angle.
Instead of performing TAN on the inner cone, we will perform it on the Complex Inner Cone Angle.
Because the calculation grew complex, I decided to make a Blueprint Pure C++ function for this.
Both the Light Blueprints will call a single Interface function on the Player Blueprint with their location passed as the parameter, to toggle between Line Tracing behaviour. (continued in player blueprint ⏬)
These Interface functions are implemented in the Player Blueprint. These are responsible for Opening and Closing the GATE node. In simple terms, these functions determine when the blueprint has to constantly check for shadows and lights and when not to.
This solves a major problem and that is Line Tracing on every frame to check if the trace is blocked by something.
Now, Line Tracing on every frame is only allowed when the player enters a collider calling the Interface function. And as a result, improves performance.
To further improve the performance, I decided to do Line tracing in C++. I made a Blueprint Pure function in C++ with the Light location as the parameter and it returns a boolean value.
Doors can be a very important piece in a stealth game. Generally I have seen two types of door systems -
Your classic toggle gate open close - Most Splinter Cell/Hitman games have this type of door. If one goes even more in depth, this system can be really useful to keep track of doors which the players have left open, and accordingly reward those players who have deliberately closed the doors for a 'No Traces' 'Ghost' walkthrough. One can also have AI react to an open door.
Physics door: This physics based door opens automatically when a player pushes it. This system can have a very interesting impact on the surroundings and AI. In Metal Gear Solid 5, if the player is not slow enough while opening a door, it will make noise and will alert nearby guards.
Both the systems add more depth to the interactivity of a stealth game. I recreated the 2nd door system in Unreal Engine.
The door simulates physics and the sound is played according to the door's velocity. If the door touches the wall with a higher velocity, it will create a bash sound which will alert nearby enemies.
The door will open silently if and only if you are crouching slowly or the velocity of door is low. Mechanism is pretty simple so only took a couple of hours to finish.
</> Code Snippet
If you want to have a chat or contact me, connect with me on LinkedIn or fill out the Contact Me form.