Search Unity

Task Management System

Discussion in 'Scripting' started by GladGoblinGames, Dec 27, 2015.

  1. GladGoblinGames

    GladGoblinGames

    Joined:
    Dec 14, 2011
    Posts:
    118
    Yo, coders

    I've been stuck on this problem all day long and through much trial and error, I still have not come to a way to achieve what I want. I'll try to explain this as best I can.

    Basically, I am trying to make it so that I have a custom menu option that attaches a script to the currently selected gameobject in the Hierarchy. That's no problem, I've done that.

    I'm trying to make it so that anyone can come in and be like "Attach New Task to this object" --> "Edit task name and description" --> "Display all the tasks that have been made via OnGUI() in character script"

    So far, I've been able to add a new task via the custom editor (as many as I like) yet, when I hit play, all tasks for some reason, get wiped?

    Here's the code..

    Editor Script (TaskManagementEditor.cs)

    Code (CSharp):
    1. using UnityEditor;
    2. using UnityEngine;
    3. using System.Collections;
    4. [CustomEditor(typeof(TaskHandler))]
    5. public class TaskManagementEditor : Editor {
    6.  
    7.     // Use this for initialization
    8.     void Start () {
    9.    
    10.     }
    11.    
    12.     // Update is called once per frame
    13.     void Update () {
    14.    
    15.     }
    16.  
    17.     public override void OnInspectorGUI()
    18.     {
    19.         TaskHandler taskHandler = (TaskHandler)target;
    20.  
    21.         taskHandler.taskListDefine.taskName = EditorGUILayout.TextField(taskHandler.taskListDefine.taskName);
    22.  
    23.         EditorGUILayout.BeginHorizontal();
    24.         if(GUILayout.Button("ADD TASK"))
    25.         {
    26.             taskHandler.AddNewTask();
    27.         }
    28.         EditorGUILayout.EndHorizontal();
    29.     }
    30. }
    31.  
    TaskHandler.cs

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections.Generic;
    3.  
    4. public class TaskHandler : MonoBehaviour {
    5.  
    6.     // We need a class that defines the variables we want to use to define a task
    7.     public class TaskListDefine
    8.     {
    9.         public string taskName;
    10.         public string taskDesc;
    11.         public bool completed;
    12.     }
    13.  
    14.     public TaskListDefine taskListDefine = new TaskListDefine();
    15.     public List<TaskListDefine> taskDefineList = new List<TaskListDefine>();
    16.  
    17.     // Use this for initialization
    18.     void Start () {
    19.    
    20.     }
    21.    
    22.     // Update is called once per frame
    23.     void Update () {
    24.    
    25.     }
    26.  
    27.     public void AddNewTask()
    28.     {
    29.         taskDefineList.Add(new TaskListDefine { taskName = taskListDefine.taskName, taskDesc = taskListDefine.taskDesc, completed = taskListDefine.completed });
    30.         Debug.Log("There are : " + taskDefineList.Count + " elements in task array");
    31.     }
    32. }
    33.  
    Here is the call I am making inside of the Character Script to see if it can see all tasks that have been added. It finds the script type, but displays no Debug.Log()

    Code (CSharp):
    1.         taskHandler = FindObjectOfType<TaskHandler>();
    2.         if(taskHandler == null)
    3.         {
    4.             Debug.Break();
    5.         }
    6.         for (int i = 0; i < taskHandler.taskDefineList.Count; i++)
    7.         {
    8.             Debug.Log(taskHandler.taskDefineList[i].taskName);
    9.         }
     
  2. ensiferum888

    ensiferum888

    Joined:
    May 11, 2013
    Posts:
    317
    It's probably because taskHandler == null.

    The for loop should give you errors if it was though. Where is the last snippet located and can you get to it if you place breakpoints your code editor?
     
  3. GladGoblinGames

    GladGoblinGames

    Joined:
    Dec 14, 2011
    Posts:
    118
    Thanks for the reply, I'm going to try explain my problem a little better if I can...

    Okay so say I have 3 keys within in the scene. I want the developer to attach an editor script to each object that allows then to edit a task name, a description, etc. Then click a button called "Add Task to Database" then when you enter play mode, each task will be displayed. Uncompleted tasks will display in white, completed tasks will appear in green.

    The problem I seem to be having is that every time I add a new instance of this editor script and click "Add Task to Database" the first object says "1 task added" but when I go onto another object which has the script attached, and I click "Add Task to Database" it says "1 task added" so its not remembering how many items are in the database between each instance of the editor class.

    That's the only way i can describe it. I can't post anymore code as through sheer frustration, I wiped it all. I just can't work out why each instance of this editor class can't remember how many items are within the list.

    I've tried everything I can think of, from System.Seriaizale to namespaces, to static classes, nothing seems to do what I am after :/
     
  4. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    It's not running under the same process. At least I'm fairly confident it's not. You've got task objects on game objects yes? And then a custom editor to add tasks outside runtime? It's not that they're getting wiped, it's just that when you click play it's starting a new runtime process in which those objects have no tasks added to them. You'd need to add the tasks in a persistent manner if you're looking to do things within the editor to carry over into runtime. I've never done what you're trying to do so I'm really just speculating here. I did some googling but in the 5 minutes didn't see anything. I think you're going to want to generate a prefab and then use the custom editor you're making to update that prefab. Uh... ya. :D Good luck!
     
  5. GladGoblinGames

    GladGoblinGames

    Joined:
    Dec 14, 2011
    Posts:
    118
    Hi there! I tried a prefab way of doing it, unfortunately for some reason, if its a prefab, the data just wipes itself even when using System.Serializable.

    I've got a few images here that better explain what the problem is :D My words do fail sometimes :p

    Image 1) Okay, so in this image you can see at the top that I have a custom menu item, which will attach the editor script to any object I want. So in this image, I am going to attach it to Gameobject 'Gkey'


    Image 2) In this image, I have edited a task name and description for this object. And then click "Add Task"



    Image 3) You can see from the debug log, if I click "Add Task" on the same object multiple times, the list goes up accordingly.


    Image 4) You can see from this image, I have selected a different gameobject. 'Main Door Key' I have edited the description and task name. But, from the debug log you can see that the list says "Task now are at 1" instead of 3.
    So esentially, it seems that between different game objects, it doesn't remember how many tasks are within the list


    The code I am working with so far...

    The Mono Script

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using System.Collections.Generic;
    4.  
    5. public class TaskSystemScript : MonoBehaviour {
    6.  
    7.     [System.Serializable]
    8.     public class TaskListData
    9.     {
    10.         public string taskName;
    11.         public string taskDesc;
    12.         public bool taskCompleted;
    13.     }
    14.  
    15.     public List<TaskListData> taskListData = new List<TaskListData>();
    16.     public string m_taskName;
    17.     public string m_taskDesc;
    18.     public bool m_taskCompleted;
    19.  
    20.     // Use this for initialization
    21.     void Start () {
    22.    
    23.     }
    24.    
    25.     // Update is called once per frame
    26.     void Update () {
    27.    
    28.     }
    29.  
    30.     public void AddNewTask()
    31.     {
    32.         taskListData.Add(new TaskListData { taskName = m_taskName, taskDesc = m_taskDesc, taskCompleted = m_taskCompleted });
    33.     }
    34.  
    35.     public void RemoveAllTasks()
    36.     {
    37.         taskListData.Clear();
    38.     }
    39. }
    40.  
    The Editor Script

    Code (CSharp):
    1. using UnityEngine;
    2. using System.Collections;
    3. using UnityEditor;
    4.  
    5. [CustomEditor(typeof(TaskSystemScript))]
    6. public class TaskManagementEditor : Editor {
    7.  
    8.     [SerializeField]
    9.     TaskSystemScript taskSystem;
    10.  
    11.     void OnEnable()
    12.     {
    13.         taskSystem = (TaskSystemScript)target;
    14.     }
    15.  
    16.     public override void OnInspectorGUI()
    17.     {
    18.        
    19.  
    20.         EditorGUILayout.BeginHorizontal();
    21.         EditorGUILayout.PrefixLabel("Task Name: ");
    22.         taskSystem.m_taskName = EditorGUILayout.TextField(taskSystem.m_taskName);
    23.         EditorGUILayout.EndHorizontal();
    24.  
    25.         EditorGUILayout.BeginHorizontal();
    26.         EditorGUILayout.PrefixLabel("Task Desc: ");
    27.         taskSystem.m_taskDesc = EditorGUILayout.TextField(taskSystem.m_taskDesc);
    28.         EditorGUILayout.EndHorizontal();
    29.  
    30.         if(GUILayout.Button("Add Task"))
    31.         {
    32.             taskSystem.AddNewTask();
    33.             Debug.Log("Tasks now are at " + taskSystem.taskListData.Count);
    34.         }
    35.  
    36.         if(GUILayout.Button("Remove All Tasks"))
    37.         {
    38.             taskSystem.RemoveAllTasks();
    39.         }
    40.     }
    41. }
    42.  
     
  6. zrrz

    zrrz

    Joined:
    Nov 14, 2012
    Posts:
    40
    TaskSystemScript taskSystem is not going to persist.
    You have to store it in a ScriptableObject or text file or something. Essentially with editor scripts you have to have them be COMPLETELY seperate. Make a system that can just read in your taskList from a hard coded ScriptableObject or something. And then make an editor script that can spit out and edit the file that your game reads from.

    It *IS* spitting out the correct number of tasks on the list, because each instance of taskSystem is different. And each taskSystem has its own taskListData.
     
  7. jtsmith1287

    jtsmith1287

    Joined:
    Aug 3, 2014
    Posts:
    787
    What zrrz said, plus you might want to use a static list since you're dealing with separate objects but want there to be one global list.
     
  8. GladGoblinGames

    GladGoblinGames

    Joined:
    Dec 14, 2011
    Posts:
    118
    Yo guys, I have been watching so many scriptable object live training videos/Unite conferences etc, and I am so confused with this problem I am now having!

    Code (CSharp):
    1.             if (taskSystemList.taskList.Count > 0)
    2.             {
    3.                 Debug.Log(taskSystemList.taskList.Count);
    4.                 GUILayout.BeginHorizontal();
    5.                 viewIndex = Mathf.Clamp(EditorGUILayout.IntField("Task No.", viewIndex, GUILayout.ExpandWidth(false)), 1, taskSystemList.taskList.Count);
    6.                 EditorGUILayout.LabelField("of " + taskSystemList.taskList.Count.ToString());
    7.                 EditorGUILayout.EndHorizontal();
    8.  
    9.                 taskSystemList.taskList[viewIndex - 1].taskName = EditorGUILayout.TextField("Task Name", taskSystemList.taskList[viewIndex - 1].taskName as string);
    10.                 taskSystemList.taskList[viewIndex - 1].taskDesc = EditorGUILayout.TextField("Task Desc", taskSystemList.taskList[viewIndex - 1].taskDesc);
    11.                 taskSystemList.taskList[viewIndex - 1].taskCompleted = EditorGUILayout.Toggle("Task Completed", taskSystemList.taskList[viewIndex - 1].taskCompleted);
    12.             }
    13.             else
    14.             {
    15.                 GUILayout.Label("This Task List is Empty");
    16.             }
    This if statement is always giving me NullReferenceException: Object reference not set to an instance of an object. From what the error tells me, it says its coming from the if statement alone. Yet when I change it to say ">= 0" it comes up. Yet when I delete this list, use the EditorWindow I made to create a new scritable object list, it gives me the null error again. I change it back to "> 0" and it works. So I'm like huh?!!?

    I should also mention as well, my scriptable object list is giving me a "Type Mismatch" in each element? Not sure why though as I followed the live training script.

    I tried script execution order to see if that helped, but nope. Didn't change anything :(

    Did another test, it seems to give me a null error to start with, but when I go into the script, change anything and save it, it works ? o_O

    UPDATE: Okay, so I fixed the type mismatch error. My bad, I put the data structure class as a scriptable object as well xD However, still having problems with the above mentioned if statement. Always null when the list is first made, go into the editor script, change it anything, save it, it works... :'(
     
    Last edited: Jan 1, 2016