简体   繁体   中英

C# frames running twice?

This has me utterly confused. I am using unity3d and c# for the scripts and it seems as if the code is running twice per frame. However on button down I have a sprite change position and it only changes once at least I think it does.

I added the Debug in and I am getting results like this:

score 1 at 3.569991 at frame 168

score 2 at 3.57414 at frame 168

score 3 at 3.818392 at frame 183

score 4 at 3.820178 at frame 183

and so forth carrying on. I am not updating the score in any other scripts. There is more to this script but it is just printing the score out on screen.

Is there any reason why a script may run like this?

full script:

 using UnityEngine;
 using System.Collections;

public class Score : MonoBehaviour {

    public static int highScore;
    public static int myScore;
    public static bool allowScore;
    public GUIText myText;

    public static bool WhichScene;

     //only allows score to start when first object has passed player object
     void OnTriggerEnter2D(Collider2D collisionObject) {
         allowScore = true;
         Debug.Log ("allowScore is true");
     }

     void Start () {

         highScore = PlayerPrefs.GetInt("highScore");

         int scale = Screen.height / 20;
         myText.fontSize = scale;
     }

     //add 1 to score every switch
     void Update () {

         // need to stop score counting
         if (DeathOnImpact.dead == true) {
            allowScore = false;

         } if (Input.GetMouseButtonDown (0) && allowScore == true && WhichScene == true) { // added SpawnerObjectMovement.WhichScene == true
             //Input.GetMouseButtonDown (0)
             //Input.GetKeyDown("space")
             myScore = myScore + 1;
            Debug.Log ("My score is " + myScore + " point(s)" + " at time:" + Time.realtimeSinceStartup + " at frame:" + Time.frameCount);

        } if (myScore > highScore) {
            highScore = myScore;
            PlayerPrefs.SetInt("highScore", highScore);
         }

        myText.text = myScore.ToString ();
        //myText.text = "Score: " + myScore.ToString ();

        if (Score.WhichScene == false) {
            int scale = Screen.height / 40;
            myText.fontSize = scale;
            myText.text = "practice mode";
         }
     }
}

The script is attached to a TriggerObject, a sprite, and a Gui Text

WhichScene referes to which button I pressed, 'play' for normal play or 'practice mode' for an easier version. Score is disabled for 'practice mode'.

UPDATE: I have just edited out everything that I have added since the problem arose and it has not been fixed. Im going to check all unity setting to see if anything has changed. It seems in build setting an old Scene which I deleted around when the problem arose is not selcted but just 'shadowed' so I cant select it. The Scene was an exact copy of the PlayScene. Is this a sign of the problem?

SOLUTION: It appears that separating the script into two smaller scripts has solved the issue. I am still unsure why it has only arisen now since it was working before as one, but oh well I guess. Thank you.

Based on your comments, where you have said that your script is attached to 3 GameObjects, that means that the Update() method is getting called 3 times per frame.

public class Score : MonoBehaviour {
    public static int myScore;

You have declared myScore as a static int . This functionally means it will be shared by all instances of the Score script that run.

The Update() method of MonoBehaviour is called once per frame for every GameObject that has this script attached. You have 3 GameObjects with this script attached. Therefore, each will call Update() on their individual instance of the Score script.

I'm not sure what you exactly intend to happen, so it's hard for me to give any advice beyond pointing out the problem.


I think that you need to split this script into multiple scripts. This script is doing too much. It's violating the Single Responsibility Principal (SRP) . This is one of the most important principles to follow in programming. I'd suggest splitting this into at least 3 scripts. I'd probably make the following scripts:

  1. PlayerStatistics - Attach this script to your player object (I'm assuming that is the sprite you mentioned). It will simply hold the statistics, including score, for your player. There should only be one attached to each player.
  2. ScoreBoard - Attach this script to your GUI component. It will take a reference to the PlayerStatistics. Notice this is a reference to the single instance that is on your Player. Your ScoreBoard script will only read the value of the score from the PlayerStatistics script.
  3. ScoringTrigger - Attach this to your TriggerObject. It would also have a reference to the PlayerStatistics script. It would have the code that checks to see if scoring should be done, and updates the value of the PlayerStatistics script.

To avoid some events to run twice a frame use Events to get imput actions:

if(Event.current.type == EventType.MouseDown){
    if(Event.current.button == 0 && allowScore && WhichScene) {
        // do it once!
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM