How can I slow the movement of a single rigidbody2D?
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.
Answer by 82MiddleMan · Mar 02, 2016 at 04:32 PM
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;
}
}
Works perfect. But only if you change Update to FixedUpdate because we use fixedDeltaTime in SlowMo.
Answer by Masterio · Feb 29, 2016 at 07:36 AM
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;
}
}
}
This didn't work. I had already tried something similar and it did the same thing. after a few frames it stops, then slowly moves towards the ground. I need it to some how know what the velocity would be normally at that point, then * 0.5. Even then I don't think it would take the same path.
Thank you for your help on this @$$anonymous$$asterio. I did try your updated script but I think some other elements in my game stopped it working properly. The solution I went with seems to do the job nicely so I've gone with that.
Your answer
Follow this Question
Related Questions
How Do I make my character move? 0 Answers
How to move rigidbodies with 2D Character controller (No rigidbody) 1 Answer
Player controlled platforms 0 Answers
Why/How 2d tower of blocks collapse? 0 Answers