Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / game

Unity3D - Easily Handling Player's Objectives

5.00/5 (1 vote)
1 Jan 2015CPOL1 min read 11.4K  
Unity3D - Easily Handling Player's Objectives

A really easy way to handle player's objectives in Unity3D is by taking advantage of these features:

  • Game Object hierarchy
  • Using public fields in scripts
  • Drag and Drop objects into public fields

With that said, this is what we can do:

  1. Create an empty game object
  2. Create a new child object per objective we want to represent
  3. Move each objective to the corresponding position (To make it easier, you can click on the cube in the inspector once you have selected the objective, this will show the icon and name of the object in the Scene view)
  4. Attach a collider marked with trigger so that it does not block the player movement.
  5. Create a custom Objective script which will contain its Name, Description, and other aspects required to handle its behavior, including the action to perform when collider is reached. One of the important keys here is that each objective would have a "NextObjective" field, which is of the same type of the script (Objective). This helps in reducing harcoded logic strings to go into the next objective.
  6. Create a Objectives script, which will contain a field for CurrentObjective and internally retrieves the list of all of the objectives in the hierarchy.
  7. Attach the Objectives script into the player's object, and drag your initial objective into the CurrentObjective field.

Image 1

Image 2

These are the sample scripts:

Objective.cs

using UnityEngine;
using System.Collections;
using System.Linq;
using System.Linq.Expressions;

public class Objective : MonoBehaviour
{

    public enum ObjectiveType
    {
        Reach = 0,
        Talk = 1,
        Defeat = 2,
    }

    public enum ObjectiveStatus
    {
        Pending = 0,
        Achieved = 1,
    }

    public enum ActionOnReach
    {
        MarkAsAchieved = 0,
        PlayCinematic = 1,
        PlayAnimation = 2,
        SetTrigger = 3,
    }

    public string Name;
    [Multiline(10)]
    public string Description;
    public ObjectiveType Kind;
    public ObjectiveStatus Status;
    public GameObject Target;
    public Objective NextObjective;
    public ActionOnReach[] ActionsOnReach;
    public Animator animator;
    public MovieTexture ClipToPlay;
    public string TriggerName;

    private void OnReach()
    {
        if (this.ActionsOnReach.Contains(ActionOnReach.MarkAsAchieved))
            this.Status = ObjectiveStatus.Achieved;
        if (this.ActionsOnReach.Contains(ActionOnReach.PlayCinematic))
            this.PlayCinematic();
        if (this.ActionsOnReach.Contains(ActionOnReach.PlayAnimation))
            this.PlayAnimation();
        if (this.ActionsOnReach.Contains(ActionOnReach.SetTrigger))
            this.NextObjective.Target.GetComponentInParent<animator>().SetTrigger(this.TriggerName);

        ParentScript.CurrentObjective = this.NextObjective;

    }

    private void PlayAnimation()
    {
        Debug.Log("On PlayAnimation: Not implemented yet");
    }

    private void PlayCinematic()
    {
        Debug.Log("On PlayCinematic: Not implemented yet ");
    }

    void OnTriggerEnter2D(Collider2D other)
    {
        if (other.tag == "Player" && this.ParentScript.CurrentObjective.name == this.name)
        {
            OnReach();
        }
    }

    public Objectives ParentScript { get; set; }
}

Objectives.cs

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

public class Objectives : MonoBehaviour {

    public Objective CurrentObjective;
    private Objective[] PlayerObjectives;
    public Image CurrentObjectiveArrow;

    public Text CurrentObjectiveDescription; 

    void Start()
    {
        var objectiveParentGameObject = this.CurrentObjective.transform.parent.gameObject;
        if (objectiveParentGameObject != null)
        {
            this.PlayerObjectives = objectiveParentGameObject.GetComponentsInChildren<Objective>();
            if (this.PlayerObjectives != null)
            {
                Debug.Log("Successfully found all player objectives");
                foreach (Objective singleObjective in PlayerObjectives)
                {
                    if (singleObjective != null)
                    {
                        singleObjective.ParentScript = this;
                    }
                }
            }
            else
                Debug.LogError("Unable to find objectives");
        }
    }

    void OnGUI()
    {
        this.CurrentObjectiveDescription.text = this.CurrentObjective.Description;
    }
}

This is just one way to do it, although it is not the only way, there are always other ways, some easier, some more complex, and complexity would be based on your game specific needs.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)