Some tips for intractable Game Elements

No matter what kind of game you’re making for whatever platform whether it’s mobile or a desktop device it’s likely that the game contains Intractable Game elements. By these I mean elements the player can interact with either through clicking, touching or maybe through pressing a certain button while near the element. For example: characters, items, switches, players or even elements in the user interface.

It’s important to get the hierarchy with these elements right, because often these elements get surrounded by all sorts of problems usually related to animation, scale, collisions or just way too many exceptions.

Bad Hierarchy

Below is an example of a really bad hierarchy for game element. There’s basically no hierarchy at all with all components attached to the parent object.

Click_tutorial_1
This might be enough for really simple objects found in hastily build up prototypes but more you use them and more complex you make them the more you’ll eventually run in to problems.

Few examples:

  1. Conflicts with the animations that modify the scale, rotation and position which you’d also like to access from your games logic.
  2. Problems with non-uniform scales which can cause a lot of unwanted weird behavior in attached child transforms.
  3. Problems with the default pivots and rotations of 3D-models e.g characters pivot is on the center of the character instead of it’s feet or character is not facing the direction it should when attached to a transform.
  4. Problems with unwanted colliders intercepting touch or click ray-casts.
  5. Physical size of the element itself could be too small and make it difficult to hit on small screens.

A lot of these problems can be solved by separating stuff like game logic, animation, interaction and user interface with a proper hierarchy.  There are many ways to do this and it’s easy to get carried away and make the hierarchy just too complex.

Below is example of the sort of hierarchy I often use in Unity3D

Click_tutorial_3

As you can probably see from the example above I like to keep the root transform fairly light. It’s also the place where I tend to put most of my game logic related to the element itself. This makes game logic easy to access from components in child transforms using:

GameElementBehavior element = transform.root.GetComponent<GameElementBehavior>();

As for rigidbodies, it’s generally recommended to keep them in the parent transform unless so that modifying the parent transforms properties won’t conflict with the physics simulation.

From the example you can also see that I tend to separate the model or in this chase sprite to it’s own game object below the parent transform. It’s usually the place where I’ll keep the animator component as well and components that listen to animator events, state or anything related to animation. This is also good place to place physical collider because sometimes you want to modify it to represent the animation e.g make it smaller when character is crouching.

Click_tutorial_2

Then if for example I need to make the element clickable i’ll simply separate that behavioral logic to it’s own child game object. This allows me to easily modify the size of the touch area by resizing the collider. I also recommend using a different layer like the UI layer for this game object and modifying the Hit-mask in Physics ray-caster attached to the camera  to only hit that specific layer.

Other things you could seperate like this are colliders for detecting hits from/to enemies or radar like trigger area around the player for disabling and enabling points of interest or systems for handling particle effects like smoke if the element has taken damage or is under a magic spell.

InteractableBehavior.cs


using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.Events;

public class InteractableBehavior : MonoBehaviour, IPointerClickHandler
{
    public UnityEvent OnRightClick;
    public UnityEvent OnLeftClick;
    public void OnPointerClick(PointerEventData eventData)
    {       
        if (OnLeftClick != null && eventData.pointerId == -1)
            OnLeftClick.Invoke();

        if (OnRightClick != null && eventData.pointerId == -2)
            OnRightClick.Invoke();
    }
}

GameElementBehavior.cs


using UnityEngine;

public class GameElementBehavior : MonoBehaviour
{
    public void ScaleUp()
    {
        if (transform.localScale.magnitude < 3.0f)
            transform.localScale += Vector3.one * 0.1f;
    }

    public void ScaleDown()
    {
        if(transform.localScale.magnitude > 0.3f)
            transform.localScale -= Vector3.one * 0.1f;
    }
}

Notes:

For InteractableBehavior to work you need:

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s