I have objects in my game which you can throw around. They all use rigidbody2D. I want to be able to freeze them, and then when you throw one that’s frozen, it will move along exactly the same path as normal only slower. To throw the object I use addForce from the player script. Ideally I want to be able to tell it what speed to go, so 0.5 would make it go half speed.
I have found a few questions along these lines but no definitive answer. I have tried playing around with the mass, drag, gravity etc. but can’t get it to behave like I want it to.
This is the script I went with in the end. It’s a heavily modified version of the answer to an older similar question. It’s not quite perfect but good enough for what I need. In the inspector, set your time scale before running (0.5 being half speed etc.), then tick the ‘Frozen’ box to go at that speed. Un-tick it and it will continue on the same path at normal speed. It should work with any object using Rigidbody2D.
using UnityEngine;
using System.Collections;
public class SlowMoScript : MonoBehaviour {
public float timeScale = 0.5f;
public bool frozen = false;
Rigidbody2D rb2d;
float startMass;
float startGravityScale;
bool slowMoBool = true;
void Awake(){
rb2d = GetComponent<Rigidbody2D> ();
startGravityScale = rb2d.gravityScale;
startMass = rb2d.mass;
}
void Update() {
if (frozen) {
SlowMo ();
} else {
StopSlowMo ();
}
}
void SlowMo () {
rb2d.gravityScale = 0;
if (slowMoBool) {
rb2d.mass /= timeScale;
rb2d.velocity *= timeScale;
rb2d.angularVelocity *= timeScale;
}
slowMoBool = false;
float dt = Time.fixedDeltaTime * timeScale;
rb2d.velocity += Physics2D.gravity / rb2d.mass * dt;
}
void StopSlowMo() {
if (!slowMoBool) {
rb2d.gravityScale = startGravityScale;
rb2d.mass = startMass;
rb2d.velocity /= timeScale;
rb2d.angularVelocity /= timeScale;
}
slowMoBool = true;
}
}
You can save the rigidbody.velocity in an variable: oldVelocity = rigidbody.velocity;
Next sets the: rigidbody.velocity = Vector3.zero;
Next after some time, assign again old velocity to the rigidbody: rigidbody.velocity = oldVelocity * slowDownValue;
Press the ‘start’ field to start the move, press it again to stop it.
using UnityEngine;
using System.Collections;
public class RigidbodyStopper : MonoBehaviour
{
public Vector3 startVelocity = Vector3.zero;
public float slowDownMod = 1f;
public bool start = false;
private Rigidbody _rigidbody = null;
private Vector3 _oldVelocity;
private bool _temp = true;
void Start ()
{
_rigidbody = GetComponent<Rigidbody>();
_rigidbody.velocity = startVelocity;
Move(false);
}
void Update ()
{
if(start)
{
Move(_temp);
_temp = !_temp;
start = false;
}
}
public void Move(bool start)
{
if(start)
{
_rigidbody.velocity = _oldVelocity * slowDownMod;
_rigidbody.isKinematic = false;
}
else
{
_oldVelocity = _rigidbody.velocity;
_rigidbody.velocity = Vector3.zero;
_rigidbody.isKinematic = true;
}
}
}