Browse Source

Added simpler Page handling, manual pan mode and more

- There is now only one Page game object. It is created automatically
by the Game class on startup.
- To control Page layout, use the new SetPageTop(), SetPageMiddle(),
SetPageBottom(), SetPageRect() & SetPageBounds() commands.
- You can still specify Page layout in the editor using the new
PageBounds script & prefab, using the SetPageBounds() method.
- Replaced Game.mainCamera with built-in Camera.main
- Added StoreView() and PanToStoredView()
- Game class now handles rendering fade texture (instead of
CameraController)
- Game class handles rendering pan / continue icons
- Added new StartManualPan() and StopManualPan() commands to manually
pan between 2 views
- Removed continueStyle class & prefab (replaced by continue icon
rendering)
- Removed Game.activeView as it’s not needed
- Parallax factor can now be controlled in X & Y
- Reorganised command classes
- Added PanToPosition() command
- Pages now default to display full-size at bottom of screen.
- Changed Page.VerticalAlign to Page.Layout and provided better options
for controlling how the page automatically resizes.
master
chrisgregan 11 years ago
parent
commit
20b795771b
  1. 98
      Assets/Fungus/Editor/PageEditor.cs
  2. BIN
      Assets/Fungus/Prefabs/ContinueStyle.prefab
  3. 4
      Assets/Fungus/Prefabs/ContinueStyle.prefab.meta
  4. BIN
      Assets/Fungus/Prefabs/Game.prefab
  5. BIN
      Assets/Fungus/Prefabs/Page.prefab
  6. 4
      Assets/Fungus/Prefabs/Page.prefab.meta
  7. BIN
      Assets/Fungus/Prefabs/PageStyle1.prefab
  8. BIN
      Assets/Fungus/Prefabs/Room.prefab
  9. 251
      Assets/Fungus/Scripts/CameraController.cs
  10. 757
      Assets/Fungus/Scripts/Commands.cs
  11. 5
      Assets/Fungus/Scripts/Commands.meta
  12. 113
      Assets/Fungus/Scripts/Commands/AudioCommands.cs
  13. 2
      Assets/Fungus/Scripts/Commands/AudioCommands.cs.meta
  14. 273
      Assets/Fungus/Scripts/Commands/CameraCommands.cs
  15. 2
      Assets/Fungus/Scripts/Commands/CameraCommands.cs.meta
  16. 168
      Assets/Fungus/Scripts/Commands/GameCommands.cs
  17. 2
      Assets/Fungus/Scripts/Commands/GameCommands.cs.meta
  18. 243
      Assets/Fungus/Scripts/Commands/PageCommands.cs
  19. 8
      Assets/Fungus/Scripts/Commands/PageCommands.cs.meta
  20. 119
      Assets/Fungus/Scripts/Commands/SpriteCommands.cs
  21. 8
      Assets/Fungus/Scripts/Commands/SpriteCommands.cs.meta
  22. 48
      Assets/Fungus/Scripts/ContinueStyle.cs
  23. 80
      Assets/Fungus/Scripts/Game.cs
  24. 234
      Assets/Fungus/Scripts/GameController.cs
  25. 168
      Assets/Fungus/Scripts/Page.cs
  26. 4
      Assets/Fungus/Scripts/Parallax.cs
  27. 18
      Assets/Fungus/Scripts/Room.cs
  28. 9
      Assets/FungusExample/Scripts/PageRoom.cs

98
Assets/Fungus/Editor/PageEditor.cs

@ -1,98 +0,0 @@
using UnityEditor;
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
namespace Fungus
{
[CanEditMultipleObjects]
[CustomEditor (typeof(Page))]
public class PageEditor : Editor
{
void OnSceneGUI ()
{
Page t = target as Page;
// Render the parent view to help user position the page
Transform parent = t.transform.parent;
if (parent != null)
{
View view = parent.gameObject.GetComponent<View>();
if (view != null)
{
ViewEditor.DrawView(view);
}
}
if (t.enabled)
{
EditPageBounds();
}
if (GUI.changed)
{
EditorUtility.SetDirty(target);
}
}
void EditPageBounds()
{
Page t = target as Page;
Vector3 pos = t.transform.position;
Vector3[] verts = new Vector3[4];
verts[0] = new Vector3(pos.x + t.pageBounds.min.x, pos.y + t.pageBounds.min.y, 0);
verts[1] = new Vector3(pos.x + t.pageBounds.min.x, pos.y + t.pageBounds.max.y, 0);
verts[2] = new Vector3(pos.x + t.pageBounds.max.x, pos.y + t.pageBounds.max.y, 0);
verts[3] = new Vector3(pos.x + t.pageBounds.max.x, pos.y + t.pageBounds.min.y, 0);
Handles.DrawSolidRectangleWithOutline(verts, new Color(1,1,1,0.2f), new Color(0,0,0,1));
for(int i = 0; i < 4; ++i)
{
Vector3 vert = verts[i];
Vector3 newPos = Handles.FreeMoveHandle(vert,
Quaternion.identity,
HandleUtility.GetHandleSize(pos) * 0.1f,
Vector3.zero,
Handles.CubeCap);
newPos.z = 0;
verts[i] = newPos;
if (vert != newPos)
{
switch(i)
{
case 0:
verts[1].x = newPos.x;
verts[3].y = newPos.y;
break;
case 1:
verts[0].x = newPos.x;
verts[2].y = newPos.y;
break;
case 2:
verts[3].x = newPos.x;
verts[1].y = newPos.y;
break;
case 3:
verts[2].x = newPos.x;
verts[0].y = newPos.y;
break;
}
break;
}
}
Bounds newBounds = new Bounds(verts[0], Vector3.zero);
newBounds.Encapsulate(verts[1]);
newBounds.Encapsulate(verts[2]);
newBounds.Encapsulate(verts[3]);
t.transform.position = newBounds.center;
newBounds.center = Vector3.zero;
t.pageBounds = newBounds;
}
}
}

BIN
Assets/Fungus/Prefabs/ContinueStyle.prefab

Binary file not shown.

4
Assets/Fungus/Prefabs/ContinueStyle.prefab.meta

@ -1,4 +0,0 @@
fileFormatVersion: 2
guid: dcca71ea1c47741ce882a7c9dea90719
NativeFormatImporter:
userData:

BIN
Assets/Fungus/Prefabs/Game.prefab

Binary file not shown.

BIN
Assets/Fungus/Prefabs/Page.prefab

Binary file not shown.

4
Assets/Fungus/Prefabs/Page.prefab.meta

@ -1,4 +0,0 @@
fileFormatVersion: 2
guid: ec557b5a76ab94961964394b8511fc9b
NativeFormatImporter:
userData:

BIN
Assets/Fungus/Prefabs/PageStyle1.prefab

Binary file not shown.

BIN
Assets/Fungus/Prefabs/Room.prefab

Binary file not shown.

251
Assets/Fungus/Scripts/CameraController.cs

@ -13,40 +13,23 @@ namespace Fungus
public class CameraController : MonoBehaviour public class CameraController : MonoBehaviour
{ {
Game game; Game game;
Camera mainCamera;
float fadeAlpha = 0f; // Manual panning control
View manualPanViewA;
View manualPanViewB;
Vector3 previousMousePos;
void Start() class CameraView
{ {
game = Game.GetInstance(); public Vector3 cameraPos;
public float cameraSize;
};
GameObject cameraObject = GameObject.FindGameObjectWithTag("MainCamera"); Dictionary<string, CameraView> storedViews = new Dictionary<string, CameraView>();
if (cameraObject == null)
{
Debug.LogError("Failed to find game object with tag 'MainCamera'");
return;
}
mainCamera = cameraObject.GetComponent<Camera>();
if (mainCamera == null)
{
Debug.LogError("Failed to find camera component");
return;
}
}
void OnGUI()
{
int drawDepth = -1000;
if (fadeAlpha < 1f) void Start()
{ {
// 1 = scene fully visible game = Game.GetInstance();
// 0 = scene fully obscured
GUI.color = new Color(1,1,1, 1f - fadeAlpha);
GUI.depth = drawDepth;
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), game.fadeTexture);
}
} }
public void Fade(float targetAlpha, float fadeDuration, Action fadeAction) public void Fade(float targetAlpha, float fadeDuration, Action fadeAction)
@ -56,11 +39,13 @@ namespace Fungus
public void FadeToView(View view, float fadeDuration, Action fadeAction) public void FadeToView(View view, float fadeDuration, Action fadeAction)
{ {
game.manualPanActive = false;
// Fade out // Fade out
Fade(0f, fadeDuration / 2f, delegate { Fade(0f, fadeDuration / 2f, delegate {
// Snap to new view // Snap to new view
PanToView(view, 0f, null); PanToPosition(view.transform.position, view.viewSize, 0f, null);
// Fade in // Fade in
Fade(1f, fadeDuration / 2f, delegate { Fade(1f, fadeDuration / 2f, delegate {
@ -74,7 +59,7 @@ namespace Fungus
IEnumerator FadeInternal(float targetAlpha, float fadeDuration, Action fadeAction) IEnumerator FadeInternal(float targetAlpha, float fadeDuration, Action fadeAction)
{ {
float startAlpha = fadeAlpha; float startAlpha = Game.GetInstance().fadeAlpha;
float timer = 0; float timer = 0;
while (timer < fadeDuration) while (timer < fadeDuration)
@ -84,11 +69,11 @@ namespace Fungus
t = Mathf.Clamp01(t); t = Mathf.Clamp01(t);
fadeAlpha = Mathf.Lerp(startAlpha, targetAlpha, t); Game.GetInstance().fadeAlpha = Mathf.Lerp(startAlpha, targetAlpha, t);
yield return null; yield return null;
} }
fadeAlpha = targetAlpha; Game.GetInstance().fadeAlpha = targetAlpha;
if (fadeAction != null) if (fadeAction != null)
{ {
@ -102,31 +87,75 @@ namespace Fungus
*/ */
public void CenterOnSprite(SpriteRenderer spriteRenderer) public void CenterOnSprite(SpriteRenderer spriteRenderer)
{ {
game.manualPanActive = false;
Sprite sprite = spriteRenderer.sprite; Sprite sprite = spriteRenderer.sprite;
Vector3 extents = sprite.bounds.extents; Vector3 extents = sprite.bounds.extents;
float localScaleY = spriteRenderer.transform.localScale.y; float localScaleY = spriteRenderer.transform.localScale.y;
mainCamera.orthographicSize = extents.y * localScaleY; Camera.main.orthographicSize = extents.y * localScaleY;
Vector3 pos = spriteRenderer.transform.position; Vector3 pos = spriteRenderer.transform.position;
mainCamera.transform.position = new Vector3(pos.x, pos.y, 0); Camera.main.transform.position = new Vector3(pos.x, pos.y, 0);
SetCameraZ();
}
/**
* Moves camera from current position to a target position over a period of time.
*/
public void PanToPosition(Vector3 targetPosition, float targetSize, float duration, Action arriveAction)
{
game.manualPanActive = false;
if (duration == 0f)
{
// Move immediately
Camera.main.orthographicSize = targetSize;
Camera.main.transform.position = targetPosition;
SetCameraZ(); SetCameraZ();
if (arriveAction != null)
{
arriveAction();
}
}
else
{
StartCoroutine(PanInternal(targetPosition, targetSize, duration, arriveAction));
}
} }
public void SnapToView(View view) /**
* Stores the current camera view using a name.
*/
public void StoreView(string viewName)
{ {
PanToView(view, 0, null); CameraView currentView = new CameraView();
currentView.cameraPos = Camera.main.transform.position;
currentView.cameraSize = Camera.main.orthographicSize;
storedViews[viewName] = currentView;
} }
/** /**
* Moves camera from current position to a target View over a period of time. * Moves the camera to a previously stored camera view over a period of time.
*/ */
public void PanToView(View view, float duration, Action arriveAction) public void PanToStoredView(string viewName, float duration, Action arriveAction)
{
if (!storedViews.ContainsKey(viewName))
{ {
// View has not previously been stored
if (arriveAction != null)
{
arriveAction();
}
return;
}
CameraView cameraView = storedViews[viewName];
if (duration == 0f) if (duration == 0f)
{ {
// Move immediately // Move immediately
mainCamera.orthographicSize = view.viewSize; Camera.main.transform.position = cameraView.cameraPos;
mainCamera.transform.position = view.transform.position; Camera.main.orthographicSize = cameraView.cameraSize;
SetCameraZ(); SetCameraZ();
if (arriveAction != null) if (arriveAction != null)
{ {
@ -135,17 +164,17 @@ namespace Fungus
} }
else else
{ {
StartCoroutine(PanInternal(view, duration, arriveAction)); StartCoroutine(PanInternal(cameraView.cameraPos, cameraView.cameraSize, duration, arriveAction));
} }
} }
IEnumerator PanInternal(View view, float duration, Action arriveAction) IEnumerator PanInternal(Vector3 targetPos, float targetSize, float duration, Action arriveAction)
{ {
float timer = 0; float timer = 0;
float startSize = mainCamera.orthographicSize; float startSize = Camera.main.orthographicSize;
float endSize = view.viewSize; float endSize = targetSize;
Vector3 startPos = mainCamera.transform.position; Vector3 startPos = Camera.main.transform.position;
Vector3 endPos = view.transform.position; Vector3 endPos = targetPos;
bool arrived = false; bool arrived = false;
while (!arrived) while (!arrived)
@ -159,8 +188,8 @@ namespace Fungus
// Apply smoothed lerp to camera position and orthographic size // Apply smoothed lerp to camera position and orthographic size
float t = timer / duration; float t = timer / duration;
mainCamera.orthographicSize = Mathf.Lerp(startSize, endSize, Mathf.SmoothStep(0f, 1f, t)); Camera.main.orthographicSize = Mathf.Lerp(startSize, endSize, Mathf.SmoothStep(0f, 1f, t));
mainCamera.transform.position = Vector3.Lerp(startPos, endPos, Mathf.SmoothStep(0f, 1f, t)); Camera.main.transform.position = Vector3.Lerp(startPos, endPos, Mathf.SmoothStep(0f, 1f, t));
SetCameraZ(); SetCameraZ();
if (arrived && if (arrived &&
@ -178,13 +207,15 @@ namespace Fungus
*/ */
public void PanToPath(View[] viewList, float duration, Action arriveAction) public void PanToPath(View[] viewList, float duration, Action arriveAction)
{ {
game.manualPanActive = false;
List<Vector3> pathList = new List<Vector3>(); List<Vector3> pathList = new List<Vector3>();
// Add current camera position as first point in path // Add current camera position as first point in path
// Note: We use the z coord to tween the camera orthographic size // Note: We use the z coord to tween the camera orthographic size
Vector3 startPos = new Vector3(mainCamera.transform.position.x, Vector3 startPos = new Vector3(Camera.main.transform.position.x,
mainCamera.transform.position.y, Camera.main.transform.position.y,
mainCamera.orthographicSize); Camera.main.orthographicSize);
pathList.Add(startPos); pathList.Add(startPos);
for (int i = 0; i < viewList.Length; ++i) for (int i = 0; i < viewList.Length; ++i)
@ -212,8 +243,8 @@ namespace Fungus
Vector3 point = iTween.PointOnPath(path, percent); Vector3 point = iTween.PointOnPath(path, percent);
mainCamera.transform.position = new Vector3(point.x, point.y, 0); Camera.main.transform.position = new Vector3(point.x, point.y, 0);
mainCamera.orthographicSize = point.z; Camera.main.orthographicSize = point.z;
SetCameraZ(); SetCameraZ();
yield return null; yield return null;
@ -225,17 +256,127 @@ namespace Fungus
} }
} }
/**
* Activates manual panning mode.
* The player can pan the camera within the area between viewA & viewB.
*/
public void StartManualPan(View viewA, View viewB, float duration, Action arriveAction)
{
manualPanViewA = viewA;
manualPanViewB = viewB;
Vector3 cameraPos = Camera.main.transform.position;
Vector3 targetPosition = CalcCameraPosition(cameraPos, manualPanViewA, manualPanViewB);
float targetSize = CalcCameraSize(cameraPos, manualPanViewA, manualPanViewB);
PanToPosition(targetPosition, targetSize, duration, delegate {
game.manualPanActive = true;
if (arriveAction != null)
{
arriveAction();
}
});
}
/**
* Deactivates manual panning mode.
*/
public void StopManualPan()
{
game.manualPanActive = false;
manualPanViewA = null;
manualPanViewB = null;
}
/** /**
* Returns the current position of the main camera. * Returns the current position of the main camera.
*/ */
public Vector3 GetCameraPosition() public Vector3 GetCameraPosition()
{ {
return mainCamera.transform.position; return Camera.main.transform.position;
} }
void SetCameraZ() void SetCameraZ()
{ {
mainCamera.transform.position = new Vector3(mainCamera.transform.position.x, mainCamera.transform.position.y, game.cameraZ); Camera.main.transform.position = new Vector3(Camera.main.transform.position.x, Camera.main.transform.position.y, game.cameraZ);
}
void Update()
{
if (!game.manualPanActive)
{
return;
}
Vector3 delta = Vector3.zero;
if (Input.touchCount > 0)
{
if (Input.GetTouch(0).phase == TouchPhase.Moved)
{
delta = Input.GetTouch(0).deltaPosition;
}
}
if (Input.GetMouseButtonDown(0))
{
previousMousePos = Input.mousePosition;
}
else if (Input.GetMouseButton(0))
{
delta = Input.mousePosition - previousMousePos;
previousMousePos = Input.mousePosition;
}
Vector3 cameraDelta = Camera.main.ScreenToViewportPoint(delta);
cameraDelta.x *= -2f;
cameraDelta.y *= -1f;
cameraDelta.z = 0f;
Vector3 cameraPos = Camera.main.transform.position;
cameraPos += cameraDelta;
Camera.main.transform.position = CalcCameraPosition(cameraPos, manualPanViewA, manualPanViewB);
Camera.main.orthographicSize = CalcCameraSize(cameraPos, manualPanViewA, manualPanViewB);
}
// Clamp camera position to region defined by the two views
Vector3 CalcCameraPosition(Vector3 pos, View viewA, View viewB)
{
Vector3 safePos = pos;
// Clamp camera position to region defined by the two views
safePos.x = Mathf.Max(safePos.x, Mathf.Min(viewA.transform.position.x, viewB.transform.position.x));
safePos.x = Mathf.Min(safePos.x, Mathf.Max(viewA.transform.position.x, viewB.transform.position.x));
safePos.y = Mathf.Max(safePos.y, Mathf.Min(viewA.transform.position.y, viewB.transform.position.y));
safePos.y = Mathf.Min(safePos.y, Mathf.Max(viewA.transform.position.y, viewB.transform.position.y));
return safePos;
}
// Smoothly interpolate camera orthographic size based on relative position to two views
float CalcCameraSize(Vector3 pos, View viewA, View viewB)
{
// Get ray and point in same space
Vector3 toViewB = viewB.transform.position - viewA.transform.position;
Vector3 localPos = pos - viewA.transform.position;
// Normalize
float distance = toViewB.magnitude;
toViewB /= distance;
localPos /= distance;
// Project point onto ray
float t = Vector3.Dot(toViewB, localPos);
t = Mathf.Clamp01(t); // Not really necessary but no harm
float cameraSize = Mathf.Lerp(viewA.viewSize, viewB.viewSize, t);
return cameraSize;
} }
} }
} }

757
Assets/Fungus/Scripts/Commands.cs

@ -1,757 +0,0 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
namespace Fungus
{
/**
* Command classes have their own namespace to prevent them popping up in code completion
*/
namespace Command
{
/**
* Call a delegate method on execution.
* This command can be used to schedule arbitrary script code.
*/
public class CallCommand : CommandQueue.Command
{
Action callAction;
public CallCommand(Action _callAction)
{
if (_callAction == null)
{
Debug.LogError("Action must not be null.");
return;
}
callAction = _callAction;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
if (callAction != null)
{
callAction();
}
// Execute next command
onComplete();
}
}
/**
* Wait for a period of time.
*/
public class WaitCommand : CommandQueue.Command
{
float duration;
public WaitCommand(float _duration)
{
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().waiting = true;
commandQueue.StartCoroutine(WaitCoroutine(duration, onComplete));
}
IEnumerator WaitCoroutine(float duration, Action onComplete)
{
yield return new WaitForSeconds(duration);
if (onComplete != null)
{
Game.GetInstance().waiting = false;
onComplete();
}
}
}
/**
* Wait for a player tap/click/key press
*/
public class WaitForInputCommand : CommandQueue.Command
{
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().waiting = true;
commandQueue.StartCoroutine(WaitCoroutine(onComplete));
}
IEnumerator WaitCoroutine(Action onComplete)
{
while (true)
{
if (Input.GetMouseButtonDown(0) || Input.anyKeyDown)
{
break;
}
yield return null;
}
if (onComplete != null)
{
Game.GetInstance().waiting = false;
onComplete();
}
}
}
/**
* Sets the currently active view immediately.
* The main camera snaps to the active view.
*/
public class SetViewCommand : CommandQueue.Command
{
View view;
public SetViewCommand(View _view)
{
if (_view == null)
{
Debug.LogError("View must not be null");
}
view = _view;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.cameraController.SnapToView(view);
game.activeView = view;
// Set the first page component found (if any) as the active page
Page page = view.gameObject.GetComponentInChildren<Page>();
if (page != null)
{
Game.GetInstance().activePage = page;
}
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets the currently active page for text rendering.
*/
public class SetPageCommand : CommandQueue.Command
{
Page page;
public SetPageCommand(Page _page)
{
page = _page;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().activePage = page;
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets the currently active Page Style for rendering Pages.
*/
public class SetPageStyleCommand : CommandQueue.Command
{
PageStyle pageStyle;
public SetPageStyleCommand(PageStyle _pageStyle)
{
pageStyle = _pageStyle;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().activePageStyle = pageStyle;
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets the header text displayed at the top of the active page.
*/
public class HeaderCommand : CommandQueue.Command
{
string titleText;
public HeaderCommand(string _titleText)
{
titleText = _titleText;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.SetHeader(titleText);
}
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets the footer text displayed at the top of the active page.
*/
public class FooterCommand : CommandQueue.Command
{
string titleText;
public FooterCommand(string _titleText)
{
titleText = _titleText;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.SetFooter(titleText);
}
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Writes story text to the currently active page.
* A 'continue' button is displayed when the text has fully appeared.
*/
public class SayCommand : CommandQueue.Command
{
string storyText;
public SayCommand(string _storyText)
{
storyText = _storyText;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.Say(storyText, onComplete);
}
}
}
/**
* Adds an option button to the current list of options.
* Use the Choose command to display added options.
*/
public class AddOptionCommand : CommandQueue.Command
{
string optionText;
Action optionAction;
public AddOptionCommand(string _optionText, Action _optionAction)
{
optionText = _optionText;
optionAction = _optionAction;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.AddOption(optionText, optionAction);
}
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Displays all previously added options.
*/
public class ChooseCommand : CommandQueue.Command
{
string chooseText;
public ChooseCommand(string _chooseText)
{
chooseText = _chooseText;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.Choose(chooseText);
}
// Choose always clears commandQueue, so no need to call onComplete()
}
}
/**
* Changes the active room to a different room
*/
public class MoveToRoomCommand : CommandQueue.Command
{
Room room;
public MoveToRoomCommand(Room _room)
{
if (_room == null)
{
Debug.LogError("Room must not be null.");
return;
}
room = _room;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
// Fade out screen
game.cameraController.Fade(0f, game.roomFadeDuration / 2f, delegate {
game.activeRoom = room;
// Notify room script that the Room is being entered
// Calling private method on Room to hide implementation
game.activeRoom.gameObject.SendMessage("Enter");
// Fade in screen
game.cameraController.Fade(1f, game.roomFadeDuration / 2f, delegate {
game.waiting = false;
});
});
// MoveToRoom always resets the command queue so no need to call onComplete
}
}
/**
* Sets a globally accessible game value
*/
public class SetValueCommand : CommandQueue.Command
{
string key;
int value;
public SetValueCommand(string _key, int _value)
{
key = _key;
value = _value;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().SetGameValue(key, value);
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Fades a sprite to a given alpha value over a period of time
*/
public class FadeSpriteCommand : CommandQueue.Command
{
SpriteRenderer spriteRenderer;
Color targetColor;
float fadeDuration;
Vector2 slideOffset = Vector2.zero;
public FadeSpriteCommand(SpriteRenderer _spriteRenderer,
Color _targetColor,
float _fadeDuration,
Vector2 _slideOffset)
{
if (_spriteRenderer == null)
{
Debug.LogError("Sprite renderer must not be null.");
return;
}
spriteRenderer = _spriteRenderer;
targetColor = _targetColor;
fadeDuration = _fadeDuration;
slideOffset = _slideOffset;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
SpriteFader.FadeSprite(spriteRenderer, targetColor, fadeDuration, slideOffset);
// Fade is asynchronous, but command completes immediately.
// If you need to wait for the fade to complete, just use an additional Wait() command
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets an animator trigger to change the animator state for an animated sprite
*/
public class SetAnimatorTriggerCommand : CommandQueue.Command
{
Animator animator;
string triggerName;
public SetAnimatorTriggerCommand(Animator _animator,
string _triggerName)
{
if (_animator == null)
{
Debug.LogError("Animator must not be null.");
return;
}
animator = _animator;
triggerName = _triggerName;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
animator.SetTrigger(triggerName);
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Display a button and set the method to be called when player clicks.
*/
public class ShowButtonCommand : CommandQueue.Command
{
Button button;
bool visible;
Action buttonAction;
public ShowButtonCommand(Button _button,
bool _visible,
Action _buttonAction)
{
if (_button == null)
{
Debug.LogError("Button must not be null.");
return;
}
button = _button;
visible = _visible;
buttonAction = _buttonAction;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
button.Show(visible, buttonAction);
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Pans the camera to a view over a period of time.
*/
public class PanToViewCommand : CommandQueue.Command
{
View view;
float duration;
public PanToViewCommand(View _view,
float _duration)
{
if (_view == null)
{
Debug.LogError("View must not be null.");
return;
}
view = _view;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
game.cameraController.PanToView(view, duration, delegate {
game.activeView = view;
game.waiting = false;
// Try to find a page that is a child of the active view.
// If there are multiple child pages then it is the client's responsibility
// to set the correct active page in the room script.
Page defaultPage = view.gameObject.GetComponentInChildren<Page>();
if (defaultPage)
{
game.activePage = defaultPage;
}
if (onComplete != null)
{
onComplete();
}
});
}
}
/**
* Pans the camera through a sequence of views over a period of time.
*/
public class PanToPathCommand : CommandQueue.Command
{
View[] views;
float duration;
public PanToPathCommand(View[] _views,
float _duration)
{
if (_views.Length == 0)
{
Debug.LogError("View list must not be empty.");
return;
}
views = _views;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
game.cameraController.PanToPath(views, duration, delegate {
if (views.Length > 0)
{
game.activeView = views[views.Length - 1];
game.waiting = false;
// Try to find a page that is a child of the active view.
// If there are multiple child pages then it is the client's responsibility
// to set the correct active page in the room script.
Page defaultPage = game.activeView.gameObject.GetComponentInChildren<Page>();
if (defaultPage)
{
game.activePage = defaultPage;
}
}
if (onComplete != null)
{
onComplete();
}
});
}
}
/**
* Fades the camera to a view over a period of time.
*/
public class FadeToViewCommand : CommandQueue.Command
{
View view;
float duration;
public FadeToViewCommand(View _view,
float _duration)
{
if (_view == null)
{
Debug.LogError("View must not be null.");
return;
}
view = _view;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
game.cameraController.FadeToView(view, duration, delegate {
game.activeView = view;
game.waiting = false;
// Try to find a page that is a child of the active view.
// If there are multiple child pages then it is the client's responsibility
// to set the correct active page in the room script.
Page defaultPage = view.gameObject.GetComponentInChildren<Page>();
if (defaultPage)
{
game.activePage = defaultPage;
}
if (onComplete != null)
{
onComplete();
}
});
}
}
/**
* Plays a music clip
*/
public class PlayMusicCommand : CommandQueue.Command
{
AudioClip audioClip;
public PlayMusicCommand(AudioClip _audioClip)
{
if (_audioClip == null)
{
Debug.LogError("Audio clip must not be null.");
return;
}
audioClip = _audioClip;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.audio.clip = audioClip;
game.audio.Play();
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Stops a music clip
*/
public class StopMusicCommand : CommandQueue.Command
{
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.audio.Stop();
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Fades music volume to required level over a period of time
*/
public class SetMusicVolumeCommand : CommandQueue.Command
{
float musicVolume;
float duration;
public SetMusicVolumeCommand(float _musicVolume, float _duration)
{
musicVolume = _musicVolume;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
iTween.AudioTo(game.gameObject, musicVolume, 1f, duration);
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Plays a sound effect once
*/
public class PlaySoundCommand : CommandQueue.Command
{
AudioClip audioClip;
float volume;
public PlaySoundCommand(AudioClip _audioClip, float _volume)
{
audioClip = _audioClip;
volume = _volume;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.audio.PlayOneShot(audioClip, volume);
if (onComplete != null)
{
onComplete();
}
}
}
}
}

5
Assets/Fungus/Scripts/Commands.meta

@ -0,0 +1,5 @@
fileFormatVersion: 2
guid: ed31c7843a16b49bb918643ab98b7f67
folderAsset: yes
DefaultImporter:
userData:

113
Assets/Fungus/Scripts/Commands/AudioCommands.cs

@ -0,0 +1,113 @@
using UnityEngine;
using System;
using System.Collections;
namespace Fungus
{
/**
* Command classes have their own namespace to prevent them popping up in code completion
*/
namespace Command
{
/**
* Plays a music clip
*/
public class PlayMusic : CommandQueue.Command
{
AudioClip audioClip;
public PlayMusic(AudioClip _audioClip)
{
if (_audioClip == null)
{
Debug.LogError("Audio clip must not be null.");
return;
}
audioClip = _audioClip;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.audio.clip = audioClip;
game.audio.Play();
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Stops a music clip
*/
public class StopMusic : CommandQueue.Command
{
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.audio.Stop();
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Fades music volume to required level over a period of time
*/
public class SetMusicVolume : CommandQueue.Command
{
float musicVolume;
float duration;
public SetMusicVolume(float _musicVolume, float _duration)
{
musicVolume = _musicVolume;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
iTween.AudioTo(game.gameObject, musicVolume, 1f, duration);
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Plays a sound effect once
*/
public class PlaySound : CommandQueue.Command
{
AudioClip audioClip;
float volume;
public PlaySound(AudioClip _audioClip, float _volume)
{
audioClip = _audioClip;
volume = _volume;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.audio.PlayOneShot(audioClip, volume);
if (onComplete != null)
{
onComplete();
}
}
}
}
}

2
Assets/Fungus/Scripts/ContinueStyle.cs.meta → Assets/Fungus/Scripts/Commands/AudioCommands.cs.meta

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: b5c35620ec53b405a8d00dcb285cd260 guid: bc443341450b64de790b66416177cca7
MonoImporter: MonoImporter:
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []

273
Assets/Fungus/Scripts/Commands/CameraCommands.cs

@ -0,0 +1,273 @@
using UnityEngine;
using System;
using System.Collections;
namespace Fungus
{
/**
* Command classes have their own namespace to prevent them popping up in code completion.
*/
namespace Command
{
/**
* Sets the currently active view immediately.
* The main camera snaps to the active view.
*/
public class SetView : CommandQueue.Command
{
View view;
public SetView(View _view)
{
if (_view == null)
{
Debug.LogError("View must not be null");
}
view = _view;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.cameraController.PanToPosition(view.transform.position, view.viewSize, 0, null);
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Pans the camera to a target position & size over a period of time.
*/
public class PanToPosition : CommandQueue.Command
{
Vector3 targetPosition;
float targetSize;
float duration;
public PanToPosition(Vector3 _targetPosition, float _targetSize, float _duration)
{
targetPosition = _targetPosition;
targetSize = _targetSize;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
game.cameraController.PanToPosition(targetPosition, targetSize, duration, delegate {
game.waiting = false;
if (onComplete != null)
{
onComplete();
}
});
}
}
/**
* Pans the camera through a sequence of views over a period of time.
*/
public class PanToPath : CommandQueue.Command
{
View[] views;
float duration;
public PanToPath(View[] _views, float _duration)
{
if (_views.Length == 0)
{
Debug.LogError("View list must not be empty.");
return;
}
views = _views;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
game.cameraController.PanToPath(views, duration, delegate {
if (views.Length > 0)
{
game.waiting = false;
}
if (onComplete != null)
{
onComplete();
}
});
}
}
/**
* Fades the camera to a view over a period of time.
*/
public class FadeToView : CommandQueue.Command
{
View view;
float duration;
public FadeToView(View _view, float _duration)
{
if (_view == null)
{
Debug.LogError("View must not be null.");
return;
}
view = _view;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
game.cameraController.FadeToView(view, duration, delegate {
game.waiting = false;
if (onComplete != null)
{
onComplete();
}
});
}
}
/**
* Switches on manual pan mode.
* This allows the player to swipe the screen to pan around a region defined by 2 views.
*/
public class StartManualPan : CommandQueue.Command
{
View viewA;
View viewB;
float duration;
public StartManualPan(View _viewA, View _viewB, float _duration)
{
if (_viewA == null ||
_viewB == null)
{
Debug.LogError("Views must not be null.");
return;
}
viewA = _viewA;
viewB = _viewB;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
game.cameraController.StartManualPan(viewA, viewB, duration, delegate {
game.waiting = false;
if (onComplete != null)
{
onComplete();
}
});
}
}
/**
* Switches off manual pan mode.
*/
public class StopManualPan : CommandQueue.Command
{
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.cameraController.StopManualPan();
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Stores the current camera position
*/
public class StoreView : CommandQueue.Command
{
string viewName;
public StoreView(string _viewName)
{
viewName = _viewName;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.cameraController.StoreView(viewName);
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Pans the camera to a view over a period of time.
*/
public class PanToStoredView : CommandQueue.Command
{
float duration;
string viewName;
public PanToStoredView(string _viewName, float _duration)
{
viewName = _viewName;
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
game.cameraController.PanToStoredView(viewName, duration, delegate {
game.waiting = false;
if (onComplete != null)
{
onComplete();
}
});
}
}
}
}

2
Assets/Fungus/Editor/PageEditor.cs.meta → Assets/Fungus/Scripts/Commands/CameraCommands.cs.meta

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: dce33924cf6804b2c94d17784a6037d1 guid: 48a11d9857cef47caad512a6e89998d3
MonoImporter: MonoImporter:
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []

168
Assets/Fungus/Scripts/Commands/GameCommands.cs

@ -0,0 +1,168 @@
using UnityEngine;
using System;
using System.Collections;
namespace Fungus
{
/**
* Command classes have their own namespace to prevent them popping up in code completion.
*/
namespace Command
{
/**
* Call a delegate method on execution.
* This command can be used to schedule arbitrary script code.
*/
public class Call : CommandQueue.Command
{
Action callAction;
public Call(Action _callAction)
{
if (_callAction == null)
{
Debug.LogError("Action must not be null.");
return;
}
callAction = _callAction;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
if (callAction != null)
{
callAction();
}
// Execute next command
onComplete();
}
}
/**
* Wait for a period of time.
*/
public class Wait : CommandQueue.Command
{
float duration;
public Wait(float _duration)
{
duration = _duration;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().waiting = true;
commandQueue.StartCoroutine(WaitCoroutine(duration, onComplete));
}
IEnumerator WaitCoroutine(float duration, Action onComplete)
{
yield return new WaitForSeconds(duration);
if (onComplete != null)
{
Game.GetInstance().waiting = false;
onComplete();
}
}
}
/**
* Wait for a player tap/click/key press
*/
public class WaitForInput : CommandQueue.Command
{
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().waiting = true;
commandQueue.StartCoroutine(WaitCoroutine(onComplete));
}
IEnumerator WaitCoroutine(Action onComplete)
{
while (true)
{
if (Input.GetMouseButtonDown(0) || Input.anyKeyDown)
{
break;
}
yield return null;
}
if (onComplete != null)
{
Game.GetInstance().waiting = false;
onComplete();
}
}
}
/**
* Changes the active room to a different room
*/
public class MoveToRoom : CommandQueue.Command
{
Room room;
public MoveToRoom(Room _room)
{
if (_room == null)
{
Debug.LogError("Room must not be null.");
return;
}
room = _room;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game game = Game.GetInstance();
game.waiting = true;
// Fade out screen
game.cameraController.Fade(0f, game.roomFadeDuration / 2f, delegate {
game.activeRoom = room;
// Notify room script that the Room is being entered
// Calling private method on Room to hide implementation
game.activeRoom.gameObject.SendMessage("Enter");
// Fade in screen
game.cameraController.Fade(1f, game.roomFadeDuration / 2f, delegate {
game.waiting = false;
});
});
// MoveToRoom always resets the command queue so no need to call onComplete
}
}
/**
* Sets a globally accessible game value
*/
public class SetValue : CommandQueue.Command
{
string key;
int value;
public SetValue(string _key, int _value)
{
key = _key;
value = _value;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().SetGameValue(key, value);
if (onComplete != null)
{
onComplete();
}
}
}
}
}

2
Assets/Fungus/Scripts/Commands.cs.meta → Assets/Fungus/Scripts/Commands/GameCommands.cs.meta

@ -1,5 +1,5 @@
fileFormatVersion: 2 fileFormatVersion: 2
guid: c82cac70434cd411b973a4c590386c63 guid: 83105d98d4aed45f9b25b7ba66e83a29
MonoImporter: MonoImporter:
serializedVersion: 2 serializedVersion: 2
defaultReferences: [] defaultReferences: []

243
Assets/Fungus/Scripts/Commands/PageCommands.cs

@ -0,0 +1,243 @@
using UnityEngine;
using System;
using System.Collections;
namespace Fungus
{
/**
* Command classes have their own namespace to prevent them popping up in code completion.
*/
namespace Command
{
/**
* Sets the display rect for the active Page using a PageBounds object.
*/
public class SetPageBounds : CommandQueue.Command
{
PageBounds pageBounds;
Page.Layout pageLayout;
public SetPageBounds(PageBounds _pageBounds, Page.Layout _pageLayout)
{
pageBounds = _pageBounds;
pageLayout = _pageLayout;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
if (pageBounds != null)
{
pageBounds.UpdatePageRect();
Game.GetInstance().activePage.layout = pageLayout;
}
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets the display rect for the active Page using normalized screen space coords.
*/
public class SetPageRect : CommandQueue.Command
{
float x1;
float y1;
float x2;
float y2;
Page.Layout layout;
public SetPageRect(float _x1, float _y1, float _x2, float _y2, Page.Layout _layout)
{
x1 = _x1;
y1 = _y1;
x2 = _x2;
y2 = _y2;
layout = _layout;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
page.SetPageRect(x1, y1, x2, y2);
page.layout = layout;
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets the currently active Page Style for rendering Pages.
*/
public class SetPageStyle : CommandQueue.Command
{
PageStyle pageStyle;
public SetPageStyle(PageStyle _pageStyle)
{
pageStyle = _pageStyle;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Game.GetInstance().activePageStyle = pageStyle;
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets the header text displayed at the top of the active page.
*/
public class SetHeader : CommandQueue.Command
{
string titleText;
public SetHeader(string _titleText)
{
titleText = _titleText;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.SetHeader(titleText);
}
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets the footer text displayed at the top of the active page.
*/
public class SetFooter : CommandQueue.Command
{
string titleText;
public SetFooter(string _titleText)
{
titleText = _titleText;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.SetFooter(titleText);
}
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Writes story text to the currently active page.
* A 'continue' icon is displayed when the text has fully appeared.
*/
public class Say : CommandQueue.Command
{
string storyText;
public Say(string _storyText)
{
storyText = _storyText;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.Say(storyText, onComplete);
}
}
}
/**
* Adds an option button to the current list of options.
* Use the Choose command to display added options.
*/
public class AddOption : CommandQueue.Command
{
string optionText;
Action optionAction;
public AddOption(string _optionText, Action _optionAction)
{
optionText = _optionText;
optionAction = _optionAction;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.AddOption(optionText, optionAction);
}
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Displays all previously added options.
*/
public class Choose : CommandQueue.Command
{
string chooseText;
public Choose(string _chooseText)
{
chooseText = _chooseText;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
if (page == null)
{
Debug.LogError("Active page must not be null");
}
else
{
page.Choose(chooseText);
}
// Choose always clears commandQueue, so no need to call onComplete()
}
}
}
}

8
Assets/Fungus/Scripts/Commands/PageCommands.cs.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ae90082ad9904474ebe8554e864a0539
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

119
Assets/Fungus/Scripts/Commands/SpriteCommands.cs

@ -0,0 +1,119 @@
using UnityEngine;
using System;
using System.Collections;
namespace Fungus
{
/**
* Command classes have their own namespace to prevent them popping up in code completion.
*/
namespace Command
{
/**
* Fades a sprite to a given alpha value over a period of time
*/
public class FadeSprite : CommandQueue.Command
{
SpriteRenderer spriteRenderer;
Color targetColor;
float fadeDuration;
Vector2 slideOffset = Vector2.zero;
public FadeSprite(SpriteRenderer _spriteRenderer,
Color _targetColor,
float _fadeDuration,
Vector2 _slideOffset)
{
if (_spriteRenderer == null)
{
Debug.LogError("Sprite renderer must not be null.");
return;
}
spriteRenderer = _spriteRenderer;
targetColor = _targetColor;
fadeDuration = _fadeDuration;
slideOffset = _slideOffset;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
SpriteFader.FadeSprite(spriteRenderer, targetColor, fadeDuration, slideOffset);
// Fade is asynchronous, but command completes immediately.
// If you need to wait for the fade to complete, just use an additional Wait() command
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Sets an animator trigger to change the animator state for an animated sprite
*/
public class SetAnimatorTrigger : CommandQueue.Command
{
Animator animator;
string triggerName;
public SetAnimatorTrigger(Animator _animator,
string _triggerName)
{
if (_animator == null)
{
Debug.LogError("Animator must not be null.");
return;
}
animator = _animator;
triggerName = _triggerName;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
animator.SetTrigger(triggerName);
if (onComplete != null)
{
onComplete();
}
}
}
/**
* Display a button and set the method to be called when player clicks.
*/
public class ShowButton : CommandQueue.Command
{
Button button;
bool visible;
Action buttonAction;
public ShowButton(Button _button,
bool _visible,
Action _buttonAction)
{
if (_button == null)
{
Debug.LogError("Button must not be null.");
return;
}
button = _button;
visible = _visible;
buttonAction = _buttonAction;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
button.Show(visible, buttonAction);
if (onComplete != null)
{
onComplete();
}
}
}
}
}

8
Assets/Fungus/Scripts/Commands/SpriteCommands.cs.meta

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: bb89d5e15bc734221b9d8fe9ae8e8153
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:

48
Assets/Fungus/Scripts/ContinueStyle.cs

@ -1,48 +0,0 @@
using UnityEngine;
using System.Collections;
public class ContinueStyle : MonoBehaviour
{
/**
* Text to use on 'Continue' buttons.
*/
public string continueText = "Continue";
/// Continue font size as a fraction of screen height.
public float continueFontScale = 1f / 30f;
/// Style for continue button
public GUIStyle style;
/**
* If true, places the continue button on the active page.
* If false, places the continue button on the screen.
*/
public bool onPage;
/**
* Specifies continue button position in normalized screen coordinates.
* This setting is ignored if onPage == true
* (0,0) is top left of screen.
* (1,1) is bottom right of screen
*/
public Vector2 screenPosition = new Vector2(1,1);
/**
* Padding distance between button and edge of the screen in pixels.
*/
public Vector2 padding = new Vector2(4,4);
/**
* Returns the style for the Continue button.
* Overrides the font size to compensate for varying device resolution.
* Font size is calculated as a fraction of the current screen height.
*/
public GUIStyle GetScaledContinueStyle()
{
GUIStyle guiStyle;
guiStyle = new GUIStyle(style);
guiStyle.fontSize = Mathf.RoundToInt((float)Screen.height * continueFontScale);
return guiStyle;
}
}

80
Assets/Fungus/Scripts/Game.cs

@ -53,6 +53,16 @@ namespace Fungus
*/ */
public Texture2D fadeTexture; public Texture2D fadeTexture;
/**
* Icon to display when manual pan mode is active.
*/
public Texture2D manualPanTexture;
/**
* Icon to display when waiting for player input to continue
*/
public Texture2D continueTexture;
/** /**
* Sound effect to play when buttons are clicked. * Sound effect to play when buttons are clicked.
*/ */
@ -63,11 +73,6 @@ namespace Fungus
*/ */
public float autoHideButtonDuration = 5f; public float autoHideButtonDuration = 5f;
/**
* References to a style object which controls the appearance & behavior of the continue button.
*/
public ContinueStyle continueStyle;
float autoHideButtonTimer; float autoHideButtonTimer;
/** /**
@ -76,9 +81,6 @@ namespace Fungus
[HideInInspector] [HideInInspector]
public Dictionary<string, int> values = new Dictionary<string, int>(); public Dictionary<string, int> values = new Dictionary<string, int>();
[HideInInspector]
public View activeView;
[HideInInspector] [HideInInspector]
public Page activePage; public Page activePage;
@ -97,6 +99,12 @@ namespace Fungus
[HideInInspector] [HideInInspector]
public bool waiting; public bool waiting;
[HideInInspector]
public bool manualPanActive;
[HideInInspector]
public float fadeAlpha = 0f;
static Game instance; static Game instance;
/** /**
@ -136,9 +144,15 @@ namespace Fungus
{ {
// Move to the active room // Move to the active room
commandQueue.Clear(); commandQueue.Clear();
commandQueue.AddCommand(new Command.MoveToRoomCommand(activeRoom)); commandQueue.AddCommand(new Command.MoveToRoom(activeRoom));
commandQueue.Execute(); commandQueue.Execute();
} }
// Create the Page game object as a child of Game
GameObject pageObject = new GameObject();
pageObject.name = "Page";
pageObject.transform.parent = transform;
activePage = pageObject.AddComponent<Page>();
} }
public virtual void Update() public virtual void Update()
@ -152,6 +166,46 @@ namespace Fungus
} }
} }
void OnGUI()
{
if (manualPanActive)
{
// Draw the swipe-to-pan icon
if (manualPanTexture)
{
Rect rect = new Rect(Screen.width - manualPanTexture.width,
0,
manualPanTexture.width,
manualPanTexture.height);
GUI.DrawTexture(rect, manualPanTexture);
}
}
if (activePage.mode == Page.Mode.Say &&
activePage.FinishedWriting())
{
// Draw the continue icon
if (continueTexture)
{
Rect rect = new Rect(Screen.width - continueTexture.width,
0,
continueTexture.width,
continueTexture.height);
GUI.DrawTexture(rect, continueTexture);
}
}
// Draw full screen fade texture
if (fadeAlpha < 1f)
{
// 1 = scene fully visible
// 0 = scene fully obscured
GUI.color = new Color(1,1,1, 1f - fadeAlpha);
GUI.depth = -1000;
GUI.DrawTexture(new Rect(0, 0, Screen.width, Screen.height), fadeTexture);
}
}
/** /**
* Plays the button clicked sound effect * Plays the button clicked sound effect
*/ */
@ -212,10 +266,10 @@ namespace Fungus
* Returns a parallax offset vector based on the camera position relative to the active Room. * Returns a parallax offset vector based on the camera position relative to the active Room.
* Higher values for the parallaxFactor yield a larger offset (appears closer to camera). * Higher values for the parallaxFactor yield a larger offset (appears closer to camera).
* Suggested range for good parallax effect is [0.1..0.5]. * Suggested range for good parallax effect is [0.1..0.5].
* @param parallaxFactor Scale factor to apply to camera offset vector. * @param parallaxFactor Horizontal and vertical scale factors to apply to camera offset vector.
* @return A parallax offset vector based on camera positon relative to current room and the parallaxFactor. * @return A parallax offset vector based on camera positon relative to current room and the parallaxFactor.
*/ */
public Vector3 GetParallaxOffset(float parallaxFactor) public Vector3 GetParallaxOffset(Vector2 parallaxFactor)
{ {
if (activeRoom == null) if (activeRoom == null)
{ {
@ -224,7 +278,9 @@ namespace Fungus
Vector3 a = activeRoom.transform.position; Vector3 a = activeRoom.transform.position;
Vector3 b = cameraController.GetCameraPosition(); Vector3 b = cameraController.GetCameraPosition();
Vector3 offset = (a - b) * parallaxFactor; Vector3 offset = (a - b);
offset.x *= parallaxFactor.x;
offset.y *= parallaxFactor.y;
return offset; return offset;
} }

234
Assets/Fungus/Scripts/GameController.cs

@ -37,7 +37,7 @@ namespace Fungus
public static void MoveToRoom(Room room) public static void MoveToRoom(Room room)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.MoveToRoomCommand(room)); commandQueue.AddCommand(new Command.MoveToRoom(room));
} }
/** /**
@ -48,7 +48,7 @@ namespace Fungus
public static void Wait(float duration) public static void Wait(float duration)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.WaitCommand(duration)); commandQueue.AddCommand(new Command.Wait(duration));
} }
/** /**
@ -58,7 +58,7 @@ namespace Fungus
public static void WaitForInput() public static void WaitForInput()
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.WaitForInputCommand()); commandQueue.AddCommand(new Command.WaitForInput());
} }
/** /**
@ -70,7 +70,7 @@ namespace Fungus
public static void Call(Action callAction) public static void Call(Action callAction)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.CallCommand(callAction)); commandQueue.AddCommand(new Command.Call(callAction));
} }
#endregion #endregion
@ -78,34 +78,46 @@ namespace Fungus
/** /**
* Sets the currently active View immediately. * Sets the currently active View immediately.
* The main camera snaps to the new active View. If the View contains a Page object, this Page becomes the active Page. * The main camera snaps to the new active View.
* This method returns immediately but it queues an asynchronous command for later execution. * This method returns immediately but it queues an asynchronous command for later execution.
* @param view The View object to make active * @param view The View object to make active
*/ */
public static void SetView(View view) public static void SetView(View view)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; PanToView(view, 0);
commandQueue.AddCommand(new Command.SetViewCommand(view));
} }
/** /**
* Pans the camera to the target View over a period of time. * Pans the camera to the target View over a period of time.
* The pan starts at the current camera position and performs a smoothed linear pan to the target View. * The pan starts at the current camera position and performs a smoothed linear pan to the target View.
* Command execution blocks until the pan completes. When the camera arrives at the target View, this View becomes the active View. * Command execution blocks until the pan completes.
* This method returns immediately but it queues an asynchronous command for later execution. * This method returns immediately but it queues an asynchronous command for later execution.
* @param targetView The View to pan the camera to. * @param targetView The View to pan the camera to.
* @param duration The length of time in seconds needed to complete the pan. * @param duration The length of time in seconds needed to complete the pan.
*/ */
public static void PanToView(View targetView, float duration) public static void PanToView(View targetView, float duration)
{
PanToPosition(targetView.transform.position, targetView.viewSize, duration);
}
/**
* Pans the camera to the target position and size over a period of time.
* The pan starts at the current camera position and performs a smoothed linear pan to the target.
* Command execution blocks until the pan completes.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param targetView The View to pan the camera to.
* @param duration The length of time in seconds needed to complete the pan.
*/
public static void PanToPosition(Vector3 targetPosition, float targetSize, float duration)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.PanToViewCommand(targetView, duration)); commandQueue.AddCommand(new Command.PanToPosition(targetPosition, targetSize, duration));
} }
/** /**
* Pans the camera through a sequence of target Views over a period of time. * Pans the camera through a sequence of target Views over a period of time.
* The pan starts at the current camera position and performs a smooth pan through all Views in the list. * The pan starts at the current camera position and performs a smooth pan through all Views in the list.
* Command execution blocks until the pan completes. When the camera arrives at the last View in the list, this View becomes the active View. * Command execution blocks until the pan completes.
* If more control is required over the camera path then you should instead use an Animator component to precisely control the Camera path. * If more control is required over the camera path then you should instead use an Animator component to precisely control the Camera path.
* This method returns immediately but it queues an asynchronous command for later execution. * This method returns immediately but it queues an asynchronous command for later execution.
* @param duration The length of time in seconds needed to complete the pan. * @param duration The length of time in seconds needed to complete the pan.
@ -114,12 +126,11 @@ namespace Fungus
public static void PanToPath(float duration, params View[] targetViews) public static void PanToPath(float duration, params View[] targetViews)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.PanToPathCommand(targetViews, duration)); commandQueue.AddCommand(new Command.PanToPath(targetViews, duration));
} }
/** /**
* Fades out the current camera View, and fades in again using the target View. * Fades out the current camera View, and fades in again using the target View.
* If the target View contains a Page object, this Page becomes the active Page.
* This method returns immediately but it queues an asynchronous command for later execution. * This method returns immediately but it queues an asynchronous command for later execution.
* @param targetView The View object to fade to. * @param targetView The View object to fade to.
* @param duration The length of time in seconds needed to complete the pan. * @param duration The length of time in seconds needed to complete the pan.
@ -127,35 +138,184 @@ namespace Fungus
public static void FadeToView(View targetView, float duration) public static void FadeToView(View targetView, float duration)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.FadeToViewCommand(targetView, duration)); commandQueue.AddCommand(new Command.FadeToView(targetView, duration));
}
/**
* Activates manual pan mode.
* The camera first pans to the nearest point between the two views over a period of time.
* The player can pan around the rectangular area defined between viewA & viewB.
* Manual panning remains active until a ManualPanOff, SetView, PanToView, FadeToPath or FadeToView command is executed.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param viewA View object which defines one extreme of the pan area.
* @param viewB View object which defines the other extreme of the pan area.
*/
public static void StartManualPan(View viewA, View viewB, float duration = 1f)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.StartManualPan(viewA, viewB, duration));
}
/**
* Deactivates manual pan mode.
* This method returns immediately but it queues an asynchronous command for later execution.
*/
public static void StopManualPan()
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.StopManualPan());
}
/**
* Stores the current camera view using a name.
* You can later use PanToStoredView() to pan back to this stored position by name.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param viewName Name to associate with the stored camera view.
*/
public static void StoreView(string viewName = "")
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.StoreView(viewName));
}
/**
* Moves camera from the current position to a previously stored view over a period of time.
* @param duration Time needed for pan to complete.
* @param viewName Name of a camera view that was previously stored using StoreView().
*/
public static void PanToStoredView(float duration, string viewName = "")
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.PanToStoredView(viewName, duration));
} }
#endregion #endregion
#region Page Methods #region Page Methods
/** /**
* Sets the currently active Page for story text display. * Sets the display rect for the active Page using a PageBounds object.
* Once this command executes, all story text added using Say(), AddOption(), Choose(), etc. will be displayed on this Page. * PageBounds objects can be edited visually in the Unity editor which is useful for accurate placement.
* When a Room contains multiple Page objects, this method can be used to control which Page object is active at a given time. * The actual screen space rect used is based on both the PageBounds values and the camera transform at the time the command is executed.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param pageBounds The bounds object to use when calculating the Page display rect.
*/
public static void SetPageBounds(PageBounds pageBounds, Page.Layout pageLayout = Page.Layout.FullSize)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SetPageBounds(pageBounds, pageLayout));
}
/**
* Sets the screen space rectangle used to display the Page.
* The rectangle coordinates are in normalized screen space. e.g. x1 = 0 (Far left), x1 = 1 (Far right).
* The origin is at the top left of the screen.
* This method returns immediately but it queues an asynchronous command for later execution. * This method returns immediately but it queues an asynchronous command for later execution.
* @param page The Page object to make active * @param x1 Page rect left coordinate in normalized screen space coords [0..1]
* @param y1 Page rect top coordinate in normalized screen space coords [0..1
* @param x2 Page rect right coordinate in normalized screen space coords [0..1]
* @param y2 Page rect bottom coordinate in normalized screen space coords [0..1]
* @param pageLayout Layout mode for positioning page within the rect.
*/ */
public static void SetPage(Page page) public static void SetPageRect(float x1, float y1, float x2, float y2, Page.Layout pageLayout = Page.Layout.FullSize)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SetPageCommand(page)); commandQueue.AddCommand(new Command.SetPageRect(x1, y1, x2, y2, pageLayout));
}
/**
* Sets the active Page to display at the top of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param scaleX Scales the width of the Page [0..1]. 1 = full screen width.
* @param scaleY Scales the height of the Page [0..1]. 1 = full screen height.
* @param pageLayout Controls how the Page is positioned and sized based on the displayed content.
*/
public static void SetPageTop(float scaleX, float scaleY, Page.Layout pageLayout)
{
float halfWidth = Mathf.Clamp01(scaleX) * 0.5f;
float x1 = 0.5f - halfWidth;
float x2 = 0.5f + halfWidth;
float y1 = 0f;
float y2 = Mathf.Clamp01(scaleY);
SetPageRect(x1, y1, x2, y2, pageLayout);
}
/**
* Sets the currently active Page to display at the top of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
*/
public static void SetPageTop()
{
SetPageTop(0.75f, 0.25f, Page.Layout.FullSize);
}
/**
* Sets the active Page to display at the middle of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param scaleX Scales the width of the Page [0..1]. 1 = full screen width.
* @param scaleY Scales the height of the Page [0..1]. 1 = full screen height.
* @param pageLayout Controls how the Page is positioned and sized based on the displayed content.
*/
public static void SetPageMiddle(float scaleX, float scaleY, Page.Layout pageLayout)
{
float halfWidth = Mathf.Clamp01(scaleX) * 0.5f;
float halfHeight = Mathf.Clamp01(scaleY) * 0.5f;
float x1 = 0.5f - halfWidth;
float x2 = 0.5f + halfWidth;
float y1 = 0.5f - halfHeight;
float y2 = 0.5f + halfHeight;
SetPageRect(x1, y1, x2, y2, pageLayout);
}
/**
* Sets the currently active Page to display at the middle of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
*/
public static void SetPageMiddle()
{
SetPageMiddle(0.5f, 0.5f, Page.Layout.FitToMiddle);
}
/**
* Sets the active Page to display at the bottom of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param scaleX Scales the width of the Page [0..1]. 1 = full screen width.
* @param scaleY Scales the height of the Page [0..1]. 1 = full screen height.
* @param pageLayout Controls how the Page is positioned and sized based on the displayed content.
*/
public static void SetPageBottom(float scaleX, float scaleY, Page.Layout pageLayout)
{
float halfWidth = Mathf.Clamp01(scaleX) / 2f;
float x1 = 0.5f - halfWidth;
float x2 = 0.5f + halfWidth;
float y1 = 1f - Mathf.Clamp01(scaleY);
float y2 = 1;
SetPageRect(x1, y1, x2, y2, pageLayout);
}
/**
* Sets the currently active Page to display at the bottom of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
*/
public static void SetPageBottom()
{
SetPageBottom(0.75f, 0.25f, Page.Layout.FullSize);
} }
/** /**
* Sets the currently active style for displaying Pages. * Sets the active style for displaying the Page.
* Once this command executes, all Pages will display using the new style.
* This method returns immediately but it queues an asynchronous command for later execution. * This method returns immediately but it queues an asynchronous command for later execution.
* @param pageStyle The style object to make active * @param pageStyle The style object to make active
*/ */
public static void SetPageStyle(PageStyle pageStyle) public static void SetPageStyle(PageStyle pageStyle)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SetPageStyleCommand(pageStyle)); commandQueue.AddCommand(new Command.SetPageStyle(pageStyle));
} }
/** /**
@ -176,7 +336,7 @@ namespace Fungus
public static void Header(string headerText) public static void Header(string headerText)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.HeaderCommand(headerText)); commandQueue.AddCommand(new Command.SetHeader(headerText));
} }
/** /**
@ -188,7 +348,7 @@ namespace Fungus
public static void Footer(string footerText) public static void Footer(string footerText)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.FooterCommand(footerText)); commandQueue.AddCommand(new Command.SetFooter(footerText));
} }
/** /**
@ -201,7 +361,7 @@ namespace Fungus
public static void Say(string storyText) public static void Say(string storyText)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SayCommand(storyText)); commandQueue.AddCommand(new Command.Say(storyText));
} }
/** /**
@ -214,7 +374,7 @@ namespace Fungus
public static void AddOption(string optionText, Action optionAction) public static void AddOption(string optionText, Action optionAction)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.AddOptionCommand(optionText, optionAction)); commandQueue.AddCommand(new Command.AddOption(optionText, optionAction));
} }
/** /**
@ -226,7 +386,7 @@ namespace Fungus
public static void AddOption(string optionText) public static void AddOption(string optionText)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.AddOptionCommand(optionText, delegate {})); commandQueue.AddCommand(new Command.AddOption(optionText, delegate {}));
} }
/** /**
@ -246,7 +406,7 @@ namespace Fungus
public static void Choose(string chooseText) public static void Choose(string chooseText)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.ChooseCommand(chooseText)); commandQueue.AddCommand(new Command.Choose(chooseText));
} }
#endregion #endregion
@ -261,7 +421,7 @@ namespace Fungus
public static void SetValue(string key, int value) public static void SetValue(string key, int value)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SetValueCommand(key, value)); commandQueue.AddCommand(new Command.SetValue(key, value));
} }
/** /**
@ -376,7 +536,7 @@ namespace Fungus
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
Color color = spriteRenderer.color; Color color = spriteRenderer.color;
color.a = targetAlpha; color.a = targetAlpha;
commandQueue.AddCommand(new Command.FadeSpriteCommand(spriteRenderer, color, duration, slideOffset)); commandQueue.AddCommand(new Command.FadeSprite(spriteRenderer, color, duration, slideOffset));
} }
/** /**
@ -391,7 +551,7 @@ namespace Fungus
public static void ShowButton(Button button, Action buttonAction) public static void ShowButton(Button button, Action buttonAction)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.ShowButtonCommand(button, true, buttonAction)); commandQueue.AddCommand(new Command.ShowButton(button, true, buttonAction));
} }
/** /**
@ -402,7 +562,7 @@ namespace Fungus
public static void HideButton(Button button) public static void HideButton(Button button)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.ShowButtonCommand(button, false, null)); commandQueue.AddCommand(new Command.ShowButton(button, false, null));
} }
/** /**
@ -415,7 +575,7 @@ namespace Fungus
public static void SetAnimatorTrigger(Animator animator, string triggerName) public static void SetAnimatorTrigger(Animator animator, string triggerName)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SetAnimatorTriggerCommand(animator, triggerName)); commandQueue.AddCommand(new Command.SetAnimatorTrigger(animator, triggerName));
} }
#endregion #endregion
@ -429,7 +589,7 @@ namespace Fungus
public static void PlayMusic(AudioClip audioClip) public static void PlayMusic(AudioClip audioClip)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.PlayMusicCommand(audioClip)); commandQueue.AddCommand(new Command.PlayMusic(audioClip));
} }
/** /**
@ -438,7 +598,7 @@ namespace Fungus
public static void StopMusic() public static void StopMusic()
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.StopMusicCommand()); commandQueue.AddCommand(new Command.StopMusic());
} }
/** /**
@ -458,7 +618,7 @@ namespace Fungus
public static void SetMusicVolume(float musicVolume, float duration) public static void SetMusicVolume(float musicVolume, float duration)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SetMusicVolumeCommand(musicVolume, duration)); commandQueue.AddCommand(new Command.SetMusicVolume(musicVolume, duration));
} }
/** /**
@ -480,7 +640,7 @@ namespace Fungus
public static void PlaySound(AudioClip audioClip, float volume) public static void PlaySound(AudioClip audioClip, float volume)
{ {
CommandQueue commandQueue = Game.GetInstance().commandQueue; CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.PlaySoundCommand(audioClip, volume)); commandQueue.AddCommand(new Command.PlaySound(audioClip, volume));
} }
#endregion #endregion

168
Assets/Fungus/Scripts/Page.cs

@ -14,18 +14,21 @@ namespace Fungus
[ExecuteInEditMode] [ExecuteInEditMode]
public class Page : MonoBehaviour public class Page : MonoBehaviour
{ {
/// Rectangular bounds used to display page text /// Page alignment options
public Bounds pageBounds = new Bounds(Vector3.zero, new Vector3(0.25f, 0.25f, 0f)); public enum Layout
/// Page position within bounds when display height is less than bounds height
public enum VerticalAlign
{ {
Top, /// Use the full rect to display the page.
Middle, FullSize,
Bottom /// Resize to fit displayed text and snap to top of rect.
FitToTop,
/// Resize to fit displayed text and snap to middle of rect.
FitToMiddle,
/// Resize to fit displayed text and snap to bottom of rect.
FitToBottom
} }
public VerticalAlign verticalAlign = VerticalAlign.Middle; /// Page position within bounds when display height is less than bounds height.
public Layout layout = Layout.FullSize;
string headerText = ""; string headerText = "";
string footerText = ""; string footerText = "";
@ -62,6 +65,26 @@ namespace Fungus
float quickContinueTimer; float quickContinueTimer;
Rect pageRect; // Screen space rect for Page in pixels
/**
* Set the screen rect in normalized screen space coords.
* The origin is at the top left of the screen.
*/
public void SetPageRect(float x1, float y1, float x2, float y2)
{
pageRect.xMin = Screen.width * x1;
pageRect.yMin = Screen.height * y1;
pageRect.xMax = Screen.width * x2;
pageRect.yMax = Screen.height * y2;
// Clamp to be on-screen
pageRect.xMax = Mathf.Min(pageRect.xMax, Screen.width);
pageRect.xMin = Mathf.Max(pageRect.xMin, 0);
pageRect.yMax = Mathf.Min(pageRect.yMax, Screen.height);
pageRect.yMin = Mathf.Max(pageRect.yMin, 0);
}
public virtual void Update() public virtual void Update()
{ {
if (quickContinueTimer > 0) if (quickContinueTimer > 0)
@ -179,6 +202,11 @@ namespace Fungus
} }
} }
public bool FinishedWriting()
{
return (displayedStoryText.Length == originalStoryText.Length);
}
public virtual void OnGUI() public virtual void OnGUI()
{ {
if (mode == Mode.Idle) if (mode == Mode.Idle)
@ -199,8 +227,7 @@ namespace Fungus
GUIStyle optionStyle = pageStyle.GetScaledOptionStyle(); GUIStyle optionStyle = pageStyle.GetScaledOptionStyle();
GUIStyle optionAlternateStyle = pageStyle.GetScaledOptionAlternateStyle(); GUIStyle optionAlternateStyle = pageStyle.GetScaledOptionAlternateStyle();
Rect pageRect = GetScreenRect(); Rect outerRect = pageRect;
Rect outerRect = FitRectToScreen(pageRect);
Rect innerRect = CalcInnerRect(outerRect); Rect innerRect = CalcInnerRect(outerRect);
// Calculate height of each section // Calculate height of each section
@ -211,31 +238,35 @@ namespace Fungus
float contentHeight = headerHeight + footerHeight + storyHeight + optionsHeight; float contentHeight = headerHeight + footerHeight + storyHeight + optionsHeight;
// Adjust outer rect position based on alignment settings // Adjust outer rect position based on alignment settings
switch (verticalAlign) switch (layout)
{ {
case VerticalAlign.Top: case Layout.FullSize:
outerRect.height = Mathf.Max(outerRect.height, contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom));
outerRect.y = Mathf.Min(outerRect.y, Screen.height - outerRect.height);
break;
case Layout.FitToTop:
outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom); outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
outerRect.y = pageRect.yMin; outerRect.y = pageRect.yMin;
break; break;
case VerticalAlign.Middle: case Layout.FitToMiddle:
outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom); outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
outerRect.y = pageRect.center.y - outerRect.height / 2; outerRect.y = pageRect.center.y - outerRect.height / 2;
break; break;
case VerticalAlign.Bottom: case Layout.FitToBottom:
outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom); outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
outerRect.y = pageRect.yMax - outerRect.height; outerRect.y = pageRect.yMax - outerRect.height;
break; break;
} }
// Force outer rect to always be on-screen
// If the rect is bigger than the screen, then the top-left corner will always be visible
outerRect = FitRectToScreen(outerRect);
innerRect = CalcInnerRect(outerRect); innerRect = CalcInnerRect(outerRect);
// Draw box // Draw box
Rect boxRect = outerRect; Rect boxRect = outerRect;
boxRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom); boxRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
if (layout == Layout.FullSize)
{
boxRect.height = Mathf.Max(boxRect.height, pageRect.height);
}
GUI.Box(boxRect, "", boxStyle); GUI.Box(boxRect, "", boxStyle);
// Draw header label // Draw header label
@ -261,20 +292,15 @@ namespace Fungus
GUI.Label(footerRect, footerText, footerStyle); GUI.Label(footerRect, footerText, footerStyle);
} }
bool finishedWriting = (displayedStoryText.Length == originalStoryText.Length); if (!FinishedWriting())
if (!finishedWriting)
{ {
return; return;
} }
// Input handling
if (mode == Mode.Say) if (mode == Mode.Say)
{ {
ContinueStyle continueStyle = Game.GetInstance().continueStyle;
if (continueStyle != null)
{
DrawContinueButton(outerRect);
}
// Player can continue by clicking anywhere // Player can continue by clicking anywhere
if (quickContinueTimer == 0 && if (quickContinueTimer == 0 &&
(Input.GetMouseButtonUp(0) || Input.anyKeyDown) && (Input.GetMouseButtonUp(0) || Input.anyKeyDown) &&
@ -437,19 +463,6 @@ namespace Fungus
return totalHeight; return totalHeight;
} }
// Force rect to always be on-screen
Rect FitRectToScreen(Rect rect)
{
Rect fittedRect = new Rect();
fittedRect.xMax = Mathf.Min(rect.xMax, Screen.width);
fittedRect.xMin = Mathf.Max(rect.xMin, 0);
fittedRect.yMax = Mathf.Min(rect.yMax, Screen.height);
fittedRect.yMin = Mathf.Max(rect.yMin, 0);
return fittedRect;
}
// Returns smaller internal box rect with padding style applied // Returns smaller internal box rect with padding style applied
Rect CalcInnerRect(Rect outerRect) Rect CalcInnerRect(Rect outerRect)
{ {
@ -469,80 +482,5 @@ namespace Fungus
return innerRect; return innerRect;
} }
/**
* Returns the page rect in screen space coords
*/
public Rect GetScreenRect()
{
// Y decreases up the screen in GUI space, so top left is rect origin
Vector3 topLeft = transform.position + pageBounds.center;
topLeft.x -= pageBounds.extents.x;
topLeft.y += pageBounds.extents.y;
Vector3 bottomRight = transform.position + pageBounds.center;
bottomRight.x += pageBounds.extents.x;
bottomRight.y -= pageBounds.extents.y;
Camera mainCamera = GameObject.FindGameObjectWithTag("MainCamera").camera;
Vector2 tl = mainCamera.WorldToScreenPoint(topLeft);
Vector2 br = mainCamera.WorldToScreenPoint(bottomRight);
Rect pageRect = new Rect(tl.x, Screen.height - tl.y, br.x - tl.x, tl.y - br.y);
return FitRectToScreen(pageRect);
}
void DrawContinueButton(Rect containerRect)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
ContinueStyle continueStyle = Game.GetInstance().continueStyle;
if (pageStyle == null ||
continueStyle == null)
{
return;
}
GUIStyle style = continueStyle.style;
if (style == null)
{
return;
}
GUIContent content = new GUIContent(continueStyle.continueText);
GUIStyle scaledContinueStyle = continueStyle.GetScaledContinueStyle();
Rect continueRect;
if (continueStyle.onPage)
{
float width = scaledContinueStyle.CalcSize(content).x;
float height = scaledContinueStyle.lineHeight;
float x = containerRect.xMin + (containerRect.width) - (width) - pageStyle.boxStyle.padding.right;
float y = containerRect.yMax - height / 2f;
continueRect = new Rect(x, y, width, height);
}
else
{
Vector2 size = scaledContinueStyle.CalcSize(content);
float x = Screen.width * continueStyle.screenPosition.x;
float y = Screen.height * continueStyle.screenPosition.y;
float width = size.x;
float height = size.y;
x = Mathf.Max(x, continueStyle.padding.x);
x = Mathf.Min(x, Screen.width - width - continueStyle.padding.x);
y = Mathf.Max(y, continueStyle.padding.y);
y = Mathf.Min(y, Screen.height - height - continueStyle.padding.y);
continueRect = new Rect(x, y, width, height);
}
GUI.Label(continueRect, content, scaledContinueStyle);
}
} }
} }

4
Assets/Fungus/Scripts/Parallax.cs

@ -12,7 +12,7 @@ namespace Fungus
/** /**
* Scale factor for calculating the parallax offset. * Scale factor for calculating the parallax offset.
*/ */
public float parallaxFactor; public Vector2 parallaxScale = new Vector2(0.1f, 0.1f);
Vector3 startPosition; Vector3 startPosition;
@ -51,7 +51,7 @@ namespace Fungus
return; return;
} }
Vector3 offset = Game.GetInstance().GetParallaxOffset(parallaxFactor); Vector3 offset = Game.GetInstance().GetParallaxOffset(parallaxScale);
// Set new position for sprite // Set new position for sprite
transform.position = startPosition + offset; transform.position = startPosition + offset;

18
Assets/Fungus/Scripts/Room.cs

@ -108,11 +108,9 @@ namespace Fungus
Game game = Game.GetInstance(); Game game = Game.GetInstance();
CameraController cameraController = game.gameObject.GetComponent<CameraController>(); CameraController cameraController = game.gameObject.GetComponent<CameraController>();
// Pick first view found in the room and snap to camera to this view. // Pick first view found in the room and snap to camera to this view.
// It is allowed for a room to not have any views. // It is allowed for a room to not have any views.
// In this case game.activeView will be null, and the camera will attempt // In this case the camera will attempt to snap to the room sprite.
// to snap to the room sprite.
View view = gameObject.GetComponentInChildren<View>(); View view = gameObject.GetComponentInChildren<View>();
if (view == null) if (view == null)
{ {
@ -130,14 +128,9 @@ namespace Fungus
else else
{ {
// Snap to new view // Snap to new view
cameraController.SnapToView(view); cameraController.PanToPosition(view.transform.position, view.viewSize, 0, null);
game.activeView = view;
} }
// Pick first page found in room
// It is allowed for a room to not have any pages. In this case game.activePage will be null
game.activePage = gameObject.GetComponentInChildren<Page>();
// Hide all buttons in the room before entering // Hide all buttons in the room before entering
// Buttons must always be made visible using a ShowButton() command // Buttons must always be made visible using a ShowButton() command
Button[] buttons = game.activeRoom.GetComponentsInChildren<Button>(); Button[] buttons = game.activeRoom.GetComponentsInChildren<Button>();
@ -146,9 +139,12 @@ namespace Fungus
button.SetAlpha(0f); button.SetAlpha(0f);
} }
// Rooms may have multiple child views and page. It is the responsibility of the client // Default to bottom aligned Page rect
// room script to set the appropriate view & page in its OnEnter method. game.activePage.SetPageRect(0.125f, 0.75f, 0.875f, 1f);
game.activePage.layout = Page.Layout.FullSize;
// Rooms may have multiple child views and page.
// It is the responsibility of the client room script to set the desired active view & page in the OnEnter method.
game.commandQueue.CallCommandMethod(game.activeRoom.gameObject, "OnEnter"); game.commandQueue.CallCommandMethod(game.activeRoom.gameObject, "OnEnter");
visitCount++; visitCount++;

9
Assets/FungusExample/Scripts/PageRoom.cs

@ -10,7 +10,7 @@ public class PageRoom : Room
// References to PageStyle prefab assets // References to PageStyle prefab assets
// Use these with SetPageStyle() to change the Page rendering style // Use these with SetPageStyle() to change the Page rendering style
public PageStyle defaultStyle; public PageStyle defaultStyle;
public PageStyle transparentStyle; public PageStyle alternateStyle;
// The OnEnter() method is called whenever the player enters the room // The OnEnter() method is called whenever the player enters the room
// You can also use the OnLeave() method to handle when the player leaves the room. // You can also use the OnLeave() method to handle when the player leaves the room.
@ -20,8 +20,13 @@ public class PageRoom : Room
Header("The Mushroom"); Header("The Mushroom");
// Each Say() command writes one line of text, followed by a continue button // Each Say() command writes one line of text, followed by a continue button
SetPageTop();
Say("One day in the forest, a mushroom grew."); Say("One day in the forest, a mushroom grew.");
SetPageMiddle();
Say("What am I doing here he wondered?"); Say("What am I doing here he wondered?");
SetPageBottom();
Say("I think I will wait for a while and see if something happens."); Say("I think I will wait for a while and see if something happens.");
// Wait for a few seconds // Wait for a few seconds
@ -68,7 +73,7 @@ public class PageRoom : Room
void ProduceSpores() void ProduceSpores()
{ {
// Set a PageStyle with no background box texture // Set a PageStyle with no background box texture
SetPageStyle(transparentStyle); SetPageStyle(alternateStyle);
Say("Yeah! I feel like doing some sporing!"); Say("Yeah! I feel like doing some sporing!");
Say("Wow - look at all these spores! COOL!"); Say("Wow - look at all these spores! COOL!");

Loading…
Cancel
Save