Search Unity

ontriggerenter does not update my score variable in gamemanager

Discussion in 'Scripting' started by ArisenShard, Dec 2, 2021.

  1. ArisenShard

    ArisenShard

    Joined:
    Jul 18, 2021
    Posts:
    9
    Hello!

    I have a bullet that triggers a score increase when it hits an enemy. But I can't figure out for the life of me why it's not working. The score (5) on the bullet triggers once, but whenever I hit enemies after that the score no longer increases. The debug stays at 5. The trigger works though because the enemy is destroyed:

    Bullet script (attached to gameobject that is spawned from the player):

    Code (CSharp):
    1.  
    2. public class Bullet : MonoBehaviour
    3. {
    4.     int score;
    5.  
    6.     void Start() {
    7.         score = GameObject.Find("GameManager").GetComponent<GameManager>().score;
    8.     }
    9.  
    10.     public void OnTriggerEnter(Collider other)
    11.     {
    12.         if(other.gameObject.CompareTag("Enemy"))
    13.         {
    14.             score += 5;
    15.             Debug.Log("hit: " + score);
    16.             Destroy(other.gameObject);
    17.             Destroy(gameObject);
    18.         }
    19.     }
    20. }
    21.  
    The gamemanager script is attached to a GameManager object in the scene:


    Code (CSharp):
    1.  
    2. public class GameManager : MonoBehaviour
    3. {
    4.     private int m_score;
    5.     public int score {
    6.         get { return m_score; }
    7.         set { m_score = score; }
    8.     }
    9.     [SerializeField] private List<GameObject> m_enemyList = new List<GameObject>();
    10.     public List<GameObject> enemyList {
    11.         get { return m_enemyList; }
    12.     }
    13.  
    14.     void Start()
    15.     {
    16.         InvokeRepeating("SpawnRandomEnemy", 1, 2);
    17.     }
    18.  
    19.     // randomise the spawned enemy
    20.     public void SpawnRandomEnemy()
    21.     {
    22.         int randomEnemy = Random.Range(0, enemyList.Count);
    23.         SpawnEnemy(enemyList[randomEnemy]);
    24.     }
    25.  
    26.     // spawn an enemy
    27.     public static void SpawnEnemy(GameObject enemyType)
    28.     {
    29.         Vector3 spawnPos;
    30.         spawnPos = new Vector3(0, 0, -35f);
    31.         Instantiate(enemyType, spawnPos, enemyType.transform.rotation);
    32.     }
    33. }
    34.  
    I can't work out what I'm doing wrong, from following various threads and posts in different forums/websites I just can't figure it out?
     
  2. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    You're increasing the score you store on the bullet. Why does a bullet have a score?

    Do you somehow think that reading the game-manager score and storing the int in the bullet somehow references the original score or something? It doesn't. "int" and other primitive types are value-types i.e. are copy-by-value, not references like classes etc.

    This just copies the current score in the GameManager instance into the bullet and you increase the bullet. It wouldn't work even once as you suggest either.
    Code (CSharp):
    1. score = GameObject.Find("GameManager").GetComponent<GameManager>().score;
    If you have to do it this way then store a reference to the GameManager component and increase the score on that, not a local copy which will be destroyed anyway.
     
  3. ArisenShard

    ArisenShard

    Joined:
    Jul 18, 2021
    Posts:
    9
    @melv
    Yeh you're right, I think my thought process is wrong with this. I'm thinking that the score has to increase when the bullet detects that it has hit an enemy. Like you said I'm assuming I can just bring in the score value and update it within bullet. Should I be running a method within GameManager instead, which increases the score? I don't have to do it the way I have coded. I just want to tell the GameManager to increase the score, when a bullet detects that it's hit an enemy. I think that's where I'm stuck. I'm still a noob and learning :D

    I've tried this but I'm still getting the same response, unless I'm misunderstanding what I'm supposed to do?

    Code (CSharp):
    1. public class Bullet : MonoBehaviour
    2. {
    3.     GameManager gameManager;
    4.  
    5.     void Start() {
    6.         gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();
    7.     }
    8.  
    9.     public void OnTriggerEnter(Collider other)
    10.     {
    11.         if(other.gameObject.CompareTag("Enemy"))
    12.         {
    13.             gameManager.score += 5;
    14.             Debug.Log("hit: " + gameManager.score);
    15.             Destroy(other.gameObject);
    16.             Destroy(gameObject);
    17.         }
    18.     }
    19. }
     
    Last edited: Dec 2, 2021
  4. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    Yes, the easiest change to your code would be to expose a method like "AddScore(int value)" in your GameManager and call that when you destroy the bullet. In reality you want to do the least work so often you'll process this in things that have the fewest so for instance if you have 1000 bullets for 10 enemies on average, you're probably best to detect the bullet hitting an enemy on the enemy and make the enemy increase the score. Mostly this saves 1000 bullets searching for a GameManager.

    Also, because your GameManager creates bullets and already has a reference to itself (this) then I'd consider assigning the GameManager reference to the Bullet rather than it searching again and again with the relatively expensive "GameObject.Find("GameManager").GetComponent<GameManager>()" which could be shortened to "myBullet.gameManager = this;" after you instantiate it.
     
  5. ArisenShard

    ArisenShard

    Joined:
    Jul 18, 2021
    Posts:
    9
    Thanks for your help, I'll give that a shot and see how I go. Pun intended :D
     
    Kurt-Dekker likes this.
  6. ArisenShard

    ArisenShard

    Joined:
    Jul 18, 2021
    Posts:
    9
    So I made a few tweaks, I was hoping I got it right but my score is still stuck at zero:

    Moved the trigger to the enemy script:

    Code (CSharp):
    1. public class Enemy : MonoBehaviour
    2. {
    3.     GameManager gameManager;
    4.  
    5.     void Start() {
    6.         gameManager = GameObject.Find("GameManager").GetComponent<GameManager>();
    7.     }
    8.  
    9.     public void OnTriggerEnter(Collider other)
    10.     {
    11.         if (other.gameObject.CompareTag("Boundary"))
    12.         {
    13.             Destroy(this.gameObject);
    14.         }
    15.  
    16.         if(other.gameObject.CompareTag("Bullet"))
    17.         {
    18.             gameManager.AddScore(5);
    19.             Destroy(this.gameObject);
    20.             Destroy(other.gameObject);
    21.         }
    22.     }
    23. }
    Added a method to GameManager to increase the score:

    Code (CSharp):
    1. public class GameManager : MonoBehaviour
    2. {
    3.     private int m_score;
    4.     public int score {
    5.         get { return m_score; }
    6.         set { m_score += score; }
    7.     }
    8.  
    9.     public void AddScore(int addPoints)
    10.     {
    11.         this.score += addPoints;
    12.         Debug.Log("Score:" + this.score);
    13.     }
    14. }

    Another thing I have are child scripts on the enemies which inherit the enemy class above. The Enemy script itself is not attached to anything. Not sure if this would affect anything. I would think not as the trigger does appear to be working.
     
  7. MelvMay

    MelvMay

    Unity Technologies

    Joined:
    May 24, 2013
    Posts:
    11,500
    So you need to debug it. If you call "gameManager.AddScore(5);" then it will increase by that amount. If it stays at zero then it's not being called or you're not displaing "gameManager.score" but something else.

    If you're not seeing "Debug.Log("Score:" + this.score);" then it's not being called. Add the same on the Enemy where you call it, likely it's not being called.
     
    ArisenShard likes this.
  8. Brathnann

    Brathnann

    Joined:
    Aug 12, 2014
    Posts:
    7,188
    Since you have a public method that modifies your score, just have it change the value of m_score directly. Your method can handle any conditionals that are needed. Get rid of the property. Just have your AddScore method += to m_score and then debug m_score.

    Also, you may want to look into manager or singleton setups in the future for classes such as GameManager, as it will remove the need to do your GameObject.Find. Or, take the advice given of just letting the GameManager assign itself on the enemy when it instantiates an enemy.
     
    ArisenShard likes this.
  9. ArisenShard

    ArisenShard

    Joined:
    Jul 18, 2021
    Posts:
    9
    Thanks, I did look at this, but I didn't quite understand what it was I needed to do. I have removed the property for the score though, so I'm getting the score back correctly now! I originally made it into a property to help me understand how they work, I guess I don't quite yet!

    Singletons are on my todo list, for sure!
     
  10. Lesk0v

    Lesk0v

    Joined:
    Aug 1, 2019
    Posts:
    5
    Hello. I'm having the same problem as ArisenShard. When I kill some zombie in my game, my "OnTriggerEnter" is called, adding some points to my variable, as you can see below:

    Code (CSharp):
    1.    
    2.  
    3. using System;
    4. using System.Collections;
    5. using System.Collections.Generic;
    6. using UnityEngine;
    7. using UnityEngine.SocialPlatforms.Impl;
    8. using UnityEngine.UI;
    9.  
    10.  
    11. public class DetectCollisions : MonoBehaviour
    12. {
    13.     public int score;
    14.  
    15.     void OnTriggerEnter(Collider other)
    16.     {
    17.         Destroy(gameObject);
    18.         Destroy(other.gameObject);
    19.         if (other.gameObject.CompareTag("Zombie"))
    20.         {
    21.             Debug.Log("Score " + score);
    22.             score++;
    23.         }
    24.         Debug.Log("Score: " + score);
    25.     }
    26. }
    I know the function is being called because it appears in the log in Unity. In Debuging mode, I see the function is being called twice and on the second call, it resets my score. Someone can help me?
     
  11. Kurt-Dekker

    Kurt-Dekker

    Joined:
    Mar 16, 2013
    Posts:
    38,751
    Probably not. If you had then the fix would have worked for you too.

    Please don't necro post. When you have an issue, make a new post... it's FREE!

    When you post, how to report your problem productively in the Unity3D forums:

    http://plbm.com/?p=220

    This is the bare minimum of information to report:

    - what you want
    - what you tried
    - what you expected to happen
    - what actually happened, especially any errors you see
    - links to documentation you used to cross-check your work (CRITICAL!!!)

    If you have no idea what code is running where or when, time to do some more debugging.

    The first question I would ask is "Why does the detect collisions script have a score?" See above.

    Time to start debugging! Here is how you can begin your exciting new debugging adventures:

    You must find a way to get the information you need in order to reason about what the problem is.

    Once you understand what the problem is, you may begin to reason about a solution to the problem.

    What is often happening in these cases is one of the following:

    - the code you think is executing is not actually executing at all
    - the code is executing far EARLIER or LATER than you think
    - the code is executing far LESS OFTEN than you think
    - the code is executing far MORE OFTEN than you think
    - the code is executing on another GameObject than you think it is
    - you're getting an error or warning and you haven't noticed it in the console window

    To help gain more insight into your problem, I recommend liberally sprinkling
    Debug.Log()
    statements through your code to display information in realtime.

    Doing this should help you answer these types of questions:

    - is this code even running? which parts are running? how often does it run? what order does it run in?
    - what are the names of the GameObjects or Components involved?
    - what are the values of the variables involved? Are they initialized? Are the values reasonable?
    - are you meeting ALL the requirements to receive callbacks such as triggers / colliders (review the documentation)

    Knowing this information will help you reason about the behavior you are seeing.

    You can also supply a second argument to Debug.Log() and when you click the message, it will highlight the object in scene, such as
    Debug.Log("Problem!",this);


    If your problem would benefit from in-scene or in-game visualization, Debug.DrawRay() or Debug.DrawLine() can help you visualize things like rays (used in raycasting) or distances.

    You can also call Debug.Break() to pause the Editor when certain interesting pieces of code run, and then study the scene manually, looking for all the parts, where they are, what scripts are on them, etc.

    You can also call GameObject.CreatePrimitive() to emplace debug-marker-ish objects in the scene at runtime.

    You could also just display various important quantities in UI Text elements to watch them change as you play the game.

    If you are running a mobile device you can also view the console output. Google for how on your particular mobile target, such as this answer or iOS: https://forum.unity.com/threads/how-to-capturing-device-logs-on-ios.529920/ or this answer for Android: https://forum.unity.com/threads/how-to-capturing-device-logs-on-android.528680/

    If you are working in VR, it might be useful to make your on onscreen log output, or integrate one from the asset store, so you can see what is happening as you operate your software.

    Another useful approach is to temporarily strip out everything besides what is necessary to prove your issue. This can simplify and isolate compounding effects of other items in your scene or prefab.

    Here's an example of putting in a laser-focused Debug.Log() and how that can save you a TON of time wallowing around speculating what might be going wrong:

    https://forum.unity.com/threads/coroutine-missing-hint-and-error.1103197/#post-7100494

    When in doubt, print it out!(tm)

    Note: the
    print()
    function is an alias for Debug.Log() provided by the MonoBehaviour class.
     
    Lesk0v likes this.
  12. Lesk0v

    Lesk0v

    Joined:
    Aug 1, 2019
    Posts:
    5
    Okay, thanks for advise. I will create another topic at the forum