Trigger Components

Expanding on the use of components from the previous post, the next game mechanic I would like to implement is that of collection. e.g. A component that can be added to an object and then allows that object to be ‘collected’ by the player; when the object is collected I want it to disappear from the players view.

Objects & Triggers

To be able to use a component which is relying on a Trigger, an object in the scene first needs to be set to a Collision Type of ‘Trigger’, the object also needs to have the option ‘Receives Update Events’ ticked – as per the options selected below.

image

A Trigger Event

Utilising the trigger event requires a method to be added to the object so that when the trigger event is raised, corresponding functionality can be triggered. This is the same regardless if we are building a component or not, however the component allows for this event and functionality to be encapsulated in a class and reused over and over amongst many objects (I do fancy this component concept).

To be able to attach the trigger event we first need to find the Scene Object we would like to attach the event to. If we weren’t building a Component we would find the Scene Object by name using the following:

SceneObject sceneobject;
sceneInterface.ObjectManager.Find("TheObject", out sceneobject);

Or if we wanted to search through the scene we could do it via:

List<ISceneEntity> foundobjects = new List<ISceneEntity>();
sceneInterface.ObjectManager.Find(foundobjects, ObjectFilter.Static);
foreach (SceneObject object1 in foundobjects)
{
    if(object1.Name == "TheObject")
    {
        //object1 is TheObject & we can do something here }
}

However, as we are building a component, we only need to use the quite straight forward cast to get the relevant Scene Object:

SceneObject sceneobject = (SceneObject)ParentObject;

Once the Scene Object reference has been obtained a subscription to the Trigger Event needs to be setup & can be done thusly:

sceneobject.CollisionTriggerEvent += new SynapseGaming.LightingSystem.Collision.CollisionTriggerDelegate(OnTrigger);

To handle the event, a method needs to be created; in this example OnTrigger. OnTrigger for the hide trigger will prevent the object from being rendered in game (but leave it rendering in the editor) and stop the object from receiving any more trigger events (so that the trigger only fires once).

// This is the method that handles the event. The handler event is unique to the component class. private void OnTrigger(IMovableObject collider, IMovableObject trigger)
{
    // handle trigger response here... SceneObject sceneobject = (SceneObject)ParentObject;

    // Hide the object, except when the editor is running sceneobject.Visibility = ObjectVisibility.RenderedInEditor;

    // Stop reciving updates for this object (Don't trigger any more events & ensure that this is only called once). sceneobject.CollisionType = SynapseGaming.LightingSystem.Collision.CollisionType.None;
}

That’s the trigger event defined and ready to handle input.

The Hide Component

Ensuring that this setup is only done once, is done with a simple little check and one pass during the first update method call & putting it together we get the following component:

[Serializable]
public class Component_Trigger_HideObject : BaseComponentManualSerialization<ISceneEntity> {
    bool setup = false;

    public override void OnUpdate(GameTime gameTime)
    {
        if (!setup)
        {
            SceneObject sceneobject = (SceneObject)ParentObject;
            // Add the collision trigger sceneobject.CollisionTriggerEvent += new SynapseGaming.LightingSystem.Collision.CollisionTriggerDelegate(OnTrigger);
            setup = true;
        }
    }

    // This is the method that handles the event. The handler event is unique to the component class. private void OnTrigger(IMovableObject collider, IMovableObject trigger)
    {
        // handle trigger response here... SceneObject sceneobject = (SceneObject)ParentObject;

        // Hide the object, except when the editor is running sceneobject.Visibility = ObjectVisibility.RenderedInEditor;

        // Stop reciving updates for this object (Don't trigger any more events & ensure that this is only called once). sceneobject.CollisionType = SynapseGaming.LightingSystem.Collision.CollisionType.None;
    }
}

Seriously, you can just copy and past that code in to your class, add it to an object with the Trigger Collision Type and Mark it to Receive Update Events and your off and running.

Serialization

One extra thing of note is the Serialization. In this example I have used BaseComponentManualSerialization<ISceneEntity> rather than BaseComponentAutoSerialization<ISceneEntity>

The reason for this is, I don’t really want the code or the output that’s effected from this Serialized and stored for the next run. E.g. If I collide with the object and trigger it to hide while I’m doing some work in the editor to test other things, I don’t really want to go back and change the visibility properties of the objects back and then update their Collision Types again. If the Component is marked for ManualSerialization, then you won’t have to, where as AutoSerialization will persist you changes for you when made in the editor. Up to you really but for a basic game mechanic I don’t need it.

Adding Points

Using the following approach makes adding points based on a trigger event really straight forward & as an object in the scene can have multiple components added it makes for a rewarding mix. Effectively a collection component by combining the hide component with a points system, rewarding the player for running in to the object.

Building on the before; here is the component itself.

[Serializable]
public class Component_Trigger_AddPoints_Small : BaseComponentManualSerialization<ISceneEntity> {
    bool setup = false;

    public override void OnUpdate(GameTime gameTime)
    {
        if (!setup)
        {
            SceneObject sceneobject = (SceneObject)ParentObject;
            sceneobject.CollisionTriggerEvent += new SynapseGaming.LightingSystem.Collision.CollisionTriggerDelegate(OnTrigger);
            setup = true;
        }
    }

    // This is the method that handles the event. The handler event is unique to the component class. private void OnTrigger(IMovableObject collider, IMovableObject trigger)
    {
        // handle trigger response here... PassThrough.LevelPoints += PassThrough.PointsSmall;
    }
}

As with my last post, this example is making use of a Static Class called PassThrough and then has added a new Static Variable named LevelPoints to store the incremented points. Also worth noting is that the amount of points being incremented is based on a value from the same static class (which allows us to then build the editor component to change the value of these points).

What I think is quite nifty is that using this approach allows for different combinations of points to be added to the score based on which components you have added to the object, here I’ve defined a Small points component but have added others with varying amounts so that different combinations of points could be added without having to edit the code.

I presume there is a performance impact of having so many instantiated trigger objects running in a scene but I haven’t yet encountered any such issues.

Obligatory Demo Video

 

View on YouTube for full screen.

Leave a Reply

Your email address will not be published. Required fields are marked *