I'm trying to reduce the gravity scale of my flappy bird game for approximately 1 second at start time. I want to give the player a little time cushion before he falls more quickly.
I originally put the function in the start method (does a timer work in a non-update function?) I then put it in the update function.
Regardless, the timer doesn't seem to trigger, and the gravityscale doesnt go to normal (1).
You'll also see my comment where I was trying to lerp the gravity scale instead. Is it possible to lerp a gravity scale?
void Update()
{
Jump();
Rotation();
PlayerHalt();
}
private void PlayerHalt()
{
float gravityTimer = 0f;
gravityTimer = Time.deltaTime;
if (gravityTimer <= 1)
{
rb.gravityScale = .2f;
//rb.gravityScale = Mathf.Lerp(.2f, 1f, gravityTimer / 1f);
}
else
{
rb.gravityScale = 1f;
}
}
CodePudding user response:
You must use IEnumerator
that acts like a Timer, at the bottom of the code you will see a simple Gravity Tweener.
private IEnumerator TweenGravity(float target, float duration)
{
var baseGravity = rigidbody2D.gravityScale;
var progress = 0f;
while (progress < 1f)
{
progress = Time.deltaTime/duration;
rigidbody2D.gravityScale = Mathf.Lerp(baseGravity, target, progress);
yield return new WaitForEndOfFrame();
}
}
public Rigidbody2D rigidbody2D; // setup your rigidbody on inspector
private void Start() => StartCoroutine(TweenGravity(1f, 1f)); // how to call IEnumerator
How To Reverting gravity?
You can use an Action
to give a callback at the end of the timer for reverting or other command.
private IEnumerator TweenGravity(float target, float duration, Action OnFinish = null)
{
///....
OnFinish?.Invoke(); // this will call after wait progress finish
}
private void Start() => StartCoroutine(TweenGravity(1f, 1f, () => Debug.Log("On Finish callback")));
CodePudding user response:
Here's a method that uses a simple time delay mechanism by taking note of the start time and measuring the current elapsed interval. You can see it in the Delay
class below.
Apart from Time
(which you could easily replace with DateTime
or even Environment.TickCount
) it's essentially technology-neutral. No nasty Unity coroutines necessary (which if used incorrectly are akin to Application.DoEvents()
).
Delay
class:
public class Delay
{
private float _lastInterval;
/// <summary>
/// The timeout in seconds
/// </summary>
/// <param name="timeout"></param>
private Delay(float timeout)
{
Timeout = timeout;
_lastInterval = Time.time;
}
public float Timeout { get; }
public bool IsTimedOut => Time.time > _lastInterval Timeout;
public void Reset()
{
_lastInterval = Time.time;
}
public static Delay StartNew(float delayInSeconds)
{
return new Delay(delayInSeconds);
}
}
Because it uses Unity's Time.time
member it can be safely used from both Update
and FixedUpdate
.
Usage
private Delay _delay;
private RigidBody rb;
void Start()
{
rb = ...
rb.gravityScale = .2f; // reduce the gravity scale
_delay = Delay.StartNew(1f); // One second
}
void Update()
{
if (_delay.IsTimedOut)
{
rb.gravityScale = 1f;
}
.
.
.
}
Render throttling / Emulate a periodic timer
It can also be used in scenarios that demand reoccurring opperations spaced by a given frequency.
e.g. I use it a-lot for throttling processing or updates for rendering where I don't want to update things every frame but maybe every 100 ms. I can achieve this by setting a Delay
whereby I update rendering to the screen/buffer/RenderTexture
/Texture2D
like so:
private void Update()
{
if (!_delay.IsTimedOut)
{
// not yet time
return;
}
// perform rendering here
_delay.Reset();
}