Desarrollo

¿Cómo crear un administrador de tareas en Unity?

La intención de esta publicación es crear un archivo para referencia futura sobre ¿Cómo crear un administrador de tareas en Unity?. No tengo la intención de hacer de esto un tutorial de ningún tipo. Sin embargo, intentaré explicar las diferentes partes de los scripts que controlan el Administrador de Tareas.

Especificaciones

Unity 2017.1.1f1

Clases

MonoSingleton
TaskManager
CompleteTask
DeleteTask
CreateTask

MonoSingleton

Este es un singleton estándar que se establece en tipo T para que pueda aceptar cualquier otra clase como una extensión.


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

public abstract class MonoSingleton : MonoBehaviour where T : MonoBehaviour
{

    static T s_instance;

    public static T Instance
    {
        get
        {
            return s_instance ?? new GameObject("SingletonInstance").AddComponent<T>();
        }
    }

    protected virtual void Awake()
    {
        if (s_instance)
        {
            Destroy(gameObject);
            return;
        }

        s_instance = GetComponent<T>();

        DontDestroyOnLoad(gameObject);
    }

    protected virtual void OnEnable()
    {
        if (!s_instance)
            s_instance = GetComponent<T>();
    }

    protected virtual void OnDestroy()
    {
        if (s_instance != GetComponent<T>())
            return;


        s_instance = null;
    }
}

 

TaskManager


Librerías para el script.

 
using System;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using UnityEngine;
using UnityEngine.UI;
using Assets.SimpleAndroidNotifications;

Este script está compuesto por tres clases. La primera clase es TaskManager_Buttons. Esta primera clase ayuda a crear botones en el inspector para diseñadores.


#if UNITY_EDITOR
using UnityEditor;

[CustomEditor(typeof(TaskManager))]
public class TaskManager_Buttons : Editor
{

    public override void OnInspectorGUI()
    {

        TaskManager taskManager = (TaskManager)target;

        if (GUILayout.Button("Button"))
        {
           //This is what you will trigger in the inspector
        }
        DrawDefaultInspector();
    }

}
#endif

Este es el núcleo de este script. La idea es crear una estructura que pueda contener toda la información importante. Cree una lista de esta estructura y administre todos los cambios de UI que suceden en el lienzo.


public class TaskManager : MonoSingleton
{

    /*Public Variables*/
    [Serializable]
    public struct Task
    {
        int m_id;
        DateTime m_date;
        int m_priority;
        string m_message;
        bool m_completed;
        int m_notification;
        DateTime m_creationdate;
        public Task(int d, DateTime dt, int p, string m, bool c, int n, DateTime cd)
        {
            m_id = d;
            m_date = dt;
            m_priority = p;
            m_message = m;
            m_completed = c;
            m_notification = n;
            m_creationdate = cd;
        }

        public int id
        {
            get {return m_id;}
            set {m_id = value;}
        }

        public DateTime dateTime
        {
            get {return m_date;}
            set {m_date = value;}
        }

        public int priority
        {
            get {return m_priority;}
            set {m_priority = value;}
        }

        public string message
        {
            get {return m_message; }
            set { m_message = value;}
        }

        public bool completed
        {
            get { return m_completed;}
            set { m_completed = value; }
        }

        public int notification
        {
            get { return m_notification; }
            set { m_notification = value; }
        }

        public DateTime creationdate
        {
            get { return m_creationdate; }
            set { m_creationdate = value; }
        }
        public void PrintTask()
        {
            Debug.Log ("ID : " + m_id + "\n Date : " + m_date + "\n Creation Date : " + m_creationdate + "\n Priority : " + m_priority + "\n Message : " + m_message + "\n Completed : " + m_completed + "\n Notification ID : " + m_notification);
        }


    }
    public GameObject taskGameObject;
    public GameObject taskListView;
    public GameObject confirmTaskView;

    /*Private Variables*/
    private GameObject taskViewer;
    RectTransform contentRectTransform;
    VerticalLayoutGroup contentVerticalLayoutGroup;
    static List taskList = new List<Task>();
    List tasksInScroll = new List<GameObject>();
    static int countID;
    GameObject completedTask;
    



    private void OnEnable()
    {
        Load();
    }
    private void Start()
    {
        //Get the current content layout
        taskViewer = GameObject.FindWithTag("TaskViewer");
       contentRectTransform = taskViewer.GetComponent<RectTransform>();
       contentVerticalLayoutGroup = taskViewer.GetComponent<VerticalLayoutGroup>();
       
       SetUpScroller();
    }

    private void SetUpScroller()
    {
        for (int i = 0; i< taskList.Count; i++)
        {
            //taskList[i].PrintTask();
            if (!taskList[i].completed)
                AddTask(taskList[i]);

        }
    }

    private int GetNextID()
    {
        countID++;
        return countID;
    }

    //Public function that gets the message, date, time and priority. It also assigns the id and sets the status of the task;
    public void CreateTask(string m, DateTime dt, int p)
    {
        //create the task
        Task task = new Task();
        task.message = m;
        
        task.dateTime = dt;
        task.completed = false;
        task.priority = p;
        task.id = GetNextID();
        task.creationdate = DateTime.Now;
        //change the 5 to the difference of time between scheduled date and now
        /*int deffferenceInSeconds = (int)(dt - DateTime.Now).TotalSeconds;
        task.notification = ScheduleNotification(deffferenceInSeconds, task.message);*/
        //adding it to the list
        taskList.Add(task);
        Save();
        AddTask(task);
        
        //Debug.Log(task.id);
       //ClearScroller();  SetUpScroller(); 
    }

    //Adds the task to the scrollbar
    private void AddTask(Task t)
    {
        //Increase the current content by the size of the task and the spacing
        contentRectTransform.sizeDelta = new Vector2(contentRectTransform.sizeDelta.x, (contentRectTransform.sizeDelta.y + 600 + contentVerticalLayoutGroup.spacing)); //this 600 has to be fix to be dynamic
        //Create the new task and set parent
        GameObject newTask =  Instantiate(taskGameObject, taskViewer.transform.position, taskViewer.transform.rotation);
        newTask.transform.SetParent(taskViewer.transform);

        SetPriority(newTask, t.priority);
        SetMessage(newTask, t.message);
        SetDate(newTask, t.dateTime);
        SetTime(newTask, t.dateTime);
        SetID(newTask, t.id);
        //Add the task to the Scroll
        tasksInScroll.Add(newTask);
        //return newTask;

    }

    public void DeleteTask(GameObject go)
    {
        //Debug.Log(GetNextID(go));
        int positionInList = FindTask(Int32.Parse(GetChildGameObject(go, "ID").GetComponent<Text>().text));
        if (positionInList != -1)
        {
            //Delete the object fotm the scroll
            Destroy(go);
            //Cancel Notification
            CancelNotification(taskList[positionInList].notification);
            //Remove from the task list
            taskList.RemoveAt(positionInList);
            //decerese the size of the container
            contentRectTransform.sizeDelta = new Vector2(contentRectTransform.sizeDelta.x, (contentRectTransform.sizeDelta.y - 600 - contentVerticalLayoutGroup.spacing));
            Save();
        }

    }

    public int FindTask(int x)
    {
        for (int i = 0; i().text));
        if (positionInList != -1)
        {
            /*
            int gold = 0;
            int differenceInSeconds = (int)(taskList[positionInList].creationdate -  DateTime.Now).TotalSeconds;
            gold = ((int)(0.5f + (0.5f * taskList[positionInList].priority) *  Mathf.Clamp((differenceInSeconds/60),0,60) / 100))* UnityEngine.Random.Range(100, 250);
            gold = gold + PlayerPrefs.GetInt("PlayerFunds");
            PlayerPrefs.SetInt("PlayerFunds", gold); */
            
            //Delete the object fotm the scroll
            Destroy(completedTask);
            //Cancel Notification
            CancelNotification(taskList[positionInList].notification);
            //Remove from the task list
            Task v = taskList[positionInList];
            v.completed = true;
            taskList[positionInList] = v;
            //Decrease the size of the container
            contentRectTransform.sizeDelta = new Vector2(contentRectTransform.sizeDelta.x, (contentRectTransform.sizeDelta.y - 600 - contentVerticalLayoutGroup.spacing));
            //Save modifications in persistent file
            Save();
        } 
        taskListView.SetActive(true);
        confirmTaskView.SetActive(false);
    }

    public void DenyCompleted()
    {
        completedTask = null;
        taskListView.SetActive(true);
        confirmTaskView.SetActive(false);
    }

    public void CompleteTask(GameObject go)
    {
        completedTask =  go;
        taskListView.SetActive(false);
        confirmTaskView.SetActive(true);
}

    public void SetMessage(GameObject go, string m)
    {
        //Get the text component of message and set it to m
        GetChildGameObject(GetChildGameObject(go,"Message"),"Text").GetComponent<Text>().text = m;
    }

    public void SetDate(GameObject go, DateTime dt)
    {
        //Get the text component of date and set it to format MM/DD/YYY
        GetChildGameObject(GetChildGameObject(go, "Date"), "Text").GetComponent<Text>().text = dt.ToShortDateString();
    }

    public void SetTime(GameObject go, DateTime dt)
    {
        //Get the text component of time and set it to 00:00 AM
        GetChildGameObject(GetChildGameObject(go, "Time"), "Text").GetComponent<Text>().text = dt.ToShortTimeString();
    }

    public void SetID(GameObject go, int i)
    {
        //Get the text component of time and set it to 00:00 AM
        GetChildGameObject(go, "ID").GetComponent<Text>().text = i.ToString();
    }

    public void SetPriority(GameObject go, int p)
    {
        //Set the Priority
        switch (p)
        {
            case 1:
                GetChildGameObject(GetChildGameObject(go, "Priority"), "Low").SetActive(true);
                break;
            case 2:
                GetChildGameObject(GetChildGameObject(go, "Priority"), "Medium").SetActive(true);
                break;
            case 3:
                GetChildGameObject(GetChildGameObject(go, "Priority"), "High").SetActive(true);
                break;
            default:
                GetChildGameObject(GetChildGameObject(go, "Priority"), "Low").SetActive(true);
                break;
        }
        
    }

    static public void Save()
    {
        BinaryFormatter bf = new BinaryFormatter();
        FileStream file = File.Create(Application.persistentDataPath + "/tasksData.dat");
        
        TaskData data = new TaskData();
        data.taskList = taskList;
        data.countID = countID;

        bf.Serialize(file, data);
        file.Close();
    }
    public void Load()
    {
        if(File.Exists(Application.persistentDataPath + "/tasksData.dat"))
        {
            BinaryFormatter bf = new BinaryFormatter();
            FileStream file = File.Open(Application.persistentDataPath + "/tasksData.dat",FileMode.Open);
            TaskData data = (TaskData)bf.Deserialize(file);
            file.Close();
            taskList = data.taskList;
            countID = data.countID;
        }
    }

    public List GetAllTasks()
    {
        return taskList;
    }

    /*
    public int ScheduleNotification(int seconds, string Message)
    {
        return NotificationManager.Send(TimeSpan.FromSeconds(seconds), Message, "A nice reminder from your cat", new Color(1, 0.3f, 0.15f));
    } */

    public void CancelNotification(int i)
    {
        NotificationManager.Cancel(i);

    }

    public int GetCompleted()
    {
        int count = 0;
        for (int i = 0; i < taskList.Count; i++)
        {
            if (taskList[i].completed)
                count++;

        }
        return count;
    }

    static public GameObject GetChildGameObject(GameObject fromGameObject, string withName)
    {
        Transform[] ts = fromGameObject.transform.GetComponentsInChildren<Transform>(true);
        foreach (Transform t in ts) if (t.gameObject.name == withName) return t.gameObject;
        return null;
    }



}

TaskData está destinados a crear valores serializables que puedan ser utilizados por las funciones Save () y Load () de la clase TaskManager


/*Serializable Data That is going to be saved*/
[Serializable]
class TaskData
{
    int m_countID;
    List m_taskList;

    public List taskList
    {
        get { return m_taskList; }
        set { m_taskList = value; }
    }
    public int countID
    {
        get { return m_countID; }
        set { m_countID = value; }
    }
}

 

CompleteTask

Este es un singleton estándar que se establece en tipo T para que pueda aceptar cualquier otra clase como una extensión.


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

public class CompleteTask : MonoBehaviour {

   

    void Start()
    {
      
        Button btn = this.GetComponent<Button>();
        btn.onClick.AddListener(CompleteButton);
    }
    public void CompleteButton()
    {

        TaskManager.Instance.CompleteTask(this.transform.parent.gameObject);
    }


    static public GameObject GetChildGameObject(GameObject fromGameObject, string withName)
    {
        Transform[] ts = fromGameObject.transform.GetComponentsInChildren<Transform>(true);
        foreach (Transform t in ts) if (t.gameObject.name == withName) return t.gameObject;
        return null;
    }
}

 

DeleteTask

Esta clase está destinada a administrar y eliminar tareas de la lista.


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

public class DeleteTask : MonoBehaviour {

    
    void Start()
    {
        Button btn = this.GetComponent<Button>();
        btn.onClick.AddListener(EraseTask);
    }

    public void EraseTask()
    {
        TaskManager.Instance.DeleteTask(this.transform.parent.gameObject);
    }
}

 

CreateTask

Esta clase está destinada a tomar todos los parámetros de la interfaz de usuario y enviarlos a la clase del TaskManager.


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

public class CreateTask : MonoBehaviour {

    
   
    int prioirty;
    DateTime dateTime;
    private void Start()
    {
        prioirty = 1;
        dateTime = DateTime.Now;
        UpdateDateTime();
    }
    private void UpdateDateTime()
    {
        SetDateTimeText("Day", dateTime.Day.ToString() );
        SetDateTimeText("Month", dateTime.Month.ToString());
        SetDateTimeText("Year", dateTime.Year.ToString());
        SetDateTimeText("Hour", dateTime.ToString("%h"));
        SetDateTimeText("Minute", dateTime.ToString("mm"));
        SetDateTimeText("AM/PM", dateTime.ToString("tt", System.Globalization.CultureInfo.InvariantCulture));
    }
    public void ChangeDays(int i)
    {
        dateTime = dateTime.AddDays(i);
        UpdateDateTime();
    }
    public void ChangeMonth(int i)
    {
        dateTime = dateTime.AddMonths(i);
        UpdateDateTime();
    }
    public void ChangeYears(int i)
    {
        dateTime = dateTime.AddYears(i);
        UpdateDateTime();
    }
    public void ChangeHours(int i)
    {
        dateTime = dateTime.AddHours(i);
        UpdateDateTime();
    }

    public void ChangeMinutes(int i)
    {
        dateTime = dateTime.AddMinutes(i);
        UpdateDateTime();
    }
    public void ChangeAMPM()
    {
        if (dateTime.ToString("tt", System.Globalization.CultureInfo.InvariantCulture) == "AM")
            ChangeHours(12);
        else
            ChangeHours(-12);
    }
    public void FinishButton()
    {
        string message = GetChildGameObject(GetChildGameObject(this.gameObject, "Message" ),"Text").GetComponent<Text>().text;
        if (dateTime < DateTime.Now)
            dateTime = DateTime.Now;
        TaskManager.Instance.CreateTask(message, dateTime, prioirty);
    }

    public void SetPriority(int p)
    {
        ResetPriorityButtons();
        switch (p)
        {
            case 1:
                GetChildGameObject(GameObject.FindWithTag("Priorities"), "Low").GetComponent<Image>().color = new Color32(255, 185, 0, 255);
                break;
            case 2:
                GetChildGameObject(GameObject.FindWithTag("Priorities"), "Medium").GetComponent<Image>().color = new Color32(255, 185, 0, 255);
                break;
            case 3:
                GetChildGameObject(GameObject.FindWithTag("Priorities"), "High").GetComponent<Image>().color = new Color32(255, 185, 0, 255);
                break;
        }
        prioirty = p;
    }

    private Text GetDateTimeText (string name )
    {
        return GetChildGameObject(GetChildGameObject(GetChildGameObject(this.gameObject, "DateTime"), name), "Text").GetComponent<Text>();
    }

    private void SetDateTimeText (string name, string info)
    {
        GetChildGameObject(GetChildGameObject(GetChildGameObject(this.gameObject, "DateTime"), name), "Text").GetComponent<Text>().text = info;
    }


    private void ResetPriorityButtons()
    {
        GameObject priorityButtons = GameObject.FindWithTag("Priorities");
        foreach (Transform child in priorityButtons.transform)
        {
            child.GetComponent<Image>().color = new Color32(255, 255, 225, 255);
        }

    }
    static public GameObject GetChildGameObject(GameObject fromGameObject, string withName)
    {
        Transform[] ts = fromGameObject.transform.GetComponentsInChildren(true);
        foreach (Transform t in ts) if (t.gameObject.name == withName) return t.gameObject;
        return null;
    }
}
          

Esto es todo. Otra Vez la idea es solo tener una referencia de ciertas técnicas en unity sobre cómo hacer un Administrador de Tareas con clases para modificar el inspector, estructuras como el singleton, etc.

Gracias por “leer” (más bien ver porque es puro código) este artículo sobre cómo hacer un Administrador de tareas en Unity y lo más probable es que próximamente desglose estos principios en artículos más detallados. También planeo crear un repositorio donde este el proyecto para poder ser descargado en Github.

Deja un comentario

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *