Torque and acceleration curve? - c#

I want to have some more acceleration control over my wheel, which is just a cylinder that gets torque added.
wheel.AddTorque(wheel.transform.up * throttle);
What I actually want is to let it accelerate very quickly but at a give speed this the acceleration should quickly fall off. Like curve that starts very steep. Is there any way I can influence this using the basic .Addtorque?
Currently, my wheel just accelerates quickly to maximum velocity. Adding drag to it slows it down but I don't have the desired control over it.

You just affect the angularVelocity property of the rigidbody directly. Just as you can affect the velocity property instead of using the .AddForce method.
Try this pseudo code
public float topSpeed;
public float decelRate;
protected bool slowDown = false;
public void Update()
{
float speed = wheel.angularVelocity.magnitude;
if (speed >= topSpeed) slowDown = true;
if (slowDown)
{
speed -= decelRate * Time.deltaTime;
wheel.angularVelocity = wheel.angularVelocity.normalized * speed;
}
}
Keep in mind that magnitude calls are expensive, due to a square root function inside, though in this case i didn't see another way around it so you should be fine. Also i am not slowing it down in a set direction which is important, because this way it will slow down no matter what direction it is rotating in, or what way it is orientated.

Related

The fastest way to rotate object Unity3D

I have a big number of objects which I would like to move and rotate in Update() method. The movement part is pretty simple. The issue comes with rotation performance. Operations with euler angles are quite expensive and I want to optimize this part.
I've tried using both
transform.rotation.eulerAngles += _rotationDirection * Time.deltaTime;
and
transform.Rotate(_rotationDirection * Time.deltaTime);
But they are expensive to call.
Since objects have a constant rotation value, I tried this:
private void Awake()
{
_rotationDelta = Quaternion.Euler(_rotationDirection * _rotationSpeed);
}
private void Update()
{
transform.rotation *= _rotationDelta;
}
This seems to be more performant but my issue now is that I don't know how to link Time.deltaTime to this because you can't just write
transform.rotation *= _rotationDelta * Time.deltaTime;
So, my question is, what is the fastest way to rotate an object if the rotation delta is constant during object's lifetime?
There are two big issues:
One call per frame (Update Method)
Unoptimized Arithmetic (Transform.rotate)
Use RigidBody instead!
Explanation:
The way Transform.Rotate works is that it calculates rotation and returns rotation as Quaternion which can be then assigned to the rotation value.
Calls in Update method are a big performance issue as they're called before each frame is dropped, and can cause stutters or constantly low fps.
The fix for all of this is simply, RigidBody.
You should set drag and angular drag to 0, so that the rotation doesn't slow down.
You can also freeze position if you will not be moving your objects.
The call will simply be once in the start of the game (in Start() method):
int angularPower = 5;
void Start(){
GetComponent<Rigidbody>().AddTorque(angularPower, 0, 0);
}

How Can I Gradually Add More Force To An Object To Increase It's Speed Regardless of It's Direction?

I'm new in Unity. I am trying to make a 2D game similar to Pong. However, I want to increase more speed to Ball over time to make it harder. I set the gravity scale of the Ball to zero so that it doesn't fall down.
I added a force and bouncy Physics element to the ball. So it bounces back from walls and it goes to different directions.
Here is a screenshot of Game I'm working on:
MY QUESTION IS:
How can I add more force to the ball regardless of which direction it
bounces back?
<Note: I tried putting it inside FixedUpdate () method but the ball goes crazy because of constantly executing same function every frame. I was thinking of adding more force to the ball over time by using InvokeRepeating ( ) method later on to set time interval. If there is better idea of using other techniques, giving me a little advice will help me a lot>
Thank you !
I would recommend using a Coroutine or an InvokeRepeating. I would also recommend changing your code a bit.
rbBall.AddForce(rbBall.transform.right * ballForce)
The above snippet will add the ballForce in the direction the rbBall is moving.
Now for the two example snippets.
Coroutine
private float timeBeforeAddForce = 5f;
private void Start()
{
StartCoroutine(GradualAddForceToBall());
}
private IEnumerator GradualAddForceToBall()
{
// wait for 5 seconds
yield return new WaitForSeconds(timeBeforeAddForce);
// add the speed
rbBall.AddForce(rbBall.transform.right * ballForce)
// call the coroutine again
StartCoroutine(GradualAddForceToBall());
}
InvokeRepeating
private void Start()
{
InvokeRepeating("GradualAddForceToBall", 0.0f, timeBeforeAddForce);
}
private void GradualAddForceToBall()
{
rbBall.AddForce(rbBall.transform.right * ballForce)
}
If you want to change the current time of how long the speed is applied, I would go with the Coroutine as you can gradually decrease the timeBeforeAddingForce every time it enters the Coroutine.
I found the answer. You can force an object to be a specific speed while keeping its same movement direction - normalize the velocity (which sets the value to have a mangitude of 1) and then multiply it by your desired speed:
Here is the code:
public float currentSpeed = 5f;
void FixedUpdate()
{
//This will let you adjust the speed of ball using normalization
rbBall.velocity = rbBall.velocity.normalized * currentSpeed;
}
Adjust the currentSpeed variable to change it's speed.
""

How can i use rigidbody2d.velocity to follow an object in Unity?

I need the Player to follow the moving Target and stop exactly when it reaches the Target.
The Player has to reach the Target almost instantaneously in every frame, so i need a high speed way to do it.
I couldn't use Transform.translate because there's a lot of physics implementations in my game and using Transform.translate or movetowards made the physics buggy.
Is there any physics based way to follow the target? velocity, AddForce, anything? For a 2D game.
Any leads would be greatly appreciated! Thank You!
If you have a Rigidbody2D you want to follow another object, the Rigidbody2D.MovePosition is the proper way to move it.
Do the following:
1.Disable gravity by setting the "Gravity Scale" to 0.
2.Change the BodyType to Kinematic.
3.You can now move the Rigidbody object to follow another GameObject with the Rigidbody2D.MovePosition function. See code below. This should be done in the FixedUpdate function and with Time.fixedDeltaTime instead of Time.deltatime.
Finally, if you still get jerky movement, change Interpolate option from None to Interpolate or Extrapolate. I would also suggest reducing the speed variable below.
//Object to follow
public Transform target;
//Rigidbody to move
public Rigidbody2D rb2d;
public float speed = 7.0f;
//Distance to start moving
public float minDistance = 0.09f;
void FixedUpdate()
{
//Find direction
Vector3 dir = (target.transform.position - rb2d.transform.position).normalized;
//Check if we need to follow object then do so
if (Vector3.Distance(target.transform.position, rb2d.transform.position) > minDistance)
{
rb2d.MovePosition(rb2d.transform.position + dir * speed * Time.fixedDeltaTime);
}
}
Changing the velocity directly is always a bad practice and should be avoided. Instead always work with AddForce.
I would calculate the distance between the target and the body and add a force based on that distance.
var dif = target.transform.pos - body.transform.pos;
bodyRigid.AddForce(dif * multiplier * Time.deltatime);
The only problem that comes with that solution might be the fact that the body 'shakes' around the target once its to close.
You could avoid this by checking if the body is close to target and then freezing it.
var dif = target.transform.pos - body.transform.pos;
if(dif.magnitude > 1) {
bodyRigid.AddForce(dif * multiplier * Time.deltatime);
} else {
bodyRigid.velocity = Vector2.zero;
}
Although I said that setting the velocity directly is a bad habit, using it to just freeze the body should be fine. I have no idea whether that might break your other physics that you use in your game, duo the fact that that just strait up freezes your object.
You can also change the distance (1 in the if statement) that it needs in order to freeze, just play around with it a bit and find a value that fits the game

How do I move a Rigidbody towards target without adding force or velocity?

I have a ball that has an initial burst of force, launching it into the air. This ball would ideally then be able to veer towards its target while continuously losing that starting momentum. It shouldn't gain any velocity when heading towards its target.
Importantly! It can also bounce against walls, this also decreases its momentum.
Unitys built in physics system works great for throwing stuff against walls and seeing it bounce in a very natural manner, I want to keep this but gently push it towards a target.
Most solutions I have found (particually for homing missiles) add a continuous amount of force, which is fine if they are self powered.
In a script before this I would give the ball a force of say... 100 using
ballRigidbody.Addforce(targetDirection, ForceMode.Impulse);
Then I'd like it to be steered using a 'Movement' class.
Below is an example of the ball being pushed by continuously adding force, so its more like a rocket (Not what I'm after!)
public class Movement : MonoBehaviour {
[Header("Get Components")]
[SerializeField]Transform targetTransform_gc;
[SerializeField]Transform ballTransform_gc;
[SerializeField]Rigidbody ballRigidbody_gc;
[Header("Settings")]
public float turnSpeed;
public float ballSpeed;
//Private
private Vector3 targetDirection;
private Quaternion targetRotation;
void Update () {
targetDirection = targetTransform_gc.position -ballRigidbody_gc.position;
targetDirection.Normalize();
targetRotation = Quaternion.LookRotation(ballRigidbody_gc.velocity);
ballTransform_gc.rotation = Quaternion.Slerp (ballTransform_gc.rotation, targetRotation , turnSpeed * Time.deltaTime);
}
void FixedUpdate(){
ballRigidbody_gc.AddForce(targetDirection * ballSpeed);
ballRigidbody_gc.velocity = new Vector3(ballRigidbody_gc.velocity.x, 0, ballRigidbody_gc.velocity.z);
}
}
I'd be really grateful if anyone has some pointers or suggestions.
Thanks very much!
If I understand you correctly, you are looking to change the direction, but not the magnitude of your velocity vector. You can get the current magnitude in 3 dimensions using:
double magnitude = Math.Sqrt(Math.Pow(x, 2) + Math.Pow(y,2) + Math.Pow(z, 2));
you can then just multiply a unit vector that points between your ball and the target by this magnitude
Edit
The magnitude of a vector is always computed using the formula I showed below. The magnitude is the total length of the vector, ignoring direction.
A unit vector is just a vector pointing in a given direction, with a magnitude of 1.
At this point you have your magnitude, which is how fast you want to go, and your unit vector, which is what direction you want to go. Multiplying these 2 values together gives you a vector that is both the direction and speed you want to go.

Constant speed for Adding Force without affecting jump

There seem to be a fair amount of questions similar to this but none seem to really answer. I have a gameobject that can jump on a click of a button and automatically keeps going right.
I need the right moving motion to be constant but it ends up building faster and faster over time. If I use Velocity instead of AddForce, the motion is constant. But when I mouse click to jump, it takes like 10 over seconds to reach back down to ground.
Can I please get assistance on how I can keep the automatic movement to the right constant and still able to jump and reach back to ground fast. The following is my code. Thank you.
Edit:
Desired result
Gameobject constantly moving same speed to the right. When I jump, gameobject jumps and comes back down to ground over a period of 0.5 secs.
Jump is expected to be like a smooth flow like a ball that jumps and comes back down smoothly.
Current result Using AddForce to move right
Gameobject starts to move right slowly and picks up speed over time getting faster and faster thus not able to keep constant same speed.
Current result Using Velocity to move right
Gameobject able to keep constant speed as wanted, but when I jump the Gameobject jumps and takes about 10 seconds to get back down to ground (It slowly glides back down).
public float jumpSpeed = 300;
public float maxSpeed = 15;
Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.velocity = Vector2.ClampMagnitude(rb.velocity, maxSpeed);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
rb.AddForce(Vector3.up * jumpSpeed);
}
}
void FixedUpdate()
{
rb.AddForce(Vector3.right * maxSpeed);
}
//Trying to change velocity instead - Able to keep constant speed but when I jump, takes about 10 secs to get back down to ground.
public float jumpSpeed = 2000;
public float maxSpeed = 5;
Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
rb.velocity = Vector2.ClampMagnitude(rb.velocity, maxSpeed);
}
void Update()
{
if (Input.GetMouseButtonDown(0))
{
rb.AddForce(Vector3.up * jumpSpeed);
}
}
void FixedUpdate()
{
rb.velocity = new Vector2(5, 0);
}
I think there are a few points of confusion here, so I'll answer some clarifying questions of my own.
Why does the speed of the object increase without bound when using add force?
The AddForce command will increase the velocity of the object every time you apply it. In the code, this means every call to FixedUpdate is increasing the velocity.
I think the misunderstanding is related to this line of code in your Start method:
rb.velocity = Vector2.ClampMagnitude(rb.velocity, maxSpeed);
Vector2.ClampMagnitude is not persistent. That is to say, it does not clamp the magnitude going forward. What you probably meant was to prevent the velocity from ever breaking "maxSpeed" in which case you should call the clamp method in FixedUpdate.
However, this would have a different effect which you might not intend. When the game object is moving along only one axis, the entire magnitude of the velocity is along that axis. Once the game object begins moving along a second axis, for instance while jumping, the magnitude of the velocity is split across both. This means that while your game object is jumping (has a y component to its velocity) its horizontal speed (the x component of its velocity) would be diminished. In other words, jumping would slow down your game object's movement to the right.
Why does my object "float" slowly downwards when setting the velocity directly?
One of the advantages of using AddForce is that it modifies the targeted axis of a vector without modifying the others. Setting the velocity directly is a little more tricky because you may accidentally clobber the velocity changes caused by physics.
For instance, in your FixedUpdate code:
rb.velocity = new Vector2(5, 0);
is setting the x velocity of your object to 5 - creating the smooth horizontal movement you want - but at the same time, setting the y velocity to 0.
This is why you needed to crank your jumpSpeed up to 2000 to see any effect on the object's height: it only has a split second to move upwards before the FixedUpdate method resets its upward motion to 0. This is also why your object appears to be "floating" back to earth. The internal physics engine is trying to apply gravity to the object but is being foiled by your code which constantly resets the objects downward velocity.
One Other Comment
I noticed you had some code in your Update method that was acting on the object's physics - that is your jump code. A good rule of thumb is to keep all the code working on an object's physics in the FixedUpdate method, since this is called just before the physics engine does it's work while the Update method is called just before the rendering engine does its work to draw the game.
One Possible Solution
The AddForce technique is normally recommended when working on an object's velocity because it creates natural looking physics through acceleration. Setting an objects velocity directly can create strange looking effects because objects in reality don't work this way. For instance, imagine what it would look like to see a car change from 0mph to 60mph in less than a split second.
If you check Unity's documentation on Rigidbody.velocity, you'll see they make this same recommendation, but add that jumping may be a scenario where you want to break this rule. However, as I mentioned earlier, we need to be careful when setting the y velocity explicitly so as to avoid changing the object's speed along other axes.
public float jumpSpeed = 2;
public float maxSpeed = 1;
Rigidbody rb;
void Start()
{
rb = GetComponent<Rigidbody>();
}
void FixedUpdate()
{
var newVelocity = rb.velocity;
if (Input.GetMouseButtonDown (0))
newVelocity.y = jumpSpeed;
newVelocity.x = maxSpeed;
rb.velocity = newVelocity;
}

Categories

Resources