How to slow down time for everything except player

I am trying to slow down time in my game but upon using timescale I find that I cannot make the player move normally. Is there any way to exclude the player from the slow motion?

code:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerMovment : MonoBehaviour {

    public float moveSpeed;
    public float jumpHeight;
    public bool timeSlowed;

	// Use this for initialization
	void Start () {
        timeSlowed = false;
	}
	
	// Update is called once per frame
	void Update () {
		
        if(Input.GetKeyDown(KeyCode.W))
        {
            GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, jumpHeight);
        }

        if (Input.GetKey(KeyCode.A))
        {
            GetComponent<Rigidbody2D>().velocity = new Vector2(-moveSpeed, GetComponent<Rigidbody2D>().velocity.y);
        }

        if (Input.GetKey(KeyCode.D))
        {
            GetComponent<Rigidbody2D>().velocity = new Vector2(moveSpeed, GetComponent<Rigidbody2D>().velocity.y);
        }

        if (Input.GetKey(KeyCode.Space ) && !timeSlowed)
        {

            Time.timeScale = 0.5f;
            Time.fixedDeltaTime = 0.02F * Time.timeScale;
            moveSpeed = moveSpeed * 2;
            jumpHeight = jumpHeight / 2;
            timeSlowed = true;
            
        }

    }
}

First before answering your question, your movement is handled by Update() method, and there is no Time.deltaTime applied, which means: different frame rate = different movement and speed.

You can multiply your movement velocity by Time.deltaTime if you want it to be affected by Time.timeScale, but if you don’t want that, then multiply it by Time.unscaledDeltaTime.

If you just want to stick to Time.deltaTime, then you may want to divide it by Time.timeScale.

1st solution:

if(Input.GetKeyDown(KeyCode.W))
         {
             GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, jumpHeight);
         }
 
         if (Input.GetKey(KeyCode.A))
         {
             GetComponent<Rigidbody2D>().velocity = new Vector2(-moveSpeed * Time.unscaledDeltaTime, GetComponent<Rigidbody2D>().velocity.y);
         }
 
         if (Input.GetKey(KeyCode.D))
         {
             GetComponent<Rigidbody2D>().velocity = new Vector2(moveSpeed * Time.unscaledDeltaTime, GetComponent<Rigidbody2D>().velocity.y);
         }

2nd solution:

    if(Input.GetKeyDown(KeyCode.W))
             {
                 GetComponent<Rigidbody2D>().velocity = new Vector2(GetComponent<Rigidbody2D>().velocity.x, jumpHeight);
             }
     
             if (Input.GetKey(KeyCode.A))
             {
                 GetComponent<Rigidbody2D>().velocity = new Vector2(-moveSpeed * Time.deltaTime / Time.timeScale, GetComponent<Rigidbody2D>().velocity.y);
             }
     
             if (Input.GetKey(KeyCode.D))
             {
                 GetComponent<Rigidbody2D>().velocity = new Vector2(moveSpeed * Time.deltaTime / Time.timeScale, GetComponent<Rigidbody2D>().velocity.y);
             }

Both of them are not tested, but should work fine.

I must make a great many assumptions. My first assumption is that all motion is from code, and you’re not using physics. If physics is involved this gets nasty.


I see one class called PlayerMovment. I can only assume that this class (many tend to say script, but that’s not really correct) is attached to all the objects being moved over time.


You must fashion a way to differentiate the player you want to retain normal time from all others. You could just create a second class that does this, attach the new class to the player you want to run at normal speed and avoid the timescale calculation for that player.


You may object at first because, I can assume, PlayerMovment might do a bunch of other things (has a number of other methods or member variables) that you don’t want to duplicate. There’s a solution (actually several).


You could merely name the object in question so it can be recognized. Set a bool to true only for that player you want to ignore the timescale, and let it be false for all others. Then, where you adjust timescale, skip it if the bool is true.


Using bools to modify behavior is a bit naive. If there’s just one thing to mutate is ok, there’s only one such test. However, it is most common that several characteristics or methods will change based on such identity, making bools messy. Instead, you can make PlayerMovment an abstract class, using a small derived class that behaves differently for one case, and another derived class for the others. This is more advanced, more flexible, more powerful, but you’ll need to read about abstract C# methods and classes, and use the override specifier in the derived classes.


Another possible way to mutate behavior is to use delegates. Delegates become member variables, but they work like functions. You can assign the delegate to any matching method signature, which means you can configure an object to call specific methods by assigning these variables during intialization. Again, this is more advanced, very flexible and much cleaner than a bunch of “if/elseif/elseif” tests on bools.