- Home /
Physics update rate problems
I couldn't find a better title for my question, so I hope it makes sense :)
Here's a quick preview of my code and my problem:
using UnityEngine;
using System.Collections;
public class Suspensions : Monobehavior
{
public float springForce = 150f;
public GUI_Controls controls;
void FixedUpdate()
{
Preload();
}
public void Preload()
{
// Define global up direction
Vector3 globalUp = transform.InverseTransformDirection( Vector3.up );
// iPhone input system...
if( controls.iphoneControls )
{
// Only preload if rear wheel is touching the ground
if( CheckWheelCollision.hasRearWC )
{
if( controls.preloadOn )
{
rigidbody.AddRelativeForce( globalUp * preloadStrenght, ForceMode.Force );
controls.preloadOn = false;
}
}
}
}
Now my problem: As you can see from the code above, I turn off the preload as soon as it gets turned on, right after rigidbody.AddRelativeForce(); happens. The problem is that it feels like it didn't have enough time to apply the force to my object, because it barely moves it.
If I remove controls.preloadOn = false; and instead move it to after my touch ended, then controls.preloadOn stays on a little longer (let's say half a second more), the force gets applied to my object a lot stronger, and my object moves a lot like it's supposed to.
But, I want to turn preloadOn = false; right away, but I can't figure out how to make the force applied to the object be the full strength like it is when preloadOn is true longer. I can do it by turning Preload() into a coroutine and forcing it to last longer then a tick, but I'd rather not do that.
Any help would be very appreciated, as I am a little stuck on this one :)
Thanks for your time guys! Stephane
Fattie, thx for the quick reply. I looked at both the ConstantForce and Explosive Force, but I don't think they will work for my case.
I think my best option is to use a coroutine and force the AddForce to run for half a second, no matter what. That way I get the same results everytime.
I guess what I need to know is this...
when you have:
void Update()
{
if( myBool == true )
{
DoSomething();
myBool = false;
}
}
myBool will be true for only 1 tick, correct? So the timeframe of doSomething() will only be 1 tick, which for applying forces, is way too short, am I correct?
Answer by Fattie · Oct 09, 2012 at 06:30 AM
it's possible you need to do something along these lines ...
in update ...
if .. whatever .. applyForceForTwoSeconds();
var IAmAlreadyBusyFDoingSomething :boolean;
function applyForceForTwoSeconds()
{
if ( IAmAlreadyBusyFDoingSomething )
Debug.Log("notice how well this works??";
return;
}
IAmAlreadyBusyFDoingSomething = true;
countHowManyTimesToApplyForce = 50 for example
while ( --countHowManyTimesToApplyForce > 0 )
{
AddForce( appropriate force amount for 1/20th of a second, say )
yield WaitForSeconds( 0.05 );
}
IAmAlreadyBusyFDoingSomething = false;
}
notice I have kept the lock concept (the boolean) entirely within the applyForceForTwoSeconds function, so it's all really clean.
you can just call applyForceForTwoSeconds any time you want without worrying about it
notice I apply the force every 1/20 of a second in the example code. do that at first but ideally you should apply it every frame. you have to calculate the force carefully using Time.deltaTime
"generally you have to apply force continuously -- indeed, usually in FixedUpdate (or conceivably in Update if your math is good!) or by using a loop with yield (a coroutine)
conceivably, the "constantForce" system could be useful to you (look in the menus and read the doco). there's also "explosive force" but possibly not for you here"
Thanks for the example code Fattie, this will work perfect for me! I'm coding everything in C# so I'll have to turn the function into an IEnumerator and call StartCoroutine()...it's the only thing about using C# that I don't like, being able to use "yield blabla" anywhere/anytime in JScript is nice :)
indeed, it's much easier to convert to other languages using that "clean away" approach! enjoy !