Browse Source

Merge branch 'develop' of https://github.com/snozbot/fungus into multiple_logical_conditions

master
vjs22334 5 years ago
parent
commit
4e5c56623b
  1. 1
      .gitignore
  2. 4
      Assets/Fungus/Scripts/Commands/FadeScreen.cs
  3. 7
      Assets/Fungus/Scripts/Commands/FadeToView.cs
  4. 6
      Assets/Fungus/Scripts/Commands/MoveToView.cs
  5. 8
      Assets/Fungus/Scripts/Commands/Property/AnimatorProperty.cs
  6. 2
      Assets/Fungus/Scripts/Commands/Property/Collision2DProperty.cs
  7. 2
      Assets/Fungus/Scripts/Commands/Property/QuaternionProperty.cs
  8. 2
      Assets/Fungus/Scripts/Commands/Property/TextureProperty.cs
  9. 7
      Assets/Fungus/Scripts/Components/Block.cs
  10. 257
      Assets/Fungus/Scripts/Components/CameraManager.cs
  11. 2
      Assets/Fungus/Scripts/Components/Draggable2D.cs
  12. 17
      Assets/Fungus/Scripts/Components/Flowchart.cs
  13. 54
      Assets/Fungus/Scripts/Components/Writer.cs
  14. 4
      Assets/Fungus/Scripts/Components/WriterAudio.cs
  15. 3
      Assets/Fungus/Scripts/Editor/CustomVariableDrawerLookup.cs
  16. 16
      Assets/Fungus/Scripts/Editor/EditorZoomArea.cs
  17. 201
      Assets/Fungus/Scripts/Editor/FlowchartWindow.cs
  18. 5
      Assets/Fungus/Scripts/Editor/FungusEditorPreferences.cs
  19. 13
      Assets/Fungus/Scripts/Editor/VariableEditor.cs
  20. 59
      Assets/Fungus/Scripts/EventHandlers/DragCancelled.cs
  21. 156
      Assets/Fungus/Scripts/EventHandlers/DragCompleted.cs
  22. 114
      Assets/Fungus/Scripts/EventHandlers/DragEntered.cs
  23. 111
      Assets/Fungus/Scripts/EventHandlers/DragExited.cs
  24. 61
      Assets/Fungus/Scripts/EventHandlers/DragStarted.cs
  25. 13
      Assets/Fungus/Scripts/Interfaces/IWriterListener.cs
  26. 12
      Assets/Fungus/Scripts/VariableTypes/Collection/Collection.cs
  27. 2
      Assets/Fungus/Scripts/VariableTypes/Collection/GenericCollection.cs
  28. 12
      Assets/Fungus/Scripts/VariableTypes/Vector2Variable.cs
  29. 1635
      Assets/FungusExamples/DragAndDrop/DragandDrop(DraggableObjectLists).unity
  30. 7
      Assets/FungusExamples/DragAndDrop/DragandDrop(DraggableObjectLists).unity.meta
  31. 6613
      Assets/FungusExamples/FungusTown/FungusTown.unity
  32. 2298
      Assets/FungusExamples/TheHunter/TheHunter.unity
  33. 2
      Assets/Tests/PlayMode/FungusPlayModeTest.cs
  34. 4
      ProjectSettings/ProjectVersion.txt

1
.gitignore vendored

@ -17,3 +17,4 @@ UWP/*
Assets/Plugins/ Assets/Plugins/
Assets/Plugins.meta Assets/Plugins.meta
Logs/* Logs/*
.vscode/launch.json

4
Assets/Fungus/Scripts/Commands/FadeScreen.cs

@ -31,6 +31,8 @@ namespace Fungus
[Tooltip("Optional texture to use when rendering the fullscreen fade effect.")] [Tooltip("Optional texture to use when rendering the fullscreen fade effect.")]
[SerializeField] protected Texture2D fadeTexture; [SerializeField] protected Texture2D fadeTexture;
[SerializeField] protected LeanTweenType fadeTweenType = LeanTweenType.easeInOutQuad;
#region Public members #region Public members
public override void OnEnter() public override void OnEnter()
@ -51,7 +53,7 @@ namespace Fungus
{ {
Continue(); Continue();
} }
}); }, fadeTweenType);
if (!waitUntilFinished) if (!waitUntilFinished)
{ {

7
Assets/Fungus/Scripts/Commands/FadeToView.cs

@ -35,6 +35,11 @@ namespace Fungus
[Tooltip("Camera to use for the fade. Will use main camera if set to none.")] [Tooltip("Camera to use for the fade. Will use main camera if set to none.")]
[SerializeField] protected Camera targetCamera; [SerializeField] protected Camera targetCamera;
[SerializeField] protected LeanTweenType fadeTweenType = LeanTweenType.easeInOutQuad;
[SerializeField] protected LeanTweenType orthoSizeTweenType = LeanTweenType.easeInOutQuad;
[SerializeField] protected LeanTweenType posTweenType = LeanTweenType.easeInOutQuad;
[SerializeField] protected LeanTweenType rotTweenType = LeanTweenType.easeInOutQuad;
protected virtual void Start() protected virtual void Start()
{ {
AcquireCamera(); AcquireCamera();
@ -87,7 +92,7 @@ namespace Fungus
{ {
Continue(); Continue();
} }
}); }, fadeTweenType, orthoSizeTweenType, posTweenType, rotTweenType);
if (!waitUntilFinished) if (!waitUntilFinished)
{ {

6
Assets/Fungus/Scripts/Commands/MoveToView.cs

@ -27,6 +27,10 @@ namespace Fungus
[Tooltip("Camera to use for the pan. Will use main camera if set to none.")] [Tooltip("Camera to use for the pan. Will use main camera if set to none.")]
[SerializeField] protected Camera targetCamera; [SerializeField] protected Camera targetCamera;
[SerializeField] protected LeanTweenType orthoSizeTweenType = LeanTweenType.easeInOutQuad;
[SerializeField] protected LeanTweenType posTweenType = LeanTweenType.easeInOutQuad;
[SerializeField] protected LeanTweenType rotTweenType = LeanTweenType.easeInOutQuad;
protected virtual void AcquireCamera() protected virtual void AcquireCamera()
{ {
if (targetCamera != null) if (targetCamera != null)
@ -69,7 +73,7 @@ namespace Fungus
{ {
Continue(); Continue();
} }
}); }, orthoSizeTweenType, posTweenType, rotTweenType);
if (!waitUntilFinished) if (!waitUntilFinished)
{ {

8
Assets/Fungus/Scripts/Commands/Property/AnimatorProperty.cs

@ -191,9 +191,11 @@ namespace Fungus
case Property.FireEvents: case Property.FireEvents:
iob.Value = target.fireEvents; iob.Value = target.fireEvents;
break; break;
case Property.KeepAnimatorControllerStateOnDisable: #if UNITY_2019_2_OR_NEWER
case Property.KeepAnimatorControllerStateOnDisable:
iob.Value = target.keepAnimatorControllerStateOnDisable; iob.Value = target.keepAnimatorControllerStateOnDisable;
break; break;
#endif
default: default:
Debug.Log("Unsupported get or set attempted"); Debug.Log("Unsupported get or set attempted");
break; break;
@ -245,10 +247,12 @@ namespace Fungus
case Property.FireEvents: case Property.FireEvents:
target.fireEvents = iob.Value; target.fireEvents = iob.Value;
break; break;
#if UNITY_2019_2_OR_NEWER
case Property.KeepAnimatorControllerStateOnDisable: case Property.KeepAnimatorControllerStateOnDisable:
target.keepAnimatorControllerStateOnDisable = iob.Value; target.keepAnimatorControllerStateOnDisable = iob.Value;
break; break;
default: #endif
default:
Debug.Log("Unsupported get or set attempted"); Debug.Log("Unsupported get or set attempted");
break; break;
} }

2
Assets/Fungus/Scripts/Commands/Property/Collision2DProperty.cs

@ -87,9 +87,11 @@ namespace Fungus
case Property.Enabled: case Property.Enabled:
iob.Value = target.enabled; iob.Value = target.enabled;
break; break;
#if UNITY_2019_2_OR_NEWER
case Property.ContactCount: case Property.ContactCount:
ioi.Value = target.contactCount; ioi.Value = target.contactCount;
break; break;
#endif
default: default:
Debug.Log("Unsupported get or set attempted"); Debug.Log("Unsupported get or set attempted");
break; break;

2
Assets/Fungus/Scripts/Commands/Property/QuaternionProperty.cs

@ -66,9 +66,11 @@ namespace Fungus
case Property.EulerAngles: case Property.EulerAngles:
iov.Value = target.eulerAngles; iov.Value = target.eulerAngles;
break; break;
#if UNITY_2019_2_OR_NEWER
case Property.Normalized: case Property.Normalized:
ioq.Value = target.normalized; ioq.Value = target.normalized;
break; break;
#endif
default: default:
Debug.Log("Unsupported get or set attempted"); Debug.Log("Unsupported get or set attempted");
break; break;

2
Assets/Fungus/Scripts/Commands/Property/TextureProperty.cs

@ -60,9 +60,11 @@ namespace Fungus
case Property.Height: case Property.Height:
ioi.Value = target.height; ioi.Value = target.height;
break; break;
#if UNITY_2019_2_OR_NEWER
case Property.IsReadable: case Property.IsReadable:
iob.Value = target.isReadable; iob.Value = target.isReadable;
break; break;
#endif
case Property.AnisoLevel: case Property.AnisoLevel:
ioi.Value = target.anisoLevel; ioi.Value = target.anisoLevel;
break; break;

7
Assets/Fungus/Scripts/Components/Block.cs

@ -375,6 +375,12 @@ namespace Fungus
public virtual List<Block> GetConnectedBlocks() public virtual List<Block> GetConnectedBlocks()
{ {
var connectedBlocks = new List<Block>(); var connectedBlocks = new List<Block>();
GetConnectedBlocks(ref connectedBlocks);
return connectedBlocks;
}
public virtual void GetConnectedBlocks(ref List<Block> connectedBlocks)
{
for (int i = 0; i < commandList.Count; i++) for (int i = 0; i < commandList.Count; i++)
{ {
var command = commandList[i]; var command = commandList[i];
@ -383,7 +389,6 @@ namespace Fungus
command.GetConnectedBlocks(ref connectedBlocks); command.GetConnectedBlocks(ref connectedBlocks);
} }
} }
return connectedBlocks;
} }
/// <summary> /// <summary>

257
Assets/Fungus/Scripts/Components/CameraManager.cs

@ -43,8 +43,7 @@ namespace Fungus
protected Vector3 previousMousePos; protected Vector3 previousMousePos;
//Coroutine handles for panning and fading commands //Coroutine handles for panning and fading commands
protected IEnumerator panCoroutine; protected LTDescr fadeTween, sizeTween, camPosTween, camRotTween;
protected IEnumerator fadeCoroutine;
protected class CameraView protected class CameraView
{ {
@ -89,122 +88,6 @@ namespace Fungus
} }
} }
protected virtual IEnumerator FadeInternal(float targetAlpha, float fadeDuration, Action fadeAction)
{
float startAlpha = fadeAlpha;
float timer = 0;
// If already at the target alpha then complete immediately
if (Mathf.Approximately(startAlpha, targetAlpha))
{
yield return null;
}
else
{
while (timer < fadeDuration)
{
float t = timer / fadeDuration;
timer += Time.deltaTime;
t = Mathf.Clamp01(t);
fadeAlpha = Mathf.Lerp(startAlpha, targetAlpha, t);
yield return null;
}
}
fadeAlpha = targetAlpha;
if (fadeAction != null)
{
fadeAction();
}
}
protected virtual IEnumerator PanInternal(Camera camera, Vector3 targetPos, Quaternion targetRot, float targetSize, float duration, Action arriveAction)
{
if (camera == null)
{
Debug.LogWarning("Camera is null");
yield break;
}
float timer = 0;
float startSize = camera.orthographicSize;
float endSize = targetSize;
Vector3 startPos = camera.transform.position;
Vector3 endPos = targetPos;
Quaternion startRot = camera.transform.rotation;
Quaternion endRot = targetRot;
bool arrived = false;
while (!arrived)
{
timer += Time.deltaTime;
if (timer > duration)
{
arrived = true;
timer = duration;
}
// Apply smoothed lerp to camera position and orthographic size
float t = 1f;
if (duration > 0f)
{
t = timer / duration;
}
if (camera != null)
{
camera.orthographicSize = Mathf.Lerp(startSize, endSize, Mathf.SmoothStep(0f, 1f, t));
camera.transform.position = Vector3.Lerp(startPos, endPos, Mathf.SmoothStep(0f, 1f, t));
camera.transform.rotation = Quaternion.Lerp(startRot, endRot, Mathf.SmoothStep(0f, 1f, t));
SetCameraZ(camera);
}
if (arrived &&
arriveAction != null)
{
arriveAction();
}
yield return null;
}
}
protected virtual IEnumerator PanToPathInternal(Camera camera, float duration, Action arriveAction, Vector3[] path)
{
if (camera == null)
{
Debug.LogWarning("Camera is null");
yield break;
}
float timer = 0;
while (timer < duration)
{
timer += Time.deltaTime;
timer = Mathf.Min(timer, duration);
float percent = timer / duration;
Vector3 point = iTween.PointOnPath(path, percent);
camera.transform.position = new Vector3(point.x, point.y, 0);
camera.orthographicSize = point.z;
SetCameraZ(camera);
yield return null;
}
if (arriveAction != null)
{
arriveAction();
}
}
protected virtual void SetCameraZ(Camera camera) protected virtual void SetCameraZ(Camera camera)
{ {
if (!setCameraZ) if (!setCameraZ)
@ -304,40 +187,6 @@ namespace Fungus
#region Public members #region Public members
/// <summary>
/// Moves camera smoothly through a sequence of Views over a period of time.
/// </summary>
public virtual void PanToPath(Camera camera, View[] viewList, float duration, Action arriveAction)
{
if (camera == null)
{
Debug.LogWarning("Camera is null");
return;
}
swipePanActive = false;
List<Vector3> pathList = new List<Vector3>();
// Add current camera position as first point in path
// Note: We use the z coord to tween the camera orthographic size
Vector3 startPos = new Vector3(camera.transform.position.x,
camera.transform.position.y,
camera.orthographicSize);
pathList.Add(startPos);
for (int i = 0; i < viewList.Length; ++i)
{
View view = viewList[i];
Vector3 viewPos = new Vector3(view.transform.position.x,
view.transform.position.y,
view.ViewSize);
pathList.Add(viewPos);
}
StartCoroutine(panCoroutine = PanToPathInternal (camera, duration, arriveAction, pathList.ToArray ()));
}
/// <summary> /// <summary>
/// Creates a flat colored texture. /// Creates a flat colored texture.
/// </summary> /// </summary>
@ -364,15 +213,35 @@ namespace Fungus
/// <summary> /// <summary>
/// Perform a fullscreen fade over a duration. /// Perform a fullscreen fade over a duration.
/// </summary> /// </summary>
public virtual void Fade(float targetAlpha, float fadeDuration, Action fadeAction) public virtual void Fade(float targetAlpha, float fadeDuration, Action fadeAction, LeanTweenType leanTweenType = LeanTweenType.easeInOutQuad)
{ {
StartCoroutine(fadeCoroutine = FadeInternal (targetAlpha, fadeDuration, fadeAction)); StopFadeTween();
if (Mathf.Approximately(fadeDuration, 0))
{
fadeAlpha = targetAlpha;
if (fadeAction != null) fadeAction();
}
else
{
fadeTween = LeanTween.value(fadeAlpha, targetAlpha, fadeDuration)
.setEase(leanTweenType)
.setOnUpdate((x) => fadeAlpha = x)
.setOnComplete(() =>
{
fadeAlpha = targetAlpha;
if (fadeAction != null) fadeAction();
fadeTween = null;
});
}
} }
/// <summary> /// <summary>
/// Fade out, move camera to view and then fade back in. /// Fade out, move camera to view and then fade back in.
/// </summary> /// </summary>
public virtual void FadeToView(Camera camera, View view, float fadeDuration, bool fadeOut, Action fadeAction) public virtual void FadeToView(Camera camera, View view, float fadeDuration, bool fadeOut, Action fadeAction,
LeanTweenType fadeType = LeanTweenType.easeInOutQuad, LeanTweenType sizeTweenType = LeanTweenType.easeInOutQuad,
LeanTweenType posTweenType = LeanTweenType.easeInOutQuad, LeanTweenType rotTweenType = LeanTweenType.easeInOutQuad)
{ {
swipePanActive = false; swipePanActive = false;
fadeAlpha = 0f; fadeAlpha = 0f;
@ -395,7 +264,7 @@ namespace Fungus
Fade(1f, outDuration, delegate { Fade(1f, outDuration, delegate {
// Snap to new view // Snap to new view
PanToPosition(camera, view.transform.position, view.transform.rotation, view.ViewSize, 0f, null); PanToPosition(camera, view.transform.position, view.transform.rotation, view.ViewSize, 0f, null, sizeTweenType, posTweenType, rotTweenType);
// Fade in // Fade in
Fade(0f, inDuration, delegate { Fade(0f, inDuration, delegate {
@ -403,8 +272,8 @@ namespace Fungus
{ {
fadeAction(); fadeAction();
} }
}); }, fadeType);
}); }, fadeType);
} }
/// <summary> /// <summary>
@ -412,15 +281,43 @@ namespace Fungus
/// </summary> /// </summary>
public virtual void Stop() public virtual void Stop()
{ {
StopAllCoroutines(); StopFadeTween();
panCoroutine = null; StopPosTweens();
fadeCoroutine = null; }
protected void StopFadeTween()
{
if (fadeTween != null)
{
LeanTween.cancel(fadeTween.id, true);
fadeTween = null;
}
}
protected void StopPosTweens()
{
if (sizeTween != null)
{
LeanTween.cancel(sizeTween.id, true);
sizeTween = null;
}
if (camPosTween != null)
{
LeanTween.cancel(camPosTween.id, true);
camPosTween = null;
}
if (camRotTween != null)
{
LeanTween.cancel(camRotTween.id, true);
camRotTween = null;
}
} }
/// <summary> /// <summary>
/// Moves camera from current position to a target position over a period of time. /// Moves camera from current position to a target position over a period of time.
/// </summary> /// </summary>
public virtual void PanToPosition(Camera camera, Vector3 targetPosition, Quaternion targetRotation, float targetSize, float duration, Action arriveAction) public virtual void PanToPosition(Camera camera, Vector3 targetPosition, Quaternion targetRotation, float targetSize, float duration, Action arriveAction,
LeanTweenType sizeTweenType = LeanTweenType.easeInOutQuad, LeanTweenType posTweenType = LeanTweenType.easeInOutQuad, LeanTweenType rotTweenType = LeanTweenType.easeInOutQuad)
{ {
if (camera == null) if (camera == null)
{ {
@ -428,11 +325,13 @@ namespace Fungus
return; return;
} }
if(setCameraZ)
{
targetPosition.z = camera.transform.position.z;
}
// Stop any pan that is currently active // Stop any pan that is currently active
if (panCoroutine != null) { StopPosTweens();
StopCoroutine(panCoroutine);
panCoroutine = null;
}
swipePanActive = false; swipePanActive = false;
if (Mathf.Approximately(duration, 0f)) if (Mathf.Approximately(duration, 0f))
@ -451,7 +350,31 @@ namespace Fungus
} }
else else
{ {
StartCoroutine(panCoroutine = PanInternal(camera, targetPosition, targetRotation, targetSize, duration, arriveAction)); sizeTween = LeanTween.value(camera.orthographicSize, targetSize, duration)
.setEase(sizeTweenType)
.setOnUpdate(x => camera.orthographicSize = x)
.setOnComplete(() =>
{
camera.orthographicSize = targetSize;
if (arriveAction != null) arriveAction();
sizeTween = null;
});
camPosTween = LeanTween.move(camera.gameObject, targetPosition, duration)
.setEase(posTweenType)
.setOnComplete(() =>
{
camera.transform.position = targetPosition;
camPosTween = null;
});
camRotTween = LeanTween.rotate(camera.gameObject, targetRotation.eulerAngles, duration)
.setEase(rotTweenType)
.setOnComplete(() =>
{
camera.transform.rotation = targetRotation;
camRotTween = null;
});
} }
} }

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

@ -137,7 +137,7 @@ namespace Fungus
for (int i = 0; i < dragCompletedHandlers.Count; i++) for (int i = 0; i < dragCompletedHandlers.Count; i++)
{ {
var handler = dragCompletedHandlers[i]; var handler = dragCompletedHandlers[i];
if (handler != null && handler.DraggableObject == this) if (handler != null && handler.DraggableObjects.Contains(this))
{ {
if (handler.IsOverTarget()) if (handler.IsOverTarget())
{ {

17
Assets/Fungus/Scripts/Components/Flowchart.cs

@ -800,6 +800,23 @@ namespace Fungus
return null; return null;
} }
/// <summary>
/// Returns a list of variables matching the specified type.
/// </summary>
public virtual List<T> GetVariables<T>() where T: Variable
{
var varsFound = new List<T>();
for (int i = 0; i < Variables.Count; i++)
{
var currentVar = Variables[i];
if (currentVar is T)
varsFound.Add(currentVar as T);
}
return varsFound;
}
/// <summary> /// <summary>
/// Register a new variable with the Flowchart at runtime. /// Register a new variable with the Flowchart at runtime.
/// The variable should be added as a component on the Flowchart game object. /// The variable should be added as a component on the Flowchart game object.

54
Assets/Fungus/Scripts/Components/Writer.cs

@ -5,7 +5,7 @@
using UnityEngine.UI; using UnityEngine.UI;
using System.Collections; using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using System; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
@ -25,7 +25,7 @@ namespace Fungus
/// <summary> Writing has resumed after a pause. </summary> /// <summary> Writing has resumed after a pause. </summary>
Resume, Resume,
/// <summary> Writing has ended. </summary> /// <summary> Writing has ended. </summary>
End End,
} }
/// <summary> /// <summary>
@ -80,6 +80,32 @@ namespace Fungus
protected bool inputFlag; protected bool inputFlag;
protected bool exitFlag; protected bool exitFlag;
//holds number of Word tokens in the currently running Write
public int WordTokensFound { get; protected set; }
/// <summary>
/// Updated during writing of Word tokens, when processed tips over found, fires NotifyAllWordsWritten
/// </summary>
public virtual int WordTokensProcessed
{
get { return wordTokensProcessed; }
protected set
{
if(wordTokensProcessed < WordTokensFound && value >= WordTokensFound)
{
NotifyAllWordsWritten();
}
wordTokensProcessed = value;
}
}
//holds count of number of Word tokens completed
protected int wordTokensProcessed;
/// <summary>
/// Does the currently processing list of Tokens have Word Tokens that are not yet processed
/// </summary>
public bool HasWordsRemaining { get { return WordTokensProcessed < WordTokensFound; } }
protected List<IWriterListener> writerListeners = new List<IWriterListener>(); protected List<IWriterListener> writerListeners = new List<IWriterListener>();
protected StringBuilder openString = new StringBuilder(256); protected StringBuilder openString = new StringBuilder(256);
@ -125,7 +151,7 @@ namespace Fungus
{ {
// Cache the hidden color string // Cache the hidden color string
Color32 c = hiddenTextColor; Color32 c = hiddenTextColor;
hiddenColorOpen = String.Format("<color=#{0:X2}{1:X2}{2:X2}{3:X2}>", c.r, c.g, c.b, c.a); hiddenColorOpen = string.Format("<color=#{0:X2}{1:X2}{2:X2}{3:X2}>", c.r, c.g, c.b, c.a);
hiddenColorClose = "</color>"; hiddenColorClose = "</color>";
} }
@ -221,19 +247,21 @@ namespace Fungus
value = defaultValue; value = defaultValue;
if (paramList.Count > index) if (paramList.Count > index)
{ {
Single.TryParse(paramList[index], out value); float.TryParse(paramList[index], out value);
return true; return true;
} }
return false; return false;
} }
protected virtual IEnumerator ProcessTokens(List<TextTagToken> tokens, bool stopAudio, Action onComplete) protected virtual IEnumerator ProcessTokens(List<TextTagToken> tokens, bool stopAudio, System.Action onComplete)
{ {
// Reset control members // Reset control members
boldActive = false; boldActive = false;
italicActive = false; italicActive = false;
colorActive = false; colorActive = false;
sizeActive = false; sizeActive = false;
WordTokensFound = tokens.Count(x => x.type == TokenType.Words);
WordTokensProcessed = 0;
colorText = ""; colorText = "";
sizeValue = 16f; sizeValue = 16f;
currentPunctuationPause = punctuationPause; currentPunctuationPause = punctuationPause;
@ -282,6 +310,7 @@ namespace Fungus
{ {
case TokenType.Words: case TokenType.Words:
yield return StartCoroutine(DoWords(token.paramList, previousTokenType)); yield return StartCoroutine(DoWords(token.paramList, previousTokenType));
WordTokensProcessed++;
break; break;
case TokenType.BoldStart: case TokenType.BoldStart:
@ -636,7 +665,7 @@ namespace Fungus
// Look ahead to find next whitespace or end of string // Look ahead to find next whitespace or end of string
for (int j = i; j < inputString.Length + 1; ++j) for (int j = i; j < inputString.Length + 1; ++j)
{ {
if (j == inputString.Length || Char.IsWhiteSpace(inputString[j])) if (j == inputString.Length || char.IsWhiteSpace(inputString[j]))
{ {
leftString.Length = j; leftString.Length = j;
rightString.Remove(0, j); rightString.Remove(0, j);
@ -694,7 +723,7 @@ namespace Fungus
} }
float duration = 1f; float duration = 1f;
if (!Single.TryParse(param, out duration)) if (!float.TryParse(param, out duration))
{ {
duration = 1f; duration = 1f;
} }
@ -847,6 +876,15 @@ namespace Fungus
} }
} }
protected virtual void NotifyAllWordsWritten()
{
for (int i = 0; i < writerListeners.Count; i++)
{
var writerListener = writerListeners[i];
writerListener.OnAllWordsWritten();
}
}
protected virtual void NotifyEnd(bool stopAudio) protected virtual void NotifyEnd(bool stopAudio)
{ {
WriterSignals.DoWriterState(this, WriterState.End); WriterSignals.DoWriterState(this, WriterState.End);
@ -907,7 +945,7 @@ namespace Fungus
/// <param name="waitForVO">Wait for the Voice over to complete before proceeding</param> /// <param name="waitForVO">Wait for the Voice over to complete before proceeding</param>
/// <param name="audioClip">Audio clip to play when text starts writing.</param> /// <param name="audioClip">Audio clip to play when text starts writing.</param>
/// <param name="onComplete">Callback to call when writing is finished.</param> /// <param name="onComplete">Callback to call when writing is finished.</param>
public virtual IEnumerator Write(string content, bool clear, bool waitForInput, bool stopAudio, bool waitForVO, AudioClip audioClip, Action onComplete) public virtual IEnumerator Write(string content, bool clear, bool waitForInput, bool stopAudio, bool waitForVO, AudioClip audioClip, System.Action onComplete)
{ {
if (clear) if (clear)
{ {

4
Assets/Fungus/Scripts/Components/WriterAudio.cs

@ -260,6 +260,10 @@ namespace Fungus
targetAudioSource.Play(); targetAudioSource.Play();
} }
public void OnAllWordsWritten()
{
}
#endregion #endregion
} }
} }

3
Assets/Fungus/Scripts/Editor/CustomVariableDrawerLookup.cs

@ -43,8 +43,9 @@ namespace Fungus.EditorUtils
/// <param name="prop"></param> /// <param name="prop"></param>
public static void DrawCustomOrPropertyField(System.Type type, Rect rect, SerializedProperty prop) public static void DrawCustomOrPropertyField(System.Type type, Rect rect, SerializedProperty prop)
{ {
System.Action<UnityEngine.Rect, UnityEditor.SerializedProperty> drawer = null;
//delegate actual drawing to the variableInfo //delegate actual drawing to the variableInfo
var foundDrawer = typeToDrawer.TryGetValue(type, out System.Action<UnityEngine.Rect, UnityEditor.SerializedProperty> drawer); var foundDrawer = typeToDrawer.TryGetValue(type, out drawer);
if (foundDrawer) if (foundDrawer)
{ {
drawer(rect, prop); drawer(rect, prop);

16
Assets/Fungus/Scripts/Editor/EditorZoomArea.cs

@ -52,6 +52,22 @@ namespace Fungus.EditorUtils
result.y += pivotPoint.y; result.y += pivotPoint.y;
return result; return result;
} }
public static Rect SnapPosition(this Rect rect, float snapInterval)
{
var tmp = rect;
var x = tmp.position.x;
var y = tmp.position.y;
tmp.position = new Vector2(Mathf.RoundToInt(x / snapInterval) * snapInterval, Mathf.RoundToInt(y / snapInterval) * snapInterval);
return tmp;
}
public static Rect SnapWidth(this Rect rect, float snapInterval)
{
var tmp = rect;
tmp.width = Mathf.RoundToInt(tmp.width / snapInterval) * snapInterval;
return tmp;
}
} }
public class EditorZoomArea public class EditorZoomArea

201
Assets/Fungus/Scripts/Editor/FlowchartWindow.cs

@ -172,12 +172,29 @@ namespace Fungus.EditorUtils
} }
} }
public const float GridLineSpacingSize = 120;
public const float GridObjectSnap = 20;
public const float DefaultBlockHeight = 40;
public const float BlockMinWidth = 60;
public const float BlockMaxWidth = 240;
public const float MinZoomValue = 0.25f;
public const float MaxZoomValue = 1f;
public const int HorizontalPad = 20;
public const int VerticalPad = 5;
//defines the distance between a down and up for a right click to be a click rather than a drag
public const float RightClickTolerance = 5f;
public const string SearchFieldName = "search";
protected readonly Color connectionColor = new Color(0.65f, 0.65f, 0.65f, 1.0f);
protected List<BlockCopy> copyList = new List<BlockCopy>(); protected List<BlockCopy> copyList = new List<BlockCopy>();
public static List<Block> deleteList = new List<Block>(); public static List<Block> deleteList = new List<Block>();
protected Vector2 startDragPosition; protected Vector2 startDragPosition;
public const float minZoomValue = 0.25f; protected GUIStyle nodeStyle, descriptionStyle, handlerStyle;
public const float maxZoomValue = 1f;
protected GUIStyle nodeStyle = new GUIStyle();
protected static BlockInspector blockInspector; protected static BlockInspector blockInspector;
protected int forceRepaintCount; protected int forceRepaintCount;
protected Texture2D addTexture; protected Texture2D addTexture;
@ -187,12 +204,9 @@ namespace Fungus.EditorUtils
protected Vector2 startSelectionBoxPosition = -Vector2.one; protected Vector2 startSelectionBoxPosition = -Vector2.one;
protected List<Block> mouseDownSelectionState = new List<Block>(); protected List<Block> mouseDownSelectionState = new List<Block>();
protected Color gridLineColor = Color.black; protected Color gridLineColor = Color.black;
protected readonly Color connectionColor = new Color(0.65f, 0.65f, 0.65f, 1.0f);
// Context Click occurs on MouseDown which interferes with panning // Context Click occurs on MouseDown which interferes with panning
// Track right click positions manually to show menus on MouseUp // Track right click positions manually to show menus on MouseUp
protected Vector2 rightClickDown = -Vector2.one; protected Vector2 rightClickDown = -Vector2.one;
protected const float rightClickTolerance = 5f;
protected const string searchFieldName = "search";
private string searchString = string.Empty; private string searchString = string.Empty;
protected Rect searchRect; protected Rect searchRect;
protected Rect popupRect; protected Rect popupRect;
@ -245,13 +259,6 @@ namespace Fungus.EditorUtils
protected virtual void OnEnable() protected virtual void OnEnable()
{ {
// All block nodes use the same GUIStyle, but with a different background
nodeStyle.border = new RectOffset(20, 20, 5, 5);
nodeStyle.padding = nodeStyle.border;
nodeStyle.contentOffset = Vector2.zero;
nodeStyle.alignment = TextAnchor.MiddleCenter;
nodeStyle.wordWrap = true;
addTexture = FungusEditorResources.AddSmall; addTexture = FungusEditorResources.AddSmall;
addButtonContent = new GUIContent(addTexture, "Add a new block"); addButtonContent = new GUIContent(addTexture, "Add a new block");
connectionPointTexture = FungusEditorResources.ConnectionPoint; connectionPointTexture = FungusEditorResources.ConnectionPoint;
@ -272,6 +279,37 @@ namespace Fungus.EditorUtils
#endif #endif
} }
//cache styles here, rather than duping them for every block we may ever draw,
// does mean any modifications made to the style when drawing must be undone as you go
protected void InitStyles()
{
if (nodeStyle == null)
{
nodeStyle = new GUIStyle();
// All block nodes use the same GUIStyle, but with a different background
nodeStyle.border = new RectOffset(HorizontalPad, HorizontalPad, VerticalPad, VerticalPad);
nodeStyle.padding = nodeStyle.border;
nodeStyle.contentOffset = Vector2.zero;
nodeStyle.alignment = TextAnchor.MiddleCenter;
nodeStyle.wordWrap = true;
}
if (EditorStyles.helpBox != null && descriptionStyle == null)
{
descriptionStyle = new GUIStyle(EditorStyles.helpBox);
descriptionStyle.wordWrap = true;
}
if (EditorStyles.whiteLabel != null && handlerStyle == null)
{
handlerStyle = new GUIStyle(EditorStyles.whiteLabel);
handlerStyle.wordWrap = true;
handlerStyle.margin.top = 0;
handlerStyle.margin.bottom = 0;
handlerStyle.alignment = TextAnchor.MiddleCenter;
}
}
protected virtual void OnDisable() protected virtual void OnDisable()
{ {
EditorApplication.update -= OnEditorUpdate; EditorApplication.update -= OnEditorUpdate;
@ -530,7 +568,7 @@ namespace Fungus.EditorUtils
break; break;
case EventType.KeyDown: case EventType.KeyDown:
if (GUI.GetNameOfFocusedControl() == searchFieldName) if (GUI.GetNameOfFocusedControl() == SearchFieldName)
{ {
var centerBlock = false; var centerBlock = false;
var selectBlock = false; var selectBlock = false;
@ -715,6 +753,8 @@ namespace Fungus.EditorUtils
return; return;
} }
InitStyles();
DeleteBlocks(); DeleteBlocks();
UpdateFilteredBlocks(); UpdateFilteredBlocks();
@ -787,7 +827,7 @@ namespace Fungus.EditorUtils
// Draw scale bar and labels // Draw scale bar and labels
GUILayout.Label("Scale", EditorStyles.miniLabel); GUILayout.Label("Scale", EditorStyles.miniLabel);
var newZoom = GUILayout.HorizontalSlider( var newZoom = GUILayout.HorizontalSlider(
flowchart.Zoom, minZoomValue, maxZoomValue, GUILayout.MinWidth(40), GUILayout.MaxWidth(100) flowchart.Zoom, MinZoomValue, MaxZoomValue, GUILayout.MinWidth(40), GUILayout.MaxWidth(100)
); );
GUILayout.Label(flowchart.Zoom.ToString("0.0#x"), EditorStyles.miniLabel, GUILayout.Width(30)); GUILayout.Label(flowchart.Zoom.ToString("0.0#x"), EditorStyles.miniLabel, GUILayout.Width(30));
@ -805,7 +845,7 @@ namespace Fungus.EditorUtils
GUILayout.FlexibleSpace(); GUILayout.FlexibleSpace();
// Draw search bar // Draw search bar
GUI.SetNextControlName(searchFieldName); GUI.SetNextControlName(SearchFieldName);
var newString = EditorGUILayout.TextField(searchString, ToolbarSeachTextFieldStyle, GUILayout.Width(150)); var newString = EditorGUILayout.TextField(searchString, ToolbarSeachTextFieldStyle, GUILayout.Width(150));
if (newString != searchString) if (newString != searchString)
{ {
@ -861,7 +901,7 @@ namespace Fungus.EditorUtils
// Draw block search popup on top of other controls // Draw block search popup on top of other controls
if (GUI.GetNameOfFocusedControl() == searchFieldName && filteredBlocks.Length > 0) if (GUI.GetNameOfFocusedControl() == SearchFieldName && filteredBlocks.Length > 0)
{ {
DrawBlockPopup(e); DrawBlockPopup(e);
} }
@ -1152,7 +1192,7 @@ namespace Fungus.EditorUtils
break; break;
case MouseButton.Right: case MouseButton.Right:
if (Vector2.Distance(rightClickDown, e.mousePosition) > rightClickTolerance) if (Vector2.Distance(rightClickDown, e.mousePosition) > RightClickTolerance)
{ {
rightClickDown = -Vector2.one; rightClickDown = -Vector2.one;
} }
@ -1207,6 +1247,11 @@ namespace Fungus.EditorUtils
Undo.RecordObject(block, "Block Position"); Undo.RecordObject(block, "Block Position");
tempRect.position += distance; tempRect.position += distance;
block._NodeRect = tempRect; block._NodeRect = tempRect;
if (FungusEditorPreferences.useGridSnap)
{
block._NodeRect = block._NodeRect.SnapPosition(GridObjectSnap);
}
Repaint();
} }
dragBlock = null; dragBlock = null;
@ -1345,12 +1390,6 @@ namespace Fungus.EditorUtils
{ {
DrawGrid(); DrawGrid();
// Draw connections
foreach (var block in blocks)
{
DrawConnections(block);
}
//draw all non selected //draw all non selected
for (int i = 0; i < blocks.Length; ++i) for (int i = 0; i < blocks.Length; ++i)
{ {
@ -1469,13 +1508,14 @@ namespace Fungus.EditorUtils
{ {
var prevZoom = flowchart.Zoom; var prevZoom = flowchart.Zoom;
flowchart.Zoom += delta; flowchart.Zoom += delta;
flowchart.Zoom = Mathf.Clamp(flowchart.Zoom, minZoomValue, maxZoomValue); flowchart.Zoom = Mathf.Clamp(flowchart.Zoom, MinZoomValue, MaxZoomValue);
var deltaSize = position.size / prevZoom - position.size / flowchart.Zoom; var deltaSize = position.size / prevZoom - position.size / flowchart.Zoom;
var offset = -Vector2.Scale(deltaSize, center); var offset = -Vector2.Scale(deltaSize, center);
flowchart.ScrollPos += offset; flowchart.ScrollPos += offset;
forceRepaintCount = 1; forceRepaintCount = 1;
} }
//Potentially could be faster using https://forum.unity.com/threads/how-do-i-access-the-background-image-used-for-the-animator.501876/
protected virtual void DrawGrid() protected virtual void DrawGrid()
{ {
float width = this.position.width / flowchart.Zoom; float width = this.position.width / flowchart.Zoom;
@ -1483,23 +1523,22 @@ namespace Fungus.EditorUtils
Handles.color = gridLineColor; Handles.color = gridLineColor;
float gridSize = 128f;
float x = flowchart.ScrollPos.x % gridSize; float x = flowchart.ScrollPos.x % GridLineSpacingSize;
while (x < width) while (x < width)
{ {
Handles.DrawLine(new Vector2(x, 0), new Vector2(x, height)); Handles.DrawLine(new Vector2(x, 0), new Vector2(x, height));
x += gridSize; x += GridLineSpacingSize;
} }
float y = (flowchart.ScrollPos.y % gridSize); float y = (flowchart.ScrollPos.y % GridLineSpacingSize);
while (y < height) while (y < height)
{ {
if (y >= 0) if (y >= 0)
{ {
Handles.DrawLine(new Vector2(0, y), new Vector2(width, y)); Handles.DrawLine(new Vector2(0, y), new Vector2(width, y));
} }
y += gridSize; y += GridLineSpacingSize;
} }
Handles.color = Color.white; Handles.color = Color.white;
@ -1543,6 +1582,9 @@ namespace Fungus.EditorUtils
return newBlock; return newBlock;
} }
//prevent every DrawConnections from allocating a new list for all of its connections
protected List<Block> connectedBlocksWorkSpace = new List<Block>();
protected virtual void DrawConnections(Block block) protected virtual void DrawConnections(Block block)
{ {
if (block == null) if (block == null)
@ -1550,7 +1592,6 @@ namespace Fungus.EditorUtils
return; return;
} }
var connectedBlocks = new List<Block>();
bool blockIsSelected = flowchart.SelectedBlock == block; bool blockIsSelected = flowchart.SelectedBlock == block;
@ -1578,10 +1619,10 @@ namespace Fungus.EditorUtils
bool highlight = command.IsExecuting || (blockIsSelected && commandIsSelected); bool highlight = command.IsExecuting || (blockIsSelected && commandIsSelected);
connectedBlocks.Clear(); connectedBlocksWorkSpace.Clear();
command.GetConnectedBlocks(ref connectedBlocks); command.GetConnectedBlocks(ref connectedBlocksWorkSpace);
foreach (var blockB in connectedBlocks) foreach (var blockB in connectedBlocksWorkSpace)
{ {
if (blockB == null || if (blockB == null ||
block == blockB || block == blockB ||
@ -1945,7 +1986,7 @@ namespace Fungus.EditorUtils
case "Find": case "Find":
blockPopupSelection = 0; blockPopupSelection = 0;
popupScroll = Vector2.zero; popupScroll = Vector2.zero;
EditorGUI.FocusTextInControl(searchFieldName); EditorGUI.FocusTextInControl(SearchFieldName);
e.Use(); e.Use();
break; break;
} }
@ -1967,10 +2008,14 @@ namespace Fungus.EditorUtils
searchString = string.Empty; searchString = string.Empty;
} }
static protected List<Block> blockGraphicsUniqueListWorkSpace = new List<Block>();
static protected List<Block> blockGraphicsConnectedWorkSpace = new List<Block>();
protected virtual BlockGraphics GetBlockGraphics(Block block) protected virtual BlockGraphics GetBlockGraphics(Block block)
{ {
var graphics = new BlockGraphics(); var graphics = new BlockGraphics();
blockGraphicsUniqueListWorkSpace.Clear();
blockGraphicsConnectedWorkSpace.Clear();
Color defaultTint; Color defaultTint;
if (block._EventHandler != null) if (block._EventHandler != null)
{ {
@ -1981,19 +2026,18 @@ namespace Fungus.EditorUtils
else else
{ {
// Count the number of unique connections (excluding self references) // Count the number of unique connections (excluding self references)
var uniqueList = new List<Block>(); block.GetConnectedBlocks(ref blockGraphicsConnectedWorkSpace);
var connectedBlocks = block.GetConnectedBlocks(); foreach (var connectedBlock in blockGraphicsConnectedWorkSpace)
foreach (var connectedBlock in connectedBlocks)
{ {
if (connectedBlock == block || if (connectedBlock == block ||
uniqueList.Contains(connectedBlock)) blockGraphicsUniqueListWorkSpace.Contains(connectedBlock))
{ {
continue; continue;
} }
uniqueList.Add(connectedBlock); blockGraphicsUniqueListWorkSpace.Add(connectedBlock);
} }
if (uniqueList.Count > 1) if (blockGraphicsUniqueListWorkSpace.Count > 1)
{ {
graphics.offTexture = FungusEditorResources.ChoiceNodeOff; graphics.offTexture = FungusEditorResources.ChoiceNodeOff;
graphics.onTexture = FungusEditorResources.ChoiceNodeOn; graphics.onTexture = FungusEditorResources.ChoiceNodeOn;
@ -2015,79 +2059,81 @@ namespace Fungus.EditorUtils
private void DrawBlock(Block block, Rect scriptViewRect) private void DrawBlock(Block block, Rect scriptViewRect)
{ {
float nodeWidthA = nodeStyle.CalcSize(new GUIContent(block.BlockName)).x + 10; float nodeWidthA = nodeStyle.CalcSize(new GUIContent(block.BlockName)).x + 10;
float nodeWidthB = 0f;
if (block._EventHandler != null)
{
nodeWidthB = nodeStyle.CalcSize(new GUIContent(block._EventHandler.GetSummary())).x + 10;
}
Rect tempRect = block._NodeRect; Rect tempRect = block._NodeRect;
tempRect.width = Mathf.Max(Mathf.Max(nodeWidthA, nodeWidthB), 120); tempRect.width = Mathf.Clamp(nodeWidthA, BlockMinWidth, BlockMaxWidth);
tempRect.height = 40; tempRect.height = DefaultBlockHeight;
if (FungusEditorPreferences.useGridSnap)
{
tempRect = tempRect.SnapWidth(GridObjectSnap);
}
block._NodeRect = tempRect; block._NodeRect = tempRect;
Rect windowRect = new Rect(block._NodeRect); // Draw blocks
windowRect.position += flowchart.ScrollPos; var graphics = GetBlockGraphics(block);
Rect windowRelativeRect = new Rect(block._NodeRect);
if (FungusEditorPreferences.useGridSnap)
{
windowRelativeRect = windowRelativeRect.SnapPosition(GridObjectSnap);
}
windowRelativeRect.position += flowchart.ScrollPos;
//skip if outside of view //skip if outside of view
if (!scriptViewRect.Overlaps(windowRect)) if (!scriptViewRect.Overlaps(windowRelativeRect))
return; return;
// Draw blocks var tmpNormBg = nodeStyle.normal.background;
GUIStyle nodeStyleCopy = new GUIStyle(nodeStyle);
var graphics = GetBlockGraphics(block);
// Make sure node is wide enough to fit the node name text
float width = nodeStyleCopy.CalcSize(new GUIContent(block.BlockName)).x;
tempRect = block._NodeRect;
tempRect.width = Mathf.Max(block._NodeRect.width, width);
block._NodeRect = tempRect;
// Draw untinted highlight // Draw untinted highlight
if (block.IsSelected && !block.IsControlSelected) if (block.IsSelected && !block.IsControlSelected)
{ {
GUI.backgroundColor = Color.white; GUI.backgroundColor = Color.white;
nodeStyleCopy.normal.background = graphics.onTexture; nodeStyle.normal.background = graphics.onTexture;
GUI.Box(windowRect, "", nodeStyleCopy); GUI.Box(windowRelativeRect, "", nodeStyle);
nodeStyle.normal.background = tmpNormBg;
} }
if (block.IsControlSelected && !block.IsSelected) if (block.IsControlSelected && !block.IsSelected)
{ {
GUI.backgroundColor = Color.white; GUI.backgroundColor = Color.white;
nodeStyleCopy.normal.background = graphics.onTexture; nodeStyle.normal.background = graphics.onTexture;
var c = GUI.backgroundColor; var c = GUI.backgroundColor;
c.a = 0.5f; c.a = 0.5f;
GUI.backgroundColor = c; GUI.backgroundColor = c;
GUI.Box(windowRect, "", nodeStyleCopy); GUI.Box(windowRelativeRect, "", nodeStyle);
nodeStyle.normal.background = tmpNormBg;
} }
// Draw tinted block; ensure text is readable // Draw tinted block; ensure text is readable
var brightness = graphics.tint.r * 0.3 + graphics.tint.g * 0.59 + graphics.tint.b * 0.11; var brightness = graphics.tint.r * 0.3 + graphics.tint.g * 0.59 + graphics.tint.b * 0.11;
nodeStyleCopy.normal.textColor = brightness >= 0.5 ? Color.black : Color.white; var tmpNormTxtCol = nodeStyle.normal.textColor;
nodeStyle.normal.textColor = brightness >= 0.5 ? Color.black : Color.white;
if (GUI.GetNameOfFocusedControl() == searchFieldName && !block.IsFiltered) if (GUI.GetNameOfFocusedControl() == SearchFieldName && !block.IsFiltered)
{ {
graphics.tint.a *= 0.2f; graphics.tint.a *= 0.2f;
} }
nodeStyleCopy.normal.background = graphics.offTexture; nodeStyle.normal.background = graphics.offTexture;
GUI.backgroundColor = graphics.tint; GUI.backgroundColor = graphics.tint;
GUI.Box(windowRect, block.BlockName, nodeStyleCopy); GUI.Box(windowRelativeRect, block.BlockName, nodeStyle);
GUI.backgroundColor = Color.white; GUI.backgroundColor = Color.white;
if (block.Description.Length > 0) if (block.Description.Length > 0)
{ {
GUIStyle descriptionStyle = new GUIStyle(EditorStyles.helpBox);
descriptionStyle.wordWrap = true;
var content = new GUIContent(block.Description); var content = new GUIContent(block.Description);
windowRect.y += windowRect.height; windowRelativeRect.y += windowRelativeRect.height;
windowRect.height = descriptionStyle.CalcHeight(content, windowRect.width); windowRelativeRect.height = descriptionStyle.CalcHeight(content, windowRelativeRect.width);
GUI.Label(windowRect, content, descriptionStyle); GUI.Label(windowRelativeRect, content, descriptionStyle);
} }
GUI.backgroundColor = Color.white; GUI.backgroundColor = Color.white;
nodeStyle.normal.textColor = tmpNormTxtCol;
nodeStyle.normal.background = tmpNormBg;
// Draw Event Handler labels // Draw Event Handler labels
if (block._EventHandler != null) if (block._EventHandler != null)
{ {
@ -2098,12 +2144,6 @@ namespace Fungus.EditorUtils
handlerLabel = "<" + info.EventHandlerName + "> "; handlerLabel = "<" + info.EventHandlerName + "> ";
} }
GUIStyle handlerStyle = new GUIStyle(EditorStyles.whiteLabel);
handlerStyle.wordWrap = true;
handlerStyle.margin.top = 0;
handlerStyle.margin.bottom = 0;
handlerStyle.alignment = TextAnchor.MiddleCenter;
Rect rect = new Rect(block._NodeRect); Rect rect = new Rect(block._NodeRect);
rect.height = handlerStyle.CalcHeight(new GUIContent(handlerLabel), block._NodeRect.width); rect.height = handlerStyle.CalcHeight(new GUIContent(handlerLabel), block._NodeRect.width);
rect.x += flowchart.ScrollPos.x; rect.x += flowchart.ScrollPos.x;
@ -2111,6 +2151,9 @@ namespace Fungus.EditorUtils
GUI.Label(rect, handlerLabel, handlerStyle); GUI.Label(rect, handlerLabel, handlerStyle);
} }
DrawConnections(block);
} }
} }
} }

5
Assets/Fungus/Scripts/Editor/FungusEditorPreferences.cs

@ -21,9 +21,11 @@ namespace Fungus
private static bool prefsLoaded = false; private static bool prefsLoaded = false;
private const string HIDE_MUSH_KEY = "hideMushroomInHierarchy"; private const string HIDE_MUSH_KEY = "hideMushroomInHierarchy";
private const string USE_LEGACY_MENUS = "useLegacyMenus"; private const string USE_LEGACY_MENUS = "useLegacyMenus";
private const string USE_GRID_SNAP = "useGridSnap";
public static bool hideMushroomInHierarchy; public static bool hideMushroomInHierarchy;
public static bool useLegacyMenus; public static bool useLegacyMenus;
public static bool useGridSnap;
static FungusEditorPreferences() static FungusEditorPreferences()
{ {
@ -63,6 +65,7 @@ namespace Fungus
// Preferences GUI // Preferences GUI
hideMushroomInHierarchy = EditorGUILayout.Toggle("Hide Mushroom Flowchart Icon", hideMushroomInHierarchy); hideMushroomInHierarchy = EditorGUILayout.Toggle("Hide Mushroom Flowchart Icon", hideMushroomInHierarchy);
useLegacyMenus = EditorGUILayout.Toggle(new GUIContent("Legacy Menus", "Force Legacy menus for Event, Add Variable and Add Command menus"), useLegacyMenus); useLegacyMenus = EditorGUILayout.Toggle(new GUIContent("Legacy Menus", "Force Legacy menus for Event, Add Variable and Add Command menus"), useLegacyMenus);
useGridSnap = EditorGUILayout.Toggle(new GUIContent("Grid Snap", "Align and Snap block positions and widths in the flowchart window to the grid"), useGridSnap);
EditorGUILayout.Space(); EditorGUILayout.Space();
//ideally if any are null, but typically it is all or nothing that have broken links due to version changes or moving files external to Unity //ideally if any are null, but typically it is all or nothing that have broken links due to version changes or moving files external to Unity
@ -113,6 +116,7 @@ namespace Fungus
{ {
EditorPrefs.SetBool(HIDE_MUSH_KEY, hideMushroomInHierarchy); EditorPrefs.SetBool(HIDE_MUSH_KEY, hideMushroomInHierarchy);
EditorPrefs.SetBool(USE_LEGACY_MENUS, useLegacyMenus); EditorPrefs.SetBool(USE_LEGACY_MENUS, useLegacyMenus);
EditorPrefs.SetBool(USE_GRID_SNAP, useGridSnap);
} }
} }
@ -120,6 +124,7 @@ namespace Fungus
{ {
hideMushroomInHierarchy = EditorPrefs.GetBool(HIDE_MUSH_KEY, false); hideMushroomInHierarchy = EditorPrefs.GetBool(HIDE_MUSH_KEY, false);
useLegacyMenus = EditorPrefs.GetBool(USE_LEGACY_MENUS, false); useLegacyMenus = EditorPrefs.GetBool(USE_LEGACY_MENUS, false);
useGridSnap = EditorPrefs.GetBool(USE_GRID_SNAP, false);
prefsLoaded = true; prefsLoaded = true;
} }
} }

13
Assets/Fungus/Scripts/Editor/VariableEditor.cs

@ -236,21 +236,28 @@ namespace Fungus.EditorUtils
protected virtual void DrawSingleLineProperty(Rect rect, GUIContent label, SerializedProperty referenceProp, SerializedProperty valueProp, Flowchart flowchart, protected virtual void DrawSingleLineProperty(Rect rect, GUIContent label, SerializedProperty referenceProp, SerializedProperty valueProp, Flowchart flowchart,
VariableInfoAttribute typeInfo) VariableInfoAttribute typeInfo)
{ {
const int popupWidth = 17; int popupWidth = Mathf.RoundToInt(EditorGUIUtility.singleLineHeight);
const int popupGap = 5;
//get out starting rect with intent honoured
Rect controlRect = EditorGUI.PrefixLabel(rect, label); Rect controlRect = EditorGUI.PrefixLabel(rect, label);
Rect valueRect = controlRect; Rect valueRect = controlRect;
valueRect.width = controlRect.width - popupWidth - 5; valueRect.width = controlRect.width - popupWidth - popupGap;
Rect popupRect = controlRect; Rect popupRect = controlRect;
//we are overriding much of the auto layout to cram this all on 1 line so zero the intend and restore it later
var prevIndent = EditorGUI.indentLevel;
EditorGUI.indentLevel = 0;
if (referenceProp.objectReferenceValue == null) if (referenceProp.objectReferenceValue == null)
{ {
DrawValueProperty(valueRect, valueProp, typeInfo); DrawValueProperty(valueRect, valueProp, typeInfo);
popupRect.x += valueRect.width + 5; popupRect.x += valueRect.width + popupGap;
popupRect.width = popupWidth; popupRect.width = popupWidth;
} }
EditorGUI.PropertyField(popupRect, referenceProp, new GUIContent("")); EditorGUI.PropertyField(popupRect, referenceProp, new GUIContent(""));
EditorGUI.indentLevel = prevIndent;
} }
protected virtual void DrawMultiLineProperty(Rect rect, GUIContent label, SerializedProperty referenceProp, SerializedProperty valueProp, Flowchart flowchart, protected virtual void DrawMultiLineProperty(Rect rect, GUIContent label, SerializedProperty referenceProp, SerializedProperty valueProp, Flowchart flowchart,

59
Assets/Fungus/Scripts/EventHandlers/DragCancelled.cs

@ -1,7 +1,8 @@
// This code is part of the Fungus library (https://github.com/snozbot/fungus) // This code is part of the Fungus library (https://github.com/snozbot/fungus)
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine; using System.Collections.Generic;
using UnityEngine;
namespace Fungus namespace Fungus
{ {
@ -12,18 +13,25 @@ namespace Fungus
"Drag Cancelled", "Drag Cancelled",
"The block will execute when the player drags an object and releases it without dropping it on a target object.")] "The block will execute when the player drags an object and releases it without dropping it on a target object.")]
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragCancelled : EventHandler public class DragCancelled : EventHandler, ISerializationCallbackReceiver
{ {
public class DragCancelledEvent public class DragCancelledEvent
{ {
public Draggable2D DraggableObject; public Draggable2D DraggableObject;
public DragCancelledEvent(Draggable2D draggableObject) public DragCancelledEvent(Draggable2D draggableObject)
{ {
DraggableObject = draggableObject; DraggableObject = draggableObject;
} }
} }
[VariableProperty(typeof(GameObjectVariable))]
[SerializeField] protected GameObjectVariable draggableRef;
[Tooltip("Draggable object to listen for drag events on")] [Tooltip("Draggable object to listen for drag events on")]
[SerializeField] protected List<Draggable2D> draggableObjects;
[HideInInspector]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
protected EventDispatcher eventDispatcher; protected EventDispatcher eventDispatcher;
@ -47,26 +55,61 @@ namespace Fungus
OnDragCancelled(evt.DraggableObject); OnDragCancelled(evt.DraggableObject);
} }
#region Compatibility
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
//add any dragableobject already present to list for backwards compatability
if (draggableObject != null)
{
if (!draggableObjects.Contains(draggableObject))
{
draggableObjects.Add(draggableObject);
}
draggableObject = null;
}
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
#endregion Compatibility
#region Public members #region Public members
public virtual void OnDragCancelled(Draggable2D draggableObject) public virtual void OnDragCancelled(Draggable2D draggableObject)
{ {
if (draggableObject == this.draggableObject) if (draggableObjects.Contains(draggableObject))
{ {
if (draggableRef != null)
{
draggableRef.Value = draggableObject.gameObject;
}
ExecuteBlock(); ExecuteBlock();
} }
} }
public override string GetSummary() public override string GetSummary()
{ {
if (draggableObject != null) string summary = "Draggable: ";
if (this.draggableObjects != null && this.draggableObjects.Count != 0)
{ {
return draggableObject.name; for (int i = 0; i < this.draggableObjects.Count; i++)
{
if (draggableObjects[i] != null)
{
summary += draggableObjects[i].name + ",";
}
}
return summary;
}
else
{
return "None";
} }
return "None";
} }
#endregion #endregion Public members
} }
} }

156
Assets/Fungus/Scripts/EventHandlers/DragCompleted.cs

@ -1,88 +1,150 @@
// This code is part of the Fungus library (https://github.com/snozbot/fungus) // This code is part of the Fungus library (https://github.com/snozbot/fungus)
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine; using System.Collections.Generic;
using UnityEngine;
namespace Fungus namespace Fungus
{ {
/// <summary> /// <summary>
/// The block will execute when the player drags an object and successfully drops it on a target object. /// The block will execute when the player drags an object and successfully drops it on a target object.
///
/// ExecuteAlways used to get the Compatibility that we need, use of ISerializationCallbackReceiver is error prone
/// when used on Unity controlled objects as it runs on threads other than main thread.
/// </summary> /// </summary>
[EventHandlerInfo("Sprite", [EventHandlerInfo("Sprite",
"Drag Completed", "Drag Completed",
"The block will execute when the player drags an object and successfully drops it on a target object.")] "The block will execute when the player drags an object and successfully drops it on a target object.")]
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragCompleted : EventHandler [ExecuteInEditMode]
public class DragCompleted : EventHandler, ISerializationCallbackReceiver
{ {
public class DragCompletedEvent public class DragCompletedEvent
{ {
public Draggable2D DraggableObject; public Draggable2D DraggableObject;
public DragCompletedEvent(Draggable2D draggableObject) public DragCompletedEvent(Draggable2D draggableObject)
{ {
DraggableObject = draggableObject; DraggableObject = draggableObject;
} }
} }
[VariableProperty(typeof(GameObjectVariable))]
[SerializeField] protected GameObjectVariable draggableRef;
[VariableProperty(typeof(GameObjectVariable))]
[SerializeField] protected GameObjectVariable targetRef;
[Tooltip("Draggable object to listen for drag events on")] [Tooltip("Draggable object to listen for drag events on")]
[HideInInspector]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
[SerializeField] protected List<Draggable2D> draggableObjects;
[Tooltip("Drag target object to listen for drag events on")] [Tooltip("Drag target object to listen for drag events on")]
[HideInInspector]
[SerializeField] protected Collider2D targetObject; [SerializeField] protected Collider2D targetObject;
[SerializeField] protected List<Collider2D> targetObjects;
// There's no way to poll if an object is touching another object, so // There's no way to poll if an object is touching another object, so
// we have to listen to the callbacks and track the touching state ourselves. // we have to listen to the callbacks and track the touching state ourselves.
protected bool overTarget = false; protected bool overTarget = false;
protected Collider2D targetCollider = null;
protected EventDispatcher eventDispatcher; protected EventDispatcher eventDispatcher;
protected virtual void OnEnable() protected virtual void OnEnable()
{ {
eventDispatcher = FungusManager.Instance.EventDispatcher; if (Application.isPlaying)
{
eventDispatcher = FungusManager.Instance.EventDispatcher;
eventDispatcher.AddListener<DragCompletedEvent>(OnDragCompletedEvent); eventDispatcher.AddListener<DragCompletedEvent>(OnDragCompletedEvent);
eventDispatcher.AddListener<DragEntered.DragEnteredEvent>(OnDragEnteredEvent); eventDispatcher.AddListener<DragEntered.DragEnteredEvent>(OnDragEnteredEvent);
eventDispatcher.AddListener<DragExited.DragExitedEvent>(OnDragExitedEvent); eventDispatcher.AddListener<DragExited.DragExitedEvent>(OnDragExitedEvent);
if(draggableObject != null) foreach (Draggable2D dragObj in draggableObjects)
{ {
draggableObject.RegisterHandler(this); dragObj.RegisterHandler(this);
}
} }
} }
protected virtual void OnDisable() protected virtual void OnDisable()
{ {
eventDispatcher.RemoveListener<DragCompletedEvent>(OnDragCompletedEvent); if (Application.isPlaying)
eventDispatcher.RemoveListener<DragEntered.DragEnteredEvent>(OnDragEnteredEvent);
eventDispatcher.RemoveListener<DragExited.DragExitedEvent>(OnDragExitedEvent);
if(draggableObject != null)
{ {
draggableObject.UnregisterHandler(this); eventDispatcher.RemoveListener<DragCompletedEvent>(OnDragCompletedEvent);
} eventDispatcher.RemoveListener<DragEntered.DragEnteredEvent>(OnDragEnteredEvent);
eventDispatcher.RemoveListener<DragExited.DragExitedEvent>(OnDragExitedEvent);
foreach (Draggable2D dragObj in draggableObjects)
{
dragObj.UnregisterHandler(this);
}
eventDispatcher = null; eventDispatcher = null;
}
} }
void OnDragCompletedEvent(DragCompletedEvent evt) private void OnDragCompletedEvent(DragCompletedEvent evt)
{ {
OnDragCompleted(evt.DraggableObject); OnDragCompleted(evt.DraggableObject);
} }
void OnDragEnteredEvent(DragEntered.DragEnteredEvent evt) private void OnDragEnteredEvent(DragEntered.DragEnteredEvent evt)
{ {
OnDragEntered(evt.DraggableObject, evt.TargetCollider); OnDragEntered(evt.DraggableObject, evt.TargetCollider);
} }
void OnDragExitedEvent(DragExited.DragExitedEvent evt) private void OnDragExitedEvent(DragExited.DragExitedEvent evt)
{ {
OnDragExited(evt.DraggableObject, evt.TargetCollider); OnDragExited(evt.DraggableObject, evt.TargetCollider);
} }
#region Compatibility
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
//presentl using awake due to errors on non main thread access of targetCollider
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
private void Awake()
{
//add any dragableobject already present to list for backwards compatability
if (draggableObject != null)
{
if (!draggableObjects.Contains(draggableObject))
{
draggableObjects.Add(draggableObject);
}
}
if (targetObject != null)
{
if (!targetObjects.Contains(targetObject))
{
targetObjects.Add(targetObject);
}
}
draggableObject = null;
targetObject = null;
}
#endregion Compatibility
#region Public members #region Public members
/// <summary> /// <summary>
/// Gets the draggable object. /// Gets the draggable object.
/// </summary> /// </summary>
public virtual Draggable2D DraggableObject { get { return draggableObject; } } public virtual List<Draggable2D> DraggableObjects { get { return draggableObjects; } }
/// <summary> /// <summary>
/// Returns true if the draggable object is over the drag target object. /// Returns true if the draggable object is over the drag target object.
@ -97,11 +159,12 @@ namespace Fungus
/// </summary> /// </summary>
public virtual void OnDragEntered(Draggable2D draggableObject, Collider2D targetObject) public virtual void OnDragEntered(Draggable2D draggableObject, Collider2D targetObject)
{ {
if (this.targetObject != null && if (this.targetObjects != null && this.draggableObjects != null &&
draggableObject == this.draggableObject && this.draggableObjects.Contains(draggableObject) &&
targetObject == this.targetObject) this.targetObjects.Contains(targetObject))
{ {
overTarget = true; overTarget = true;
targetCollider = targetObject;
} }
} }
@ -110,11 +173,12 @@ namespace Fungus
/// </summary> /// </summary>
public virtual void OnDragExited(Draggable2D draggableObject, Collider2D targetObject) public virtual void OnDragExited(Draggable2D draggableObject, Collider2D targetObject)
{ {
if (this.targetObject != null && if (this.targetObjects != null && this.draggableObjects != null &&
draggableObject == this.draggableObject && this.draggableObjects.Contains(draggableObject) &&
targetObject == this.targetObject) this.targetObjects.Contains(targetObject))
{ {
overTarget = false; overTarget = false;
targetCollider = null;
} }
} }
@ -123,13 +187,23 @@ namespace Fungus
/// </summary> /// </summary>
public virtual void OnDragCompleted(Draggable2D draggableObject) public virtual void OnDragCompleted(Draggable2D draggableObject)
{ {
if (draggableObject == this.draggableObject && if (this.draggableObjects.Contains(draggableObject) &&
overTarget) overTarget)
{ {
// Assume that the player will have to do perform another drag and drop operation // Assume that the player will have to do perform another drag and drop operation
// to complete the drag again. This is necessary because we don't get an OnDragExited if the // to complete the drag again. This is necessary because we don't get an OnDragExited if the
// draggable object is set to be inactive. // draggable object is set to be inactive.
if (draggableRef != null)
{
draggableRef.Value = draggableObject.gameObject;
}
if (targetRef != null)
{
targetRef.Value = targetCollider.gameObject;
}
overTarget = false; overTarget = false;
targetCollider = null;
ExecuteBlock(); ExecuteBlock();
} }
@ -137,14 +211,28 @@ namespace Fungus
public override string GetSummary() public override string GetSummary()
{ {
string summary = ""; string summary = "Draggable: ";
if (draggableObject != null) if (this.draggableObjects != null && this.draggableObjects.Count != 0)
{ {
summary += "\nDraggable: " + draggableObject.name; for (int i = 0; i < this.draggableObjects.Count; i++)
{
if (draggableObjects[i] != null)
{
summary += draggableObjects[i].name + ",";
}
}
} }
if (targetObject != null)
summary += "\nTarget: ";
if (this.targetObjects != null && this.targetObjects.Count != 0)
{ {
summary += "\nTarget: " + targetObject.name; for (int i = 0; i < this.targetObjects.Count; i++)
{
if (targetObjects[i] != null)
{
summary += targetObjects[i].name + ",";
}
}
} }
if (summary.Length == 0) if (summary.Length == 0)
@ -155,6 +243,6 @@ namespace Fungus
return summary; return summary;
} }
#endregion #endregion Public members
} }
} }

114
Assets/Fungus/Scripts/EventHandlers/DragEntered.cs

@ -1,58 +1,115 @@
// This code is part of the Fungus library (https://github.com/snozbot/fungus) // This code is part of the Fungus library (https://github.com/snozbot/fungus)
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic; using System.Collections.Generic;
using UnityEngine;
namespace Fungus namespace Fungus
{ {
/// <summary> /// <summary>
/// The block will execute when the player is dragging an object which starts touching the target object. /// The block will execute when the player is dragging an object which starts touching the target object.
///
/// ExecuteAlways used to get the Compatibility that we need, use of ISerializationCallbackReceiver is error prone
/// when used on Unity controlled objects as it runs on threads other than main thread.
/// </summary> /// </summary>
[EventHandlerInfo("Sprite", [EventHandlerInfo("Sprite",
"Drag Entered", "Drag Entered",
"The block will execute when the player is dragging an object which starts touching the target object.")] "The block will execute when the player is dragging an object which starts touching the target object.")]
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragEntered : EventHandler [ExecuteInEditMode]
public class DragEntered : EventHandler, ISerializationCallbackReceiver
{ {
public class DragEnteredEvent public class DragEnteredEvent
{ {
public Draggable2D DraggableObject; public Draggable2D DraggableObject;
public Collider2D TargetCollider; public Collider2D TargetCollider;
public DragEnteredEvent(Draggable2D draggableObject, Collider2D targetCollider) public DragEnteredEvent(Draggable2D draggableObject, Collider2D targetCollider)
{ {
DraggableObject = draggableObject; DraggableObject = draggableObject;
TargetCollider = targetCollider; TargetCollider = targetCollider;
} }
} }
[VariableProperty(typeof(GameObjectVariable))]
[SerializeField] protected GameObjectVariable draggableRef;
[VariableProperty(typeof(GameObjectVariable))]
[SerializeField] protected GameObjectVariable targetRef;
[Tooltip("Draggable object to listen for drag events on")] [Tooltip("Draggable object to listen for drag events on")]
[HideInInspector]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
[SerializeField] protected List<Draggable2D> draggableObjects;
[Tooltip("Drag target object to listen for drag events on")] [Tooltip("Drag target object to listen for drag events on")]
[HideInInspector]
[SerializeField] protected Collider2D targetObject; [SerializeField] protected Collider2D targetObject;
[SerializeField] protected List<Collider2D> targetObjects;
protected EventDispatcher eventDispatcher; protected EventDispatcher eventDispatcher;
protected virtual void OnEnable() protected virtual void OnEnable()
{ {
eventDispatcher = FungusManager.Instance.EventDispatcher; if (Application.isPlaying)
{
eventDispatcher = FungusManager.Instance.EventDispatcher;
eventDispatcher.AddListener<DragEnteredEvent>(OnDragEnteredEvent); eventDispatcher.AddListener<DragEnteredEvent>(OnDragEnteredEvent);
}
} }
protected virtual void OnDisable() protected virtual void OnDisable()
{ {
eventDispatcher.RemoveListener<DragEnteredEvent>(OnDragEnteredEvent); if (Application.isPlaying)
{
eventDispatcher.RemoveListener<DragEnteredEvent>(OnDragEnteredEvent);
eventDispatcher = null; eventDispatcher = null;
}
} }
void OnDragEnteredEvent(DragEnteredEvent evt) private void OnDragEnteredEvent(DragEnteredEvent evt)
{ {
OnDragEntered(evt.DraggableObject, evt.TargetCollider); OnDragEntered(evt.DraggableObject, evt.TargetCollider);
} }
#region Compatibility
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
private void Awake()
{
//add any dragableobject already present to list for backwards compatability
if (draggableObject != null)
{
if (!draggableObjects.Contains(draggableObject))
{
draggableObjects.Add(draggableObject);
}
}
if (targetObject != null)
{
if (!targetObjects.Contains(targetObject))
{
targetObjects.Add(targetObject);
}
}
draggableObject = null;
targetObject = null;
}
#endregion Compatibility
#region Public members #region Public members
/// <summary> /// <summary>
@ -60,23 +117,46 @@ namespace Fungus
/// </summary> /// </summary>
public virtual void OnDragEntered(Draggable2D draggableObject, Collider2D targetObject) public virtual void OnDragEntered(Draggable2D draggableObject, Collider2D targetObject)
{ {
if (draggableObject == this.draggableObject && if (this.targetObjects != null && this.draggableObjects != null &&
targetObject == this.targetObject) this.draggableObjects.Contains(draggableObject) &&
this.targetObjects.Contains(targetObject))
{ {
if (draggableRef != null)
{
draggableRef.Value = draggableObject.gameObject;
}
if (targetRef != null)
{
targetRef.Value = targetObject.gameObject;
}
ExecuteBlock(); ExecuteBlock();
} }
} }
public override string GetSummary() public override string GetSummary()
{ {
string summary = ""; string summary = "Draggable: ";
if (draggableObject != null) if (this.draggableObjects != null && this.draggableObjects.Count != 0)
{ {
summary += "\nDraggable: " + draggableObject.name; for (int i = 0; i < this.draggableObjects.Count; i++)
{
if (draggableObjects[i] != null)
{
summary += draggableObjects[i].name + ",";
}
}
} }
if (targetObject != null)
summary += "\nTarget: ";
if (this.targetObjects != null && this.targetObjects.Count != 0)
{ {
summary += "\nTarget: " + targetObject.name; for (int i = 0; i < this.targetObjects.Count; i++)
{
if (targetObjects[i] != null)
{
summary += targetObjects[i].name + ",";
}
}
} }
if (summary.Length == 0) if (summary.Length == 0)
@ -87,6 +167,6 @@ namespace Fungus
return summary; return summary;
} }
#endregion #endregion Public members
} }
} }

111
Assets/Fungus/Scripts/EventHandlers/DragExited.cs

@ -1,23 +1,29 @@
// This code is part of the Fungus library (https://github.com/snozbot/fungus) // This code is part of the Fungus library (https://github.com/snozbot/fungus)
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine; using System.Collections.Generic;
using UnityEngine;
namespace Fungus namespace Fungus
{ {
/// <summary> /// <summary>
/// The block will execute when the player is dragging an object which stops touching the target object. /// The block will execute when the player is dragging an object which stops touching the target object.
///
/// ExecuteAlways used to get the Compatibility that we need, use of ISerializationCallbackReceiver is error prone
/// when used on Unity controlled objects as it runs on threads other than main thread.
/// </summary> /// </summary>
[EventHandlerInfo("Sprite", [EventHandlerInfo("Sprite",
"Drag Exited", "Drag Exited",
"The block will execute when the player is dragging an object which stops touching the target object.")] "The block will execute when the player is dragging an object which stops touching the target object.")]
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragExited : EventHandler [ExecuteInEditMode]
public class DragExited : EventHandler, ISerializationCallbackReceiver
{ {
public class DragExitedEvent public class DragExitedEvent
{ {
public Draggable2D DraggableObject; public Draggable2D DraggableObject;
public Collider2D TargetCollider; public Collider2D TargetCollider;
public DragExitedEvent(Draggable2D draggableObject, Collider2D targetCollider) public DragExitedEvent(Draggable2D draggableObject, Collider2D targetCollider)
{ {
DraggableObject = draggableObject; DraggableObject = draggableObject;
@ -25,33 +31,85 @@ namespace Fungus
} }
} }
[VariableProperty(typeof(GameObjectVariable))]
[SerializeField] protected GameObjectVariable draggableRef;
[VariableProperty(typeof(GameObjectVariable))]
[SerializeField] protected GameObjectVariable targetRef;
[Tooltip("Draggable object to listen for drag events on")] [Tooltip("Draggable object to listen for drag events on")]
[HideInInspector]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
[SerializeField] protected List<Draggable2D> draggableObjects;
[Tooltip("Drag target object to listen for drag events on")] [Tooltip("Drag target object to listen for drag events on")]
[HideInInspector]
[SerializeField] protected Collider2D targetObject; [SerializeField] protected Collider2D targetObject;
[SerializeField] protected List<Collider2D> targetObjects;
protected EventDispatcher eventDispatcher; protected EventDispatcher eventDispatcher;
protected virtual void OnEnable() protected virtual void OnEnable()
{ {
eventDispatcher = FungusManager.Instance.EventDispatcher; if (Application.isPlaying)
{
eventDispatcher = FungusManager.Instance.EventDispatcher;
eventDispatcher.AddListener<DragExitedEvent>(OnDragEnteredEvent); eventDispatcher.AddListener<DragExitedEvent>(OnDragEnteredEvent);
}
} }
protected virtual void OnDisable() protected virtual void OnDisable()
{ {
eventDispatcher.RemoveListener<DragExitedEvent>(OnDragEnteredEvent); if (Application.isPlaying)
{
eventDispatcher.RemoveListener<DragExitedEvent>(OnDragEnteredEvent);
eventDispatcher = null; eventDispatcher = null;
}
} }
void OnDragEnteredEvent(DragExitedEvent evt) private void OnDragEnteredEvent(DragExitedEvent evt)
{ {
OnDragExited(evt.DraggableObject, evt.TargetCollider); OnDragExited(evt.DraggableObject, evt.TargetCollider);
} }
#region Compatibility
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
private void Awake()
{
//add any dragableobject already present to list for backwards compatability
if (draggableObject != null)
{
if (!draggableObjects.Contains(draggableObject))
{
draggableObjects.Add(draggableObject);
}
}
if (targetObject != null)
{
if (!targetObjects.Contains(targetObject))
{
targetObjects.Add(targetObject);
}
}
draggableObject = null;
targetObject = null;
}
#endregion Compatibility
#region Public members #region Public members
/// <summary> /// <summary>
@ -59,23 +117,46 @@ namespace Fungus
/// </summary> /// </summary>
public virtual void OnDragExited(Draggable2D draggableObject, Collider2D targetObject) public virtual void OnDragExited(Draggable2D draggableObject, Collider2D targetObject)
{ {
if (draggableObject == this.draggableObject && if (this.targetObjects != null && this.draggableObjects != null &&
targetObject == this.targetObject) this.draggableObjects.Contains(draggableObject) &&
this.targetObjects.Contains(targetObject))
{ {
if (draggableRef != null)
{
draggableRef.Value = draggableObject.gameObject;
}
if (targetRef != null)
{
targetRef.Value = targetObject.gameObject;
}
ExecuteBlock(); ExecuteBlock();
} }
} }
public override string GetSummary() public override string GetSummary()
{ {
string summary = ""; string summary = "Draggable: ";
if (draggableObject != null) if (this.draggableObjects != null && this.draggableObjects.Count != 0)
{ {
summary += "\nDraggable: " + draggableObject.name; for (int i = 0; i < this.draggableObjects.Count; i++)
{
if (draggableObjects[i] != null)
{
summary += draggableObjects[i].name + ",";
}
}
} }
if (targetObject != null)
summary += "\nTarget: ";
if (this.targetObjects != null && this.targetObjects.Count != 0)
{ {
summary += "\nTarget: " + targetObject.name; for (int i = 0; i < this.targetObjects.Count; i++)
{
if (targetObjects[i] != null)
{
summary += targetObjects[i].name + ",";
}
}
} }
if (summary.Length == 0) if (summary.Length == 0)
@ -86,6 +167,6 @@ namespace Fungus
return summary; return summary;
} }
#endregion #endregion Public members
} }
} }

61
Assets/Fungus/Scripts/EventHandlers/DragStarted.cs

@ -1,7 +1,8 @@
// This code is part of the Fungus library (https://github.com/snozbot/fungus) // This code is part of the Fungus library (https://github.com/snozbot/fungus)
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine; using System.Collections.Generic;
using UnityEngine;
namespace Fungus namespace Fungus
{ {
@ -12,17 +13,24 @@ namespace Fungus
"Drag Started", "Drag Started",
"The block will execute when the player starts dragging an object.")] "The block will execute when the player starts dragging an object.")]
[AddComponentMenu("")] [AddComponentMenu("")]
public class DragStarted : EventHandler public class DragStarted : EventHandler, ISerializationCallbackReceiver
{ {
public class DragStartedEvent public class DragStartedEvent
{ {
public Draggable2D DraggableObject; public Draggable2D DraggableObject;
public DragStartedEvent(Draggable2D draggableObject) public DragStartedEvent(Draggable2D draggableObject)
{ {
DraggableObject = draggableObject; DraggableObject = draggableObject;
} }
} }
[VariableProperty(typeof(GameObjectVariable))]
[SerializeField] protected GameObjectVariable draggableRef;
[SerializeField] protected List<Draggable2D> draggableObjects;
[HideInInspector]
[SerializeField] protected Draggable2D draggableObject; [SerializeField] protected Draggable2D draggableObject;
protected EventDispatcher eventDispatcher; protected EventDispatcher eventDispatcher;
@ -41,11 +49,32 @@ namespace Fungus
eventDispatcher = null; eventDispatcher = null;
} }
void OnDragStartedEvent(DragStartedEvent evt) private void OnDragStartedEvent(DragStartedEvent evt)
{ {
OnDragStarted(evt.DraggableObject); OnDragStarted(evt.DraggableObject);
} }
#region Compatibility
void ISerializationCallbackReceiver.OnAfterDeserialize()
{
//add any dragableobject already present to list for backwards compatability
if (draggableObject != null)
{
if (!draggableObjects.Contains(draggableObject))
{
draggableObjects.Add(draggableObject);
}
draggableObject = null;
}
}
void ISerializationCallbackReceiver.OnBeforeSerialize()
{
}
#endregion Compatibility
#region Public members #region Public members
/// <summary> /// <summary>
@ -53,22 +82,38 @@ namespace Fungus
/// </summary> /// </summary>
public virtual void OnDragStarted(Draggable2D draggableObject) public virtual void OnDragStarted(Draggable2D draggableObject)
{ {
if (draggableObject == this.draggableObject) if (draggableObjects.Contains(draggableObject))
{ {
if (draggableRef != null)
{
draggableRef.Value = draggableObject.gameObject;
}
ExecuteBlock(); ExecuteBlock();
} }
} }
public override string GetSummary() public override string GetSummary()
{ {
if (draggableObject != null) string summary = "Draggable: ";
if (this.draggableObjects != null && this.draggableObjects.Count != 0)
{
for (int i = 0; i < this.draggableObjects.Count; i++)
{
if (draggableObjects[i] != null)
{
summary += draggableObjects[i].name + ",";
}
}
}
if (summary.Length == 0)
{ {
return draggableObject.name; return "None";
} }
return "None"; return summary;
} }
#endregion #endregion Public members
} }
} }

13
Assets/Fungus/Scripts/Interfaces/IWriterListener.cs

@ -2,7 +2,6 @@
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
using UnityEngine; using UnityEngine;
using System.Collections;
namespace Fungus namespace Fungus
{ {
@ -28,10 +27,20 @@ namespace Fungus
/// Called when the Writer has resumed writing text. /// Called when the Writer has resumed writing text.
void OnResume(); void OnResume();
/// Called when the Writer has finished writing text. /// Called when the Writer has finished.
/// <param name="stopAudio">Controls whether audio should be stopped when writing ends.</param> /// <param name="stopAudio">Controls whether audio should be stopped when writing ends.</param>
void OnEnd(bool stopAudio); void OnEnd(bool stopAudio);
/// <summary>
/// Called when the Writer has no more Words remaining, but may have waits or other tokens still pending.
/// Will not be called if there is NO Words for the writer to process in the first place. e.g. Audio only says
/// do not trigger this.
///
/// Note that the writer does not know what may happen after it's job is done. If a following Say does
/// not clear the existing, you'll get what looks like AllWordsWritten and then more words written.
/// </summary>
void OnAllWordsWritten();
/// Called every time the Writer writes a new character glyph. /// Called every time the Writer writes a new character glyph.
void OnGlyph(); void OnGlyph();

12
Assets/Fungus/Scripts/VariableTypes/Collection/Collection.cs

@ -17,13 +17,13 @@ namespace Fungus
{ {
public abstract int Capacity { get; set; } public abstract int Capacity { get; set; }
public abstract int Count { get; } public abstract int Count { get; }
public bool IsFixedSize => false; public bool IsFixedSize { get { return false; } }
public bool IsReadOnly => false; public bool IsReadOnly { get { return false; } }
public bool IsSynchronized => false; public bool IsSynchronized { get { return false; } }
public object SyncRoot => null; public object SyncRoot { get { return null; } }
public string Name => name; public string Name { get { return name; } }
public object this[int index] { get => Get(index); set => Set(index, value); } public object this[int index] { get { return Get(index); } set { Set(index, value); } }
public abstract int Add(object o); public abstract int Add(object o);

2
Assets/Fungus/Scripts/VariableTypes/Collection/GenericCollection.cs

@ -38,7 +38,7 @@ namespace Fungus
} }
} }
public override int Count => collection.Count; public override int Count { get { return collection.Count; } }
public override int Add(object o) public override int Add(object o)
{ {

12
Assets/Fungus/Scripts/VariableTypes/Vector2Variable.cs

@ -33,10 +33,22 @@ namespace Fungus
Value -= value; Value -= value;
break; break;
case SetOperator.Multiply: case SetOperator.Multiply:
#if UNITY_2019_2_OR_NEWER
Value *= value; Value *= value;
#else
var tmpM = Value;
tmpM.Scale(value);
Value = tmpM;
#endif
break; break;
case SetOperator.Divide: case SetOperator.Divide:
#if UNITY_2019_2_OR_NEWER
Value /= value; Value /= value;
#else
var tmpD = Value;
tmpD.Scale(new Vector2(1.0f / value.x, 1.0f / value.y));
Value = tmpD;
#endif
break; break;
default: default:
base.Apply(setOperator, value); base.Apply(setOperator, value);

1635
Assets/FungusExamples/DragAndDrop/DragandDrop(DraggableObjectLists).unity

File diff suppressed because it is too large Load Diff

7
Assets/FungusExamples/DragAndDrop/DragandDrop(DraggableObjectLists).unity.meta

@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a8833e6d8e2df434a83b8d9a29907351
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

6613
Assets/FungusExamples/FungusTown/FungusTown.unity

File diff suppressed because it is too large Load Diff

2298
Assets/FungusExamples/TheHunter/TheHunter.unity

File diff suppressed because it is too large Load Diff

2
Assets/Tests/PlayMode/FungusPlayModeTest.cs

@ -1,6 +1,7 @@
// This code is part of the Fungus library (https://github.com/snozbot/fungus) // This code is part of the Fungus library (https://github.com/snozbot/fungus)
// It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE) // It is released for free under the MIT open source license (https://github.com/snozbot/fungus/blob/master/LICENSE)
#if UNITY_2019_2_OR_NEWER
using NUnit.Framework; using NUnit.Framework;
using System.Collections; using System.Collections;
using UnityEngine.TestTools; using UnityEngine.TestTools;
@ -29,3 +30,4 @@ namespace Fungus.Tests
} }
} }
} }
#endif

4
ProjectSettings/ProjectVersion.txt

@ -1,2 +1,2 @@
m_EditorVersion: 2019.2.15f1 m_EditorVersion: 2019.2.11f1
m_EditorVersionWithRevision: 2019.2.15f1 (dcb72c2e9334) m_EditorVersionWithRevision: 2019.2.11f1 (5f859a4cfee5)

Loading…
Cancel
Save