Browse Source

Portrait reworked to store all

Character PortraitState now contains all the all character portraits underneath a single container object, at all times. The holder moves and the individual portraits fade in and out. Previous method created and destroyed as needed and was susceptible to the 'white square' UI Image bug.
master
shalliwell 5 years ago
parent
commit
fa7105ffac
  1. 2
      Assets/Fungus/Scripts/Commands/Portrait.cs
  2. 386
      Assets/Fungus/Scripts/Components/PortraitController.cs
  3. 2
      Assets/Fungus/Scripts/Components/Stage.cs
  4. 11
      Assets/Fungus/Scripts/Utils/PortraitUtils.cs

2
Assets/Fungus/Scripts/Commands/Portrait.cs

@ -116,7 +116,7 @@ namespace Fungus
if (stage == null)
{
// If no default specified, try to get any portrait stage in the scene
stage = FindObjectOfType<Stage>();
stage = Stage.GetActiveStage();
// If portrait stage does not exist, do nothing
if (stage == null)
{

386
Assets/Fungus/Scripts/Components/PortraitController.cs

@ -52,8 +52,13 @@ namespace Fungus
OffsetRight
}
[AddComponentMenu("")]
/// <summary>
/// Controls the Portrait sprites on stage
/// Controls the Portrait sprites on stage.
///
/// Is only really used via Stage, it's child class. This class continues to exist to support existing API
/// dependant code. All functionality is stage dependant.
/// </summary>
public class PortraitController : MonoBehaviour
{
@ -104,7 +109,7 @@ namespace Fungus
// if no previous portrait, use default portrait
if (options.character.State.portrait == null)
{
options.character.State.portrait = options.character.ProfileSprite;
options.character.State.SetPortraitImageBySprite(options.character.ProfileSprite);
}
// Selected "use previous portrait"
@ -184,29 +189,55 @@ namespace Fungus
/// <param name="fadeDuration"></param>
protected virtual void CreatePortraitObject(Character character, float fadeDuration)
{
// 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.overrideSprite = character.ProfileSprite;
portraitImage.color = new Color(1f, 1f, 1f, 0f);
if (character.State.holder == null)
{
character.State.holder = new GameObject(character.name + " holder",
typeof(RectTransform)
//typeof(CanvasRenderer),
//typeof(Image)
).GetComponent<RectTransform>();
// LeanTween doesn't handle 0 duration properly
float duration = (fadeDuration > 0f) ? fadeDuration : float.Epsilon;
// Set it to be a child of the stage
character.State.holder.transform.SetParent(stage.PortraitCanvas.transform, false);
// Fade in character image (first time)
LeanTween.alpha(portraitImage.transform as RectTransform, 1f, duration).setEase(stage.FadeEaseType).setRecursive(false);
SetRectTransform(character.State.holder, stage.DefaultPosition.GetComponent<RectTransform>());
}
// Tell character about portrait image
character.State.portraitImage = portraitImage;
if (character.State.allPortraits.Count == 0)
{
foreach (var item in character.Portraits)
{
// Create a new portrait object
GameObject po = new GameObject(item.name,
typeof(RectTransform),
typeof(CanvasRenderer),
typeof(Image));
// Set it to be a child of the stage
po.transform.SetParent(character.State.holder, false);
// Configure the portrait image
Image pi = po.GetComponent<Image>();
pi.preserveAspect = true;
pi.sprite = item;
pi.color = new Color(1f, 1f, 1f, 0f);
if (item == character.ProfileSprite)
{
character.State.portraitImage = pi;
}
//expand to fit parent
RectTransform rt = po.GetComponent<RectTransform>();
rt.sizeDelta = Vector2.zero;
rt.anchorMin = Vector2.zero;
rt.anchorMax = Vector2.one;
rt.pivot = Vector2.one * 0.5f;
rt.ForceUpdateRectTransforms();
character.State.allPortraits.Add(pi);
}
}
}
protected virtual IEnumerator WaitUntilFinished(float duration, Action onComplete = null)
@ -232,39 +263,30 @@ namespace Fungus
protected virtual void SetupPortrait(PortraitOptions options)
{
SetRectTransform(options.character.State.portraitImage.rectTransform, options.fromPosition);
if (options.character.State.holder == null)
return;
SetRectTransform(options.character.State.holder, options.fromPosition);
if (options.character.State.facing != options.character.PortraitsFace)
{
options.character.State.portraitImage.rectTransform.localScale = new Vector3(-1f, 1f, 1f);
options.character.State.holder.localScale = new Vector3(-1f, 1f, 1f);
}
else
{
options.character.State.portraitImage.rectTransform.localScale = new Vector3(1f, 1f, 1f);
options.character.State.holder.localScale = new Vector3(1f, 1f, 1f);
}
if (options.facing != options.character.PortraitsFace)
{
options.character.State.portraitImage.rectTransform.localScale = new Vector3(-1f, 1f, 1f);
options.character.State.holder.localScale = new Vector3(-1f, 1f, 1f);
}
else
{
options.character.State.portraitImage.rectTransform.localScale = new Vector3(1f, 1f, 1f);
options.character.State.holder.localScale = new Vector3(1f, 1f, 1f);
}
}
protected virtual void DoMoveTween(Character character, RectTransform fromPosition, RectTransform toPosition, float moveDuration, Boolean waitUntilFinished)
{
PortraitOptions options = new PortraitOptions(true);
options.character = character;
options.fromPosition = fromPosition;
options.toPosition = toPosition;
options.moveDuration = moveDuration;
options.waitUntilFinished = waitUntilFinished;
DoMoveTween(options);
}
protected virtual void DoMoveTween(PortraitOptions options)
{
CleanPortraitOptions(options);
@ -273,7 +295,8 @@ namespace Fungus
float duration = (options.moveDuration > 0f) ? options.moveDuration : float.Epsilon;
// LeanTween.move uses the anchoredPosition, so all position images must have the same anchor position
LeanTween.move(options.character.State.portraitImage.gameObject, options.toPosition.position, duration).setEase(stage.FadeEaseType);
LeanTween.move(options.character.State.holder.gameObject, options.toPosition.position, duration)
.setEase(stage.FadeEaseType);
if (options.waitUntilFinished)
{
@ -281,22 +304,20 @@ namespace Fungus
}
}
#region Public members
/// <summary>
/// Performs a deep copy of all values from one RectTransform to another.
/// </summary>
public static void SetRectTransform(RectTransform oldRectTransform, RectTransform newRectTransform)
public static void SetRectTransform(RectTransform target, RectTransform from)
{
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;
target.eulerAngles = from.eulerAngles;
target.position = from.position;
target.rotation = from.rotation;
target.anchoredPosition = from.anchoredPosition;
target.sizeDelta = from.sizeDelta;
target.anchorMax = from.anchorMax;
target.anchorMin = from.anchorMin;
target.pivot = from.pivot;
target.localScale = from.localScale;
}
/// <summary>
@ -354,17 +375,7 @@ namespace Fungus
}
}
/// <summary>
/// Moves Character in front of other characters on stage
/// </summary>
public virtual void MoveToFront(Character character)
{
PortraitOptions options = new PortraitOptions(true);
options.character = character;
MoveToFront(CleanPortraitOptions(options));
}
/// <summary>
/// Moves Character in front of other characters on stage
/// </summary>
@ -375,51 +386,6 @@ namespace Fungus
FinishCommand(options);
}
/// <summary>
/// Shows character at a named position in the stage
/// </summary>
/// <param name="character"></param>
/// <param name="position">Named position on stage</param>
public virtual void Show(Character character, string position)
{
PortraitOptions options = new PortraitOptions(true);
options.character = character;
options.fromPosition = options.toPosition = stage.GetPosition(position);
Show(options);
}
/// <summary>
/// Shows character moving from a position to a position
/// </summary>
/// <param name="character"></param>
/// <param name="portrait"></param>
/// <param name="fromPosition">Where the character will appear</param>
/// <param name="toPosition">Where the character will move to</param>
public virtual void Show(Character character, string portrait, string fromPosition, string toPosition)
{
PortraitOptions options = new PortraitOptions(true);
options.character = character;
options.portrait = character.GetPortrait(portrait);
options.fromPosition = stage.GetPosition(fromPosition);
options.toPosition = stage.GetPosition(toPosition);
options.move = true;
Show(options);
}
/// <summary>
/// From lua, you can pass an options table with named arguments
/// example:
/// stage.show{character=jill, portrait="happy", fromPosition="right", toPosition="left"}
/// Any option available in the PortraitOptions is available from Lua
/// </summary>
/// <param name="optionsTable">Moonsharp Table</param>
public virtual void Show(Table optionsTable)
{
Show(PortraitUtil.ConvertTableToPortraitOptions(optionsTable, stage));
}
/// <summary>
/// Show portrait with the supplied portrait options
/// </summary>
@ -454,40 +420,18 @@ namespace Fungus
// LeanTween doesn't handle 0 duration properly
float duration = (options.fadeDuration > 0f) ? options.fadeDuration : float.Epsilon;
// Fade out a duplicate of the existing portrait image
if (options.character.State.portraitImage != null && options.character.State.portraitImage.overrideSprite != null)
{
GameObject tempGO = GameObject.Instantiate(options.character.State.portraitImage.gameObject);
//Fix for white box issue introduced by unity UI circa 2019.1
for (int i = 0; i < tempGO.transform.childCount; i++)
{
DestroyImmediate(tempGO.transform.GetChild(i).gameObject);
}
tempGO.transform.SetParent(options.character.State.portraitImage.transform, false);
tempGO.transform.localPosition = Vector3.zero;
tempGO.transform.localScale = options.character.State.position.localScale;
Image tempImage = tempGO.GetComponent<Image>();
tempImage.overrideSprite = options.character.State.portraitImage.overrideSprite;
tempImage.preserveAspect = true;
tempImage.color = options.character.State.portraitImage.color;
var prevPortrait = options.character.State.portrait;
LeanTween.alpha(tempImage.rectTransform, 0f, duration).setEase(stage.FadeEaseType).setOnComplete(() => {
Destroy(tempGO);
}).setRecursive(false);
}
// Fade in the new sprite image
if (options.character.State.portraitImage.overrideSprite != options.portrait ||
options.character.State.portraitImage.color.a < 1f)
if (options.character.State.portrait != null && options.character.State.portrait != options.portrait)
{
options.character.State.portraitImage.overrideSprite = options.portrait;
options.character.State.portraitImage.color = new Color(1f, 1f, 1f, 0f);
LeanTween.alpha(options.character.State.portraitImage.rectTransform, 1f, duration).setEase(stage.FadeEaseType).setRecursive(false);
LeanTween.alpha(options.character.State.portraitImage.rectTransform, 0f, duration)
.setEase(stage.FadeEaseType)
.setRecursive(false);
}
options.character.State.SetPortraitImageBySprite(options.portrait);
LeanTween.alpha(options.character.State.portraitImage.rectTransform, 1f, duration).setEase(stage.FadeEaseType).setRecursive(false);
DoMoveTween(options);
FinishCommand(options);
@ -497,14 +441,117 @@ namespace Fungus
stage.CharactersOnStage.Add(options.character);
}
MoveToFront(options);
// Update character state after showing
options.character.State.onScreen = true;
options.character.State.display = DisplayType.Show;
options.character.State.portrait = options.portrait;
options.character.State.facing = options.facing;
options.character.State.position = options.toPosition;
}
/// <summary>
/// Hide portrait with provided options
/// </summary>
public virtual void Hide(PortraitOptions options)
{
CleanPortraitOptions(options);
if (options.character.State.display == DisplayType.None)
{
return;
}
SetupPortrait(options);
// LeanTween doesn't handle 0 duration properly
float duration = (options.fadeDuration > 0f) ? options.fadeDuration : float.Epsilon;
LeanTween.alpha(options.character.State.portraitImage.rectTransform, 0f, duration).setEase(stage.FadeEaseType).setRecursive(false);
DoMoveTween(options);
//update character state after hiding
options.character.State.onScreen = false;
options.character.State.facing = options.facing;
options.character.State.position = options.toPosition;
options.character.State.display = DisplayType.Hide;
if (stage.CharactersOnStage.Remove(options.character))
{
}
FinishCommand(options);
}
/// <summary>
/// Sets the dimmed state of a character on the stage.
/// </summary>
public virtual void SetDimmed(Character character, bool dimmedState)
{
if (character.State.dimmed == dimmedState)
{
return;
}
character.State.dimmed = dimmedState;
Color targetColor = dimmedState ? stage.DimColor : 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).setRecursive(false);
}
#region Overloads and Helpers
/// <summary>
/// Shows character at a named position in the stage
/// </summary>
/// <param name="character"></param>
/// <param name="position">Named position on stage</param>
public virtual void Show(Character character, string position)
{
PortraitOptions options = new PortraitOptions(true);
options.character = character;
options.fromPosition = options.toPosition = stage.GetPosition(position);
Show(options);
}
/// <summary>
/// Shows character moving from a position to a position
/// </summary>
/// <param name="character"></param>
/// <param name="portrait"></param>
/// <param name="fromPosition">Where the character will appear</param>
/// <param name="toPosition">Where the character will move to</param>
public virtual void Show(Character character, string portrait, string fromPosition, string toPosition)
{
PortraitOptions options = new PortraitOptions(true);
options.character = character;
options.portrait = character.GetPortrait(portrait);
options.fromPosition = stage.GetPosition(fromPosition);
options.toPosition = stage.GetPosition(toPosition);
options.move = true;
Show(options);
}
/// <summary>
/// From lua, you can pass an options table with named arguments
/// example:
/// stage.show{character=jill, portrait="happy", fromPosition="right", toPosition="left"}
/// Any option available in the PortraitOptions is available from Lua
/// </summary>
/// <param name="optionsTable">Moonsharp Table</param>
public virtual void Show(Table optionsTable)
{
Show(PortraitUtil.ConvertTableToPortraitOptions(optionsTable, stage));
}
/// <summary>
/// Simple show command that shows the character with an available named portrait
/// </summary>
@ -566,60 +613,31 @@ namespace Fungus
{
Hide(PortraitUtil.ConvertTableToPortraitOptions(optionsTable, stage));
}
/// <summary>
/// Hide portrait with provided options
/// Moves Character in front of other characters on stage
/// </summary>
public virtual void Hide(PortraitOptions options)
public virtual void MoveToFront(Character character)
{
CleanPortraitOptions(options);
if (options.character.State.display == DisplayType.None)
{
return;
}
SetupPortrait(options);
// LeanTween doesn't handle 0 duration properly
float duration = (options.fadeDuration > 0f) ? options.fadeDuration : float.Epsilon;
LeanTween.alpha(options.character.State.portraitImage.rectTransform, 0f, duration).setEase(stage.FadeEaseType).setRecursive(false);
DoMoveTween(options);
stage.CharactersOnStage.Remove(options.character);
//update character state after hiding
options.character.State.onScreen = false;
options.character.State.portrait = options.portrait;
options.character.State.facing = options.facing;
options.character.State.position = options.toPosition;
options.character.State.display = DisplayType.Hide;
PortraitOptions options = new PortraitOptions(true);
options.character = character;
FinishCommand(options);
MoveToFront(CleanPortraitOptions(options));
}
/// <summary>
/// Sets the dimmed state of a character on the stage.
/// </summary>
public virtual void SetDimmed(Character character, bool dimmedState)
{
if (character.State.dimmed == dimmedState)
{
return;
}
character.State.dimmed = dimmedState;
Color targetColor = dimmedState ? stage.DimColor : Color.white;
// LeanTween doesn't handle 0 duration properly
float duration = (stage.FadeDuration > 0f) ? stage.FadeDuration : float.Epsilon;
protected virtual void DoMoveTween(Character character, RectTransform fromPosition, RectTransform toPosition, float moveDuration, Boolean waitUntilFinished)
{
PortraitOptions options = new PortraitOptions(true);
options.character = character;
options.fromPosition = fromPosition;
options.toPosition = toPosition;
options.moveDuration = moveDuration;
options.waitUntilFinished = waitUntilFinished;
LeanTween.color(character.State.portraitImage.rectTransform, targetColor, duration).setEase(stage.FadeEaseType).setRecursive(false);
DoMoveTween(options);
}
#endregion
#endregion
}
}

2
Assets/Fungus/Scripts/Components/Stage.cs

@ -9,7 +9,7 @@ using System.Collections.Generic;
namespace Fungus
{
/// <summary>
/// Define a set of screen positions where character sprites can be displayed.
/// Define a set of screen positions where character sprites can be displayed and controls portraits.
/// </summary>
[ExecuteInEditMode]
public class Stage : PortraitController

11
Assets/Fungus/Scripts/Utils/PortraitUtils.cs

@ -4,6 +4,7 @@
using UnityEngine;
using UnityEngine.UI;
using MoonSharp.Interpreter;
using System.Collections.Generic;
namespace Fungus
{
@ -60,10 +61,16 @@ namespace Fungus
public bool onScreen;
public bool dimmed;
public DisplayType display;
public Sprite portrait;
public RectTransform position;
public RectTransform position, holder;
public FacingDirection facing;
public Image portraitImage;
public Sprite portrait { get { return portraitImage != null ? portraitImage.sprite : null; } }
public List<Image> allPortraits = new List<Image>();
public void SetPortraitImageBySprite(Sprite portrait)
{
portraitImage = allPortraits.Find(x => x.sprite == portrait);
}
}
/// <summary>

Loading…
Cancel
Save