skip to Main Content

Recreating Sniper Elite’s killshot cameras

In this post we’re going to recreate Sniper Elite’s killshot cameras. This post is written using Unreal Engine 4.12.5 so your implementation might differ in case you’re working with a different version of the engine.

Before we start, here is the end result:

Before we start recreating this mechanic, let’s take a step back and analyze how everything works. The mechanic is triggered when the character that we’re shooting at is going to die. For the sake of simplicity, we’re going to assume that every enemy character dies with one shot only. For the rest of this post, a successful shot will be considered a shot that hits an enemy target.

Assuming that our character fired a successful shot, our system’s logic is divided into the following steps:

  1. We dilate the world’s time by a specified value
  2. We make a transition from a First Person Camera view to a Third Person Camera view in order to see the character that fired the shot.
  3. After a specified time, we transition from a Third Person Camera view to a camera that is attached to the fired projectile.
  4. When the projectile is within a specified range from the enemy character we transition from the projectile’s camera to a camera that is attached to the enemy character
  5. The moment that the enemy character hits the ground, we transition from the active camera to First Person Camera view again.

For this project, I’m using the First Person C++ Template that comes with UE4. Before we achieve the end result shown in the video above, we will modify some functions and properties that come with the c++ template. This means that we’re going to strip down some functionality and add our own.

Step 1. Configuring World’s Time dilation

In order to dilate the World’s Time, expose the following property in your charater’s header file:

Then, navigate on the OnFire() function in your source file and add the following line right after the Projectile’s spawn to dilate the time:

UGameplayStatics::SetGlobalTimeDilation(World, TimeDilationMultiplier);

To clarify, here is the whole OnFire function at this step:

Step 2. Transition from First Person to Third Person View

In order to switch a perspective, we’re going to use a new camera that is attached to a spring arm component which is attached to our character’s root component.

Having said that, add the following components and properties to your character’s header file:

Then, navigate in your character’s constructor and type in the following code (in order to create our components):

Moreover, make sure to change the option SetOnlyOwnerSee from true to false on Mesh1P and FP_Gun. Here is my complete constructor at this stage:

Then in order to switch from the first person to third person camera, declare the following function in the header file of your character:

In your character’s source file type in the following implementation of the above function:

When you’re done with that, right after the Time Dilation on the OnFire() function, call the above function. Here is the complete OnFire function at this step:

Save and compile your code. Then, open up the Character’s Blueprint and assign the following options in your SpringArmComponent:

mainchar_thirdpersonspringarmoptions

In case you’re wondering how I came up with these values it was just by trial and error.

At this point, the active camera will change when the character fires his weapon. However you won’t be able to see the fired projectile just yet. This is because the projectile that comes with the First Person C++ Template contains an initial speed. This means that by the time you switch the active camera the projectile will have moved “a bit” forward.

Step 3. Transition from a Third Person Camera to the camera that is attached to the fired projectile

Before we modify the projectile class that comes with the demo to suits our needs, we need to inform the character’s controller that in case we attempt to set a new view target, the controller will search the new target’s hierarchy until it finds a valid camera. Then, it automatically activates that camera.

To do that, inside the BeginPlay function in your character’s source file type in the following code:

GetController()->bFindCameraComponentWhenViewTarget = true;

Here is my complete BeginPlay function at this point:

We’re now ready to modify the projectile class. Specifically we need to:

  1. Create a Spring Arm Component attached to the root component.
  2. Create a Camera Component attached to the aforementioned component.
  3. Since the World’s time is dilated we need to apply a velocity multiplier in order to adjust the movement speed of our projectile. This is done because we need to find a “sweetspot”, meaning that the projectiles should not travel too fast or too slow either.

Let’s get started then. In your projectile’s header file, type in the following declarations:

Then, open up the source file of your projectile’s class and inside the constructor:

  1. Adjust the projectile’s max speed to 0.f
  2. Disable it’s bounce effect
  3. Adjust the initial life span to 0.f. This is done because we want the projectile to exist until it hits somethings. Please note that we’re not going to modify the OnHit function just yet!

Here is the needed code to apply all the menionted changes, plus the implementation of the ApplyVelocityMultiplier function:

Save and compile your code. Then, assign the following values to the projectile’s spring arm component:

projectile_springarm_comp_details

At this point, we need to modify our character’s class again in order to transition from it’s third person camera to the camera that is attached to the fired projectile. Before we do that, make sure to include the projectile’s header file right before the .generated.h file. Then, type in the following declarations:

Then, open up your character’s source file and type in the following implementation for the ActivateProjectileCamera function:

When you’re done with that, navigate to the OnFire function which resides inside the character’s source file and:

  1. Grab a reference of the spawned projectile
  2. Execute the ActivateProjectileCamera function after the ThirdPersonToProjectileTransitionDelay seconds.

To execute a function after a specified time in UE4 we’re going to use a timer. Here is my OnFire function at this point (which implements the mentioned steps):

At this point, if we fire a projectile, the cameras will get activated with the following order:

  1. Third Person Camera
  2. Projectile Camera

Let’s continue on Step 4.

When the projectile is within a specified range from the enemy character we transition from the projectile’s camera to a camera that is attached to the enemy character

Step 4. Transition from the projectile’s camera to a camera attached to an enemy character

In order to complete this step we’re going to divide it into two sub steps:

  1. Create an Enemy Character
  2. Create the camera transition (this step includes 2 more sub-steps).

Step 4.1. Creating an Enemy Character

In this post, I’m going to use the skeletal mesh with the animations that reside in the Third Person Template Project. So, before we dive into our code, create the mentioned template project, and migrate those assets to your project. When you’re done with that, create a new C++ class which inherits from the Character class (in my case this class is named DummyEnemyCharacter). Then, we’re going to create a SpringArmComponent and a CameraComponent (just like in our projectile’s class) in order to achieve a camera transition.

Open up the header file of your DummyEnemyCharacter and add the following declarations:

Then, type in the following implementations in the source file of the character:

Save and compile your code. Then:

  1. Create a Blueprint based on the above class
  2. Assign the ThirdPerson Static Mesh from the Third Person Template project to the Mesh component
  3. Assign the Pre-Built Anim_BP to the above mesh

Steps 2 and 3 can be seen below:

dummychar_bp

Moreover, configure the following options for the enemy character’s spring arm component:

dummychar_bp_springarm

Step 4.2. Creating the transition from the projectile’s camera to the enemy’s camera

In order to create this transition, we need to know two things:

  1. The distance between the projectile and the enemy in order to create a smooth transition.
  2. That the projectile will hit an enemy. Up until now, we’re transition from the character’s camera to the projectile’s camera even if we don’t hit an enemy.

Step 4.2.1 Determining the distance between the projectile and the enemy

In case our spawned projectile hits an enemy, we’re going to store a reference to that enemy before the actual hit, so we can transition to his camera and see the hit result from that point of view. This reference will come from the Step 4.2.2 which is written below. For now we’re going to assume that we have a valid reference and focus on calling the camera transition.

To do that, go to your projectile’s header file and when you include the DummyEnemyCharacter.h (right before the .generated.h file), type in the following code:

As you might notice, we need to override the Tick function (which isn’t overriden by default). This is happening because we need to check the distance between the EnemyToKill and the projectile in order to activate our camera transition. Please note that the Projectile provided in the First Person Template project does not tick by default. With that said, we need to tell the engine that we want our projectiles to call the tick function. To do that, open up the constructor of your projectile class and add the following line:

PrimaryActorTick.bCanEverTick = true;

Once you have included the above line of code, here is the implementation of the tick function:

Save and compile your code. Then, let’s move to the next step.

Step 4.2.2 Making sure that the spawned projectile hits an enemy

To make sure that the spawned projectile hits an enemy, we’re going to implement a line raycast. If we have a hit, we’re going to store a reference to our projectile. Before we implement the actual raycast, make sure to include the DummyEnemyCharacter.h file in your Character’s header files right before the .generated.h file. Then, type the following declarations:

Open up your character’s source file and type in the following implementations:

When you’re done with that, navigate to the OnFire function and make the following changes:

At this point, if you place a DummyEnemyCharacter blueprint in your level and shoot him every camera transition will work. However, the projectile will stop the moment it hits the enemy. Don’t worry about that, we’re going to fix this in Step 5 which is written below. Moreover, at this point, only the projectiles that are lethal slow the world’s time.

Step 5. Configuring a Death for the DummyEnemyCharacter and resetting the cameras

Open up the header file of your main character and declare the following function:

Then, type in the following function:

One you’re done with that, open up the header file of your DummyEnemyCharacter add declare the following function and property:

Then, open up the source file of the DummyEnemyCharacter and when you include the main character’s header file, provide the following logic for the Die function:

The last step, is to modify the OnHit function inside the projectile’s class in order to match our needs. To do that, locate that function and type in the following logic:

Save and compile your code. You have re-created the cameras transition successfully!

Avatar photo

This Post Has 0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Back To Top