Building a flexible drag and drop hacking system with Scriptable Objects.

The Mission of this devlog: To provide players with the power to hack various objects in the game world, unleashing a multitude of actions, from disabling cameras to causing explosions. In short: Causing Mayhem. So, let’s get right into it.

Drawing Inspiration from Watch Dogs

Watch Dogs, a game that allows players to hack into an interconnected city, served as my primary muse. I was captivated by the idea of giving players the ability to manipulate their surroundings and devised a plan to bring this level of interactivity into my own project. Also I am very inspired by its clean and functional UI.

Conceptualizing the System

My system revolves around a few core components:

1. HackableSO (Scriptable Object): At the heart of my system lies the HackableSO, a Scriptable Object representing objects in the game world that can be hacked. Each HackableSO carries critical information such as descriptions, sprites, battery costs (if applicable), and most importantly, a list of HackableActionSOs.

2. HackableActionSO (Scriptable Object): These Scriptable Objects hold the logic for actions that can be executed on a HackableSO. Actions like “Disable Camera” or “Trigger Explosion” are defined as HackableActionSOs. They encapsulate the execution logic for their respective actions.

3. Drag-and-Drop Interface: My system makes it possible to include as many interactions to one hackable as I want. Just to select a HackableSO and attach HackableActionSOs to it. Done.

4. Runtime Execution: When a player decides to hack a HackableSO, all the associated HackableActionSOs spring into action, executing their designated functions.

Code Examples

Here’s a sneak peek into the code that brings my dynamic hacking system to life. I’ll focus on the two key Parts: HackableSO and HackableActionSO. These just get called via a hacking ability like that: hackableSO.Execute();

C#
// HackableSO.cs
using System.Collections.Generic;
using UnityEngine;

[CreateAssetMenu(fileName = "Hackable", menuName = "Scriptable Objects/Hackable", order = 0)]
public class HackableSO : ScriptableObject
{
    // ... (other variables)

    public List<HackableActionSO> hackableActions;
    List<HackableActionSO> instances = new List<HackableActionSO>();

    public void Initialize(Transform position, GameObject gameObject, ObjectHackable objectHackable)
    {
        // Initialization logic for HackableSO
        // Instantiate HackableActionSOs and add them to the 'instances' list
    }

    public void Execute(Transform position, GameObject gameObject, ObjectHackable objectHackable)
    {
        // Execution logic for HackableSO
        // Loop through 'instances' and execute associated HackableActionSOs
    }

    public void Deinitialize(Transform position, GameObject gameObject, ObjectHackable objectHackable)
    {
        // Deinitialization logic for HackableSO
    }
}

In this code snippet, HackableSO is responsible for initializing and executing HackableActions. It maintains a list of instances of HackableActionSOs to ensure that each action can be executed independently.

C#
// HackableActionSO.cs
using UnityEngine;

public class HackableActionSO : ScriptableObject
{
    public virtual void Initialize(Transform senderTransform, GameObject senderGO, ObjectHackable senderObjectHackable)
    {
        // Initialization logic for the action
    }

    public virtual void Execute(Transform senderTransform, GameObject senderGO, ObjectHackable senderObjectHackable)
    {
        // Execution logic for the action
    }

    public virtual void Deinitialize(Transform senderTransform, GameObject senderGO, ObjectHackable senderObjectHackable)
    {
        // Deinitialization logic for the action
    }
}

Meanwhile, HackableActionSO serves as the base class for all hackable actions, providing methods for initialization, execution, and deinitialization, making it easy for me to create custom actions.

Example for a HackableSO Configuration

Here is an example for that Hackable Action that just instantiates Objects like particle effects and sound.

C#
public class InstantiatePrefabAndSound : HackableActionSO
{
    public bool stopAfterSeconds;
    public float secondsToStop;
    public List<GameObject> ObjectsToInstantiate;
    public List<AudioClip> audioClips;
    
    public override void Initialize(Transform sendertransform, GameObject senderGo, ObjectHackable senderobjectHackable)
    {
        // Additional initialization logic can be added here
    }

    public override void Execute(Transform sendertransform, GameObject senderGo, ObjectHackable senderobjectHackable)
    { 
        foreach (var gameObject in ObjectsToInstantiate)
        {
            var go = Instantiate(gameObject, sendertransform.position, Quaternion.identity);
            go.transform.parent = sendertransform;
            go.SetActive(true);
            if (stopAfterSeconds) Destroy(go, secondsToStop);
        }
        
        foreach (var audioClip in audioClips)
        {
            // Play sound once
            AudioSource audio = senderGo.AddComponent<AudioSource>();
            audio.clip = audioClip;
            audio.spatialBlend = 1;
            audio.Play();
            if (stopAfterSeconds) Destroy(audio, secondsToStop);
        }
    }
    
    public override void Deinitialize(Transform sendertransform, GameObject senderGo, ObjectHackable senderobjectHackable)
    {
        // Additional deinitialization logic can be added here
    }
}

Leave a Comment