Implementing slow motion

Since Remedy Entertainment's Max Payne, slow motion, or bullet-time, has become a popular feature in games. For example, Criterion's Burnout series has successfully explored the slow-motion effect in the racing genre. In this recipe, we will implement slow motion while the player presses down the right mouse button or the Alt key.

Getting ready

For this recipe, we will use the same prepared package as the previous recipe: BallShooterGame from the 0423_10_01 folder. We will also need a texture for a time progress bar, which is named barTexture.png and can be found in the 0423_10_02 folder.

How to do it...

To implement slow-motion, perform the following steps:

  1. Start a new Unity project and import the texture image file: barTexture.png.
  2. Import the package named BallShooterGame into your project and open the level named RoomLevel (from the Scenes folder).
  3. We need to replace all of the exiting C# ShooterScript with new code to implement slow motion time effects. Open ShooterScript and replace everything with the following code:
    // file: ShooterScript.cs
    using UnityEngine;
    using System.Collections;
    
    public class ShooterScript : MonoBehaviour
    {
      public Rigidbody projectile;
      public float projectileForce = 5000.0f;
      public bool compensateBulletSpeed = true;
      public float slowMotionSpeed = 10.0f;
      public Texture2D slowMotionBar;
      public float slowMotionTotalTime = 10.0f;
      public float recoverTimeRate = 0.5f;
      
      private bool isSlowMotionMode = false;
      private float remainingSloMoTime;
      private float startSloMoTimestamp;
      private float elapsedTime = 0.0f;
      private float actualForce;
    
      private void Start() {
        Screen.showCursor = false;
        remainingSloMoTime = slowMotionTotalTime;
        actualForce = projectileForce;
      }
    
      private void Update() {
        CheckUserInput();
    
        if( isSlowMotionMode )
          SlowMotionModeActions();
        else
          NormalTimeActions();
      }
    
      private void CheckUserInput() {
        if (Input.GetButtonDown("Fire1")){
          Rigidbody clone = (Rigidbody) Instantiate(projectile, Camera.main.transform.position, Camera.main.transform.rotation);
          clone.AddForce(clone.transform.forward * actualForce);
       }
        if (Input.GetButtonDown("Fire2") && remainingSloMoTime > 0)
          ActivateSloMo();
    
        if (Input.GetButtonUp("Fire2"))
          DeactivateSloMo();
        }
    
      private void SlowMotionModeActions() {
        elapsedTime = (Time.time - startSloMoTimestamp) * slowMotionSpeed;
        remainingSloMoTime = slowMotionTotalTime - elapsedTime;
    
        if (elapsedTime >= slowMotionTotalTime)
          DeactivateSloMo();
      }
    
      private void NormalTimeActions() {
        if( remainingSloMoTime < slowMotionTotalTime )
          remainingSloMoTime += Time.deltaTime * recoverTimeRate;
        else
          remainingSloMoTime = slowMotionTotalTime;
      }
    
      private void ActivateSloMo() {
        Time.timeScale = 1.0f / slowMotionSpeed;
        Time.fixedDeltaTime = 0.02f / slowMotionSpeed;
        actualForce = projectileForce * slowMotionSpeed;
        isSlowMotionMode = true;
    
        float timeLeftToRefill = (slowMotionTotalTime - remainingSloMoTime)  / slowMotionSpeed;
        startSloMoTimestamp = (Time.time - timeLeftToRefill);
      }
    
      private void DeactivateSloMo() {
        Time.timeScale = 1.0f;
        Time.fixedDeltaTime = 0.02f;
        actualForce = projectileForce;
        isSlowMotionMode = false;
      }
    
      private void OnGUI() {
        float proportionRemaining = remainingSloMoTime / slowMotionTotalTime;
        float barDisplayWidth = slowMotionBar.width * proportionRemaining;
    
        int proportionRemaininInt = (int)(proportionRemaining * 100);
        string percentageString = proportionRemaininInt + "%";
        GUI.Label(new Rect(10, 15, 40, 20), percentageString);
        Rect newRect = new Rect(50, 10, barDisplayWidth, slowMotionBar.height);
        GUI.DrawTexture( newRect, slowMotionBar, ScaleMode.ScaleAndCrop, true, 10.0f);
      }
    }
  4. With the First Person Controller selected in the Hierarchy panel, drag the texture image barTexture into the Inspector for the slowMotionBar public variable of the ShooterScript component.
  5. Play your game. You should be able to activate slow motion by keeping the right mouse button or the Alt key pressed. A progress bar will slowly shrink to indicate how much slow motion time you have remaining.
    How to do it...

How it works...

Basically, all we need to do to have the slow motion effect is decrease the value of the Time.timeScale variable. In our script, we do that by dividing it by the slowMotionSpeed variable. We do the same to the Time.fixedDeltaTime variable, which updates the physics simulation of our game. The ActivateSloMo() method sets values for slow motion effects, and the DeactivateSloMo() method returns values for normal speed time.

In order to make the experience more challenging, we have also implemented a sort of "energy bar" to indicate how much bullet time the player has left (the initial value is given by the slowMotionDuration variable). Whenever the player is not using bullet time, he has his quota filled according to the recoverTimeRate variable.

The GUI is implemented based on finding the proportion of slow motion time remaining, and sizing the width of the bar texture accordingly.

There's more...

The following are some suggestions for you to improve your slow motion effect even further:

Adding Motion Blur (Unity Pro only)

Motion Blur is an image effect frequently identified with slow motion. Once attached to the camera, it could be enabled and disabled through the ActivateSloMo() and DeactivateSloMo() methods respectively. More information on the Motion Blur image effect can be found at docs.unity3d.com/Documentation/Components/script-MotionBlur.html.

Creating sonic ambience

Max Payne famously used a strong, heavy heartbeat sound as sonic ambience. You could also try lowering the sound effects volume to convey the character "focus" when in slow motion. Plus, using audio filters on the camera could be an interesting option (provided you have Unity Pro).

See also

  • The Pausing the game recipe
..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.147.27.131