Unity-Press Button to slowly increment number - unity3d

I'm trying to do something like the old GTA style money system like in Gta vice city or san andreas. So when you add or obtain money, the number doesn't just jump to the result. It slowly increments till the value added is done.
I want to do this by clicking buttons, so one button will add 100 dollars and other will subtract 100 dollars and so on.
The buttons don't seem to be playing nice with update and Time.deltatime.

To slowly increment a number over the time, you can do something like this:
public float money = 100;
public int moneyPerSecond = 25;
public int moneyToReach = 100;
bool addingMoney = false;
private void Update()
{
if (addingMoney)
{
if (money < moneyToReach)
{
money += moneyPerSecond * Time.deltaTime;
}
else { addingMoney = false; money = Mathf.RoundToInt(money); }
}
}
public void addMoney()
{
moneyToReach += 100;
addingMoney = true;
}

Related

How do I you images as a score into my game?

I have been trying to make a game that's a parody off of minesweeper in unity. I have gotten most of the stuff done including the timer. One problem I have been having is the score count. The score count consists of 3 images. What I am looking is a way so that I can change each image based on how many mines have been caught. Here's the code for it:
public int scorecount = 0;
int i = 0;
int a;
public int amountOfMines;
public Image faceImage;
public Sprite sprite;
private Timer timer;
public ItemDrag itemDrag;
public List<Image> scoreCountImages;
public Sprite[] digitSprites;
void Start()
{
timer = GetComponent<Timer>();
}
void Update()
{
if(scorecount >= i)
{
if(scorecount == amountOfMines) //If the score equals the amount of mines, stop timer, change face sprite.
{
Debug.Log("All the Mines have been cleared");
faceImage.sprite = sprite;
timer.isStop = true;
itemDrag.thereAreStillMines = false;
}
}
}
Your question has a simple solution. Easily use multiple if, In the following code, there is a Sprite coordinator with points that you can match the desired Sprites with the desired conditions.
public void SyncSprite()
{
if (score >= amountOfMines) faceImage.sprite = faceSprites[2]; // total mines
else if (score >= 7) faceImage.sprite = faceSprites[1]; // for e.g after 7 score change to second sprite
else if (score >= 0) faceImage.sprite = faceSprites[0]; // default sprite
}
For Example, at the bottom, then click on a box and there is no mine there. The score goes higher and the sync code is executed at the end of the score calculation and syncs the sprite with the score.
public void OnClickedBox()
{
// do something...
if (noMineWasHere) score++;
SyncSprite();
}
TLDR; Your mistake was rendering 3-digits as a whole thing; You should have 3-sprite renderer, each displaying a single digit.
Set in the inspector, an array of Sprites for the digits, ordered properly.You will use the array as a Dictionary to easily access any digit-sprite by a corresponding number:
[SerializeField, Tooltip("Your number 0-9 sprites should be here, ordered correctly.")]
private Sprite[] numberSprites;
// ......
numberSprites[4] // will output '4' sprite;
Next, rather than have 1 big whole renderer to represent all 3 digits, we can split it into 3 renderer, and expose it to the inspector as an array:
[SerializeField]
private SpriteRenderer[] scoreSpriteRenderers;
Each of this renderer should only render 1 single-digit, something like this:
Now we can easily set-up a loop, to loop through each number in the score, and change the sprite based on the number.
The full result:
[SerializeField, ToolTip("Your number 0-9 sprites should be here, ordered correctly.")]
private Sprite[] numberSprites;
[SerializeField]
private SpriteRenderer[] scoreSpriteRenderers;
private int scoreCount;
// Converts the '123' into a {1, 2, 3}
// See: https://stackoverflow.com/questions/829174/is-there-an-easy-way-to-turn-an-int-into-an-array-of-ints-of-each-digit
public int[] NumbersIn(int value) {
var numbers = new Stack<int>();
for(; value > 0; value /= 10)
numbers.Push(value % 10);
return numbers.ToArray();
}
// Call this whenever score is updated
private void UpdateScoreUI() {
int[] arrScore = NumbersIn(scoreCount);
for (int i = 2; i > 0; --i) {
// If the number was say, 11, the list will only be { 1, 1 }
// So we will need to handle the last digit that is out-of-index.
if (arrScore.Length - 1 <= i){
int currNumber = arrScore[i];
scoreSpriteRenderers[i].sprite = scoreSpriteRenderers[currNumber];
} else {
scoreSpriteRenderers[i].sprite = scoreSpriteRenderers[0];
}
}
}
Edit
Yes, this method works with Image objects as well, since they have a sprite property, and we are only interacting with that property.

Unity - Decreasing float var with "Time.deltaTime" never going down

I'm try to create a function to stop player control, but when I pass the duration as a parameter in the function, the variable keeps ina huge number never really decreasing.
public void StopAllPlayerControl(float duration) {
stopPlayerDuration = duration;
stopPlayerDuration -= Time.deltaTime;
//stop here what you need.
playerInput.enableMovement = false;
if (stopPlayerDuration <= 0) {
//restore here to normal state
playerInput.enableMovement = true;
}
}
And Im calling this funct in a Update method like this
StopAllPlayerControl(3);
Image here to show that stopPlayerDuration getsm huge but stays in those big numbers never really decreasing. huge number
I used a combination of both answers, organized my logic better and, in this case, I used a coroutine.
This function starts the coroutine and I can call it and control it with a bool
public void startStopPlayerCo(float dur) {
//function to start stop player courutine from anywhere.
StartCoroutine(StopPlayerCo(dur));
}
This is the coroutine that works well now
public IEnumerator StopPlayerCo(float dur) {
while (startCO) {
GetComponent<PlayerMove>().enabled = false;
yield return new WaitForSeconds(dur);
//reset
GetComponent<PlayerMove>().enabled = true;
startCO = false;
}
}
And I call it in Update Method like this:
startStopPlayerCo(2) //2 seconds, or any var for desired time
Try this:
float startTime = 0;
float duration = 0;
public void StopAllPlayerControl(float duration)
{
this.duration = duration;
if(playerInput.enableMovement)
{
startTime = Time.time;
playerInput.enableMovement = false;
}
if(Time.time - startTime >= this.duration)
{
playerInput.enableMovement = true;
}
}
Explaination
Step 1
Firstly, we need to check if movement is already enabled. If it is, we mark the point that we started the timer, and disable movement. We also store our duration in a variable, and reference it locally with the `this` keyword.
if(playerInput.enableMovement)
{
startTime = Time.time;
playerInput.enableMovement = false;
}
Step 2
If the timer exceeds the duration then movement is enabled.
if(Time.time - startTime < duration)
{
playerInput.enableMovement = true;
}
It is also good practice to enclose this method in a boolean lock to prevent it from being called again while the timer is running, unless you want such a feature to be allowed.

Counting number of clicks

I want to use Unity to calculate the number of clicks on the page as well as the number of clicks on a coin that appears every few seconds. Can you tell me how I can get the number of clicks on the page?
each time I want the number of clicks on the coins and the page to be calculated separately.
Its not clear what you have in mind about coin. Its a UI element or a GameObejct.
I suppose its an object with RigidBody and Collider:
public class HitDetector : MonoBehaviour
{
public static int allCounter = 0;
public static int hitCounter = 0;
private void Update()
{
if (Input.GetMouseButtonDown(0))
{
allCounter++;
if (IsHit())
{
hitCounter++;
}
Debug.Log($"All: {allCounter} & hit: {hitCounter}");
}
}
private bool IsHit()
{
return Physics2D.Raycast(Camera.current.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
}
}

Unity2D Disable player movement for X seconds

I am trying to disable a player movement for 1 second when it collides with a specific object. The object collides and it detects that just fine however currently the entire game freezes and does not return.
Ive implemented a 0 value (as found in other examples) to the X and Y movements with a timer. This freezes the game entirely and I have to kill process and reopen Unity.
public Boolean frozen = false;
float shipDisabledTimer = 1f;
// Start is called before the first frame update
void Start()
{
SetUpMoveBoundaries();
gameSession = FindObjectOfType<GameSession>();
}
// Update is called once per frame
void Update()
{
Move(frozen);
Fire();
if (SceneManager.GetActiveScene() == SceneManager.GetSceneByName("Game"))
{
if (Input.GetKey(KeyCode.Escape))
SceneManager.LoadScene("Game Over");
}
}
public void Move(Boolean Frozen)
{
UnityEngine.Debug.Log("Update1 - " + Frozen);
var deltaX = Input.GetAxis("Horizontal") * Time.deltaTime * moveSpeed;
var deltaY = Input.GetAxis("Vertical") * Time.deltaTime * moveSpeed;
var newXPos = Mathf.Clamp(transform.position.x + deltaX, xMin, xMax);
var newYPos = Mathf.Clamp(transform.position.y + deltaY, yMin, yMax);
transform.position = new Vector2(newXPos, newYPos);
if (frozen == true)
{
float timer = 0f;
timer += Time.deltaTime;
UnityEngine.Debug.Log(frozen);
while (timer < shipDisabledTimer)
{
newXPos = 0;
newYPos = 0;
}
disableship(frozen = false);
}
}
public Boolean disableship(Boolean frozen)
{
return frozen;
}
private void OnTriggerEnter2D(Collider2D other)
{
UnityEngine.Debug.Log(other.gameObject.name);
if (other.gameObject.name.Equals("Orb Shot(Clone)"))
{
UnityEngine.Debug.Log("Orb hit player");
//StartCoroutine(countdownTimer());
disableship(frozen = true);
}
}
The ship alone should freeze. No other game object should freeze. All scores, counters, enemies should continue onward. Only the player X,Y are disabled for 1 second.
This
while (timer < shipDisabledTimer)
{
newXPos = 0;
newYPos = 0;
}
entirely blocks your game's main thread since the timer nor shipDisabledTime are not changed within the loop so it will never end.
There are a few ways you could go here.
Invoke
Invoke allows you to call a method after a certain delay so you could easily do something like
public void Freeze()
{
frozen = true;
Invoke("Unfreeze"; shipDisabledTime);
}
private void Unfreeze()
{
frozen = false;
}
Coroutine
A Coroutine is like a temporary Update method. Simplest way in your case is using WaitForSeconds and do something like
public void Freeze()
{
StartCoroutine (FreezeRoutine());
}
private IEnumerator FreezeRoutine()
{
frozen = true;
yield return new WaitForSeconds(shipDisabledTime);
frozen = false;
}
simple timer
Or you could use a simple timer but in Update (not a while loop) like
private float timer = -1;
public void Freeze()
{
frozen = true;
timer = shipDisabledTime;
}
private void Update()
{
if(timer > 0)
{
timer -= Time.deltaTime;
if(timer <= 0)
{
timer = -1;
frozen = false;
}
}
...
}
And then either way you simply don't take any movement input in the meantime
public void Move()
{
if(frozen) return;
...
}
Except for the Invoke solution you can also extend them and decided whether you want to e.g. stack multiple freezes, ignore them while already frozen or simply start the timers over.
General note: In c# rather simply use bool it's basically the same but easier to read and write ;)
Also note that this call
disableship(frozen = false);
...
public Boolean disableship(Boolean frozen)
{
return frozen;
}
Is pretty strange ... first of all this method does absolutely nothing than just return the same value you pass in as parameter .. you are hiding the frozen field with a same named parameter so this does nothing!
Second your method returns a Boolean but you are not assigning it to anything.
If you want to change the value simply set it using frozen = XY but don't pass this in as parameter further.
Aaand avoid calling Debug.Log every frame .. it will slow down your app even in a build where you don't even see the log!

Time Based Scoring Unity

Hi I'm a beginner in unity and I want to be able to add 10 points to the score every 5 seconds since the game started, this is how i tried to implement it
private int score;
void Update () {
Timer = Time.time;
if (Timer > 5f) {
score += 5;
Timer -= 5f;
}
ScoreText.text = score.ToString ();
}
this is not working what happens is the score increases rapidly after 5f and then it crashes my game.
The math for calculating every 5 seconds is wrong. You should not be doing Timer = Time.time; every loop, that just throws away the old value of Timer. Use Time.deltaTime and add it to the timer instead.
//Be sure to assign this a value in the designer.
public Text ScoreText;
private int timer;
private int score;
void Update () {
timer += Time.deltaTime;
if (timer > 5f) {
score += 5;
//We only need to update the text if the score changed.
ScoreText.text = score.ToString();
//Reset the timer to 0.
timer = 0;
}
}
I know I am a bit late to answer, but the same can be done with Mathf.FloorToInt(Time.timeSinceLevelLoad)