Adventure Creator Wikia
Register
Advertisement

This script shows one way in which articy:draft flows can be made to work with AC's dialogue and conversation system. It is able to display articy speech and conversation trees in AC.

NOTE: For a thorough and robust link between AC and articy:draft, try Dialogue System on the Asset Store.

To use this script, paste it in a C# file named ArticyFlowIntegration, attach it to an Articy Flow Player component in your scene (provided by articy's own Unity integration package), and invoke its RunFlow() method to run it.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Articy.Unity;
using Articy.Unity.Interfaces;

namespace AC
{

[RequireComponent (typeof (ArticyFlowPlayer))]
public class ArticyFlowIntegration : MonoBehaviour, IArticyFlowPlayerCallbacks
{

public IArticyObject startObject;

private ArticyFlowPlayer articyFlowPlayer;
private Branch autoRunBranch;
private Speech currentSpeech;
private IList<Branch> conversationBranches;
private Conversation conversation;

private NPC[] npcs;
private bool isRunning;
private bool isPaused;


private void OnEnable ()
{
// Hook into the OnClickConversation event, which we'll use to handle conversation clicks
EventManager.OnClickConversation += OnClickConversation;

// Assign and disable the ArticyFlowPlayer component until we're ready for it
articyFlowPlayer = GetComponent <ArticyFlowPlayer>();
articyFlowPlayer.enabled = false;

// Get a collection of NPCs to refer to later
npcs = FindObjectsOfType <NPC>();
}


private void Update ()
{
if (isPaused)
{
UpdateFlow ();
}
}


// Call this function externally to run the ArticyFlowPlayer
public void RunFlow ()
{
// Place the game into scripted-cutscene mode
KickStarter.stateHandler.StartCutscene ();

// Make sure a Conversation component is attached, and is set to rely on script for its interactions
if (conversation == null)
{
conversation = gameObject.AddComponent <Conversation>();
}
conversation.interactionSource = InteractionSource.CustomScript;

// Enable the ArticyFlowPlayer component
articyFlowPlayer.enabled = true;
isRunning = true;

// Record the StartOn IArticyObject, or restore it if this has already been played once
if (startObject == null)
{
startObject = articyFlowPlayer.StartOn;
}
else
{
articyFlowPlayer.StartOn = startObject;
}
}


private void OnDisable ()
{
// Unhook from the OnClickConversation event
EventManager.OnClickConversation -= OnClickConversation;
}


private void UpdateFlow ()
{
// Wait for no Speech or Conversation to be active
if ((currentSpeech == null || !currentSpeech.isAlive) && KickStarter.playerInput.activeConversation == null)
{
currentSpeech = null;

if (autoRunBranch != null)
{
// Play the next branch automatically
articyFlowPlayer.Play (autoRunBranch);
}
else if (conversationBranches != null)
{
// Show the branches as a Conversation
conversation.Interact ();
}
else if (KickStarter.playerInput.activeConversation == null)
{
// Can't find anything else to run, so stop the flow
StopRunning ();
}
}
}


public void OnFlowPlayerPaused (IFlowObject aObject)
{
if (aObject is IDialogue)
{
articyFlowPlayer.Play ();
return;
}

isPaused = true;
currentSpeech = null;

// Check for a speaking character
var dlgSpeaker = aObject as IObjectWithSpeaker;
if (dlgSpeaker != null)
{
Sprite portraitGraphic = null;
string displayName = "";
string speechText = "";

// Grab the speaker's portrait graphic
if (dlgSpeaker.Speaker != null)
{
IAsset speakerAsset = ((dlgSpeaker.Speaker as IObjectWithPreviewImage).PreviewImage.Asset as IAsset);
if (speakerAsset != null)
{
portraitGraphic = speakerAsset.LoadAssetAsSprite ();
}
}

// Grab the speaker's name
var modelWithDisplayName = aObject as IObjectWithDisplayName;
if (modelWithDisplayName != null)
{
displayName = modelWithDisplayName.DisplayName;
}

// Assign the portrait graphic and name to the correct AC character
Char speaker = GetCharacterWithName (dlgSpeaker.Speaker.TechnicalName);
if (speaker != null)
{
if (!string.IsNullOrEmpty (displayName))
{
speaker.speechLabel = displayName;
}
if (portraitGraphic != null && portraitGraphic.texture != null)
{
speaker.portraitIcon.texture = portraitGraphic.texture;
}
}

// Extract the dialogue text and play it in AC
var txtObj = aObject as IObjectWithText;
if (txtObj != null)
{
speechText = txtObj.Text;
currentSpeech = KickStarter.dialog.StartDialog (speaker, speechText);
}
}
}


public void OnBranchesUpdated (IList<Branch> aBranches)
{
conversationBranches = null;
autoRunBranch = null;

if (aBranches.Count == 1)
{
// Only one branch, so prepare to run it automatically
autoRunBranch = aBranches[0];
}
else if (aBranches.Count > 1)
{
// Multiple branches, so prepare them as a Conversation
conversationBranches = aBranches;

conversation.interactionSource = InteractionSource.CustomScript;
conversation.options.Clear ();
for (int i=0; i<aBranches.Count; i++)
{
string optionText = "Option " + i.ToString ();

var obj = aBranches[i].Target as IObjectWithMenuText;
if (obj != null)
{
optionText = obj.MenuText;
}

ButtonDialog buttonDialog = new ButtonDialog (i, optionText, true);
conversation.options.Add (buttonDialog);
}
}
}


private void StopRunning ()
{
if (isRunning)
{
// End the flow, and exit scripted-cutscene mode

isRunning = false;
articyFlowPlayer.enabled = false;
conversationBranches = null;
currentSpeech = null;

KickStarter.stateHandler.EndCutscene ();
}
}


private void OnClickConversation (Conversation _conversation, int optionID)
{
if (conversation == _conversation)
{
// Run the Branch if the object's own Conversation component was interacted with

KickStarter.playerInput.EndConversation ();
articyFlowPlayer.Play (conversationBranches[optionID]);
conversationBranches = null;
}
}


private Char GetCharacterWithName (string technicalName)
{
if (!string.IsNullOrEmpty (technicalName))
{
foreach (NPC npc in npcs)
{
if (npc.gameObject.name == technicalName)
{
return npc;
}
}

if (KickStarter.player)
{
if (KickStarter.player.gameObject.name == technicalName)
{
return KickStarter.player;
}
}
}
return null;
}


public bool IsRunning
{
get
{
return isRunning;
}
}

}

}

Additionally, this script allows for your articy project's language to be automatically synced with AC's language:

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Articy.Unity;

namespace AC
{

public class ArticyLanguageSync : MonoBehaviour
{

public string[] languageNames;


private void OnEnable ()
{
EventManager.OnChangeLanguage += OnChangeLanguage;
OnChangeLanguage (Options.GetLanguage ());
}


private void OnDisable ()
{
EventManager.OnChangeLanguage -= OnChangeLanguage;
}


private void OnChangeLanguage (int index)
{
if (languageNames != null && languageNames.Length > index)
{
string languageName = languageNames[index];
ArticyDatabase.Localization.Language = languageName;
ACDebug.Log ("Articy:Draft - changed language to " + languageName, this);
}
else
{
ACDebug.LogWarning ("Articy:Draft - cannot change language because languageNames does not have " + (index+1) + " elements.", this);
}
}

}

}
Advertisement