I want to create a timer/stopwatch on an event - c#

I have a code that works just fine but i think if i keep following the same strategy to do all the same things it's gonna over load on the processor for no reason
I have a variable that represents the time and this variable rests to 0 in every frame that the gameObject has a velocity higher than 0.5f so instead of resetting it every frame i want to start the timer when it's below 0.5f
if (speed >= 0.5f)
{
t = 0;
}
t = t + Time.deltaTime;

You could use a bool value to save performance.
public static bool isTimerMoving = false;
public void Update()
{
if (speed < 0.5f)
{
t = t + Time.deltaTime;
isTimerMoving = true;
}
else if (isTimerMoving) {
t = 0;
isTimerMoving = false;
}
}
This code resets the timer whenever speed reaches 0.5f. If you only want to pause the timer, you can remove the t = 0 from it.
P.S. using > or < is faster than using <= or >=. Not by very much, but I like keeping things efficient ;)
EDIT: After asking a question, responses indicate that this statement is false, my apologies.

Related

Lerp for lighting brightness is not gradually increasing

My implementation of Lerp should gradually increase the light from minbrightness to maxBrightness over time. It does change the range of my light however it is immediately going to my maxBrightness instead of gradually increasing. Where have I gone wrong?
Here is the code I am using
private void Update()
{
//this is a timer that will only only count down when collided = true
if (_collided == true)
{
timeLeft -= Time.deltaTime;
_light1.range = Mathf.Lerp(minbrightness, maxBrightness, lightTimer);
//increases interloper
lightTimer += _brightenRate * Time.deltaTime;
}
else
{
//this sets the lights range value to be bigger then normal
_light1.range = Mathf.Lerp(maxBrightness, minbrightness, lightTimer);
//increases interloper
lightTimer += _brightenRate * Time.deltaTime;
}
//checks if the time value is 0
if (timeLeft <= 0)
{
//this resets the value back
timeLeft = timeLeftReset;
_collided = false;
}
}
I have heard of IEnumerator, but am unsure of how to apply it to my current solution or if that will even fix my current problem.

How to make a combotimer in Unity

I'm making a game currently and I got stuck while I was thinking about a combotimer.
Now in my game, there are enemies that run through my character and I hit them. Yet, at some point, if I can correctly hit the enemies, I want to add a powerful combo option like hitting them without any difficulty. I thought like I can create a class or a value that keeps the correct hits and let's say it's 5. When it reaches 5, then I can change the hitting options. Yet, where I'm stuck is that how I can identify after how many hits or seconds the combo can end. And in here what came to my mind is that I can make it with time. So here's the thing. I want to detect 5 hits and then I want a combotimer which makes the value of 5 decreased. So that when the value reaches 0 then I can continue to play my game with the normal standards of it. How can I do this?
Since you didn't provide anything here is what I would do as dummy code. This does
Everytime you hit an enemy check the time since last hit
If under the maximum delay => add to combo
If not reset the combo counter and start over
If reaching enough hits => enable isSuperCombo
Over time reset the isSuperCombo
As long as you are isSuperCombo you can still add hits even if they happen after the normal maxTimeBetweenHits to enlarge the duration of isSuperCombo as a little bonus
Something like
public class ComboCounter : MonoBehaviour
{
public bool isSuperCombo;
// Maimum delay in seconds since the hit for counting the current hit as combo
[SerializeField] private float maxTimeBetweenHits = 1;
// Requried hits in one combo in order to activate power bonus
[SerializeField] private int hitsUntilSuperCombo = 5;
// Delay in seconds to reset the powerup after the last hit
[SerializeField] private float powerUpDuration = 5;
private int hitCounter;
private float lastHitTime;
private float powerUpResetTimer;
private void Update()
{
if(isSuperCombo)
{
powerUpResetTimer -= Time.deltaTime;
if(powerUpResetTimer <= 0)
{
isSuperCombo = false;
hitCounter = 0;
}
}
}
// Call when you hit an enemy
public void AddHit()
{
if(Time.time - lastHitTime < maxTimeBetweenHits)
{
// then add to the hit counter
hitCounter++;
if(hitCounter >= hitsUntilSuperCombo)
{
isSuperCombo = true;
powerUpResetTimer = powerUpDuration;
}
}
else
{
// otherwise the delay was too big => not a combo anymore
// => Reset the counter and start over with this hit as the first one
hitCounter = 1;
}
// update the lastHitTime
lastHitTime = Time.time;
}
}
Then you could e.g. in another class check something like
public void CauseDamage(Enemy enemy)
{
enemy.health -= GetComponent<ComboCounter>().isSuperCombo ? 4 : 1;
}
If you need to note 5 seconds of increased damage you can use coroutine
private float _damage = 10;
public void StartCombo(float duration = 5)
{
StartCoroutine(ComboHandler(duration));
}
private IEnumerator ComboHandler(float duration)
{
_damage *= 2; //_damage = _damage * 2;
yield return new WaitForSeconds(duration); //wait necessary amount of real time
_damage /= 2; //_damage = _damage / 2;
}
If you need to do only 5 blows with increased damage, you can use something
private float _damage = 10;
private int _increasedBlows = 0; //amount of blows with increased damage
private float _increasingCoeff = 2; //ratio of damage increase of blow
//add new increased blows after doing combo
public void AddIncreasedBlows(int amount)
{
_increasedBlows += amount;
}
//return blow damage
public float GetHitDamage()
{
if (_increasedBlows > 0)
{
_increasedBlows--;
return _damage * -_increasingCoeff; //return increased damage
}
else
{
return _damage; //return usual damage
}
}

Jump height in relation to timeheld of spacebar

This has been asked before, but none of the answers solved my problem because the problem was always slightly different.
I have a character that jumps on spacebar down. I want it to make higher jumps when the spacebar is pressed longer, with a maximum of twice the normal jump height.
Here's what I came up with so far:
void FixedUpdate () {
if (Input.GetKeyDown(KeyCode.Space) && myRB.velocity.y == 0)
{
timeHeld = 1;
}
if (Input.GetKey(KeyCode.Space) && myRB.velocity.y == 0)
{
myRB.AddForce(Vector3.up * 20,ForceMode2D.Impulse);
timeHeld += Time.deltaTime;
myRB.mass = myRB.mass - timeHeld/10;
}
if (Input.GetKeyUp(KeyCode.Space))
{
myRB.mass = 1;
}
}
Since the jump has to happen on keydown (not keyup), I can't increase the force added on jump, because the force is already applied on keydown. Therefore, I was thinking of lowering the mass of my rigidbody.
The above code "works" if I keep holding spacebar: the character jumps (minimum height), lands, jumps again but now a bit higher, etc. But that's not what I'm looking for, obviously.
This can easily be done by making a Time frame in which Jumping occurs;
Within this time frame u allow upward forces to be applied by holding space bar down. As soon as you reach either the end of the time frame or the end of the button press; you restrict upward velocity until the character has landed.
Let gravity take its own course after you end the jump.
As for the coding part i suggest you start a co routine when the jump happens.
here is some code to u help you get started;
IEnumerator Jumper()
{
if (maxjumpduration!=jumpduration)
{
jumpduration = jumpduration + 0.1f;
yield return new WaitForSeconds(0.1f);
}
else
{
jumpduration = 0;
StopCoroutine(Jumper());
}
}
As for the fact you want have a regular jump as well; make another time frame in which is decided if the press of space bar is considered either a regular jump or a controlled jump; During that initial time frame in which you are still deciding what kind of jump it is; you execute a short part of the jump until you reach a conclusion and then you send it to the correct method.
I added Some ground work for u but try to finish the code yourself;
{
private bool shortjump = false;
private bool checkphase = false;
private bool hitground = false;
private Rigidbody player = new Rigidbody();
private bool jumping = false;
Vector3 sharedjumpforce = new Vector3();
private void Update()
{
if (Input.GetKeyDown(KeyCode.Space))
{
Initialjump();
}
if (Input.GetKeyUp(KeyCode.Space))
{
if (jumping)
{
shortjump = true;
}
}
if (jumping)
{
if (hitground)
{
jumping = false;
}
}
}
void Initialjump()
{
if (jumping = false)
{
checkphase = true;
jumping = true;
player.AddForce(sharedjumpforce);
Invoke("Standardorcontrolledjump", 0.2f);
}
}
void Standardorcontrolledjump()
{
checkphase = false;
if (shortjump)
{
}
else
{
}
}
}
I don't understand why are you putting
&& myRB.velocity.y == 0
You want it to reduce its mass while in air don't you. Assuming that reducing the mass after the initial force has been applied does allow the Rigidbody to go higher, (force of gravity weakens, im not sure if that happens in Unity)
Why don't you try this
void FixedUpdate () {
// apply force the instant button is pressed. That is only once
if (Input.GetKeyDown(KeyCode.Space) && myRB.velocity.y == 0)
{
myRB.AddForce(Vector3.up * 20,ForceMode2D.Impulse);
timeHeld = 1;
}
// keep subtracting from mass while its held
if (Input.GetKey(KeyCode.Space))
{
timeHeld += Time.deltaTime;
myRB.mass = myRB.mass - timeHeld/10;
}
if (Input.GetKeyUp(KeyCode.Space))
{
myRB.mass = 1;
}
}

Unity: How to Delay button call by time?

I desire to increment an float by 0.5 every time the user clicks the UI button and if the user presses the button for more than 2 second want to continuously increment the float by 0.5, to do so i use Event trigger (PointerDown, PointerUp) and call the functions in update. When i user the down below code i cant increment the float value continuously.
Update Code
void Update () {
transform.rotation = Quaternion.Lerp (qStart, qEnd, (Mathf.Sin(Time.time * speed) + 1.0f) / 2.0f);
if(Time.timeScale == 0)
transform.rotation = Quaternion.Euler(0,0,0);
clickCondition ();
}
PointerDown Function
public void WhenIncreaseClicked()
{
if (timeDown < 2.0f)
IncreaseBPM ();
else
increase = true;
}
PinterUp function
public void WhenIncreaseNotClicked()
{
increase = false;
Time.timeScale = 1;
}
IncreaseBPM
public void IncreaseBPM()
{
if (speed < 12)
{
speed += 0.05f;
bpmText.GetComponent<BeatTextControl> ().beats += 1;
PlayerPrefs.SetFloat ("savedBPM", speed);
}
}
ClickCondition
public void clickCondition()
{
if(increase)
{
IncreaseBPM();
}
else if(decrease)
{
DecreaseBPM();
}
}
Start
void Start () {
qStart = Quaternion.AngleAxis ( angle, Vector3.forward);
qEnd = Quaternion.AngleAxis (-angle, Vector3.forward);
timeDown = Time.deltaTime;
if (PlayerPrefs.HasKey ("savedBPM"))
speed = PlayerPrefs.GetFloat ("savedBPM");
else
speed = 1.5f;
}
I have set timeDown = Time.deltaTime in Start().
Assuming no other code alters your increase variable, you'll be unable to increment it continuously because it will never be set to true.
In Start() you have a line timeDown = Time.deltaTime;, so timeDown will be equal to the number of seconds since the last frame. Not only is this an issue because timeDown never changes (Start() is only called once), but it's an issue because it's not likely to ever be above 2.0f since a single frame is highly unlikely to take 2 seconds to complete. It will generally be a very small number, for example 0.06f.
Due to this, in your WhenIncreaseClicked() method, the if (timeDown < 2.0f) will always equate to true. Thus the else clause is never executed and increase is never set to true.
To resolve this you could create a new boolean variable, e.g. clicked and set it to true at the start of WhenIncreaseClicked() and false at the start of WhenIncreaseNotClicked(). Then in Update() you can just add Time.deltaTime to timeDown if clicked is true. You'll also want to move that if/else outside of WhenIncreaseClicked() also, and into Update(), making sure it's only run when clicked is true.
For example:
void Update () {
transform.rotation = Quaternion.Lerp (qStart, qEnd, (Mathf.Sin(Time.time * speed) + 1.0f) / 2.0f);
if(Time.timeScale == 0)
transform.rotation = Quaternion.Euler(0,0,0);
if(clicked) {
timeDown += Time.deltaTime;
if (timeDown >= 2.0f) // note the >= not <
increase = true;
}
clickCondition ();
}
and WhenIncreaseClicked():
public void WhenIncreaseClicked()
{
clicked = true;
IncreaseBPM();
}
and WhenIncreaseNotClicked():
public void WhenIncreaseNotClicked()
{
clicked = false;
increase = false;
Time.timeScale = 1;
}
You can also remove the assignment to timeDown in Start() since it's not useful.
First of all, Unity documentation says about Time.deltaTime
The time in seconds it took to complete the last frame.
When you set timeDown = Time.deltaTime timeDown becomes a tiny fraction, for example 0.01621689. Therefore, timeDown < 2.0f always returns true and your code never reaches increase = true; line.
Second point you should know is Time.time
The time at the beginning of this frame (Read Only). This is the time in seconds since the start of the game.
You used Time.time in your Update() method as Mathf.Sin(Time.time * speed). Bear in mind that Time.time can be enough large number representing the time in seconds since the start of the game as mentioned in document. When you do Time.time * speed the output number may be huge (assuming speed > 1) causing some problems. Luckily, you are using it inside Mathf.Sin() you get number only between [0, 1]. Probably, you intended to use Time.deltaTime instead.
Let's remember Time.time:
The time in seconds since the start of the game
You can use this to check time difference.
float lastDownTime;
bool isDown;
void OnPointerDown() // Method name itself says when it should be called
{
lastDownTime = Time.time;
isDown = true;
}
void OnPointerUp()
{
isDown = false;
}
void Update ()
{
if (isDown)
{
if (Time.time - lastDownTime > 2) // 2 seconds
{
IncreaseBPM ();
}
}
}
Note: Unity says about Time.timeScale:
Except for realtimeSinceStartup, timeScale affects all the time and delta time measuring variables of the Time class.
So if you insist on using Time.timeScale, instead of using Time.time you should use Time.realtimeSinceStartup in above example.

Unity increment velocity based on interval

I am trying to get a background to start moving to the left faster and faster.
Was thinking of using two values one for the amount in percent to increase and one value for the interval between incrementing which would also get larger the more times an interval is hit?
public float interval = 1; // 1 second between intervals starting off
public float speed = 2; // the starting speedi
void Start () {
// move left
GetComponent<Rigidbody2D>().velocity = Vector2.left * speed;
}
void Update () {
// check if interval has been reached? How?
//if interval has been reached then ( This does not work for me..
GetComponent<Rigidbody2D>().velocity = GetComponent<Rigidbody2D>().velocity * 0.01f;
interval = interval * 2;
}
I think there's a few things you need to fix here:
1.) you are multiplying velocity by .01 every frame, this will practically freeze it completely. I'm not sure what you mean to do by that.
2.) You are calling GetComponent>Rigidbody2D<() every frame, which is very expensive! You should create a variable for it something like:
Rigidbody2d RB;
void Start () {
RB = GetComponent<Rigidbody2D>();
}
For how to increase speed after each interval, I might declare a counter which you increase every frame. And if the counter > interval then interval *= 2 and counter = 0
Well, first of all take Rigidbody2D in a variable once then play with it.
You can use Coroutine for this purpose.
public float interval = 1; // 1 second between intervals starting off
public float speed = 2; // the starting speed
Rigidbody2D _rb;
void Start () {
// move left
_rb = GetComponent<Rigidbody2D>();
_rb.velocity = Vector2.left * speed;
StartCoroutine("IncreaseSpeedWithInterval");
}
void Update () {
}
IEnumerator IncreaseSpeedWithInterval()
{
while(true){
yield return new WaitForSeconds(interval);
// Now either Multiply your velocity by 1.01f or Add by 0.01f
_rb.velocity *= 1.01f;
// ========== OR ========== //
_rb.velocity += (Vector2.one * 0.01f);
}
}

Categories