How to Call Function Each Time Score Increases by same Amount ?

Hi,

I have some functions to call once each time score increases by same amount.

For example;
I spawn objects when score reaches 24. What i want to do is, spawn objects once when score reaches 24, 48, 72,… so on.

Can anyone help me? Thanks…

First, you’ll also need some way of representing the triggers so that this routine knows when they are supposed to trigger. Let’s suppose you’ve got a data structure something like this:

public struct ScoreTrigger
{
    public int pointsToTrigger;
    public Action functionToInvoke;
}

Then, you’ll need a routine that looks at the score and decides which triggers need to fire based on how the score has changed. That might look something like this:

IEnumerable<ScoreTrigger> allTriggers;
int highestScoreSoFar;

void CheckScoreTriggers()
{
    int currentScore = GetCurrentScore();
    foreach (ScoreTrigger trigger in allTriggers)
    {
        // Notice that these are integer divisions, and therefore
        // will implicitly "round down"
        int previousInvocations = highestScoreSoFar / trigger.pointsToTrigger;
        int desiredInvocations = currentScore / trigger.pointsToTrigger;

        // Using a loop so that we can "catch up" to missed invocations
        // if score suddenly jumps upwards by a large amount
        for (int i = previousInvocations; i < desiredInvocations; ++i)
        {
            trigger.functionToInvoke();
        }
    }

    // Remember what triggers have already been set off
    // based on how high a score we've ever processed
    highestScoreSoFar = Mathf.Max(currentScore, highestScoreSoFar);
}

Finally, you’ll need a way to run that function whenever score increases.

Your simplest option is just to call it from an Update() function somewhere; that means it will run every frame, which is probably overkill, but this function should be cheap enough that it doesn’t especially matter. You could even add a condition near the top that returns early if (currentScore <= highestScoreSoFar) as an optimization.

The “cleaner” but slightly-more-complex option is to run it only when the score increases, which basically means that every function in your game that increases score would have to directly or indirectly call this. Probably you’d make the actual score variable private so that it can’t be modified from random places, and force everyone who wants to change it to go through a wrapper function (perhaps a property) that automatically does house-keeping tasks like running this function as part of updating the score.

2 Likes

@Antistone you are making this way more complicated than needed man, @CoolCosmos just check your score variable against 24 and if the result is 0, you have your condition, simple as that…
This will work for every number dividable by 24 (24, 48, 72,…).

if (score%24 == 0)
{
    // call your functions
}
1 Like

What you wrote is in no way scalable. What @Antistone wrote is scalable, and definately the prefered solution if choosing between the two (but it also is way too verbose considering what it effectively does is execute an event upon a value being reached). Otherwise this is only really a solution if they want to check a single number, but what about if they want multiple? What about 100, would you write an if case for every single one by hand?

Anyway personally I would just do this:

UnityEvent spawnEvent;
void ScoreBasedSpawn(int score, int  target)
{
   if(score == target)
    {
       // do some stuff
      spawnEvent.Invoke();
    }
}

In order to be reusable but minimise amount of code. Good luck.

1 Like

@MadeFromPolygons_1 what?
The only thing CoolChaser12 want’s to do is call some function(s) whenever score has reached 24 or a multitude of 24, which is exactly what my suggested code does. if you want a different number than 24 then just change the number 24 by a different number or by a variable and your done.

1 Like

I agree with Team2Studio, the mod method solves the OP issue. He’s not checking a single number, but MANY all at once.

1 Like

@Team2Studio 's method will work if you can guarantee that the code runs exactly once for each unique score value as your score changes. (He didn’t discuss at all where to put this code or when it’s supposed to run.)

You can’t just run it from Update, because if score stays equal to 24 for more than one frame then it will call your function multiple times.

If your score ever somehow jumps directly from 23 to 25, then the function won’t be called at all.

And if your score somehow goes down from 25 back to 24, then the function will be called again, even if it already ran the first time your score was equal to 24.

His example code also hard-codes “24” and the function being called as “magic values” rather than parameters. If you just have a single thing that you want to happen at each multiple of 24, that is perhaps reasonable. If you have a bunch of different functions that you want to call at a bunch of different score thresholds, he’ll have to use a lot of copypasta, whereas my solution handles all of them in a single loop. (I assume this is what GameDevCouple_I is referring to when he talks about scalability.)

2 Likes

@Antistone I think we may assume (without making an ass out of u and me) that the OP already has implemented a method that takes care of increasing the score, and also that the score most likely reaches 24 or a multitude of 24 as that is what the OP exactly describes in the question.

I do not think that the conditions you describe, like score decreasing, or score increasing by more than 1, are likely to happen in the OP’s situation and therefor posted the most simplest code as I do think keeping it simple is always a good design choice, if not only for the developers sanity when trying to.debug code.
If need be, when things get more complicated, it’s always possible to add code to solve a problem, but that was not what the OP was asking.

If you like an example implementation here’s the code for you:

using UnityEngine;

public class MyScript : MonoBehaviour
{
    int score;
    int numberToCheck;

    /// <summary>
    /// Call this method when you have killed an enemy, jumped a platform or discovered that the cake was a lie
    /// </summary>
    public void AddScore()
    {
        score += 1;
        if (score % numberToCheck == 0)
        {
            // Do stuff
        }
    }
}

Edit: In case you are not familiar with it, the remainder operator % computes the remainder after dividing its left-hand operand by its right-hand operand. Found on Microsoft docs link.

1 Like

Thank you all for you help :slight_smile: I got it solved this way. I share it so that it may help someone else as well.

(Note: oneTime bool is used to run MyScore once in update.)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class CountStar : MonoBehaviour
{
    private bool oneTime;
    private int countStar;
    private int myLimit;
    void Awake()
    {
        oneTime = false;
        myLimit = 24;
        countStar = 0;
    }
    void Update()
    {
        MyScore();
    }
    public void MyScore()
    {
        if (!oneTime && countStar >= myLimit)
        {
            myLimit += 24;
            oneTime = true;
        }
        if (oneTime && countStar < myLimit)
        {
            oneTime = false;
        }
    }
    public void OnCollisionEnter(Collision collision)
    {
        if (collision.gameObject.tag == "Star")
        {
            countStar += 1;
            Destroy(collision.gameObject);
        }
    }
}

Where do you spawn an object then the score is 48?

Line 24 increments myLimit by 24 each time the limit is reached. (We don’t actually see the spawning code, but presumably setting oneTime = true is a flag that the spawning logic should run.)

I was asking the OP to avoid such assumptions.

I don’t follow. What’s being assumed?

Clearly you said so yourself with “presumably”. I asked for the code. The OP asked “What i want to do is, spawn objects once when score reaches 24, 48, 72,… so on”. The OP said he solved it, but is not showing the corresponding code, so I asked. You presumed.

Then I don’t understand the part of your question where you said “…when the score is 48”. We don’t see the actual spawn code for any score value, but 48 does the same thing as 24 or 72.

Exactly! I was looking for the spawn code when the score specifically becomes 48 which is one of the example values as mentioned in the original question. I was curious what technique that we suggested that they finally chose. And once again, you are assuming that 48 does the same thing as 24 or 72, how do you know? I find these threads quite comical where it leads to such back and forth and the OP is no where in sight :slight_smile:

The OP only mentions 48 as being a multiple of 24, to communicate the idea that he wants the same code to trigger on every multiple of the base number.

1 Like

The answer is 42

1 Like

Hi guys, i run spawn method in if statement so each time it reaches the limit then it will spawn.

  public void MyScore()
    {
        if (!oneTime && countStar >= myLimit)
        {
            myLimit += 24;
            oneTime = true;
            Spawn();
        }
        if (oneTime && countStar < myLimit)
        {
            oneTime = false;
        }
    }

If countStar somehow jumped from 23 to 48 in a single frame, that would spawn once, and then never spawn again for the rest of your game no matter how high countStar gets (because the second condition–where oneTime is set to false–would never trigger.)

What is the intended purpose of the variable “oneTime”? Since you are already increasing myLimit each time you spawn, you don’t need that to prevent multi-spawning at a single threshold.

1 Like