Page 1 of 1

Triggering DialogueSystemTrigger via C# ?

Posted: Tue Jul 18, 2023 2:41 pm
by PolarJam
Greetings,

I am looking to integrate Dialogue Machine, Quest Machine & Love/Hate into an existing project.

Currently, I am able to trigger conversations & quests using DM/QM but I am yet to integrate love/hate.

I have two DialogueTriggers set up in my scene currently, one that uses:

Quest Giver Script
Dialogue Actor Script
Usable
Dialogue System Trigger
SphereCollider / Rigidbody

This actor/gameObject is able to start a conversation from the DM database and update QM quests via conditional checks and lua scripting / node updates.

Alternatively, I have a different QuestGiver that uses the following components:

Sphere Collider
Quest Giver
Dialogue Actor
Trigger Event

Although these set-ups work for basic functionality, I would like more control over triggering Dialogue Machine Conversations, Alerts, Barks, etc from within my existing action scripts / Iinteractable interface.

I would like some tips on how to approach integrating Dialogue Manager functionality into my existing scripts.

I have attached some examples of my action/interaction scripts.

Code: Select all

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public abstract class BaseAction : MonoBehaviour
{
    public static event EventHandler OnAnyActionStarted; // Generic Event that can be fired when any action starts - can hook into other systems where needed. 
    public static event EventHandler OnAnyActionCompleted; // Generic Event that can be fired when any action is completed - can hook into other systems where needed. 

    protected Unit unit;
    protected bool isActive;

    protected Action onActionComplete;

    protected virtual void Awake()
    {
        unit = GetComponent<Unit>();
    }

    public abstract string GetActionName();

    public abstract void TakeAction(GridPosition gridPosition, Action onActionComplete);

    public virtual bool isValidActionGridPosition(GridPosition gridPosition)
    {
        List<GridPosition> validGridPositionList = GetValidActionGridPositionList();
        return validGridPositionList.Contains(gridPosition);
    }

    public abstract List<GridPosition> GetValidActionGridPositionList();

    public virtual int GetActionPointCost() // Default cost of 1, but can be overriden by other actions. 
    {
        return 1;
    }

    public virtual int GetSpecialPointCost()
    {
        return 1;
    }

    public virtual int GetUltimatePointCost()
    {
        return 1; 
    }

    protected void ActionStart(Action onActionComplete)
    {
        isActive = true;
        this.onActionComplete = onActionComplete;

        OnAnyActionStarted?.Invoke(this, EventArgs.Empty);
    }

    protected void ActionComplete()
    {
        isActive = false; 
        onActionComplete();

        OnAnyActionCompleted?.Invoke(this, EventArgs.Empty); // Broadcast OnAnyActionCompleted Event.
    }

    public Unit GetUnit()
    {
        return unit;
    }

    public EnemyAIAction GetBestEnemyAIAction()
    {
        List<EnemyAIAction> enemyAIActionList = new List<EnemyAIAction>(); // Create a list of EnemyAIActions.

        List<GridPosition> validActionGridPositionList = GetValidActionGridPositionList(); // Get a list of ValidActionGridPositions.

        foreach (GridPosition gridPosition in validActionGridPositionList) // Cycle through list of validActionGridPositions.
        {
            EnemyAIAction enemyAIAction = GetEnemyAIAction(gridPosition);
            enemyAIActionList.Add(enemyAIAction);
        }

        if (enemyAIActionList.Count > 0) // Check if the list of enemyAIActions has actions in it. 
        {
            enemyAIActionList.Sort((EnemyAIAction a, EnemyAIAction b) => b.actionValue - a.actionValue); // Sort the list based on ActionValue. 
            return enemyAIActionList[0]; // Returns the action at index 0, the top of the list. As the list has been sorted, action zero will be the action with the highest action value.
        }
        else
        {
            // There are no actions available for this Enemy AI.
            return ; 
        }

    }

    public abstract EnemyAIAction GetEnemyAIAction(GridPosition gridPosition);
}

Code: Select all

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class InteractAction : BaseAction
{
    public event EventHandler OnInteractActionStarted;
    public event EventHandler OnInteractActionCompleted;

    private int maxInteractDistance = 1;

    private void Update()
    {
        if (!isActive)
        {
            return;
        }

    }
    public override string GetActionName()
    {
        return ("Interact");
    }

    public override EnemyAIAction GetEnemyAIAction(GridPosition gridPosition)
    {
        return new EnemyAIAction()
        {
            gridPosition = gridPosition,
            actionValue = 0, 
        };
    }

    public override List<GridPosition> GetValidActionGridPositionList()
    {
        List<GridPosition> validGridPositionList = new List<GridPosition>();

        GridPosition unitGridPosition = unit.GetGridPosition();

        for (int x = -maxInteractDistance; x <= maxInteractDistance; x++)
        {
            for (int z = -maxInteractDistance; z <= maxInteractDistance; z++)
            {
                GridPosition offsetGridPosition = new GridPosition(x, z);
                GridPosition testGridPosition = unitGridPosition + offsetGridPosition;

                if (!LevelGrid.Instance.IsValidGridPosition(testGridPosition))
                {
                    // Testing if the grid position is within the bounds of the move distance of the unit. 
                    continue;
                }

                IInteractable interactable = LevelGrid.Instance.GetInteractableAtGridPosition(testGridPosition);
                if (interactable == )
                {
                    // No Interactable on this Grid Position. 
                    continue;
                }

                validGridPositionList.Add(testGridPosition);

                // After each test of the grid positions, the available spaces to move are modified as any conditional checks that are 'valid' are removed from the list of available positions to move to.
                // If the current unit is occuping that space, remove it from the moveTo List, if another Unit is occuping that space, remove it from the MoveTo List, If it is out of bounds remove it from the list, etc. 

            }
        }

        return validGridPositionList;

    }

    public override void TakeAction(GridPosition gridPosition, Action onActionComplete)
    {
        // Debug.Log("InteractAction");

        IInteractable interactable = LevelGrid.Instance.GetInteractableAtGridPosition(gridPosition);
        interactable.Interact(OnInteractComplete);

        OnInteractActionStarted?.Invoke(this, EventArgs.Empty);

        ActionStart(onActionComplete);
    }

    private void OnInteractComplete()
    {
        ActionComplete();

        OnInteractActionCompleted?.Invoke(this, EventArgs.Empty);
    }
}

Code: Select all

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Door : MonoBehaviour, IInteractable
{
    [SerializeField] private bool isOpen;
    [SerializeField] private bool isLocked;

    private GridPosition gridPosition;
    private Animator animator;
    private Action onInteractionComplete;

    private bool isActive;
    private float timer;

    private void Awake()
    {
        animator = GetComponent<Animator>();
    }

    private void Start()
    {
        gridPosition = LevelGrid.Instance.GetGridPosition(transform.position);
        LevelGrid.Instance.SetInteractableAtGridPosition(gridPosition, this);

        if (isOpen) // Check if door bool is set to true (open), if so run the OpenDoor function.
        {
            OpenDoor();
        }
        else // If the door isOpen bool is false, run the closeDoor function.
        {
            CloseDoor();
        }
    }
    private void Update()
    {
        if (!isActive)
        {
            return;
        }

        timer -= Time.deltaTime;
        if (timer <= 0f)
        {
            isActive = false; 
            onInteractionComplete();
        }
    }
    public void Interact(Action onInteractionComplete)
    {
        this.onInteractionComplete = onInteractionComplete;
        isActive = true;
        timer = .5f;

        if (isOpen) // Check if door bool is set to true (open), if so run the OpenDoor function.
        {
            CloseDoor();
        }
        else // If the door isOpen bool is false, run the closeDoor function.
        {
            OpenDoor();
        }
    }

    private void OpenDoor()
    {
        if (isLocked == false) // Conditional Check - if the door is not locked, then OpenDoor.
        {
            isOpen = true;
            animator.SetBool("IsOpen", isOpen); // Bool to be set on the DoorAnimator - case sensitive string, passes in the private bool isOpen to determine the setting in the animator.
            Pathfinding.Instance.SetIsWalkableGridPosition(gridPosition, true); // When the door is open, make this grid position a walkable gridPosition. 
        }

        return; // If the door is locked - then return here. 
    }

    private void CloseDoor()
    {
        isOpen = false;
        animator.SetBool("IsOpen", isOpen); // Bool to be set on the DoorAnimator - case sensitive string, passes in the private bool isOpen to determine the setting in the animator.
        Pathfinding.Instance.SetIsWalkableGridPosition(gridPosition, false); // When the door is closed, make this gridPosition unwalkable.
    }

I would like to be able to invoke an event and trigger the usable/onuse functionality of the Dialogue System Trigger directly instead of using the proximity selector/selectors / overlap triggers.

If anybody could give me a nudge in the right direction I would be thankful.

I think using the usable and dialogue system trigger components, but calling the OnUse Method at the same time as invoking my events may be a suitable solution but if there is a better way to approach this I would appreciate the help.

Re: Triggering DialogueSystemTrigger via C# ?

Posted: Tue Jul 18, 2023 4:15 pm
by Tony Li
Hi,

The Dialogue System Trigger component is just a convenience. You can call DialogueManager.StartConversation() directly in C# if you prefer. However, if you want to use Dialogue System Trigger components, you can call DialogueSystemTrigger.OnUse() in your C# code.

BTW, there's a video tutorial series on integrating DS + QM + LH: Video Tutorial Part 1