Need Help With A Scoring System

I am some What a beginner in the C# Buisness, and even more so a beginner in the Unity Business. I need to have a script that tells how many enemies there are (21 at the beginning), and when that number goes down, it adds 100 points. Here is what I have in my code right now:

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

public class GameController : MonoBehaviour {

    public float shootingInterval = 3f;
    public float shootingSpeed = 2f;
    public GameObject enemyMissilePrefab;
    public GameObject enemyContainer;
    public Player player;
    public float maximumMovingInterval = 0.4f;
    public float minimumMovingInterval = 0.05f;
    public float movingDistance = 0.1f;
    public float horizontalLimit = 2.5f;
    public int ScoreRaw;
    public int ScoreNew;

    private int score;
    private float movingInterval;
    private float movingDirection = 1;
    private float movingTimer;
    private float shootingTimer;
    private int enemyCount;


    // Use this for initialization
    void Start () {
        movingInterval = maximumMovingInterval;
        shootingTimer = shootingInterval;
        enemyCount = GetComponentsInChildren<Enemy> ().Length;
    }
   
    // Update is called once per frame
    void Update () {
        int currentEnemyCount = GetComponentsInChildren<Enemy> ().Length;
       

        // Shooting logic.
        shootingTimer -= Time.deltaTime;
        if (currentEnemyCount > 0 && shootingTimer <= 0f) {
            shootingTimer = shootingInterval;

            Enemy[] enemies = GetComponentsInChildren<Enemy> ();
            Enemy randomEnemy = enemies[Random.Range(0, enemies.Length)];

            GameObject missileInstance = Instantiate (enemyMissilePrefab);
            missileInstance.transform.SetParent (transform);
            missileInstance.transform.position = randomEnemy.transform.position;
            missileInstance.GetComponent<Rigidbody2D> ().velocity = new Vector2 (0, -shootingSpeed);
            Destroy (missileInstance, 5f);
        }
        
        //Score Logic.
        ScoreRaw = (currentEnemyCount * 100);
        ScoreNew = (((((ScoreRaw / 2100) - 1) * 10) * -1) * 100);
        Debug.Log(ScoreNew);

        // Movement logic.
        movingTimer -= Time.deltaTime;
        if (movingTimer <= 0f) {
            float difficulty = 1f - (float) currentEnemyCount / enemyCount;

            movingInterval = maximumMovingInterval - (maximumMovingInterval - minimumMovingInterval) * difficulty;
            movingTimer = movingInterval;

            enemyContainer.transform.position = new Vector2 (
                enemyContainer.transform.position.x + (movingDistance * movingDirection),
                enemyContainer.transform.position.y
            );

            if (movingDirection > 0) {
                float rightmostPosition = 0f;
                foreach (Enemy enemy in GetComponentsInChildren<Enemy>()) {
                    if (enemy.transform.position.x > rightmostPosition) {
                        rightmostPosition = enemy.transform.position.x;
                    }
                }

                if (rightmostPosition > horizontalLimit) {
                    movingDirection *= -1;

                    enemyContainer.transform.position = new Vector2 (
                        enemyContainer.transform.position.x,
                        enemyContainer.transform.position.y - movingDistance
                    );
                }
            } else {
                float leftmostPosition = 0f;
                foreach (Enemy enemy in GetComponentsInChildren<Enemy>()) {
                    if (enemy.transform.position.x < leftmostPosition) {
                        leftmostPosition = enemy.transform.position.x;
                    }
                }

                if (leftmostPosition < -horizontalLimit) {
                    movingDirection *= -1;

                    enemyContainer.transform.position = new Vector2 (
                        enemyContainer.transform.position.x,
                        enemyContainer.transform.position.y - movingDistance
                    );
                }
            }
        }

        if (currentEnemyCount == 0 || player == null) {
            SceneManager.LoadScene ("Game");
        }
    }
}

This seems to work in the calculator, But in the game it goes to 1000 when the enemy is destroyed, and does not go up anymore after that.

Help would be greatly appreciated.

Thanks

you should rework your code, some things you have here are very bad for performance.

GetComponentsInChildren

should never be used in the update function

call it once in start to get how many enemies you have.
after that everytime 1 enemy dies simply do

enemyCount -=1;
score+=100;

if you dont want to improve your code but just want it to work as it is, just count your score like this:

ScoreNew = (21 - currentEnemyCount )*100;

Ok, thank you, but could you explain why GetComponentsInChildren shouldn’t be used?

yes, its because GetComponent is a very costly operation that searches through your project without using references, due to that you should use it only once in start and save it in a variable(reference) so you can then use that variable without having to call getcomponent constantly.

you have this in start() and it is a good use:

 enemyCount = GetComponentsInChildren<Enemy> ().Length;

you then should only use enemyCount, and instead of checking over and over again how many enemies are in the scene you should make your enemies register their deaths and reduce the enemy count when they die.

Also, if GetComponent in update() is already bad, you are doing even worse by using GetComponents which if you have 21 enemies is as bad as calling get component 21 times. And you are doing that multiple times per frame in your code, its just very bad.

Of course if you had this only in this 1 script it will be alright, but if you keep coding like that one day your game will run at 10 fps and you will have to recode everything.

Ok, thank you, is there any way to edit a UI with this code, because I have tried the things in other forums, and they dont work, Here is my Hierarchy:


I need the highlighted GameObject, Text, To be updated, (Btw the script is on the GameController Empty) with the score. I tried doing it, and it goes back and forth 0, score, 0, score so fast that it shows 0

Is there any way to update the UI without it doing the back and forth?

Thanks

yes, but you have an error in your code if its doing that

I made a new script for the UI, also on the game controller empty:

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

public class UIController : MonoBehaviour
{
    [SerializeField]
    private UnityEngine.UI.Text scoreUI;
    public GameController gameController;
    // Start is called before the first frame update
    void Start()
    {
        gameController = FindObjectOfType<GameController>();
    }

    public void Update()
    {
        scoreUI.text = gameController.ScoreNew.ToString()
    }
}

But that doesn’t seem to work either. What is the error in my code?

Thanks,

its not efficient to constantly update the score, instead update it only when it changes. Go back to your gamecontroller script and add this:

using UnityEngine.UI;// add this together with the others on the top of the script

// then in the variables
public Text scoreUI;

//then when you do
ScoreNew = (21 - currentEnemyCount )*100;
//add also
scoreUI.text = ScoreNew.ToString();

}

Sadly, this code does not work either, It fixed the back and forth problem, but is now just doing nothing, the UI wont update. Here is the current script:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;

public class GameController : MonoBehaviour {

    public float shootingInterval = 3f;
    public float shootingSpeed = 2f;
    public GameObject enemyMissilePrefab;
    public GameObject enemyContainer;
    public Player player;
    public float maximumMovingInterval = 0.4f;
    public float minimumMovingInterval = 0.05f;
    public float movingDistance = 0.1f;
    public float horizontalLimit = 2.5f;
    public int ScoreRaw;
    public int ScoreNew;
    public Text scoreUI;

    private int score;
    private float movingInterval;
    private float movingDirection = 1;
    private float movingTimer;
    private float shootingTimer;
    private int enemyCount;
  


    // Use this for initialization
    void Start () {
        movingInterval = maximumMovingInterval;
        shootingTimer = shootingInterval;
        enemyCount = GetComponentsInChildren<Enemy> ().Length;
      
    }
  
    // Update is called once per frame
    void Update () {
        int currentEnemyCount = GetComponentsInChildren<Enemy> ().Length;
      

        // Shooting logic.
        shootingTimer -= Time.deltaTime;
        if (currentEnemyCount > 0 && shootingTimer <= 0f) {
            shootingTimer = shootingInterval;

            Enemy[] enemies = GetComponentsInChildren<Enemy> ();
            Enemy randomEnemy = enemies[Random.Range(0, enemies.Length)];

            GameObject missileInstance = Instantiate (enemyMissilePrefab);
            missileInstance.transform.SetParent (transform);
            missileInstance.transform.position = randomEnemy.transform.position;
            missileInstance.GetComponent<Rigidbody2D> ().velocity = new Vector2 (0, -shootingSpeed);
            Destroy (missileInstance, 5f);
        }

       //Score Logic.
        ScoreRaw = (currentEnemyCount * 100);
        ScoreNew = (21 - currentEnemyCount) * 100;
        scoreUI.text = ScoreNew.ToString();
        Debug.Log(ScoreNew);
      
      

        // Movement logic.
        movingTimer -= Time.deltaTime;
        if (movingTimer <= 0f) {
            float difficulty = 1f - (float) currentEnemyCount / enemyCount;

            movingInterval = maximumMovingInterval - (maximumMovingInterval - minimumMovingInterval) * difficulty;
            movingTimer = movingInterval;

            enemyContainer.transform.position = new Vector2 (
                enemyContainer.transform.position.x + (movingDistance * movingDirection),
                enemyContainer.transform.position.y
            );

            if (movingDirection > 0) {
                float rightmostPosition = 0f;
                foreach (Enemy enemy in GetComponentsInChildren<Enemy>()) {
                    if (enemy.transform.position.x > rightmostPosition) {
                        rightmostPosition = enemy.transform.position.x;
                    }
                }

                if (rightmostPosition > horizontalLimit) {
                    movingDirection *= -1;

                    enemyContainer.transform.position = new Vector2 (
                        enemyContainer.transform.position.x,
                        enemyContainer.transform.position.y - movingDistance
                    );
                }
            } else {
                float leftmostPosition = 0f;
                foreach (Enemy enemy in GetComponentsInChildren<Enemy>()) {
                    if (enemy.transform.position.x < leftmostPosition) {
                        leftmostPosition = enemy.transform.position.x;
                    }
                }

                if (leftmostPosition < -horizontalLimit) {
                    movingDirection *= -1;

                    enemyContainer.transform.position = new Vector2 (
                        enemyContainer.transform.position.x,
                        enemyContainer.transform.position.y - movingDistance
                    );
                }
            }
        }

        if (currentEnemyCount == 0 || player == null) {
            SceneManager.LoadScene ("Game");
        }
    }
}

did you drag your text object into the inspector?

also try removing your canvas object from being a child of game controller, put it in the main hierarchy

Thanks for the help, that seemed to have fixed that!
I have another game that I am making, a breakout clone, and I am having a problem where the script is detecting a collision, but only once, and never again, here is the script:

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

public class Player : MonoBehaviour
{
    Rigidbody _rigidbody;

    public GameObject thisGameObject;
    public GameObject laserPrefab;
    public GameObject[] powerUpSPrefabs;


    public int currentPowerupNumber;
    public string currentPowerupName = "none";

    void Start()
    {
       
        _rigidbody = GetComponent<Rigidbody>();
    }


    void FixedUpdate()
    {
        _rigidbody.MovePosition(new Vector3(Camera.main.ScreenToWorldPoint(new Vector3(Input.mousePosition.x, 0, 50)).x, -17, 0));
        if (currentPowerupName == "Sticky")
        {
            Ball.Instance._rigidbody.velocity = Vector3.zero;
            Ball.Instance._rigidbody.transform.position = new Vector3(thisGameObject.transform.position.x, -19, 0);
            Invoke("Launch", 10f);
            // Return to previous mesh
            ReturnToPreviousMesh();
            //reset current powerup name
            currentPowerupName = "none";
        }
        else if (currentPowerupName == "Laser")
        {
            //shoot lasers
            for (int i = 0; i < 100; i++)
            {
                //shoot lasers
                Instantiate(laserPrefab);
            }
            //return to previous mesh.
            ReturnToPreviousMesh();
            //reset current powerup name
            currentPowerupName = "none";
        }
        else if (currentPowerupName == "none")
        {
            Debug.Log("No current powerup");
        }

    }

    private void OnTriggerEnter(Collider other)
    {
        currentPowerupNumber = Random.Range(0, powerUpSPrefabs.Length - 1);
        currentPowerupName = powerUpSPrefabs[currentPowerupNumber].name;
        thisGameObject.GetComponent<MeshFilter>().sharedMesh = powerUpSPrefabs[currentPowerupNumber].GetComponent<MeshFilter>().sharedMesh;
        thisGameObject.GetComponent<MeshCollider>().sharedMesh = powerUpSPrefabs[currentPowerupNumber].GetComponent<MeshCollider>().sharedMesh;
    }

    void Launch()
    {
        Ball.Instance._rigidbody.velocity = Vector3.up * 20f;
    }

    void ReturnToPreviousMesh()
    {
        thisGameObject.GetComponent<MeshFilter>().sharedMesh = powerUpSPrefabs[4].GetComponent<MeshFilter>().sharedMesh;
        thisGameObject.GetComponent<MeshCollider>().sharedMesh = powerUpSPrefabs[4].GetComponent<MeshCollider>().sharedMesh;
    }
}

the problem is the OnTriggerEnter function, it seems to work the first time, but stop working after this. Is there a solution to this?