Wayback Machinekoobas.hobune.stream
May JUN Jul
Previous capture 13 Next capture
2021 2022 2023
1 capture
13 Jun 22 - 13 Jun 22
sparklines
Close Help
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
  • Asset Store
  • Get Unity

UNITY ACCOUNT

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account
  • Blog
  • Forums
  • Answers
  • Evangelists
  • User Groups
  • Beta Program
  • Advisory Panel

Navigation

  • Home
  • Products
  • Solutions
  • Made with Unity
  • Learning
  • Support & Services
  • Community
    • Blog
    • Forums
    • Answers
    • Evangelists
    • User Groups
    • Beta Program
    • Advisory Panel

Unity account

You need a Unity Account to shop in the Online and Asset Stores, participate in the Unity Community and manage your license portfolio. Login Create account

Language

  • Chinese
  • Spanish
  • Japanese
  • Korean
  • Portuguese
  • Ask a question
  • Spaces
    • Default
    • Help Room
    • META
    • Moderators
    • Topics
    • Questions
    • Users
    • Badges
  • Home /
  • Help Room /
avatar image
0
Question by DexterDev · Oct 14, 2020 at 09:26 AM · nullreferenceexceptionbug-perhapsinheritancemonobehaviourarchitecture

Strange behaviour when inheriting parent class with Monobehaviour

Hi all,

I am having some strange behavior with Unity and my code itself. Now I can firmly say the cause is the inheritance of a parent class with Monobehaviour as it could be a bug. My issues is that sometimes my code works, sometimes it just doesn't, closing Unity often seems to break it, and only way to fix it is to delete the Prefab and drag it back into the scene. Details below.


I have the following :


  • Task Bar Manager- This is attached to a prefab with a Slider and text. Is going to keep track of all the tasks that need to be done.

  • Task Controller - This is the Parent class that inherits Monobehaviour, this class is inherited by the individual task controllers.

  • Individual Task Controller (Computer Controller) - This is the class that inherits Task Controller, Task Controller contains all the generic task code and the individual task controller will contain code specific to this task.


Code for each class is shown below. Further details on the issues below. ps. Sorry for weird formatting.


public class TaskBarManager : MonoBehaviour {

 public static Canvas canvas;
 public static Slider slider;
 public static Text text;

 public static int tasksTotalCount = 0;
 public static int tasksCompleted = 0;
 public static int tasksRemaining = 0;

 private static float targetProgress = 0;
 private float fillSpeed = 0.5f;

 // Start is called before the first frame update
 void Start()
 {

     canvas = GetComponent<Canvas>();
     slider = GetComponentInChildren<Slider>();
     text = GetComponentInChildren<Text>();
 
     Debug.Log("Task-Bar finalised.");
     
 }

 // Update is called once per frame
 void Update()
 {
     if (slider.value <= tasksCompleted) {
           slider.value += fillSpeed * Time.deltaTime;
     }   
 }

 public static void IncrementProgress(float newProgress) {
    targetProgress = newProgress;
 }

 public static void UpdateTasksCompleted(int Value) {
     tasksCompleted = Value;
     IncrementProgress(Value);

     text.text = "Tasks Remaining " + tasksCompleted + " / " + tasksTotalCount;

     TaskBarDidComplete();
 }

 public static void UpdateTaskBarMaxValue(int Value) {
     tasksTotalCount = Value;
     slider.maxValue = Value; 
     
     text.text = "Tasks Remaining " + tasksCompleted + " / " + tasksTotalCount;
 }

 public static void TaskBarDidComplete() { // - Maybe an Event would be good here?
     if (tasksCompleted == tasksTotalCount) {
         SceneManager.LoadScene("Game-Over");
     }
 }

}

public class TaskController : MonoBehaviour {

 [HideInInspector] public Canvas canvas;
 [HideInInspector] public CircleCollider2D detectionRadius;
 [HideInInspector] public SpriteRenderer spriteRenderer;

 [HideInInspector] public TaskManager taskManager;

 [HideInInspector] public Slider progressBar;
 [HideInInspector] public Text interactionText;

 // - SETUP

 public void InstantiateTask(Task task) {
     
     canvas = gameObject.GetComponent<Canvas>();
     detectionRadius = gameObject.GetComponent<CircleCollider2D>();
     spriteRenderer = gameObject.GetComponent<SpriteRenderer>();

     taskManager = gameObject.GetComponent<TaskManager>();

     progressBar = gameObject.GetComponentInChildren<Slider>();
     interactionText = gameObject.GetComponentInChildren<Text>();
     
     ShowProgressBar(false);
     SetInteractionTextPrefix(task.taskPrefix);
     ShowInteractionText(false);

     Debug.Log(task.taskName + " instantiated.");

 }

 // - USER INTERFACE HANDLING

 public void ShowCanvas(bool Bool) {
     canvas.gameObject.SetActive(Bool);
 }

 public void ShowInteractionText(bool Bool) {
     interactionText.gameObject.SetActive(Bool);
 }

 public void SetInteractionTextPrefix(string Prefix) {
     interactionText.text = "Hold 'Left-Click' to " + Prefix;
 }

 public void ShowProgressBar(bool Bool) {
     progressBar.gameObject.SetActive(Bool);
 }

 // - COLLISION HANDLING

 public void HandleTriggerEnter2D(Collider2D collider, Task task) {

     if (!task.isCompleted) {
         if (detectionRadius.IsTouching(collider.gameObject.GetComponent<BoxCollider2D>())) {
             task.SetState(Task.TaskState.Hightlight);
             spriteRenderer.sprite = task.activeSprite;

             ShowInteractionText(true);
         }
     }
 }

 public void HandleTriggerExit2D(Collider2D collider, Task task) {

     if (!task.isCompleted) {
         task.SetState(Task.TaskState.Default);
         spriteRenderer.sprite = task.activeSprite;

         ShowInteractionText(false);
         ShowProgressBar(false);
     }
 }

     // CANVAS OVERLAY
 
 private float targetProgress = 0;

 public void CalculateProgress(Task task) {

     if (progressBar.gameObject.activeInHierarchy && Input.GetButton("Fire1")) {
         
         IncrementProgress(1f);

         if (progressBar.value <  targetProgress) {
             progressBar.value += task.openSpeed * Time.deltaTime;
         }

         if (progressBar.value == 1) {
             task.SetState(Task.TaskState.Complete);
             spriteRenderer.sprite = task.activeSprite;
             ShowProgressBar(false);

             taskManager.OnTaskComplete();

             if (!task.canBeCompleted) {
                 progressBar.value = 0;
                 task.isCompleted = false;
                 targetProgress = 0;
             }
         }

     } else if (progressBar.gameObject.activeInHierarchy) {
         ShowProgressBar(false);
         ShowInteractionText(true);
     }
 }

 public void IncrementProgress(float newProgress) {
    targetProgress =  progressBar.value + newProgress;
 }

 // COLLISION HANDLING

 public void OpenTaskListener() { // NEEDS TO BE RECODED - JUST FOR TESTING
     
     if (Input.GetMouseButtonDown(0)) {

         GameObject player = GameObject.Find("Player-Prefab");
         PlayerController pc = player.GetComponent<PlayerController>();

         if (!pc.player.GetPlayerIsThing()) {
             
             BoxCollider2D collider = player.GetComponent<BoxCollider2D>();

             if(detectionRadius.IsTouching(collider.gameObject.GetComponent<BoxCollider2D>())) {
                 ShowProgressBar(true);
                 ShowInteractionText(false);
             }
         }else{ 
             Debug.Log("Player is the Thing, cannot fix JB.");
         }
     }
 }

}

public class ComputerController : TaskController, TaskManager {

 public Task task;

 void Start()
 {
     InstantiateTask(task);
     TaskBarManager.UpdateTaskBarMaxValue(TaskBarManager.tasksTotalCount+1);
 }

 void Update()
 {
     CalculateProgress(task);
     OpenTaskListener(); 
 }


 private void OnTriggerEnter2D(Collider2D collider) {
     HandleTriggerEnter2D(collider, task);
 }

 private void OnTriggerExit2D(Collider2D collider) {
     HandleTriggerExit2D(collider, task);
 }

 // - INTERFACE

 public void OnTaskOpen() {
     Debug.Log("Task has opened.");
 }

 public void OnTaskComplete() { 
     TaskBarManager.UpdateTasksCompleted(TaskBarManager.tasksCompleted+1);
 }

}

As mentioned above, for some reason I get strange behavior. One of the following will happen.

  1. The Task counter will stay at 0 / 0, or rather be set to 0 / 0. It's almost like the TaskBarManager class is loading before the individual Task classes and not getting updated.

  2. Closing Unity seems to unset the Object Reference, I get a NullReferenceException (NullReferenceException: Object reference not set to an instance of an object TaskBarManager.UpdateTaskBarMaxValue (System.Int32 Value) (at Assets/Tasks/TaskBarManager.cs:60)) which can only be fixed by deleting the prefab and dragging it back to the scene. (This happens on re-opening Unity after closing it)

    1. The counter will update the max value won't, i.e. it will say 0 / 2 but when one is completed the slider will act as if the Max value is only one.

Please point out if I have made any architectural mistakes in my code,

Any help is greatly appreciated,

Thanks

Comment
Add comment
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users

1 Reply

· Add your reply
  • Sort: 
avatar image
1
Best Answer

Answer by streeetwalker · Oct 14, 2020 at 01:58 PM

Sounds like a serialization issue. Static variables are shared by all instances of a class and cannot be serialized. This would explain why you are losing the connection to your prefab when you quit, and probably also on recompilation.

I haven't followed through your code with a fine toothed comb, but it seems like the problem has something to do with your use of static variables.

Comment
Add comment · Show 3 · Share
10 |3000 characters needed characters left characters exceeded
▼
  • Viewable by all users
  • Viewable by moderators
  • Viewable by moderators and the original poster
  • Advanced visibility
Viewable by all users
avatar image DexterDev · Oct 14, 2020 at 02:07 PM 0
Share

Interesting, thanks for your response. I will go through and change it from static. I want to be able to access the class from multiple individual Task controllers without creating a new instance for each one. Any suggestions?

A quick Google search for how to access non-static methods without instancing suggests using Events to listen for task completion etc.

avatar image streeetwalker DexterDev · Oct 14, 2020 at 04:11 PM 0
Share

A singleton would give you a single instance of an object that contains references to shared resources to make available to multiple objects, but you do have to create an instance of it.

Seems like you could also create a scriptableobject to contain the references to your shared objects, which itself would not need to be instantiated at all because it seems like you want to use it as a shared asset. Scriptableobjects can also contain any code you want to run except for $$anonymous$$onoBehavior functions - aside from those, I think the only thing you don't get is a convenient global object reference like you do with a singleton.

You'd just need to attach the scriptableobject ( to the classes you do instantiate) using a variable, but those variables will reference the shared scriptableobject that is not itself instantiated.

I think that would work in your situation.

avatar image DexterDev streeetwalker · Oct 15, 2020 at 07:04 AM 0
Share

Wanted to update you, I decided to go with the Singleton. It was the perfect solution as there was only ever going to be one instance of TaskBar$$anonymous$$anager, similar to that of a Game$$anonymous$$anager. I switched everything from static and used the singleton instance and everything worked no errors during runtime, no errors after restart.

If anyone else is experiencing similar issues (NullReference Exception on restarting Unity + weird code behaviour) please ensure that you check if you are using static variables / references to objects as mentioned above.

Thanks

Your answer

Hint: You can notify a user about this post by typing @username

Up to 2 attachments (including images) can be used with a maximum of 524.3 kB each and 1.0 MB total.

Follow this Question

Answers Answers and Comments

218 People are following this question.

avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image avatar image

Related Questions

Object Reference to a global private variable is set in Awake function but lost in another function in the same class. 0 Answers

Adventure interactionSystem Structure (ScriptableObject,MonoBehavior,POO?) 0 Answers

advice on resource management system architecture 2 Answers

Show variable of class that dont inherit from MonoBehaviour in Inspector 1 Answer

NullReferenceException: Object reference not set to an instance of an object in Singleton class. 1 Answer


Enterprise
Social Q&A

Social
Subscribe on YouTube social-youtube Follow on LinkedIn social-linkedin Follow on Twitter social-twitter Follow on Facebook social-facebook Follow on Instagram social-instagram

Footer

  • Purchase
    • Products
    • Subscription
    • Asset Store
    • Unity Gear
    • Resellers
  • Education
    • Students
    • Educators
    • Certification
    • Learn
    • Center of Excellence
  • Download
    • Unity
    • Beta Program
  • Unity Labs
    • Labs
    • Publications
  • Resources
    • Learn platform
    • Community
    • Documentation
    • Unity QA
    • FAQ
    • Services Status
    • Connect
  • About Unity
    • About Us
    • Blog
    • Events
    • Careers
    • Contact
    • Press
    • Partners
    • Affiliates
    • Security
Copyright © 2020 Unity Technologies
  • Legal
  • Privacy Policy
  • Cookies
  • Do Not Sell My Personal Information
  • Cookies Settings
"Unity", Unity logos, and other Unity trademarks are trademarks or registered trademarks of Unity Technologies or its affiliates in the U.S. and elsewhere (more info here). Other names or brands are trademarks of their respective owners.
  • Anonymous
  • Sign in
  • Create
  • Ask a question
  • Spaces
  • Default
  • Help Room
  • META
  • Moderators
  • Explore
  • Topics
  • Questions
  • Users
  • Badges