Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Making A score counter go up after I click a game object 2D

Discussion in 'Scripting' started by HorizonHD, Mar 24, 2016.

  1. HorizonHD

    HorizonHD

    Joined:
    Jan 27, 2015
    Posts:
    11
    Im trying to make a text score go up after I click on a instantiated prefab thats moving on the screen, so far I have a canvas with Text, and a script for a meteor that crashes into a planet, anyways in the meteor script I have it set so if you click on it, the meteor gets destroyed, eventually ill have it so that if the meteor hits earth you lose. My main problem is that I cant figure out how to get the text to increase by 1 every time you destroy a meteor. Heres my script for the meteor.

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

    public class Meteor : MonoBehaviour {
    public GameObject Earth;
    public int intScore;

    // Use this for initialization
    void Start () {
    intScore = 0;
    }

    // Update is called once per frame
    void Update () {
    CheckInput();
    Attack();
    }
    void Attack()
    {
    transform.position = Vector2.MoveTowards(transform.position, Earth.transform.position, 0.3f * Time.deltaTime);
    }
    void CheckInput()
    {
    if(Input.GetKeyDown(KeyCode.Mouse0))
    {
    RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
    if (hit.collider != null)
    {
    if (hit.collider.gameObject == gameObject)
    {
    Destroy(gameObject);
    intScore = intScore + 1;

    }
    }
    }
    }
    }
     
  2. Meganaught

    Meganaught

    Joined:
    Mar 5, 2016
    Posts:
    23
    Do you have anything telling the text to display intScore? If not, you will have to make sure that you are using the text on the canvas and set it to print intScore. As far as I can tell, other than that, everything looks good. But, I am still pretty new to Unity so if you have already done all this, then I can't really help you much.
     
  3. HorizonHD

    HorizonHD

    Joined:
    Jan 27, 2015
    Posts:
    11
    That sounds like it would work but im unsure how I would go about it, Do I need to declare a new text variable in this script? cause that didnt work when I tried it.
     
  4. Meganaught

    Meganaught

    Joined:
    Mar 5, 2016
    Posts:
    23
    Make a public Text Variable then in the unity editor, drag the text from the canvas to fill the variable slot that was formed by the script. Then you should be able to change the string that the text prints in the game (In this case it will be intScore.
     
  5. Jason_ioosh

    Jason_ioosh

    Joined:
    Mar 21, 2016
    Posts:
    16
    Hi @HorizonHD,

    To illustrate what @Meganaught is saying, first declare a public text variable.

    Code (CSharp):
    1. public Text textObj;
    In the Inspector you should have something like this what I have inside 6.png, drag the Text object into it to make it like 5.png.

    Then add the following line of code into your script

    Code (CSharp):
    1. intScore = intScore + 1;
    2. textObj.text = intScore.ToString ("0");
    3. //The "0" inside ToString makes it so that the number has 0 decimal place.
    Hope this illustrates more clearly what you're supposed to do.

    Regards,
    Jason
     

    Attached Files:

    • 6.PNG
      6.PNG
      File size:
      7.8 KB
      Views:
      760
    • 5.PNG
      5.PNG
      File size:
      7.6 KB
      Views:
      1,170
  6. JoshuaMcKenzie

    JoshuaMcKenzie

    Joined:
    Jun 20, 2015
    Posts:
    897
    Looking at the code, the suggestions made don't make sense. You see, as soon as you click on the meteor you destroy it, but then you are also having that meteor also store the score. well since the meteor is destroyed that score will also be erased. The score shouldn't be in the Meteor class, it should be kept on a separate object.

    Furthermore changing the text of a text component every frame is a bad idea since it'll chew through the GC, which can cause consistent lag spikes depending on the platform. Use static events so that the meteor can notify the relevant classes that its state has changed. Events are great for this as the invoking script doesn't even need to know about the scripts that are listening to it. Meteor is decoupled from its listeners which is great for Meteor as now it doesn't need to make special code for each class that attaches to it.

    using the UnityEvent you can make a simple call
    Code (CSharp):
    1. OnMeteorInterception.Invoke();
    and every script that wants to know when a meteor was clicked on will be notified and then they can play their own scripts. Changing their data (like the text score) only once and on the exact frame if happened without wasting Garbage collection.

    I would also recommend using the EventSystem for catching click events on the meteors. With the current implementation every single meteor in existence is tasked to grabbing and checking the mouse position, even if its not over the meteor. Instead you have the event system catch a single click event,make a single raycast to the object the mouse is over, and run the special function on that gameObject. This is one calculation and one raycast compared to a raycast for each meteor in existence. though performance isn't the real selling point here, look at how much cleaner the code is.

    Code (CSharp):
    1. public void OnPointerDown(PointerEventData eventData)
    2.     {
    3.         OnMeteorInterception.Invoke();
    4.         Destroy(gameObject);
    5.     }
    looks so much more cleaner than...
    Code (CSharp):
    1. void CheckInput()
    2. {
    3.     if(Input.GetKeyDown(KeyCode.Mouse0))
    4.     {
    5.         RaycastHit2D hit = Physics2D.Raycast(Camera.main.ScreenToWorldPoint(Input.mousePosition), Vector2.zero);
    6.         if (hit.collider != null)
    7.         {
    8.             if (hit.collider.gameObject == gameObject)
    9.             {
    10.                 Destroy(gameObject);
    11.                 intScore = intScore + 1;
    12.              
    13.             }
    14.         }
    15.     }
    16. }
    this is also more stable and enables cross-platform support.

    that aside I think its time to show the entire Meteor script...

    Code (CSharp):
    1. using UnityEngine;
    2. using UnityEngine.Events;//for UnityEvents and UnityAction
    3. using UnityEngine.EventSystems;// for IPointerDownHandler
    4.  
    5. [RequireComponent(typeof(Collider))]
    6. //IPointerDownHandler requires a collider to catch click events
    7. // the Camera should also have a graphics raycaster component
    8. // and there needs to be an EventSystem GameObject in the scene (which
    9. // is added automatically when you add a canvas, or you can manually add
    10. // it in via the menus [GameObject > UI > EventSystem])
    11. public class Meteor : MonoBehaviour, IPointerDownHandler
    12. {
    13.     //personally I would move earth and Update() to a separate script
    14.     // probably called MoveToTarget, with a speed variable. main reason is that
    15.     // now the meteor class is violating the single responsibilitiy principal
    16.     // it now has two responsibilities and two possible reasons to change
    17.     // (movement and raising Events) increasing the risk that the class will
    18.     // be changed in the future, and increasing the chance of adding bugs later on
    19.  
    20.     public Transform earth;
    21.  
    22.  
    23.  
    24.     void Update ()
    25.     {
    26.         transform.position
    27.             = Vector2.MoveTowards(transform.position, earth.position, 0.3f * Time.deltaTime);
    28.     }
    29.  
    30.     #region IPointerDownHandler implementation
    31.     //doesn't need to be called in Update, the Input Manager will call this if a pointerDown
    32.     // event happens over the meteor
    33.     public void OnPointerDown(PointerEventData eventData)
    34.     {
    35.         //tell the classes that care (the scoreboard) that the meteor has been intercepted
    36.         OnMeteorInterception.Invoke();
    37.         Destroy(gameObject);
    38.     }
    39.  
    40.     #endregion
    41.  
    42.  
    43.     void OnTriggerEnter(Collider other)
    44.     //or OnCollisionEnter(Collider other), depending on how you have the collider set up
    45.     {
    46.         //assuming that the earth has the tag labeled "Earth"
    47.         if(other.CompareTag("Earth"))
    48.         {
    49.             // tell the classes that care (the game controller) that the meteor hit the earth
    50.             // the GameController will then know to execute the lose condition
    51.             OnMeteorCollision.Invoke();
    52.  
    53.             Destroy(gameObject);
    54.         }
    55.     }
    56.  
    57.     #region Meteor Events
    58.     // all these events are used so that the Meteor script can notify other scripts
    59.     // that "any" (since they are static) Meteor state has changed, specifically lets the scorboard know when a
    60.     // meteor is clicked on, or when the meteor collides with the earth
    61.     private static UnityEvent OnMeteorInterception = new UnityEvent();
    62.     private static UnityEvent OnMeteorCollision = new UnityEvent();
    63.  
    64.  
    65.     public static void AddOnMeteorInterception(UnityAction handler)
    66.     {
    67.         OnMeteorInterception.AddListener(handler);
    68.     }
    69.     public static void RemoveOnMeteorInterception(UnityAction handler)
    70.     {
    71.         OnMeteorInterception.RemoveListener(handler);
    72.     }
    73.     public static void AddOnMeteorCollision(UnityAction handler)
    74.     {
    75.         OnMeteorCollision.AddListener(handler);
    76.     }
    77.     public static void RemoveOnMeteorCollision(UnityAction handler)
    78.     {
    79.         OnMeteorCollision.RemoveListener(handler);
    80.     }
    81.     #endregion
    82. }

    then for a score script that updates the text component when a meteor is intercepted
    Code (CSharp):
    1. public class ScoreScript : MonoBehaviour
    2. {
    3.     Text txt;
    4.     public int score = 0;
    5.  
    6.     void Awake()
    7.     {
    8.         txt = GetComponent<Text>();
    9.         txt.text = score;
    10.     }
    11.  
    12.     void OnEnable()
    13.     {
    14.         Meteor.AddOnMeteorInterception(WhenMeteorIntercepted);
    15.     }
    16.     void OnDisable()
    17.     {
    18.      
    19.         Meteor.RemoveOnMeteorInterception(WhenMeteorIntercepted);
    20.     }
    21.  
    22.     void WhenMeteorIntercepted()
    23.     {
    24.         score++;
    25.         txt.text = score;
    26.     }
    27. }
     
    Last edited: Mar 24, 2016
    Ultra_B and Jason_ioosh like this.