I'm not entirely sure how to phrase question so sorry if this is confusing. Anyways for context I'm making a sort of minesweeper type of game in unity and one of the things the original game had was a timer.
CodePudding user response:
Coroutines are perfect for this. Try this code here:
public Image image;
public Sprite[] sprites;
private bool isStop = true;
private void Start()
{
isStop = false;
StartCoroutine(Timer());
}
private IEnumerator Timer()
{
while (!isStop)
{
for (int i = 0; i < sprites.Length; i )
{
if (isStop) break;
image.sprite = sprites[i];
yield return new WaitForSeconds(1f);
}
}
}
CodePudding user response:
You can convert float
to int
int spriteIndex = (int)Math.Round(timer);
And used spriteIndex
as index to array sprites.
Or... if you need used different time interval for every sprite, you can make special struct for this animation.
For example:
[Serializable]
public struct SpriteFrame
{
public Sprite FrameSprite;
public float TimeToShow;
}
public class SpriteAnimationComponent : MonoBehaviour
{
public Image ScoreCount;
public List<SpriteFrame> Frames = new List<SpriteFrame>();
private int _currentFrame = 0;
private float _currentPlayAnimationTime = 0f;
private bool IsPlay => _currentFrame < Frames.Count;
public void Start()
{
UpdateFrame();
}
public void Update()
{
if(!IsPlay)
return;
_currentPlayAnimationTime = Time.deltaTime;
if(NeedShowNextFrame())
ShowNextFrame();
}
private bool NeedShowNextFrame()
=> Frames[_currentFrame].TimeToShow < _currentPlayAnimationTime;
private void ShowNextFrame()
{
_currentPlayAnimationTime -= Frames[_currentFrame].TimeToShow;
_currentFrame ;
if(IsPlay)
{
UpdateFrame();
}
}
private void UpdateFrame()
{
ScoreCount.sprite = Frames[_currentFrame].FrameSprite;
}
}
You need used SerializableAttribute ([Serializable]
) on SpriteFrame for show struct in Unity Inspector. In current code animation show once, but you can make it loop. For loop animation just add _currentFrame %= Frames.Count
after _currentFrame
CodePudding user response:
I'm assuming you have 10 sprites for you numbers 0-9.
numberSprite[0] would hold the sprite for "0", numberSprite[1] would hole "1", etc.
Let's say the timer is at 319.8f seconds on the back end. You would want 3 sprites to display: 3, 1, 9.
To do this, you'll need to break your timer value and sprite into the hundredths, tenths, and seconds individually. You could do this:
int timerInt = (int)Mathf.floor(timer); //Get the int value of the timer
int hundredth = (timerInt/100) % 10; // (319/100) => 3 ... (3 % 10) => 3
scoreCountHundredths.sprite = numberSprite[hundredth];
int tenth = (timerInt /10) % 10; //(319/10) => 31 ... (31 % 10) => 1
scoreCountTenths.sprite = numberSprite[tenth];
int second = timerInt % 10; // (319 % 10) => 9
scoreCountSeconds.sprite = numberSprite[second];
With the above code, your timer should correctly update to any number between 000-999 requiring only 10 sprites uploaded. Additionally, it will automatically loop if your timer goes above 999 due to the modulo (%) logic.
Warning. Coroutines or InvokeRepeating may be a trap here: Coroutines can be used to track the time between updating the sprites, but you'll likely be wanting to tie this display directly to the in-game time. relying on coroutines to update the sprite de-couples the in-game timer from the display, as they do not have built-in catchup behaviour. If your frames are slightly delayed or lag at all, you run the risk of the time running slower when using coroutines or InvokeRepeating.