Monday, December 8, 2014

Unity 2D: Simple system for moving platforms (not only!) - improving events






 Other Unity articles
  Simple system for moving platforms (not only!)
  Traversing GameObjects hierarchy



 In article "Simple system for moving platforms (not only!)" we created simple system that allowed us to move platforms or other objects along path defined with path nodes. This path had visual representation in editor and the system had some parameters that allowed us easy parametrization (waiting in nodes of our choice, setting speed and speed modifiers, moving in ping-pong way, loops or only once, setting movement type like linear, cos, quadratic ...).

 One of the features was ability to send events when platform or any other object following path arrived to destination path node or when leaving current path node. Originally this event was defined like stupid enum - just listing of some generalized event names:

public enum ePathNodeEventType
    {
        Nothing,
        Hit
    }

 In this tutorial we will change this enum to regular event object. The result animated above shows small dust animation when platform is hit. This animation is initiated with event. Each event will have also some parameters as pre-delay and post-delay and also it will have possibility to point to next event. In this way we can initiate chains of events. Here is how our inspector for PathNode will change:


 You can download final source files here. We first change two public variables holding enum values in PathNode.cs to this:

    public PathNodeEvent mOnArriveEvent;
    public PathNodeEvent mOnLeaveEvent;

 This will cause small change in our existing PathFollower class where we have to change OnLeaveEvent and OnArriveEvent like this:

    // -------------------------------------------------------------------------
    public virtual void OnLeaveEvent(PathNodeEvent aEvent)
    {
        if (aEvent != null)
            aEvent.ProcessEvent(gameObject);
    }

    // -------------------------------------------------------------------------
    public virtual void OnArriveEvent(PathNodeEvent aEvent)
    {
        if (aEvent != null)
            aEvent.ProcessEvent(gameObject);
    }

 Now we need to create new class. This class will name PathNodeEvent. Its properties will be delay before event is processed and time after the event is processed. The delay after event may seem unnecessary, but there is one more property - next event (again PathNodeEvent or derived class). The delay after processing current event says how much time to wait before processing next event. The event chain is stopped when next event is null.

 Here is listing of the beginning of PathNodeEvent class:

using UnityEngine;
using System.Collections;

public class PathNodeEvent : MonoBehaviour
{
    public float mDelayBefore = 0.0f;
    public float mDelayAfter = 0.0f;
    public PathNodeEvent mNextEvent = null;

 And here is rest of this small, but powerful class:

    // -------------------------------------------------------------------------
    public virtual void ProcessEvent(GameObject aGameObject)
    {
        StartCoroutine(Process(aGameObject));
    }

    // -------------------------------------------------------------------------
    protected virtual void DoProcess(GameObject aGameObject)
    {
        Debug.Log(gameObject.name + ": processing event");
    }

    // -------------------------------------------------------------------------
    protected IEnumerator Process(GameObject aGameObject)
    {
        if (mDelayBefore > 0)
            yield return new WaitForSeconds(mDelayBefore);

        DoProcess(aGameObject);

        if (mDelayAfter > 0)
            yield return new WaitForSeconds(mDelayAfter);

        if (mNextEvent != null)
            mNextEvent.ProcessEvent(aGameObject);
    }
}

 From the PathFollower class you see that ProcessEvent is called. The method is virtual so we can override it in subclasses. The implementation here is default. What it does is, that coroutine (Process) is started. There is first processed delay before event, then event itself - DoProcess. If some delay after event is entered, it is processed next and finally we check if there is any next event.

 This class does not do anything interesting except it prints message to debug console. Most of the real event will be subclasses of this class. You can override ProcessEvent if you are not interesting in delays or in chaining (for some simple event) or you can override DoProcess and you will have all the features described above.

 So, let's subclass it with simple SpawnEvent. The class is note derived from MonoBehaviour, but from our PathNodeEvent:


using UnityEngine;
using System.Collections;

public class SpawnEvent : PathNodeEvent
{
    public Transform mSpawnPoint;
    public GameObject mSpawnObject;

    // -------------------------------------------------------------------------
    public override void ProcessEvent(GameObject aGameObject)
    {
        // check for undefined spawn object or point
        if (mSpawnObject == null)
        {
            Debug.LogError("Spwan object is not defined");
            return;
        }
        else if (mSpawnPoint == null)
        {
            Debug.LogError("Spawn point is note defined");
            return;
        }

        // all ok, all defined
        /*GameObject spawnObject = (GameObject) */ Instantiate(mSpawnObject,
            mSpawnPoint.position, mSpawnPoint.rotation);
    }
}

 This type of event is very simple, so we override directly ProcessEvent and are not interested in delays. It has two additional public properties - Spawn Point and Spawn Object. Spawn object is "something" that will be spawned at "point". the inspector view looks like this:


 It means, you have to create event object somewhere in the scene. Spawn point can be any other Transform in the scene. SpawnObject can be prefab, which is very useful. To save one one GameObject in scene, the event here has its own Transform as spawn point - it is pointing to itself. Object in scene are arranged like this:


 The yellow squares are PathNodes from previous tutorial. The blue circle is event. The spawn object I am pointing to is short dust animation. When running it. you will get the result already shown in the beginning:


 The event spawns the dust when second PathNode is reached. But you can also play sound in the same event or chain sound event and animation event.

 Download (4 kb) here

 As you can imagine, the original PathFollowing system in connection with events can have lot of usages. I think it can also be used for some character animation scenes. Good thing is that both, the path system and events are easily extensible.