Oscillate object with forces/velocity
I want to oscillate my GameObject in a wave like form for it to appear floating. Now this works fine when I manipulate position manually using Mathf.Sin, but since that doesn't really play nice with collisions I'd like to do it with oscillating the force applied to the object, or even just velocity.
However, every time I try this in some form with adding forces, the object moves up, then pauses, then keeps moving up, (seems like velocity pingponging to 0 rather than oscillating from -foo to +foo) I got to my force formula by taking the 2nd derivative of the position formula and multiplying by mass. I checked wolfram and it seems like my derivatives are correct.
This is driving me crazy. is my math wrong or my code?
Forces version (doesn't work, just keeps going up)
void FixedUpdate()
{
t += Time.fixedDeltaTime;
float magnitude = rb.mass * (4*Pow(pi,2)/90)* Sin((t/3)*2* pi);
rb.AddForce(magnitude * Vector2.up);
}
Velocity version (oscillates but slowly moves downwards)
void FixedUpdate()
{
t += Time.fixedDeltaTime;
float magnitude = 2*pi/30 *Cos((t / 3) * 2 * pi);
rb.velocity += magnitude * Vector2.up;
}
Position version- works perfectly
void FixedUpdate()
{
t += Time.fixedDeltaTime;
float magnitude = 0.1f * Sin((t / 3) * 2 * pi);
Vector3 newPos = transform.position;
newPos.y += magnitude;
transform.position = newPos;
}
Notes:
t is a time counter, rb is the RigidBody2D component, Sin/Cos/Pow are wrappers for Mathf functions
my object has a RigidBody2D attached with gravity scale set to 0, mass set to 1 (tried auto mass, didn't seem to affect behavior).
force formula derivation:
Pos(t)= 0.1*sin((t/3) *2pi) V(t) = Pos'(t) = (2pi/30)cos((t/3)*2pi) F(t) = m * a(t) F(t) = m * V'(t) F(t) = -m *(4pi^2/90)sin((t/3)*2pi)
also I tried this in various ways in Update using Time.deltatime and with Lerp. no dice.
Any help would be really appreciated :)
Answer by MelvMay · Jan 16, 2017 at 07:47 AM
If you have a position you want a Rigidbody2D to move to then simply use MovePosition (you should never set the Transform position with a Rigidbody2D attached as adding a Rigidbody2D is asking Unity to give it control of the Transform). This calculates the velocity required to move to the specified position during the next fixed-update. Note that this doesn't alter the body velocity that you see via scripts at all; it'll have the same velocity after it has moved as it did before it moved. Because the body is moving under its own velocity, it'll detect collisions (especially continuous ones) correctly. Technically this is most useful for Kinematic body types however it does work for Dynamic body types as well.
This was a good fix for using collisions, thanks! :) However, I still don't know why my derived functions didn't work. So I'm leaving this question open in hopes that someone can point out my error or whether there's a bug in there somewhere
I suspect the problem with the 'force' one is that you have not set the Rigidbody2D.gravityScale to zero on the Rigidbody2D therefore gravity is added to the velocity each fixed update.
When you simply set the position, it won't matter what the velocity is (even if it's continually increasing because of gravity) because you're constantly repositioning it back.
Try dumping out the Rigidbody2D velocity in the 'position' one and you'll see the velocity increasing.
Answer by TheyLeftMe4Dead · Jan 16, 2017 at 04:55 AM
Without reading any of your code, if I were scripting this, I'd let Unity handle most of the hard work. First, I would allow Gravity to pull my GameObject. My code would look like this:
Update () {
if (transform.position < minHeight) {
//AddUpwardsForce
}
}
This would keep pushing the GameObject up when it fell below X coordinates. I would adjust the oscillating speed by adjusting the object weight/ the force I apply to it.
Alternatively, I would change the Object's position rather than use velocity or force. Using Velocity or force means that the object will move a bit before the next calculation can be preformed. So instead, I would first calculate the next position then add/subtract from it's transform.position.y. This will mean that the object wouldn't move unless you specifically told it to in your script, allowing you more control over it.
Your answer
Follow this Question
Related Questions
How do I keep rigidbodies from pushing each other? 2 Answers
Collision sticking? 1 Answer