You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
564 lines
15 KiB
564 lines
15 KiB
using UnityEngine; |
|
using UnityEngine.UI; |
|
using UnityEngine.Events; |
|
using System; |
|
using System.Collections; |
|
using System.Collections.Generic; |
|
|
|
namespace Fungus |
|
{ |
|
public struct PortraitState |
|
{ |
|
public bool onScreen; |
|
public bool dimmed; |
|
public DisplayType display; |
|
public Sprite portrait; |
|
public RectTransform position; |
|
public FacingDirection facing; |
|
public Image portraitImage; |
|
} |
|
|
|
public enum DisplayType |
|
{ |
|
None, |
|
Show, |
|
Hide, |
|
Replace, |
|
MoveToFront |
|
} |
|
|
|
public enum FacingDirection |
|
{ |
|
None, |
|
Left, |
|
Right |
|
} |
|
|
|
public enum PositionOffset |
|
{ |
|
None, |
|
OffsetLeft, |
|
OffsetRight |
|
} |
|
|
|
[CommandInfo("Narrative", |
|
"Portrait", |
|
"Controls a character portrait. ")] |
|
public class Portrait : Command |
|
{ |
|
[Tooltip("Stage to display portrait on")] |
|
public Stage stage; |
|
|
|
[Tooltip("Display type")] |
|
public DisplayType display; |
|
|
|
[Tooltip("Character to display")] |
|
public Character character; |
|
|
|
[Tooltip("Character to swap with")] |
|
public Character replacedCharacter; |
|
|
|
[Tooltip("Portrait to display")] |
|
public Sprite portrait; |
|
|
|
[Tooltip("Move the portrait from/to this offset position")] |
|
public PositionOffset offset; |
|
|
|
[Tooltip("Move the portrait from this position")] |
|
public RectTransform fromPosition; |
|
|
|
[Tooltip("Move the portrait to this positoin")] |
|
public RectTransform toPosition; |
|
|
|
[Tooltip("Direction character is facing")] |
|
public FacingDirection facing; |
|
|
|
[Tooltip("Use Default Settings")] |
|
public bool useDefaultSettings = true; |
|
|
|
[Tooltip("Fade Duration")] |
|
public float fadeDuration = 0.5f; |
|
|
|
[Tooltip("Movement Duration")] |
|
public float moveDuration = 1f; |
|
|
|
[Tooltip("Shift Offset")] |
|
public Vector2 shiftOffset; |
|
|
|
[Tooltip("Move")] |
|
public bool move; |
|
|
|
[Tooltip("Start from offset")] |
|
public bool shiftIntoPlace; |
|
|
|
[Tooltip("Wait until the tween has finished before executing the next command")] |
|
public bool waitUntilFinished = false; |
|
|
|
// Timer for waitUntilFinished functionality |
|
protected float waitTimer; |
|
|
|
public override void OnEnter() |
|
{ |
|
// If no display specified, do nothing |
|
if (display == DisplayType.None) |
|
{ |
|
Continue(); |
|
return; |
|
} |
|
|
|
// If no character specified, do nothing |
|
if (character == null) |
|
{ |
|
Continue(); |
|
return; |
|
} |
|
|
|
// If Replace and no replaced character specified, do nothing |
|
if (display == DisplayType.Replace && replacedCharacter == null) |
|
{ |
|
Continue(); |
|
return; |
|
} |
|
|
|
// Selected "use default Portrait Stage" |
|
if (stage == null) // Default portrait stage selected |
|
{ |
|
if (stage == null) // If no default specified, try to get any portrait stage in the scene |
|
{ |
|
stage = GameObject.FindObjectOfType<Stage>(); |
|
} |
|
} |
|
|
|
// If portrait stage does not exist, do nothing |
|
if (stage == null) |
|
{ |
|
Continue(); |
|
return; |
|
} |
|
|
|
// Early out if hiding a character that's already hidden |
|
if (display == DisplayType.Hide && |
|
!character.state.onScreen) |
|
{ |
|
Continue(); |
|
return; |
|
} |
|
|
|
// Use default settings |
|
if (useDefaultSettings) |
|
{ |
|
fadeDuration = stage.fadeDuration; |
|
moveDuration = stage.moveDuration; |
|
shiftOffset = stage.shiftOffset; |
|
} |
|
|
|
if (character.state.portraitImage == null) |
|
{ |
|
CreatePortraitObject(character, stage); |
|
} |
|
|
|
// if no previous portrait, use default portrait |
|
if (character.state.portrait == null) |
|
{ |
|
character.state.portrait = character.profileSprite; |
|
} |
|
|
|
// Selected "use previous portrait" |
|
if (portrait == null) |
|
{ |
|
portrait = character.state.portrait; |
|
} |
|
|
|
// if no previous position, use default position |
|
if (character.state.position == null) |
|
{ |
|
character.state.position = stage.defaultPosition.rectTransform; |
|
} |
|
|
|
// Selected "use previous position" |
|
if (toPosition == null) |
|
{ |
|
toPosition = character.state.position; |
|
} |
|
|
|
if (replacedCharacter != null) |
|
{ |
|
// if no previous position, use default position |
|
if (replacedCharacter.state.position == null) |
|
{ |
|
replacedCharacter.state.position = stage.defaultPosition.rectTransform; |
|
} |
|
} |
|
|
|
// If swapping, use replaced character's position |
|
if (display == DisplayType.Replace) |
|
{ |
|
toPosition = replacedCharacter.state.position; |
|
} |
|
|
|
// Selected "use previous position" |
|
if (fromPosition == null) |
|
{ |
|
fromPosition = character.state.position; |
|
} |
|
|
|
// if portrait not moving, use from position is same as to position |
|
if (!move) |
|
{ |
|
fromPosition = toPosition; |
|
} |
|
|
|
if (display == DisplayType.Hide) |
|
{ |
|
fromPosition = character.state.position; |
|
} |
|
|
|
// if no previous facing direction, use default facing direction |
|
if (character.state.facing == FacingDirection.None) |
|
{ |
|
character.state.facing = character.portraitsFace; |
|
} |
|
|
|
// Selected "use previous facing direction" |
|
if (facing == FacingDirection.None) |
|
{ |
|
facing = character.state.facing; |
|
} |
|
|
|
switch(display) |
|
{ |
|
case (DisplayType.Show): |
|
Show(character, fromPosition, toPosition); |
|
character.state.onScreen = true; |
|
if (!stage.charactersOnStage.Contains(character)) |
|
{ |
|
stage.charactersOnStage.Add(character); |
|
} |
|
break; |
|
|
|
case (DisplayType.Hide): |
|
Hide(character, fromPosition, toPosition); |
|
character.state.onScreen = false; |
|
stage.charactersOnStage.Remove(character); |
|
break; |
|
|
|
case (DisplayType.Replace): |
|
Show(character, fromPosition, toPosition); |
|
Hide(replacedCharacter, replacedCharacter.state.position, replacedCharacter.state.position); |
|
character.state.onScreen = true; |
|
replacedCharacter.state.onScreen = false; |
|
stage.charactersOnStage.Add(character); |
|
stage.charactersOnStage.Remove(replacedCharacter); |
|
break; |
|
|
|
case (DisplayType.MoveToFront): |
|
MoveToFront(character); |
|
break; |
|
} |
|
|
|
if (display == DisplayType.Replace) |
|
{ |
|
character.state.display = DisplayType.Show; |
|
replacedCharacter.state.display = DisplayType.Hide; |
|
} |
|
else |
|
{ |
|
character.state.display = display; |
|
} |
|
|
|
character.state.portrait = portrait; |
|
character.state.facing = facing; |
|
character.state.position = toPosition; |
|
|
|
waitTimer = 0f; |
|
if (!waitUntilFinished) |
|
{ |
|
Continue(); |
|
} |
|
else |
|
{ |
|
StartCoroutine(WaitUntilFinished(fadeDuration)); |
|
} |
|
} |
|
|
|
protected virtual IEnumerator WaitUntilFinished(float duration) |
|
{ |
|
// Wait until the timer has expired |
|
// Any method can modify this timer variable to delay continuing. |
|
|
|
waitTimer = duration; |
|
while (waitTimer > 0f) |
|
{ |
|
waitTimer -= Time.deltaTime; |
|
yield return null; |
|
} |
|
|
|
Continue(); |
|
} |
|
|
|
protected virtual void CreatePortraitObject(Character character, Stage stage) |
|
{ |
|
// Create a new portrait object |
|
GameObject portraitObj = new GameObject(character.name, |
|
typeof(RectTransform), |
|
typeof(CanvasRenderer), |
|
typeof(Image)); |
|
|
|
// Set it to be a child of the stage |
|
portraitObj.transform.SetParent(stage.portraitCanvas.transform, true); |
|
|
|
// Configure the portrait image |
|
Image portraitImage = portraitObj.GetComponent<Image>(); |
|
portraitImage.preserveAspect = true; |
|
portraitImage.sprite = character.profileSprite; |
|
portraitImage.color = new Color(1f, 1f, 1f, 0f); |
|
|
|
// LeanTween doesn't handle 0 duration properly |
|
float duration = (fadeDuration > 0f) ? fadeDuration : float.Epsilon; |
|
|
|
// Fade in character image (first time) |
|
LeanTween.alpha(portraitImage.transform as RectTransform, 1f, duration).setEase(stage.fadeEaseType); |
|
|
|
// Tell character about portrait image |
|
character.state.portraitImage = portraitImage; |
|
} |
|
|
|
protected void SetupPortrait(Character character, RectTransform fromPosition) |
|
{ |
|
SetRectTransform(character.state.portraitImage.rectTransform, fromPosition); |
|
|
|
if (character.state.facing != character.portraitsFace) |
|
{ |
|
character.state.portraitImage.rectTransform.localScale = new Vector3(-1f, 1f, 1f); |
|
} |
|
else |
|
{ |
|
character.state.portraitImage.rectTransform.localScale = new Vector3(1f, 1f, 1f); |
|
} |
|
|
|
if (facing != character.portraitsFace) |
|
{ |
|
character.state.portraitImage.rectTransform.localScale = new Vector3(-1f, 1f, 1f); |
|
} |
|
else |
|
{ |
|
character.state.portraitImage.rectTransform.localScale = new Vector3(1f, 1f, 1f); |
|
} |
|
} |
|
|
|
public static void SetRectTransform(RectTransform oldRectTransform, RectTransform newRectTransform) |
|
{ |
|
oldRectTransform.eulerAngles = newRectTransform.eulerAngles; |
|
oldRectTransform.position = newRectTransform.position; |
|
oldRectTransform.rotation = newRectTransform.rotation; |
|
oldRectTransform.anchoredPosition = newRectTransform.anchoredPosition; |
|
oldRectTransform.sizeDelta = newRectTransform.sizeDelta; |
|
oldRectTransform.anchorMax = newRectTransform.anchorMax; |
|
oldRectTransform.anchorMin = newRectTransform.anchorMin; |
|
oldRectTransform.pivot = newRectTransform.pivot; |
|
oldRectTransform.localScale = newRectTransform.localScale; |
|
} |
|
|
|
protected void Show(Character character, RectTransform fromPosition, RectTransform toPosition) |
|
{ |
|
if (shiftIntoPlace) |
|
{ |
|
fromPosition = Instantiate(toPosition) as RectTransform; |
|
if (offset == PositionOffset.OffsetLeft) |
|
{ |
|
fromPosition.anchoredPosition = new Vector2(fromPosition.anchoredPosition.x - Mathf.Abs(shiftOffset.x), fromPosition.anchoredPosition.y - Mathf.Abs(shiftOffset.y)); |
|
} |
|
else if (offset == PositionOffset.OffsetRight) |
|
{ |
|
fromPosition.anchoredPosition = new Vector2(fromPosition.anchoredPosition.x + Mathf.Abs(shiftOffset.x), fromPosition.anchoredPosition.y + Mathf.Abs(shiftOffset.y)); |
|
} |
|
else |
|
{ |
|
fromPosition.anchoredPosition = new Vector2(fromPosition.anchoredPosition.x, fromPosition.anchoredPosition.y); |
|
} |
|
} |
|
|
|
SetupPortrait(character, fromPosition); |
|
|
|
// LeanTween doesn't handle 0 duration properly |
|
float duration = (fadeDuration > 0f) ? fadeDuration : float.Epsilon; |
|
|
|
// Fade out a duplicate of the existing portrait image |
|
if (character.state.portraitImage != null) |
|
{ |
|
GameObject tempGO = GameObject.Instantiate(character.state.portraitImage.gameObject); |
|
tempGO.transform.SetParent(character.state.portraitImage.transform, false); |
|
tempGO.transform.localPosition = Vector3.zero; |
|
tempGO.transform.localScale = character.state.position.localScale; |
|
|
|
Image tempImage = tempGO.GetComponent<Image>(); |
|
tempImage.sprite = character.state.portraitImage.sprite; |
|
tempImage.preserveAspect = true; |
|
tempImage.color = character.state.portraitImage.color; |
|
|
|
LeanTween.alpha(tempImage.rectTransform, 0f, duration).setEase(stage.fadeEaseType).setOnComplete(() => { |
|
Destroy(tempGO); |
|
}); |
|
} |
|
|
|
// Fade in the new sprite image |
|
character.state.portraitImage.sprite = portrait; |
|
character.state.portraitImage.color = new Color(1f, 1f, 1f, 0f); |
|
LeanTween.alpha(character.state.portraitImage.rectTransform, 1f, duration).setEase(stage.fadeEaseType); |
|
|
|
DoMoveTween(character, fromPosition, toPosition); |
|
} |
|
|
|
protected void Hide(Character character, RectTransform fromPosition, RectTransform toPosition) |
|
{ |
|
if (character.state.display == DisplayType.None) |
|
{ |
|
return; |
|
} |
|
|
|
SetupPortrait(character, fromPosition); |
|
|
|
// LeanTween doesn't handle 0 duration properly |
|
float duration = (fadeDuration > 0f) ? fadeDuration : float.Epsilon; |
|
|
|
LeanTween.alpha(character.state.portraitImage.rectTransform, 0f, duration).setEase(stage.fadeEaseType); |
|
|
|
DoMoveTween(character, fromPosition, toPosition); |
|
} |
|
|
|
protected void MoveToFront(Character character) |
|
{ |
|
character.state.portraitImage.transform.SetSiblingIndex(character.state.portraitImage.transform.parent.childCount); |
|
} |
|
|
|
protected void DoMoveTween(Character character, RectTransform fromPosition, RectTransform toPosition) |
|
{ |
|
// LeanTween doesn't handle 0 duration properly |
|
float duration = (moveDuration > 0f) ? moveDuration : float.Epsilon; |
|
|
|
// LeanTween.move uses the anchoredPosition, so all position images must have the same anchor position |
|
LeanTween.move(character.state.portraitImage.gameObject, toPosition.position, duration).setEase(stage.fadeEaseType); |
|
if (waitUntilFinished) |
|
{ |
|
waitTimer = duration; |
|
} |
|
} |
|
|
|
public static void SetDimmed(Character character, Stage stage, bool dimmedState) |
|
{ |
|
if (character.state.dimmed == dimmedState) |
|
{ |
|
return; |
|
} |
|
|
|
character.state.dimmed = dimmedState; |
|
|
|
Color targetColor = dimmedState ? new Color(0.5f, 0.5f, 0.5f, 1f) : Color.white; |
|
|
|
// LeanTween doesn't handle 0 duration properly |
|
float duration = (stage.fadeDuration > 0f) ? stage.fadeDuration : float.Epsilon; |
|
|
|
LeanTween.color(character.state.portraitImage.rectTransform, targetColor, duration).setEase(stage.fadeEaseType); |
|
} |
|
|
|
public override string GetSummary() |
|
{ |
|
if (display == DisplayType.None && character == null) |
|
{ |
|
return "Error: No character or display selected"; |
|
} |
|
else if (display == DisplayType.None) |
|
{ |
|
return "Error: No display selected"; |
|
} |
|
else if (character == null) |
|
{ |
|
return "Error: No character selected"; |
|
} |
|
|
|
string displaySummary = ""; |
|
string characterSummary = ""; |
|
string fromPositionSummary = ""; |
|
string toPositionSummary = ""; |
|
string stageSummary = ""; |
|
string portraitSummary = ""; |
|
string facingSummary = ""; |
|
|
|
displaySummary = StringFormatter.SplitCamelCase(display.ToString()); |
|
|
|
if (display == DisplayType.Replace) |
|
{ |
|
if (replacedCharacter != null) |
|
{ |
|
displaySummary += " \"" + replacedCharacter.name + "\" with"; |
|
} |
|
} |
|
|
|
characterSummary = character.name; |
|
if (stage != null) |
|
{ |
|
stageSummary = " on \"" + stage.name + "\""; |
|
} |
|
|
|
if (portrait != null) |
|
{ |
|
portraitSummary = " " + portrait.name; |
|
} |
|
|
|
if (shiftIntoPlace) |
|
{ |
|
if (offset != 0) |
|
{ |
|
fromPositionSummary = offset.ToString(); |
|
fromPositionSummary = " from " + "\"" + fromPositionSummary + "\""; |
|
} |
|
} |
|
else if (fromPosition != null) |
|
{ |
|
fromPositionSummary = " from " + "\"" + fromPosition.name + "\""; |
|
} |
|
|
|
if (toPosition != null) |
|
{ |
|
string toPositionPrefixSummary = ""; |
|
if (move) |
|
{ |
|
toPositionPrefixSummary = " to "; |
|
} |
|
else |
|
{ |
|
toPositionPrefixSummary = " at "; |
|
} |
|
|
|
toPositionSummary = toPositionPrefixSummary + "\"" + toPosition.name + "\""; |
|
} |
|
|
|
if (facing != FacingDirection.None) |
|
{ |
|
if (facing == FacingDirection.Left) |
|
{ |
|
facingSummary = "<--"; |
|
} |
|
if (facing == FacingDirection.Right) |
|
{ |
|
facingSummary = "-->"; |
|
} |
|
|
|
facingSummary = " facing \"" + facingSummary + "\""; |
|
} |
|
|
|
return displaySummary + " \"" + characterSummary + portraitSummary + "\"" + stageSummary + facingSummary + fromPositionSummary + toPositionSummary; |
|
} |
|
|
|
public override Color GetButtonColor() |
|
{ |
|
return new Color32(230, 200, 250, 255); |
|
} |
|
|
|
public override void OnCommandAdded(Block parentBlock) |
|
{ |
|
//Default to display type: show |
|
display = DisplayType.Show; |
|
} |
|
} |
|
} |