Add a constant force in Unity2D - unity3d

I have a ball and I want to move it on the X axis, so, in the FixedUpdate method I added a force:
rigidbody2D.AddForce(Vector2.right * speed);
The ball's speed increases because of this code I wrote. I want to make this force to be constant, so the ball's speed not to increase. How can I do that? Thanks a lot!

Applying a constant force will accelerate the object, because that's how real physics work:
Force = mass * acceleration
In your case, the resulting acceleration is:
Acceleration = Force / mass
If you want to set the object speed to be constant, you should modify the rigidBody's velocity:
http://docs.unity3d.com/ScriptReference/Rigidbody2D-velocity.html
Something like this:
rigidbody2D.velocity = new Vector2(speed, 0);

Related

Rotate Object around point and move it along sine function

First off: I am very new to Unity, as in VERY new.
I want to do the following: I want to rotate a cube around a stationary point (in my case a camera) with a radius that is adjustable in the inspector. The cube should always have its Z-axis oriented towards the camera's position. While the cube is orbiting around the camera, it should additionally follow a sine function to move up and down with a magnitude of 2.
I have some working code, the only problem is an increase in distance over time. The longer the runtime, the higher the distance between the cube and the camera.
Here is what I currently have:
void Awake()
{
cameraPosition = GameObject.FindGameObjectWithTag("MainCamera").transform;
transform.position = new Vector3(x: transform.position.x,
y: transform.position.y,
z: cameraPosition.position.z + radius);
movement = transform.position;
}
I instantiate some variables in the Awake()-method and set the cube's position to where it should be (do you instantiate in Awake()?). I'll use the Vector3 movement later in my code for the "swinging" of the cube.
void Update()
{
transform.LookAt(cameraPosition);
transform.RotateAround(cameraPosition.position, cameraPosition.transform.up, 30 * Time.deltaTime * rotationSpeed);
MoveAndRotate();
}
Here I set the orientation of the cube's z-axis and rotate it around the camera. 30 is just a constant i am using for tests.
void MoveAndRotate()
{
movement += transform.right * Time.deltaTime * movementSpeed;
transform.position = movement + Vector3.up * Mathf.Sin(Time.time * frequency) * magnitude;
}
To be quite frank, I do not understand this bit of code completely. I do however understand that this includes a rotation as it moves the cube along it's x-axis as well as along the world's y-axis. I have yet to get into Vector and matrices, so if you could share your knowledge on that topic as well I'd be grateful for that.
It seems like I have found the solution for my problem, and it is an easy one at that.
First of all we need the initial position of our cube because we need to have access to its original y-coordinate to account for offsets.
So in Awake(), instead of
movement = transform.position;
We simply change it to
initialPosition = transform.position;
To have more readable code.
Next, we change our MoveAndRotate()-method to only be a single line long.
void MoveAndRotate()
{
transform.position = new Vector3(transform.position.x,
Mathf.Sin(Time.time * frequency) * magnitude + initialPosition.y,
transform.position.z);
}
What exactly does that line then? It sets the position of our cube to a new Vector3. This Vector consists of
its current x-value
our newly calculated y-value (our height, if you want to say so) + the offset from our original position
its current z value
With this, the cube will only bop up and down with distancing itself from the camera.
I have also found the reason for the increase in distance: My method of movement does not describe a sphere (which would keep the distance the same no matter how you rotate the cube) but rather a plane. Of course, moving the cube along a plane will automatically increase the distance for some points of the movement.
For instantiating variables in Awake it should be fine, but you could also do it in the Start(){} Method that Unity provides if you wanted to.
For the main problem itself I'm guessing that calling this function every frame is the Problem, because you add on to the position.
movement += transform.right * Time.deltaTime * movementSpeed;
Would be nice if you could try to replace it with this code and see if it helped.
movement = transform.right * Time.deltaTime * movementSpeed;

How to add inertia to object 3d in Unity?

I create a game and I need use inertia for object.
Example:
The image shows all what I need.
When I touch on screen, blueObject no longer uses the position of brownObject and rotation of redObject. And I add component Rigidbody. The object just falls down. I need him to fall further along his trajectory (inertia).
I tried to use addForce(transform.forward * float), this not work.
By setting the position of the transform, you don't use Unity Physics engine. Your cube must have a rigidbody from the begin of the simulation and what you need here is a spring joint (https://docs.unity3d.com/Manual/class-SpringJoint.html) or a fixed joint.
You need to calculate the current speed, when releasing the object.
Track the positions over the last frame & current frame, and use Time.deltaTime to compensate different frame-rates.
Then set this velocity to your objects rigidbody. (AddForce is just manipulating the velocity, but depending on the ForceMode it respects mass etc.)
public Vector3 lastPosition = Vector3.zero;
void Update()
{
// maybe do : if(lastPosition != Vector3.zero) to be sure
Vector3 obj_velocity = (lastPosition - transform.position) * Time.deltaTime;
lastPosition = transform.position;
// if you release the object, do your thing, add rigidbody, then:
rb.velocity = obj_velocity;
}
That should create the "inertia". the velocity contains the direction and the speed.

Quaternion correction

I'm trying to implement network correction for a client simulated Rigidbody. 30 times a seconds I get the target rotation from which I calculate the rotation correction. Then I apply this correction over a number of frames.
Network update:
rotationCorrection = receivedRotation * Quaternion.Inverse(transform.rotation);
Every frame:
var a = Mathf.Min(1, Time.deltaTime * 8);
var final = Quaternion.Slerp(transform.rotation, transform.rotation * rotationCorrection, a);
var actualCorrection = final * Quaternion.Inverse(transform.rotation);
rotationCorrection *= Quaternion.Inverse(actualCorrection);
//rotationCorrection = Quaternion.Slerp(rotationCorrection, Quaternion.identity, a); // First try
_rigidbody.MoveRotation(final);
The reason I don't just interpolate the current rotation to the corrected on is the GameObject contains a Rigidbody which should simulate the object in addition to the correction.
This does work sometimes (at least the first try version), except at angles between roughly -90 and 90. I suspect its the code to slerp the rotationCorrection to identity.
(work in progress since the question was not 100% clear)
The subtraction formulae yield wrong results. Please try using euler, subtract the angles and you can make the desired quaternion.
Are you sure you don't need Lerp instead of Slerp?
Anyway final should not use Lerp or Slerp.
If as final you want transform.rotation * rotationCorrection (which is the current rotation plus the correction), then just use it as that. Multiplications actually add the rotation.
Lerp and Slerp are to be used with an a parametric to time, where a==0 will return the starting rotation, a==1 will return the final rotation. So a should be scaled with time. If, on the other hand, the network correction is exactly what you need and you get it at specific fixed-time updates, then without any Lerp, might as well try transform.rotation = transform.rotation*rotationCorrection.
rotationCorrection = receivedRotation * Quaternion.Inverse(transform.rotation);
What this does is return a rotation that starts from receivedRotation and ends to the opposite rotation of the current transform rotation. So neither the start nor the end point match with the current one.
so:
You set a final quaternion as currentRot * change
a starting as currentRot
and then update transform.rotation by making it = (S)Lerp with start, end and a parameter that equals 0 at starting time and 1 at ending time.
The network update was wrong. Corrected:
rotationCorrection = Quaternion.Inverse(transform.rotation) * receivedRotation;

Unity3d - Random Start direction and ForceMode.Impulse?

I have a cube. A script is attached to it. I want, that the cube gets an impulse at the start in a random direction. My problem is the addForce. I don't know what to add there.
public Transform myObject;
void Start () {
Vector3 randomDirection = new Vector3(0f,0f,Random.Range(-359, 359));
myObject.Rotate (randomDirection);
myObject.rigidbody.AddForce(transform.?????? * speed, ForceMode.Impulse);
}
For random you want
myObject.rigid body.AddForce(Random.Range(0, 10), Random.Range(0, 10), Random.Range(0, 10), ForceMode.Impulse);
The code is saying, give me a random force value for the x, y, z.
Rotation has nothing to do with it. If you push a cat from a random Angle, you add force to the cat. You don't need to rotate the cat to push it. Although you shouldn't go around pushing cats.
If you insist on random rotation then make your object fire off forwards:
myObject.rigid body.AddForce(myObject.transform.forward * speed, ForceMode.Impulse);
transform.forward is a property on Transform that represents the direction the object is facing. In the Editor, it is represented by the blue axis on the object's transform handle.
If you use it in your script, the object will have a force applied to it in the random direction determined by the myObject.Rotate(...) line.

accelerated addforce for rigidbody

I need a method for accelerating the addforce method to the object.
Force Result feels too slow and I want it to be applied faster and for the final result time lapse shorten.
void FixedUpdate()
{....
Vector3 v_x = new Vector3(keyb_x, 0, 0);
Vector3 force_ = v_x * kspeed * Time.deltaTime;
float speed = rigidbody.velocity.magnitude;
rigidbody.AddForce(force_, ForceMode.Impulse);
....}
Raising gravity from -9 to -19 or more in the y direction gives the expected result, but all other objects are affected. I want only it to apply to a specific object only.
All gravity does is apply a downward force to all of your rigidbodies every physics update. For 2D unity physics you could use rigidbody2D.GravityScale, which scales gravity's effect on a per-rigidbody basis, but for 3D rigid bodies you should apply a constant force equal to the change in gravity you want for your object
e.g.
//adds a downforce of 10 per second
rigidbody.AddForce(Vector3.down * 10f * Time.fixedDeltaTime);
You'll want to put this in your fixed update function.
object_Rigid2D.gravityScale += gravity_Increase * Time.deltaTime;
I found an easy way to reach this. Consider you have an object which you move with addForce (I use impulse, other modes probably work too) by 1 unit (so vector is something like (1, 0, 0)) and object mass and drag are both 1, so the object moves properly but you want to make it quicker/slower. In that case you need to reduce it's mass and increase drag to make it quick and vice versa. For example you can make it quicker if you set mass to 2 and drag for 0.5 or slower if mass is 0.25 and drag is 4. Only rule is that drag * mass = 1.