using System; using UnityEngine; using Framework.Services; namespace Framework.Dialogue { /// Manages the dialogue UI elements in the world [ServiceScope(Scope.Session)] public class DialogueManager : ScriptComponent, IDialogueManager { /// Maximum distance from which a dialogue UI can be triggered public const float DefaultMaximumDistance = 2.5f; /// Prefab that will be instantiated when a dialogue canvas is needed public DialogueCanvas Prefab; /// Finds the best dialogue canvas placement on an owner /// Viewer for which a placement will be searched /// Actor the placement has to be attached to /// The best dialogue canvas placement for the specified owner public DialoguePlacement FindPlacementOnActor( Transform viewer, GameObject actor ) { return FindPlacementOnActor(viewer, actor, DefaultMaximumDistance); } /// Finds the best dialogue canvas placement on an owner /// Viewer for which a placement will be searched /// Actor the placement has to be attached to /// /// Maximum distance the placement may have from the viewer /// /// The best dialogue canvas placement for the specified owner public DialoguePlacement FindPlacementOnActor( Transform viewer, GameObject actor, float maximumDistance ) { DialogueOwner owner = actor.GetComponentInChildren(); if(owner != null) { Transform placement = owner.GetBestPlacement(viewer, maximumDistance); if(placement == null) { Debug.LogWarning( "No suitable dialogue placement found on owner '" + actor.name + "', " + "falling back to default placement." ); } else { return new DialoguePlacement(actor, owner, placement); } } return new DialoguePlacement( actor, owner, getOrCreateFallbackPlacement(viewer, owner.transform) ); } /// Finds the best dialogue canvas placement not attached to an owner /// Position of the viewer in the world /// The best dialogue canvas placement not attached to any owner public DialoguePlacement FindPlacementInWorld(Transform viewer) { throw new NotImplementedException("Not implemented yet"); } /// Displays a new dialogue canvas at a specific location /// Where the dialogue canvas will be displayed public IDialogueCanvas ShowDialogue(DialoguePlacement placement) { // See if we already have a canvas open for this actor and if so, just move it if(this.currentDialogueCanvas != null) { if(ReferenceEquals(this.currentActor, placement.Actor)) { // TODO: Animate canvas towards new placement //this.currentDialogueCanvas.transform.position = placement.Transform.position; //this.currentDialogueCanvas.transform.rotation = placement.Transform.rotation; this.currentDialogueCanvas.transform.SetParent(placement.Transform); return this.currentDialogueCanvas; } else { this.currentDialogueCanvas.Hide(); // TODO: Destroy canvas after hiding // Requires an event notifying us when the canvas finished its hiding anim } } IDialogueCanvas canvas = placement.Owner.GetOrCreateDialogueCanvas(placement.Transform); // TODO: Get rid of ugly downcast // If the canvas can move to a new location (see IDialogueCanvas2), // we don't need to deal with transforms by hand and have a clean interface this.currentDialogueCanvas = canvas as DialogueCanvas; return canvas; } /// Moves the currently active dialoge to a new location /// New location the dialoge should be moved to public void MoveDialogue(Transform newTransform) { if(this.currentDialogueCanvas != null) { // TODO: Animate canvas towards new placement this.currentDialogueCanvas.transform.position = newTransform.position; this.currentDialogueCanvas.transform.rotation = newTransform.rotation; } } /// Kills the currently active dialogue public void HideDialogue() { if(this.currentDialogueCanvas != null) { this.currentDialogueCanvas.Hide(); // TODO: Destroy canvas after hiding this.currentDialogueCanvas = null; this.currentActor = null; } } /// Currently active dialogue UI public IDialogueCanvas ActiveDialogueCanvas { get { return this.currentDialogueCanvas; } } /// Creates a fallback placement for the specified game object /// Position of the viewer in the scene /// Position of the dialogue owner /// A transform that serves as a fallback placement for dialogue UI private static Transform getOrCreateFallbackPlacement(Transform viewer, Transform owner) { const string FallbackObjectName = "FallbackDialoguePlacement"; Transform placement = owner.transform.Find(FallbackObjectName); if(placement == null) { var placementGameObject = new GameObject(FallbackObjectName); placement = placementGameObject.transform; placement.SetParent(owner); } // TODO: Position placement between viewer and owner return placement; } /// Transform to which the canvas has been attached private Transform currentCanvasRoot; /// Currently active dialogue canvas, if any private DialogueCanvas currentDialogueCanvas; /// Actor the active dialogue canvas is being shown for private GameObject currentActor; // null for world } } // namespace Framework.Dialogue