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