0
\$\begingroup\$

I have a score counter, but I've noticed that the lower the framerate is, the slower it counts. How can I make it so it ignores the framerate?

using System.Collections;
using UnityEngine;
using UnityEngine.UI;

public class Score : MonoBehaviour {
    private Text scoreText;
    private static int score;
    private static int finalScore;
    private static bool count;
    public static int scoreMultiplier;

    private void Start() {
        scoreText = GetComponent<Text>();
        count = false;
        scoreMultiplier = 1;
    }

    public static void StartCounting() {
        count = true;
    }

    public static void StopCounting() {
        count = false;
    }

    public static void Reset() {
        count = false;
        score = 0;
    }

    public static IEnumerator MultiplyBy(int scoreMultiplier) {
        Score.scoreMultiplier = scoreMultiplier;
        yield return new WaitForSeconds(6f);
        Score.scoreMultiplier = 1;
    }

    private void Update() {
        if (count) {
            score += scoreMultiplier;
        }

        // Slice the score so the number doesn't get too big
        finalScore = score / 4;

        scoreText.text = finalScore.ToString("00000");
    }
}

Edit: Fixed by adding Time.deltaTime and putting it in FixedUpdate instead of Update

private void FixedUpdate() {
    if (count) {
        score += scorePerSecond * Time.deltaTime * scoreMultiplier;
    }

    finalScore = Convert.ToInt32(score);
    scoreText.text = finalScore.ToString("000000");
}
\$\endgroup\$
2
\$\begingroup\$

You have to use the frame time, and make your score based on time instead of on frames:

Here is the pseudo-code:

float scorePerSecond = 1000.0 // A parameter of some sort
float score = 0.0

update( )
  if ( count )
    score += scorePerSecond * deltaTime * scoreMultiplier;

In this example, deltaTime is assumed to be in seconds. In Unity, the deltaTime seems to be fetched by using Time.deltaTime. Also, note that the score is now a floating point value (because everything else is calculated in floating point values). You'll have to convert that to int before displaying to the user.

Everything in your game that happens over time should be done in that fashion.


Edit based on comments.

Alternatively, you can use Unity's FixedUpdate method to have the update done on a more precise basis. (In Unity, menu Edit > Project Settings > Time to set your fixed timestep; thanks @Chris.)

You then have 2 options.

You can either still use the delta time provided by Unity:

float scorePerSecond = 1000.0 // A parameter of some sort
float score = 0.0

fixedUpdate( )
  if ( count )
    score += scorePerSecond * deltaTime * scoreMultiplier;

This method will 'shield' you from when Unity is not able (for a reason or for another) give you the rate you request, but the extra multiplication (when compared to the next method) can introduce a small fixed point manipulation error.

Or you can use a pre-computed 'by frame' value, based on the framerate that you set Unity's value.

int scoreMultiplier; // A parameter of some sort, assume that the frame rate is fixed at 30 hz
int score = 0

fixedUpdate( )
  if ( count )
    score += scoreMultiplier;

No floating point error is introduced here, and you can use integers.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ Because of the finite precision of floating point values this code makes the player's score dependent of framerate. This way two players playing the game for exactly the same amount of time may have different score (assuming they don't gain it any other way). I personally find it unacceptable. \$\endgroup\$ – pampeho Mar 18 '16 at 19:26
  • \$\begingroup\$ @pampeho So how should I do it with just integers? \$\endgroup\$ – Milen Pivchev Mar 19 '16 at 1:25
  • \$\begingroup\$ @Milen the idea is not fixing it by using integers instead; if you use a variable timestep, the issue @pampeho raises will be there as well. Fixed timestep's (FixedUpdate) contract is that it will run 30 times per second, not more, not less (as much as possible), while the variable timestep (Update) will run as often as possible, depending on the device performance and what you ask your game to do. The variable number of calls in Update may introduce discrepancy in the score when running on different devices, while you will achieve a more constant score by using FixedUpdate. \$\endgroup\$ – Vaillancourt Mar 20 '16 at 21:36
  • \$\begingroup\$ @Milen The concern of pampeho is that this discrepancy caused by the differences in device performances and in-game situations (e.g. some parts of your game may take longer to render, resulting in a temporary lower frame rate) will make some users have a lower score than they should have when comparing to their friends on a different device. At this point, this is a game-design situation: is this point crucial for your situation? Is the difference noticeable? Could it affect your player base? Are the scores shared among your players? You have the information, you decide what to do next :) \$\endgroup\$ – Vaillancourt Mar 20 '16 at 21:42
  • \$\begingroup\$ @AlexandreVaillancourt So if I put it in FixedUpdate instead of Update it will be more accurate? \$\endgroup\$ – Milen Pivchev Mar 20 '16 at 21:51
0
\$\begingroup\$

MonoBehaviour has a method called FixedUpdate, I suggest you to use it instead of Update. Multiplying by frames' delta time gives results that are dependent of the framerate, which is unstable and thus unreliable.

| improve this answer | |
\$\endgroup\$
  • \$\begingroup\$ How reliable is FixedUpdate? If for some reason the game process takes more time (perhaps due to other processes running on the client's machine), my understanding is that even with fixed updates one should still rely on deltatimes to update anything. \$\endgroup\$ – Felsir Mar 18 '16 at 13:21
  • 1
    \$\begingroup\$ Perhaps using fixedUpdate for things that matter is important (like physics), but IMHO, you don't need fixed update to calculate a score. (I'm not implying to not use fixed update; I haven't tested the behaviour difference between both methods so I can't commit on that.) \$\endgroup\$ – Vaillancourt Mar 18 '16 at 13:23
  • \$\begingroup\$ @Felsir I have not written that delta time itself is bad, because you need it to calculate the fixed timestep anyway – however, multiplying values (yes, especially in physics) with delta time makes whole simulation dependent of the framerate – which is glitch-prone and exploitable (for example one may arbitrarily lower their framerate because it would decrease the chance of two actors colliding). \$\endgroup\$ – pampeho Mar 18 '16 at 19:12

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.