Synchronize "Score" with a timer? (Unity) - c#

I have a "Player score: 100 pts" text with a timer that counts from 50 seconds to 0. I want to make it so every 5 seconds that goes by, 10 points are removed from the "Player score". So every 5 seconds it would be 10, 90, 80, etc.. how can I achieve that? I'm using Unity and coding in C#
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class ScoreCountdownn : MonoBehaviour
{
float scoreReductionTime = 5.0f;
int scoreReductionAmount = 10;
int maxScore = 100;
int scoreReduction = 5;
float timeUntilScoreReduction;
int currentScore;
void Start()
{
// Set the time until the next score reduction
timeUntilScoreReduction = scoreReductionTime;
// Set the current score to the max score
currentScore = maxScore;
}
// Can be Update or FixedUpdate depending on your goal
void Update()
{
// Reduce the time until score reduction
// by the time interval that has just passed
timeUntilScoreReduction -= Time.deltaTime;
// If the timeUntilScoreReduction reaches 0 or below,
// the score is reduced and the timeUntilScoreReduction
// is reset to the next time at which score reduction occurs
if (timeUntilScoreReduction <= 0.0f)
{
currentScore -= scoreReduction;
timeUntilScoreReduction = scoreReductionTime;
ScoreCountdown.text = currentScore;
}
Debug.Log(timeUntilScoreReduction);
Debug.Log(currentScore);
}
}

In your Update or FixedUpdate function, you can access Time.deltaTime.
It is the difference in time in seconds since the last call of the Update or FixedUpdate function. Hence, you can keep track of how much time has passed, by adding up these time intervals between every repetition.
Since you didn't include any code, I'll try to help you with some general code that you can look at for reference.
EDIT: The code was altered when the original question was edited to provide more information.
using UnityEngine;
using UnityEngine.UI;
public class ExampleClass : MonoBehaviour
{
float scoreReductionTime = 5.0f;
int scoreReductionAmount = 10;
int maxScore = 100;
int scoreReduction = 5;
float timeUntilScoreReduction;
int currentScore;
// You can drag your UI gameobject from the hierarchy
// to this field in the editor to link them.
// That way Unity knows what the gameobject is without
// you having to specify it here in the code
public GameObject ScoreCountdown;
void Start()
{
// Set the time until the next score reduction
timeUntilScoreReduction = scoreReductionTime;
// Set the current score to the max score
currentScore = maxScore;
// The gameobject has components, one of which is the text component.
// You have to access this component and set its text value
// to the desired string. Since the currentScore is an integer,
// and text is a string, you have to make a string of the integer.
ScoreCountdown.GetComponent<Text>().text = currentScore.ToString();
}
// Can be Update or FixedUpdate depending on your goal
void Update()
{
// Reduce the time until score reduction
// by the time interval that has just passed
timeUntilScoreReduction -= Time.deltaTime;
// If the timeUntilScoreReduction reaches 0 or below,
// the score is reduced and the timeUntilScoreReduction
// is reset to the next time at which score reduction occurs
if (timeUntilScoreReduction <= 0.0f)
{
currentScore -= scoreReduction;
timeUntilScoreReduction = scoreReductionTime;
ScoreCountdown.GetComponent<Text>().text = currentScore.ToString();
}
}
}
Note that in your question, you said that the score should decrease by 10 every 5 seconds, but then you gave the example of the score decreasing as 95, 90, 85, ... I chose to consider the first statement within the code, with a score reduction of 10 instead of the 5 in the second statement.

Related

c# Spawn Interval Changer

I add my codes below. What is my fault, can anyone help me?
I want to when SpawnRandomBall function run two times, spawnInternal turn into spawnInternal2. So I create a new variable, called 'check'. The variable increase when SpawnRandomBall function run. I set the variable as a public. In this way I can see that 'check' variable increase or doesn't increase. 'Check' variable is increasing without problem. When the veriable value equal to 3, it must be 'else if' run. But unfortunately it doesn't work.
I guess problem is I run my codes in Start() function. But I don't know how can I do properly.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class SpawnManagerX : MonoBehaviour
{
public GameObject[] ballPrefabs;
private float spawnLimitXLeft = 14.5f;
private float spawnLimitXRight = 24;
private float spawnPosY = 10;
private float startDelay = 1.0f;
private float spawnInterval = 4.0f;
private float spawnInterval2 = 2.0f;
public int check;
// Start is called before the first frame update
void Start()
{
if (check <= 2)
{
InvokeRepeating("SpawnRandomBall", startDelay, spawnInterval);
}
else if (check > 2)
{
InvokeRepeating("SpawnRandomBall", startDelay, spawnInterval2);
}
}
// Spawn random ball at random x position at top of play area
void SpawnRandomBall ()
{
// Generate random ball index and random spawn position
Vector3 spawnPos = new Vector3(-21, spawnPosY, Random.Range(spawnLimitXLeft, spawnLimitXRight));
int ballIndex = Random.Range(0, 3);
// instantiate ball at random spawn location
Instantiate(ballPrefabs[ballIndex], spawnPos, ballPrefabs[ballIndex].transform.rotation);
check += 1;
}
}
I want to change SpawnInternal variable into SpawnInternal2
The situation you describe is that you want a method to run. And for the first two iterations, you’d like one particular delay interval, and then after that you’d like a different delay interval. With that being the case, I would suggest you’re using the wrong tools. I would personally start a Coroutine like this:
public class SpawnManagerX : MonoBehaviour
{
public GameObject[] ballPrefabs;
private float spawnLimitXLeft = 14.5f;
private float spawnLimitXRight = 24;
private float spawnPosY = 10;
private float startDelay = 1.0f;
private float spawnInterval = 4.0f;
private float spawnInterval2 = 2.0f;
public int check;
void Start()
{
StartCoroutine ( SpawnRandomBall () );
}
// Spawn random ball at random x position at top of play area
IEnumerator SpawnRandomBall ()
{
while ( true )
{
// yielding here will produce an initial delay when the coroutine is run.
yield return new WaitForSeconds (
(check++ < 2) ? spawnInterval : spawnInterval2 );
// Generate random ball index and random spawn position
var spawnPos = new Vector3(-21, spawnPosY, Random.Range(spawnLimitXLeft, spawnLimitXRight));
var ballIndex = Random.Range(0, 3);
// instantiate ball at random spawn location
Instantiate( ballPrefabs[ballIndex], spawnPos, ballPrefabs[ballIndex].transform.rotation );
}
}
}
It’s also possible to run the Start method as a coroutine as well, but I feel, especially for newcomers, that the intent can sometimes be lost.
What this is saying is, start a coroutine, and in that coroutine, keep looping while (true) (which means “forever”). The line that change the amount of time that it waits is the last line, the “return”. We WaitForSeconds and the number of seconds we wait is based on the current count value. NB: written on phone but not tested.
Edited to create an initial delay in the coroutine.
If Start gets called once then the else if is never run. The code doesn't just wait at the else if waiting for check to update.
You just need to manage what code gets run in the SpawnRandomBall method.
You're going to need to try something like this this:
// Start is called before the first frame update
void Start()
{
InvokeRepeating("SpawnRandomBall", startDelay, spawnInterval2);
}
// Spawn random ball at random x position at top of play area
void SpawnRandomBall()
{
check++;
if (check == 1 || check == 3)
return;
// Generate random ball index and random spawn position
Vector3 spawnPos = new Vector3(-21, spawnPosY, Random.Range(spawnLimitXLeft, spawnLimitXRight));
int ballIndex = Random.Range(0, 3);
// instantiate ball at random spawn location
Instantiate(ballPrefabs[ballIndex], spawnPos, ballPrefabs[ballIndex].transform.rotation);
}

Wrong number converting int to string c#

I have simple coin counter, in 2d Unity game. But It's count one coin as 2. I think that it's because of wrong converting int to string.
public GameObject coin; // Gameobject with coin
public Text CoinCounter; // Text with counter that shows in game
private float TotalCounter = 0; // Float for counting total amount of picked up coins
{
TotalCounter = Convert.ToInt32((CoinCounter.text)); // Converting text counter to Numbers
}
private void Update()
{
TotalCounter = Convert.ToInt32((CoinCounter.text)); // Updating Counter evry frame update
Debug.Log(TotalCounter); // Showing Counter in Console
}
private void OnTriggerEnter2D(Collider2D collision)
{
TotalCounter = (TotalCounter + 1); // adding 1 to total amount when player touching coin
CoinCounter.text = TotalCounter.ToString(); // Converting to Text, and showing up in UI
coin.SetActive(false); // Hiding coin
}
So, in Debug Log it's showing right Total amount, but in UI, It's Showing wrong number. As example, When Total Amount is 1 it's showing 2 etc.
It's better to write your convertor code into the trigger void , after that check it ; this might be happened because of update function, try like that and check again: `
public GameObject coin;
public Text CoinCounter;
private float TotalCounter = 0;
private void Update()
{}
private void OnTriggerEnter2D(Collider2D collision)
{
TotalCounter = (TotalCounter + 1);
Debug.Log(TotalCounter);
CoinCounter.text = TotalCounter.ToString();
Debug.Log(CoinCounter.text);
coin.SetActive(false);
}
`
You don't have to do it in Update but only when you actually change it.
The method you are looking for is probably int.TryParse
you should use int for amounts (unless will you have values like 1.5 coins later)
Than you execute your code everytime it collides ... with anything. You should only collide with a coin instead. Either use tags or compare with the referenced value in your case
public GameObject Coin; // Gameobject with coin
public Text CoinCounter; // Text with counter that shows in game
private int _totalCounter = 0; // Int for counting total amount of picked up coins
// I guess it's supposed to be Start here
void Start()
{
// Converting text counter to Numbers
int.TryParse(CoinCounter.text, out _totalCounter);
}
private void OnTriggerEnter2D(Collider2D collision)
{
if(collision.gameObject != Coin) return;
// later this should probably rather be
//if(collision.gameObject.tag != "Coin") return
_totalCounter += 1; // adding 1 to total amount when player touching coin
CoinCounter.text = _totalCounter.ToString(); // Converting to Text, and showing up in UI
Coin.SetActive(false); // Hiding coin
// later this should probably rather be
//collision.gameObject.SetActive(false);
}
Problem was not in converting, trigger worked twice. Need check if the coin is enabled before disabling it and adding to the coin counter. Eg:
if (coin.activeSelf)
{
coin.SetActive(false);
Debug.Log("Object is not active ");
TotalCounter += 1;
Debug.Log("Total Counter + :" + TotalCounter);
CoinCounter.text = TotalCounter.ToString();
Debug.Log("Text after +:" + CoinCounter.text);
}

Decrease variable over a specific amount of time

So when my character gets hit by the enemies fire breath, I want to create the feel of the character being set on fire. So while the character is on fire I want him to lose a specific amount of health for a specific amount of time.
For example; lets say he is on fire for 3 seconds and I want to make him lose 30 health for being on fire, how would I evenly distribute losing 30 health for 3 seconds? I dont want the 30 damage to be applied instantly to the health, I want it to slowly tick away at the players health so that at the 3 second mark 30 damage has been dealt.
The game is being made with c#.
Thanks.
This is just like moving Gameobject over time or doing something over time. The only difference is that you have to use Mathf.Lerp instead of Vector3.Lerp. You also need to calculate the end value by subtracting the value you want to lose over time from the current value of the player's life. You pass this into the b or second parameter of the Mathf.Lerp function.
bool isRunning = false;
IEnumerator loseLifeOvertime(float currentLife, float lifeToLose, float duration)
{
//Make sure there is only one instance of this function running
if (isRunning)
{
yield break; ///exit if this is still running
}
isRunning = true;
float counter = 0;
//Get the current life of the player
float startLife = currentLife;
//Calculate how much to lose
float endLife = currentLife - lifeToLose;
//Stores the new player life
float newPlayerLife = currentLife;
while (counter < duration)
{
counter += Time.deltaTime;
newPlayerLife = Mathf.Lerp(startLife, endLife, counter / duration);
Debug.Log("Current Life: " + newPlayerLife);
yield return null;
}
//The latest life is stored in newPlayerLife variable
//yourLife = newPlayerLife; //????
isRunning = false;
}
Usage:
Let's say that player's life is 50 and we want to remove 2 from it within 3 seconds. The new player's life should be 48 after 3 seconds.
StartCoroutine(loseLifeOvertime(50, 2, 3));
Note that the player's life is stored in the newPlayerLife variable. At the end of the coroutine function, you will have to manually assign your player's life with the value from the newPlayerLife variable.
I suppose, what you are looking for is a Coroutine. Check out here and here for the documentation. It will allow you to do your custom health reducing actions separately from update function. Using coroutines you can make something happening by ticks, and you can determine how much time the tick is.
You could use couroutines. Something like this:
void OnHitByFire()
{
StartCoroutine(DoFireDamage(5f, 4, 10f));
}
IEnumerator DoFireDamage(float damageDuration, int damageCount, float damageAmount)
{
int currentCount = 0;
while (currentCount < damageCount)
{
HP -= damageAmount;
yield return new WaitForSeconds(damageDuration);
currentCount++;
}
}
So this is what I ended up doing. It causes the character on fire to lose 30 health and you can see the health ticking down instead of it happening over intervals.
IEnumerator OnFire()
{
bool burning = true;
float timer = 0;
while (burning)
{
yield return new WaitForSeconds(0.1f);
hp -= 1;
timer += 0.1f;
if (timer >= 3)
{
burning = false;
}
}
}

When scaling back to "original" scale after shrinking, it defaults to 1,1,1, which isn't what I want

The game object I'm scaling is simple. It shows the thrust for the ship being used (this last for 2 seconds as the bar decreases). Then for 3 seconds, the object scales back up to almost exactly where it was, but it needs to be exact or over time the object will not look correct after several uses (the scaling would get exponentially worse, and we know this is no good). I've researched this for the past hour or 2 with no avail in anything I try. This is the closest thing I've been able to mash up.
Overall problem: It needs to be EXACTLY 5 every time it scales back. I realize if I take off the last else if statement it works (poorly), but no matter what number I put in for the X it doesn't always scale to the exact same number, which is a problem, and why I need to return it's original scale.
tl;dr My object's X value scales from 5 to near 0, when trying to return it to its original scale (of 5) it scales up to near 5 then goes to 1,1,1.
using UnityEngine;
using System.Collections;
public class ShipPlayerController : MonoBehaviour {
[Header ("Camera(s)")]
public Camera CameraObject;
[Header ("Float(s)")]
public float fireRate = 0.3f;
public float fireTimer = 0.0f;
public float moveSpeedX = 12.0f;
public float moveSpeedY = 8.0f;
//counts from 0 to 5, so I can use the thrust again (starts at 5 so they can use it initially, this resets to 0 every time they press T and its been over 5 seconds)
public float thrusterTimer = 5.0f;
//the rate at which I can thrust, the lower the number the more often you can use it
public float thrusterRate = 5.0f;
//how long the player is actually thrusting
public float thrusterActive = 2.0f;
private Vector3 movement = Vector3.zero;
//supposed to be the original scale i've made for the game object???
private Vector3 originalScale; //(also have tried adding = Vector3.zero;)
[Header ("Script(s)")]
public Projectile bullet;
public HUD hudScript;
// Update is called once per frame
void Update () {
updatePosition ();
updateFiring ();
updateThrust ();
//calling the method when I push "t" for thrust
updateThrusterBar ();
}
//Skipping a bunch of unneeded code
........................................
//Gets called once I press "T"
public void updateThrusterBar () {
//Supposed to be the original scale???
originalScale = transform.lossyScale;
//When I press "T" the bar shrinks showing the player is using their thrust
if (thrusterActive > thrusterTimer) {
hudScript.thrustBar.transform.localScale += new Vector3 (-0.04187f, 0, 0);
//Fills the thrust back up so they can see when its full
} else if (thrusterTimer < thrusterRate) {
hudScript.thrustBar.transform.localScale += new Vector3 (0.029f, 0, 0);
//(Doesn't work): Logically, if the X scale isn't 5, then go back to your original scale i've made for you, which in the game is (5,0.3,1)
//What happens: defaults to (1,1,1) in the game, which is a square...
} else if (hudScript.thrustBar.transform.localScale.x != 5.0f) {
hudScript.thrustBar.transform.localScale = originalScale;
}
}
}

How to Get Constant Force To Increase Over Time? (Unity 5)

My game is an over-the-shoudler endless runner style game. I have the obstacles coming down the screen using constant force. My question is, how do I make this Constant Force Script make the obstacle go gradually faster as the game progresses and the player goes longer into the game? If you try out this script yourself (just attach it to a cube or a sphere), you'll notice how it starts off slow at first then literally 2 seconds later, it goes into Rocket Speed lol. ( I am working on an Object Pooler Script also, since I do not want to waste CPU with Instantiate and Destroy) Thank you to all who attempt and help me solve this! :)
Here is the Script I made:
using UnityEngine;
using System.Collections;
[RequireComponent(typeof(ConstantForce))]
public class AddConstantForce : MonoBehaviour
{
float speed = 1.0f;
Vector3 force;
void Awake()
{
//Another way to "Require" the component.
if(!GetComponent<ConstantForce>())
gameObject.AddComponent<ConstantForce>();
//
force = GetComponent<ConstantForce>().force;
GetComponent<Rigidbody>().useGravity = false;
}
void Update()
{
GetComponent<ConstantForce>().force = force;
force += -transform.forward * speed * Time.deltaTime;
/* Transform is negative because in my game, I have the
illusion of the objects coming down my mountain.
*/
}
}
Usually, to do stuff like this, you need 2 variables:
1. Time in which you want the speed to increase in. (For example, increase every 5 seconds) secondsToIncreaseIn.
2. Value to increase by.(For example, increment speed by 2 every time in #1 seconds) valueToIncreaseBy.
This way you have flexible ways to speed up or slow down how much your speed increments by changing either variable. With experiment setting secondsToIncreaseIn to 5 and valueToIncreaseBy to 0.0007f made the game last longer. You can increase valueToIncreaseBy to make it even last longer.You can change the startingSpeed variable if the starting speed is too slow or high.
private float speed = 0f;
private Vector3 force;
private ConstantForce cachedConstantForce;
private float counter = 0; //Dont change(Used for counting)
public float startingSpeed = 5f;//Start with 5 speed
public int secondsToIncreaseIn = 5; //Increase in every 5 seconds
public float valueToIncreaseBy = 0.0007f; //Increase by 0.0007 in secondsToIncreaseIn time/seconds
void Awake()
{
//Another way to "Require" the component.
cachedConstantForce = gameObject.GetComponent<ConstantForce>();
if (cachedConstantForce == null)
{
gameObject.AddComponent<ConstantForce>();
}
cachedConstantForce = GetComponent<ConstantForce>();
}
void Start()
{
force = cachedConstantForce.force;
GetComponent<Rigidbody>().useGravity = false;
speed = startingSpeed;
}
void Update()
{
cachedConstantForce.force = force;
force = -transform.forward * speed * Time.deltaTime;
/* Transform is negative because in my game, I have the
illusion of the objects coming down my mountain.
*/
if (counter < secondsToIncreaseIn)
{
counter += Time.deltaTime;
}
else
{
//Time has reached to Increase value
counter = 0; //Reset Timer
//Increase Spped
speed += valueToIncreaseBy;
Debug.Log("Increased Speed!");
}
}
Initially I was going to suggest use Time.time as factor (since Time.time is constantly increasing), but then, if you have to wait for some input for the run to start, Time.time could already be to big the the time that the run actually starts.
Instead I would suggest to keep a third variable that works as Time.time (keeps updating every frame by Time.deltaTime) and use that third variable to constantly keep increasing the applied force.
For example:
float speed = 1.0f;
Vector3 force;
float time = 0;
void Awake()
{
//Another way to "Require" the component.
if(!GetComponent<ConstantForce>())
gameObject.AddComponent<ConstantForce>();
//
force = GetComponent<ConstantForce>().force;
GetComponent<Rigidbody>().useGravity = false;
}
void Update()
{
GetComponent<ConstantForce>().force = force;
time += Time.deltaTime;
force += (-transform.forward * speed * Time.deltaTime) * time;
/* Transform is negative because in my game, I have the
illusion of the objects coming down my mountain.
*/
}
NOTE: You will probably have to apply a bigger value to speed since this operation will return quite a small value. Or you could add another variable that will increase the small value returned by the operation. Also consider that once you start testing the difficulty you might need to use a bigger or smaller value than Time.deltaTime to increase time, to either make the game harder or easier.

Categories