Organizing game logic scripts

3 minute read

Showcase

Today I will share the way I build up game objects in unity3d. As an example, I will take spaceship controlled by a player. I’ve spent a good amount of time figuring how to organize my game logic code and game object tree. It’s essential to build clear rules that you follow during the whole developing process. Though you also need a way to break the rule if needed. While I looked at different patterns implemented to Unity3d, I thought they are way overpowered or too complicated.

My attempt in making easy to follow pattern is dead simple and flexible : ) First, we generate a game object in a special way dividing model view, game logic scripts and data. Inside the desired game object, I attach three empty objects:

  • bindings

You put here all game logic scripts. You even can customize this part more by dividing scripts into states. For example STATE:ACTIVE, STATE:DESTROYED and so on. Also, it will be a good idea to add separate folders for different types of scripts. In my case, I’ve added DECORATOR child that holds all my ship decoration scripts. This child attached to STATE:ACTIVE so if I decide to switch state to something like STATE:PAUSE the scripts there will be deactivated automatically.

decorators

  • model

Represents your sprites or 3d models, effects, flares, generally everything that must be shown to the player. You can also attach some scripts here if they make small particular view related job. In my case, I’ve added flares, thrusters special effects and some empty transform attachments to control local rotations, scales, offsets.

  • settings

I use this for initial setup file and in-game data container related to the object. During the game, all scripts from the game object turn here to fetch specific variables.

The script that generates game object tree in this way described in previous post

Showcase_01

But how our scripts will communicate? We can’t just use GetComponentInParent/Children as we have a lot of siblings in our object that can contain the script we are looking.

We will solve that problem with using extended method and some initial object setups.

First, we need a script attached to the top of the game object tree, RootComponent.cs

using UnityEngine;
public class RootComponent : MonoBehaviour
 {
 }

My version of the RootComponent is a little bit different, but for example it does the job. Next, we make an extension to our transforms. To do that I’ve made a script, TransfromExtensions.cs

using UnityEngine;
public static class TransformExtensions {

     public static T Bind<T>(this Transform transform,int cycles = 1,bool searchInactive = true)
    {
      T desiredComponent = default (T);
      var root=transform.GetComponentInParent<RootComponent> ();
      if (cycles>1)
      {
        var parent=root.transform.parent;
        for (int i = 1; i<cycles; i++)
        {
          parent=root.transform.parent;
          if (parent==null)
          {
            Debug.LogError ("Index out of range!");
            return default (T);
          }
        }
        root=parent.GetComponentInParent<RootComponent> ();
      }

      if (root==null)
        return default (T);

      MonoBehaviour[] behaviours = root.GetComponentsInChildren<MonoBehaviour> (searchInactive);
      for (int i = 0; i<behaviours.Length; i++)
      {
        if (behaviours[i] is T)
        {

          desiredComponent=behaviours[i].GetComponent<T> ();
        }
      }
      return desiredComponent;
    }
  }

The idea is simple. Find main “index” named RootComponent in your object. Search for desired component in children of RootComponent.

And now we can do something like this :

I have a script, let’s assume shipmovement.cs, and it needs to be linked to setup asset and data script. They are placed in settings/data.

var setupRef = transform.Bind<ShipSetup> ().Asset;
var dataRef = transform.Bind<ShipData> ();

showcase_03

There are some options for .Bind you can use as well: For example, you have a gun structure object that is placed on the top of the platform object. You put the gun structure as a child of the platform object and want to get a platform-specific script from the gun.

To do that you need deeper bind to get platform’s root component. You can do that by setting search cycles.

var script = transform.Bind<MyCoolPlatfromScript>(2);

.Bind will ignore RootParent of the gun structure and will look further for the next RootParent that is attached to the platform object. Also, you can toggle active/inactive components search filter. By the default .Bind looks up for the inactive components.

// won't add deactivated EntitySetup component.
var t = transform.Bind<EntitySetup> (1,false);

I’m still working on making this system better and definitely will write more about it later. If you like what I’m doing you can support me by signing up to newsletter : )

Comments