Browse Source

Backwards compatibility support for v1.2.0

master
chrisgregan 11 years ago
parent
commit
242c905857
  1. 18
      Assets/Fungus/Editor/PageEditor.cs
  2. 0
      Assets/Fungus/Editor/PageEditor.cs.meta
  3. BIN
      Assets/Fungus/Prefabs/Page.prefab
  4. 2
      Assets/Fungus/Prefabs/Page.prefab.meta
  5. 4
      Assets/Fungus/Scripts/Button.cs
  6. 101
      Assets/Fungus/Scripts/Commands/PageCommands.cs
  7. 27
      Assets/Fungus/Scripts/Game.cs
  8. 61
      Assets/Fungus/Scripts/GameController.cs
  9. 599
      Assets/Fungus/Scripts/Page.cs
  10. 2
      Assets/Fungus/Scripts/Page.cs.meta
  11. 45
      Assets/Fungus/Scripts/PageBounds.cs
  12. 594
      Assets/Fungus/Scripts/PageController.cs
  13. 2
      Assets/Fungus/Scripts/PageController.cs.meta
  14. 2
      Assets/Fungus/Scripts/Room.cs
  15. BIN
      Assets/FungusExample/Scenes/Example.unity

18
Assets/Fungus/Editor/PageBoundsEditor.cs → Assets/Fungus/Editor/PageEditor.cs

@ -6,12 +6,12 @@ using System.Collections.Generic;
namespace Fungus
{
[CanEditMultipleObjects]
[CustomEditor (typeof(PageBounds))]
public class PageBoundsEditor : Editor
[CustomEditor (typeof(Page))]
public class PageEditor : Editor
{
void OnSceneGUI ()
{
PageBounds t = target as PageBounds;
Page t = target as Page;
// Render the parent view to help user position the page
Transform parent = t.transform.parent;
@ -37,14 +37,14 @@ namespace Fungus
void EditPageBounds()
{
PageBounds t = target as PageBounds;
Page t = target as Page;
Vector3 pos = t.transform.position;
Vector3[] verts = new Vector3[4];
verts[0] = new Vector3(pos.x + t.bounds.min.x, pos.y + t.bounds.min.y, 0);
verts[1] = new Vector3(pos.x + t.bounds.min.x, pos.y + t.bounds.max.y, 0);
verts[2] = new Vector3(pos.x + t.bounds.max.x, pos.y + t.bounds.max.y, 0);
verts[3] = new Vector3(pos.x + t.bounds.max.x, pos.y + t.bounds.min.y, 0);
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));
@ -92,7 +92,7 @@ namespace Fungus
t.transform.position = newBounds.center;
newBounds.center = Vector3.zero;
t.bounds = newBounds;
t.pageBounds = newBounds;
}
}
}

0
Assets/Fungus/Editor/PageBoundsEditor.cs.meta → Assets/Fungus/Editor/PageEditor.cs.meta

BIN
Assets/Fungus/Prefabs/PageBounds.prefab → Assets/Fungus/Prefabs/Page.prefab

Binary file not shown.

2
Assets/Fungus/Prefabs/PageBounds.prefab.meta → Assets/Fungus/Prefabs/Page.prefab.meta

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

4
Assets/Fungus/Scripts/Button.cs

@ -80,7 +80,7 @@ namespace Fungus
if (autoHide)
{
if (showButton &&
Game.GetInstance().ShowAutoButtons())
Game.GetInstance().GetShowAutoButtons())
{
targetAlpha = 1f;
@ -125,7 +125,7 @@ namespace Fungus
// Ignore button press if sprite is not fully visible or
// if the game is not in an idle state
if (spriteRenderer.color.a != 1f ||
!Game.GetInstance().ShowAutoButtons())
!Game.GetInstance().GetShowAutoButtons())
{
return;
}

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

@ -10,25 +10,25 @@ namespace Fungus
namespace Command
{
/**
* Sets the display rect for the active Page using a PageBounds object.
* Sets the display rect for the PageController using a Page object.
*/
public class SetPageBounds : CommandQueue.Command
public class SetPage : CommandQueue.Command
{
PageBounds pageBounds;
Page.Layout pageLayout;
Page page;
PageController.Layout pageLayout;
public SetPageBounds(PageBounds _pageBounds, Page.Layout _pageLayout)
public SetPage(Page _page, PageController.Layout _pageLayout)
{
pageBounds = _pageBounds;
page = _page;
pageLayout = _pageLayout;
}
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
if (pageBounds != null)
if (page != null)
{
pageBounds.UpdatePageRect();
Game.GetInstance().activePage.layout = pageLayout;
page.UpdatePageRect();
Game.GetInstance().pageController.layout = pageLayout;
}
if (onComplete != null)
@ -39,14 +39,14 @@ namespace Fungus
}
/**
* Sets the display rect for the active Page using normalized screen space coords.
* Sets the screen rect for displaying story text using normalized screen space coords.
*/
public class SetPageRect : CommandQueue.Command
{
Page.ScreenRect screenRect;
Page.Layout layout;
PageController.ScreenRect screenRect;
PageController.Layout layout;
public SetPageRect(Page.ScreenRect _screenRect, Page.Layout _layout)
public SetPageRect(PageController.ScreenRect _screenRect, PageController.Layout _layout)
{
screenRect = _screenRect;
layout = _layout;
@ -54,8 +54,8 @@ namespace Fungus
public override void Execute(CommandQueue commandQueue, Action onComplete)
{
Page page = Game.GetInstance().activePage;
page.pageRect = Page.CalcPageRect(screenRect);
PageController page = Game.GetInstance().pageController;
page.pageRect = PageController.CalcPageRect(screenRect);
page.layout = layout;
if (onComplete != null)
@ -66,7 +66,7 @@ namespace Fungus
}
/**
* Sets the currently active Page Style for rendering Pages.
* Sets the active Page Style for rendering story text.
*/
public class SetPageStyle : CommandQueue.Command
{
@ -88,7 +88,7 @@ namespace Fungus
}
/**
* Sets the header text displayed at the top of the active page.
* Sets the header text displayed at the top of the page.
*/
public class SetHeader : CommandQueue.Command
{
@ -101,15 +101,9 @@ namespace Fungus
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);
}
PageController page = Game.GetInstance().pageController;
page.SetHeader(titleText);
if (onComplete != null)
{
onComplete();
@ -118,7 +112,7 @@ namespace Fungus
}
/**
* Sets the footer text displayed at the top of the active page.
* Sets the footer text displayed at the bottom of the page.
*/
public class SetFooter : CommandQueue.Command
{
@ -131,15 +125,9 @@ namespace Fungus
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);
}
PageController page = Game.GetInstance().pageController;
page.SetFooter(titleText);
if (onComplete != null)
{
onComplete();
@ -148,8 +136,8 @@ namespace Fungus
}
/**
* Writes story text to the currently active page.
* A 'continue' icon is displayed when the text has fully appeared.
* Writes story text to the page.
* A continue icon is displayed when the text has fully appeared.
*/
public class Say : CommandQueue.Command
{
@ -162,15 +150,8 @@ namespace Fungus
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);
}
PageController page = Game.GetInstance().pageController;
page.Say(storyText, onComplete);
}
}
@ -191,15 +172,9 @@ namespace Fungus
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);
}
PageController page = Game.GetInstance().pageController;
page.AddOption(optionText, optionAction);
if (onComplete != null)
{
onComplete();
@ -221,16 +196,10 @@ namespace Fungus
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()
PageController page = Game.GetInstance().pageController;
page.Choose(chooseText);
// Choose always clears the commandQueue, so there's no need to call onComplete()
}
}
}

27
Assets/Fungus/Scripts/Game.cs

@ -82,7 +82,7 @@ namespace Fungus
/**
* Default screen position for Page when player enters a Room.
*/
public Page.PagePosition defaultPagePosition;
public PageController.PagePosition defaultPagePosition;
/**
* Default width and height of Page as a fraction of screen height [0..1]
@ -106,9 +106,6 @@ namespace Fungus
[HideInInspector]
public Dictionary<string, int> values = new Dictionary<string, int>();
[HideInInspector]
public Page activePage;
[HideInInspector]
public StringTable stringTable = new StringTable();
@ -118,6 +115,9 @@ namespace Fungus
[HideInInspector]
public CameraController cameraController;
[HideInInspector]
public PageController pageController;
/**
* True when executing a Wait() or WaitForTap() command
*/
@ -156,6 +156,7 @@ namespace Fungus
// Add components for additional game functionality
commandQueue = gameObject.AddComponent<CommandQueue>();
cameraController = gameObject.AddComponent<CameraController>();
pageController = gameObject.AddComponent<PageController>();
AudioSource audioSource = gameObject.AddComponent<AudioSource>();
audioSource.playOnAwake = false;
@ -174,12 +175,6 @@ namespace Fungus
commandQueue.AddCommand(new Command.MoveToRoom(activeRoom));
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()
@ -215,8 +210,8 @@ namespace Fungus
}
}
if (activePage.mode == Page.Mode.Say &&
activePage.FinishedWriting())
if (pageController.mode == PageController.Mode.Say &&
pageController.FinishedWriting())
{
// Draw the continue icon
if (continueIcon)
@ -261,17 +256,17 @@ namespace Fungus
/**
* Returns true if the game should display 'auto hide' buttons.
* Buttons will be displayed if the active page is not currently displaying story text/options, and no Wait command is in progress.
* Buttons will be displayed if the game is not currently displaying story text/options, and no Wait command is in progress.
*/
public bool ShowAutoButtons()
public bool GetShowAutoButtons()
{
if (waiting)
{
return false;
}
if (activePage == null ||
activePage.mode == Page.Mode.Idle)
if (pageController == null ||
pageController.mode == PageController.Mode.Idle)
{
return (autoHideButtonTimer > 0f);
}

61
Assets/Fungus/Scripts/GameController.cs

@ -193,27 +193,32 @@ namespace Fungus
#region Page Methods
/**
* Sets the display rect for the active Page using a PageBounds object.
* Sets the screen space rectangle used to display the story text using a Page object.
* PageBounds objects can be edited visually in the Unity editor which is useful for accurate placement.
* 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.
* @param page A Page object which defines the screen rect to use when rendering story text.
*/
public static void SetPageBounds(PageBounds pageBounds, Page.Layout pageLayout = Page.Layout.FullSize)
public static void SetPage(Page page, PageController.Layout pageLayout = PageController.Layout.FullSize)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SetPageBounds(pageBounds, pageLayout));
commandQueue.AddCommand(new Command.SetPage(page, pageLayout));
}
public static void SetPageRect(Page.ScreenRect screenRect, Page.Layout pageLayout = Page.Layout.FullSize)
/**
* Sets the screen space rectangle used to display the story text using a ScreenRect object.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param screenRect A ScreenRect object which defines a rect in normalized screen space coordinates.
*/
public static void SetPageRect(PageController.ScreenRect screenRect, PageController.Layout pageLayout = PageController.Layout.FullSize)
{
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.AddCommand(new Command.SetPageRect(screenRect, 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).
* Sets the screen space rectangle used to display the story text.
* The rectangle coordinates are in normalized screen space. e.g. x1 = 0 (left), y1 = 0 (top) x2 = 1 (right) y2 = 1 (bottom).
* The origin is at the top left of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param x1 Page rect left coordinate in normalized screen space coords [0..1]
@ -222,9 +227,9 @@ namespace Fungus
* @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 SetPageRect(float x1, float y1, float x2, float y2, Page.Layout pageLayout = Page.Layout.FullSize)
public static void SetPageRect(float x1, float y1, float x2, float y2, PageController.Layout pageLayout = PageController.Layout.FullSize)
{
Page.ScreenRect screenRect = new Page.ScreenRect();
PageController.ScreenRect screenRect = new PageController.ScreenRect();
screenRect.x1 = x1;
screenRect.y1 = y1;
screenRect.x2 = x2;
@ -233,72 +238,72 @@ namespace Fungus
}
/**
* Sets the active Page to display at the top of the screen.
* Display story page 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)
public static void SetPageTop(float scaleX, float scaleY, PageController.Layout pageLayout)
{
Page.ScreenRect screenRect = Page.CalcScreenRect(new Vector2(scaleX, scaleY), Page.PagePosition.Top);
PageController.ScreenRect screenRect = PageController.CalcScreenRect(new Vector2(scaleX, scaleY), PageController.PagePosition.Top);
SetPageRect(screenRect, pageLayout);
}
/**
* Sets the currently active Page to display at the top of the screen.
* Display story page at the top of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
*/
public static void SetPageTop()
{
Vector2 pageScale = Game.GetInstance().defaultPageScale;
SetPageTop(pageScale.x, pageScale.y, Page.Layout.FullSize);
SetPageTop(pageScale.x, pageScale.y, PageController.Layout.FullSize);
}
/**
* Sets the active Page to display at the middle of the screen.
* Display story page 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)
public static void SetPageMiddle(float scaleX, float scaleY, PageController.Layout pageLayout)
{
Page.ScreenRect screenRect = Page.CalcScreenRect(new Vector2(scaleX, scaleY), Page.PagePosition.Middle);
PageController.ScreenRect screenRect = PageController.CalcScreenRect(new Vector2(scaleX, scaleY), PageController.PagePosition.Middle);
SetPageRect(screenRect, pageLayout);
}
/**
* Sets the currently active Page to display at the middle of the screen.
* Display story page at the middle of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
*/
public static void SetPageMiddle()
{
Vector2 pageScale = Game.GetInstance().defaultPageScale;
SetPageMiddle(pageScale.x, pageScale.y, Page.Layout.FitToMiddle);
SetPageMiddle(pageScale.x, pageScale.y, PageController.Layout.FitToMiddle);
}
/**
* Sets the active Page to display at the bottom of the screen.
* Display story page 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)
public static void SetPageBottom(float scaleX, float scaleY, PageController.Layout pageLayout)
{
Page.ScreenRect screenRect = Page.CalcScreenRect(new Vector2(scaleX, scaleY), Page.PagePosition.Bottom);
PageController.ScreenRect screenRect = PageController.CalcScreenRect(new Vector2(scaleX, scaleY), PageController.PagePosition.Bottom);
SetPageRect(screenRect, pageLayout);
}
/**
* Sets the currently active Page to display at the bottom of the screen.
* Display story page at the bottom of the screen.
* This method returns immediately but it queues an asynchronous command for later execution.
*/
public static void SetPageBottom()
{
Vector2 pageScale = Game.GetInstance().defaultPageScale;
SetPageBottom(pageScale.x, pageScale.y, Page.Layout.FullSize);
SetPageBottom(pageScale.x, pageScale.y, PageController.Layout.FullSize);
}
/**
@ -322,7 +327,7 @@ namespace Fungus
}
/**
* Sets the header text displayed at the top of the active Page.
* Sets the header text displayed at the top of the page.
* The header text is only displayed when there is some story text or options to be shown.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param footerText The text to display as the header of the Page.
@ -334,7 +339,7 @@ namespace Fungus
}
/**
* Sets the footer text displayed at the top of the active Page.
* Sets the footer text displayed at the top of the page.
* The footer text is only displayed when there is some story text or options to be shown.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param footerText The text to display as the footer of the Page.
@ -346,11 +351,11 @@ namespace Fungus
}
/**
* Writes story text to the currently active Page.
* Writes story text to the page.
* A 'continue' button is displayed when the text has fully appeared.
* Command execution halts until the user chooses to continue.
* This method returns immediately but it queues an asynchronous command for later execution.
* @param storyText The text to be written to the currently active Page.
* @param storyText The text to be written to the page.
*/
public static void Say(string storyText)
{

599
Assets/Fungus/Scripts/Page.cs

@ -1,596 +1,45 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Fungus
{
/**
* A rectangular screen area for rendering story text.
* Rooms may contain any number of Pages.
* If a Page is a child of a View, then transitioning to that View will automatically activate the Page.
* Defines a user editable screen aligned rect for setting Page bounds.
*/
[ExecuteInEditMode]
public class Page : MonoBehaviour
{
/// Options for default Page position on screen
public enum PagePosition
{
/// Page appears full-size and horizontally centered at top of screen.
Top,
/// Page appears centered in middle of screen, with height fitted to content.
Middle,
/// Page appears full-size and horizontally centered at bottom of screen.
Bottom
}
/**
* Defines a rect in normalized screen space coordinates.
* e.g. x1 = 0 means left of screen, x2 = 1 means right of screen.
*/
public class ScreenRect
{
public float x1;
public float y1;
public float x2;
public float y2;
}
/// Options for controlling page layout
public enum Layout
{
/// Use the full rect to display the page.
FullSize,
/// 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
}
/// Controls layout of content within Page rect.
public Layout layout = Layout.FullSize;
/// Supported states for Page
public enum Mode
{
/// No content to be displayed.
Idle,
/// Show a single line of text and wait for player input.
Say,
/// Show a multiple choice menu and wait for player to select an option.
Choose
};
[HideInInspector]
public Mode mode = Mode.Idle;
/// Screen space rect for Page in pixels.
public Rect pageRect;
string headerText = "";
string footerText = "";
string displayedStoryText = "";
string originalStoryText = "";
/// Rectangular bounds used to display page text.
public Bounds pageBounds = new Bounds(Vector3.zero, new Vector3(0.25f, 0.25f, 0f));
Action deferredAction;
Action continueAction;
class Option
{
public string optionText;
public Action optionAction;
public Option(string _optionText, Action _optionAction)
{
optionText = _optionText;
optionAction = _optionAction;
}
}
List<Option> options = new List<Option>();
float quickContinueTimer;
/// Layout style to use for Page
public PageController.Layout layout = PageController.Layout.FullSize;
/**
* Calculate a screen space rectangle given normalized screen space coords.
* The resulting rect is clamped to always be on-screen.
* Modifies the PageController to use a rect defined by the bounds and the current camera transform
*/
public static Rect CalcPageRect(ScreenRect screenRect)
{
Rect rect = new Rect();
rect.xMin = Screen.width * screenRect.x1;
rect.yMin = Screen.height * screenRect.y1;
rect.xMax = Screen.width * screenRect.x2;
rect.yMax = Screen.height * screenRect.y2;
// Clamp to be on-screen
rect.xMax = Mathf.Min(rect.xMax, Screen.width);
rect.xMin = Mathf.Max(rect.xMin, 0);
rect.yMax = Mathf.Min(rect.yMax, Screen.height);
rect.yMin = Mathf.Max(rect.yMin, 0);
return rect;
}
/**
* Calculates a screen rect in normalized screen space coordinates in one of the 'standard' Page positions (top, middle, bottom).
*/
public static ScreenRect CalcScreenRect(Vector2 pageScale, PagePosition pagePosition)
{
float width = Mathf.Clamp01(pageScale.x);
float height = Mathf.Clamp01(pageScale.y);
ScreenRect screenRect = new ScreenRect();
switch (pagePosition)
{
case PagePosition.Top:
screenRect.x1 = 0.5f - width * 0.5f;
screenRect.x2 = 0.5f + width * 0.5f;
screenRect.y1 = 0f;
screenRect.y2 = height;
break;
case PagePosition.Middle:
screenRect.x1 = 0.5f - width * 0.5f;
screenRect.x2 = 0.5f + width * 0.5f;
screenRect.y1 = 0.5f - height * 0.5f;
screenRect.y2 = 0.5f + height * 0.5f;
break;
case PagePosition.Bottom:
screenRect.x1 = 0.5f - width * 0.5f;
screenRect.x2 = 0.5f + width * 0.5f;
screenRect.y1 = 1f - Mathf.Clamp01(height);
screenRect.y2 = 1;
break;
}
return screenRect;
}
/**
* Reset to the default page layout based on properties in Game class.
*/
public void SetDefaultPageLayout()
{
Game game = Game.GetInstance();
ScreenRect screenRect = CalcScreenRect(game.defaultPageScale, game.defaultPagePosition);
pageRect = CalcPageRect(screenRect);
switch (game.defaultPagePosition)
{
case Page.PagePosition.Top:
game.activePage.layout = Page.Layout.FullSize;
break;
case Page.PagePosition.Middle:
game.activePage.layout = Page.Layout.FitToMiddle;
break;
case Page.PagePosition.Bottom:
game.activePage.layout = Page.Layout.FullSize;
break;
}
}
void Update()
{
if (quickContinueTimer > 0)
{
quickContinueTimer -= Time.deltaTime;
quickContinueTimer = Mathf.Max(quickContinueTimer, 0f);
}
}
public void SetHeader(string _headerText)
{
headerText = _headerText;
}
public void SetFooter(string _footerText)
{
footerText = _footerText;
}
public void Say(string sayText, Action sayAction)
{
mode = Mode.Say;
StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.SubstituteStrings(sayText);
continueAction = sayAction;
WriteStory(subbedText);
}
public void AddOption(string optionText, Action optionAction)
{
StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.FormatLinkText(stringTable.SubstituteStrings(optionText));
options.Add(new Option(subbedText, optionAction));
}
public void Choose(string _chooseText)
{
mode = Mode.Choose;
StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.SubstituteStrings(_chooseText);
WriteStory(subbedText);
}
void WriteStory(string storyText)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null)
{
return;
}
// Disable quick continue for a short period to prevent accidental taps
quickContinueTimer = 0.8f;
originalStoryText = storyText;
// Hack to avoid displaying partial color tag text
if (storyText.Contains("<"))
{
displayedStoryText = storyText;
}
else
{
// Use a coroutine to write the story text out over time
StartCoroutine(WriteStoryInternal());
}
}
// Coroutine to write story text out over a period of time
IEnumerator WriteStoryInternal()
{
int charactersPerSecond = Game.GetInstance().charactersPerSecond;
// Zero CPS means write instantly
if (charactersPerSecond == 0)
{
displayedStoryText = originalStoryText;
yield break;
}
displayedStoryText = "";
// Make one character visible at a time
float writeDelay = (1f / (float)charactersPerSecond);
float timeAccumulator = 0f;
int i = 0;
while (true)
{
timeAccumulator += Time.deltaTime;
while (timeAccumulator > writeDelay)
{
i++;
timeAccumulator -= writeDelay;
}
if (i >= originalStoryText.Length)
{
displayedStoryText = originalStoryText;
break;
}
else
{
string left = originalStoryText.Substring(0, i + 1);
string right = originalStoryText.Substring(i + 1);
displayedStoryText = left;
displayedStoryText += "<color=#FFFFFF00>";
displayedStoryText += right;
displayedStoryText += "</color>";
}
yield return null;
}
}
public bool FinishedWriting()
{
return (displayedStoryText.Length == originalStoryText.Length);
}
public virtual void OnGUI()
{
if (mode == Mode.Idle)
{
return;
}
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null)
{
return;
}
GUIStyle boxStyle = pageStyle.boxStyle;
GUIStyle headerStyle = pageStyle.GetScaledHeaderStyle();
GUIStyle footerStyle = pageStyle.GetScaledFooterStyle();
GUIStyle sayStyle = pageStyle.GetScaledSayStyle();
GUIStyle optionStyle = pageStyle.GetScaledOptionStyle();
GUIStyle optionAlternateStyle = pageStyle.GetScaledOptionAlternateStyle();
Rect outerRect;
Layout tempLayout;
Game game = Game.GetInstance();
if (mode == Mode.Choose &&
game.centerChooseMenu)
{
// Position the Choose menu in middle of screen
// The width is controlled by game.chooseMenuWidth
// The height is automatically fitted to the text content
Vector2 pageScale = new Vector2(game.chooseMenuWidth, 0.5f);
Page.ScreenRect screenRect = Page.CalcScreenRect(pageScale, Page.PagePosition.Middle);
outerRect = Page.CalcPageRect(screenRect);
tempLayout = Page.Layout.FitToMiddle;
}
else
{
outerRect = pageRect;
tempLayout = layout;
}
Rect originalRect = outerRect;
Rect innerRect = CalcInnerRect(outerRect);
// Calculate height of each section
float headerHeight = CalcHeaderHeight(innerRect.width);
float footerHeight = CalcFooterHeight(innerRect.width);
float storyHeight = CalcStoryHeight(innerRect.width);
float optionsHeight = CalcOptionsHeight(innerRect.width);
float contentHeight = headerHeight + footerHeight + storyHeight + optionsHeight;
// Adjust outer rect position based on alignment settings
switch (tempLayout)
{
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.y = originalRect.yMin;
break;
case Layout.FitToMiddle:
outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
outerRect.y = originalRect.center.y - outerRect.height / 2;
break;
case Layout.FitToBottom:
outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
outerRect.y = originalRect.yMax - outerRect.height;
break;
}
innerRect = CalcInnerRect(outerRect);
// Draw box
Rect boxRect = outerRect;
boxRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
if (tempLayout == Layout.FullSize)
{
boxRect.height = Mathf.Max(boxRect.height, originalRect.height);
}
GUI.Box(boxRect, "", boxStyle);
// Draw header label
Rect headerRect = innerRect;
headerRect.height = headerHeight;
if (headerHeight > 0)
{
GUI.Label(headerRect, headerText, headerStyle);
}
// Draw say label
Rect storyRect = innerRect;
storyRect.y += headerHeight;
storyRect.height = storyHeight;
GUI.Label(storyRect, displayedStoryText, sayStyle);
// Draw footer label
Rect footerRect = innerRect;
footerRect.y += storyHeight;
footerRect.height = footerHeight;
if (footerHeight > 0)
{
GUI.Label(footerRect, footerText, footerStyle);
}
if (!FinishedWriting())
{
return;
}
// Input handling
if (mode == Mode.Say)
{
// Player can continue by clicking anywhere
if (quickContinueTimer == 0 &&
(Input.GetMouseButtonUp(0) || Input.anyKeyDown) &&
continueAction != null)
{
deferredAction = continueAction;
}
}
else if (mode == Mode.Choose)
{
// Draw option buttons
Rect buttonRect = innerRect;
buttonRect.y += headerHeight + storyHeight;
bool alternateRow = false;
foreach (Option option in options)
{
GUIContent buttonContent = new GUIContent(option.optionText);
buttonRect.height = optionStyle.CalcHeight(buttonContent, innerRect.width);
// Select style for odd/even colored rows
GUIStyle style;
if (alternateRow)
{
style = optionAlternateStyle;
}
else
{
style = optionStyle;
}
alternateRow = !alternateRow;
if (GUI.Button(buttonRect, buttonContent, style))
{
if (option.optionAction != null)
{
// We can't execute the option action yet because OnGUI
// may be called multiple times during a frame, and it's
// not permitted to modify GUI elements within a frame.
// We defer executing the action until OnGUI has completed.
deferredAction = option.optionAction;
break;
}
}
buttonRect.y += buttonRect.height;
}
}
if (Event.current.type == EventType.Repaint)
{
if (deferredAction != null)
{
Game.GetInstance().PlayButtonClick();
Action tempAction = deferredAction;
displayedStoryText = "";
originalStoryText = "";
deferredAction = null;
if (mode == Mode.Choose)
{
options.Clear();
// Reset to idle, but calling action may set this again
mode = Mode.Idle;
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.CallCommandMethod(tempAction);
}
else if (mode == Mode.Say )
{
// Reset to idle, but calling action may set this again
mode = Mode.Idle;
// Execute next command
tempAction();
}
}
}
}
float CalcHeaderHeight(float boxWidth)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null ||
mode == Mode.Idle ||
headerText.Length == 0)
{
return 0;
}
GUIStyle headerStyle = pageStyle.GetScaledHeaderStyle();
GUIContent headerContent = new GUIContent(headerText);
return headerStyle.CalcHeight(headerContent, boxWidth);
}
float CalcFooterHeight(float boxWidth)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null ||
mode == Mode.Idle ||
footerText.Length == 0)
{
return 0;
}
GUIStyle footerStyle = pageStyle.GetScaledFooterStyle();
GUIContent headerContent = new GUIContent(headerText);
return footerStyle.CalcHeight(headerContent, boxWidth);
}
float CalcStoryHeight(float boxWidth)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
GUIStyle sayStyle = pageStyle.GetScaledSayStyle();
if (pageStyle == null ||
mode == Mode.Idle ||
originalStoryText.Length == 0)
{
// Allow a space for story even if there's no text
return sayStyle.lineHeight;
}
GUIContent storyContent = new GUIContent(originalStoryText + "\n");
return sayStyle.CalcHeight(storyContent, boxWidth);
}
float CalcOptionsHeight(float boxWidth)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null ||
mode == Mode.Idle ||
options.Count == 0)
{
return 0;
}
// This assumes that the alternate option style is the same height as the regular style
GUIStyle optionStyle = pageStyle.GetScaledOptionStyle();
float totalHeight = 0;
foreach (Option option in options)
{
GUIContent optionContent = new GUIContent(option.optionText);
float optionHeight = optionStyle.CalcHeight(optionContent, boxWidth);
totalHeight += optionHeight;
}
// Add space at bottom
GUIStyle sayStyle = pageStyle.GetScaledSayStyle();
totalHeight += sayStyle.lineHeight;
return totalHeight;
}
// Returns smaller internal box rect with padding style applied
Rect CalcInnerRect(Rect outerRect)
public void UpdatePageRect()
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
// Y increases down 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;
if (pageStyle == null)
{
return new Rect();
}
Vector3 bottomRight = transform.position + pageBounds.center;
bottomRight.x += pageBounds.extents.x;
bottomRight.y -= pageBounds.extents.y;
GUIStyle boxStyle = pageStyle.boxStyle;
Vector2 tl = Camera.main.WorldToScreenPoint(topLeft);
Vector2 br = Camera.main.WorldToScreenPoint(bottomRight);
Rect innerRect = new Rect(outerRect.x + boxStyle.padding.left,
outerRect.y + boxStyle.padding.top,
outerRect.width - (boxStyle.padding.left + boxStyle.padding.right),
outerRect.height - (boxStyle.padding.top + boxStyle.padding.bottom));
PageController.ScreenRect screenRect = new PageController.ScreenRect();
screenRect.x1 = (tl.x / Screen.width);
screenRect.y1 = 1f - (tl.y / Screen.height);
screenRect.x2 = (br.x / Screen.width);
screenRect.y2 = 1f - (br.y / Screen.height);
return innerRect;
PageController page = Game.GetInstance().pageController;
page.pageRect = PageController.CalcPageRect(screenRect);
page.layout = layout;
}
}
}

2
Assets/Fungus/Scripts/Page.cs.meta

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 2154cd49b43b3450fb92da231e24e065
guid: 627f97c837bdf479aa14a90d8ea3a736
MonoImporter:
serializedVersion: 2
defaultReferences: []

45
Assets/Fungus/Scripts/PageBounds.cs

@ -1,45 +0,0 @@
using UnityEngine;
using System.Collections;
namespace Fungus
{
/**
* Defines a screen aligned rectangular area for setting Page bounds
*/
public class PageBounds : MonoBehaviour
{
/// Rectangular bounds used to display page text.
public Bounds bounds = new Bounds(Vector3.zero, new Vector3(0.25f, 0.25f, 0f));
/// Layout style to use for Page
public Page.Layout layout = Page.Layout.FullSize;
/**
* Modifies the active Page to use a rect defined by the bounds and the current camera transform
*/
public void UpdatePageRect()
{
// Y increases down the screen in GUI space, so top left is rect origin
Vector3 topLeft = transform.position + bounds.center;
topLeft.x -= bounds.extents.x;
topLeft.y += bounds.extents.y;
Vector3 bottomRight = transform.position + bounds.center;
bottomRight.x += bounds.extents.x;
bottomRight.y -= bounds.extents.y;
Vector2 tl = Camera.main.WorldToScreenPoint(topLeft);
Vector2 br = Camera.main.WorldToScreenPoint(bottomRight);
Page.ScreenRect screenRect = new Page.ScreenRect();
screenRect.x1 = (tl.x / Screen.width);
screenRect.y1 = 1f - (tl.y / Screen.height);
screenRect.x2 = (br.x / Screen.width);
screenRect.y2 = 1f - (br.y / Screen.height);
Page page = Game.GetInstance().activePage;
page.pageRect = Page.CalcPageRect(screenRect);
page.layout = layout;
}
}
}

594
Assets/Fungus/Scripts/PageController.cs

@ -0,0 +1,594 @@
using UnityEngine;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Text.RegularExpressions;
namespace Fungus
{
/**
* Manages and draws a text box for rendering story text and multiple choice menus.
*/
[ExecuteInEditMode]
public class PageController : MonoBehaviour
{
/// Options for default Page position on screen
public enum PagePosition
{
/// Page appears full-size and horizontally centered at top of screen.
Top,
/// Page appears centered in middle of screen, with height fitted to content.
Middle,
/// Page appears full-size and horizontally centered at bottom of screen.
Bottom
}
/**
* Defines a rect in normalized screen space coordinates.
* e.g. x1 = 0 means left of screen, x2 = 1 means right of screen.
*/
public class ScreenRect
{
public float x1;
public float y1;
public float x2;
public float y2;
}
/// Options for controlling page layout
public enum Layout
{
/// Use the full rect to display the page.
FullSize,
/// 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
}
/// Controls layout of content within Page rect.
public Layout layout = Layout.FullSize;
/// Supported states for Page
public enum Mode
{
/// No content to be displayed.
Idle,
/// Show a single line of text and wait for player input.
Say,
/// Show a multiple choice menu and wait for player to select an option.
Choose
};
/// Current Page story telling state
public Mode mode = Mode.Idle;
/// Screen space rect for Page in pixels.
public Rect pageRect;
string headerText = "";
string footerText = "";
string displayedStoryText = "";
string originalStoryText = "";
Action deferredAction;
Action continueAction;
class Option
{
public string optionText;
public Action optionAction;
public Option(string _optionText, Action _optionAction)
{
optionText = _optionText;
optionAction = _optionAction;
}
}
List<Option> options = new List<Option>();
float quickContinueTimer;
/**
* Calculate a screen space rectangle given normalized screen space coords.
* The resulting rect is clamped to always be on-screen.
*/
public static Rect CalcPageRect(ScreenRect screenRect)
{
Rect rect = new Rect();
rect.xMin = Screen.width * screenRect.x1;
rect.yMin = Screen.height * screenRect.y1;
rect.xMax = Screen.width * screenRect.x2;
rect.yMax = Screen.height * screenRect.y2;
// Clamp to be on-screen
rect.xMax = Mathf.Min(rect.xMax, Screen.width);
rect.xMin = Mathf.Max(rect.xMin, 0);
rect.yMax = Mathf.Min(rect.yMax, Screen.height);
rect.yMin = Mathf.Max(rect.yMin, 0);
return rect;
}
/**
* Calculates a screen rect in normalized screen space coordinates in one of the 'standard' Page positions (top, middle, bottom).
*/
public static ScreenRect CalcScreenRect(Vector2 pageScale, PagePosition pagePosition)
{
float width = Mathf.Clamp01(pageScale.x);
float height = Mathf.Clamp01(pageScale.y);
ScreenRect screenRect = new ScreenRect();
switch (pagePosition)
{
case PagePosition.Top:
screenRect.x1 = 0.5f - width * 0.5f;
screenRect.x2 = 0.5f + width * 0.5f;
screenRect.y1 = 0f;
screenRect.y2 = height;
break;
case PagePosition.Middle:
screenRect.x1 = 0.5f - width * 0.5f;
screenRect.x2 = 0.5f + width * 0.5f;
screenRect.y1 = 0.5f - height * 0.5f;
screenRect.y2 = 0.5f + height * 0.5f;
break;
case PagePosition.Bottom:
screenRect.x1 = 0.5f - width * 0.5f;
screenRect.x2 = 0.5f + width * 0.5f;
screenRect.y1 = 1f - Mathf.Clamp01(height);
screenRect.y2 = 1;
break;
}
return screenRect;
}
/**
* Reset to the default page layout based on properties in Game class.
*/
public void SetDefaultPageLayout()
{
Game game = Game.GetInstance();
ScreenRect screenRect = CalcScreenRect(game.defaultPageScale, game.defaultPagePosition);
pageRect = CalcPageRect(screenRect);
switch (game.defaultPagePosition)
{
case PageController.PagePosition.Top:
game.pageController.layout = PageController.Layout.FullSize;
break;
case PageController.PagePosition.Middle:
game.pageController.layout = PageController.Layout.FitToMiddle;
break;
case PageController.PagePosition.Bottom:
game.pageController.layout = PageController.Layout.FullSize;
break;
}
}
void Update()
{
if (quickContinueTimer > 0)
{
quickContinueTimer -= Time.deltaTime;
quickContinueTimer = Mathf.Max(quickContinueTimer, 0f);
}
}
public void SetHeader(string _headerText)
{
headerText = _headerText;
}
public void SetFooter(string _footerText)
{
footerText = _footerText;
}
public void Say(string sayText, Action sayAction)
{
mode = Mode.Say;
StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.SubstituteStrings(sayText);
continueAction = sayAction;
WriteStory(subbedText);
}
public void AddOption(string optionText, Action optionAction)
{
StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.FormatLinkText(stringTable.SubstituteStrings(optionText));
options.Add(new Option(subbedText, optionAction));
}
public void Choose(string _chooseText)
{
mode = Mode.Choose;
StringTable stringTable = Game.GetInstance().stringTable;
string subbedText = stringTable.SubstituteStrings(_chooseText);
WriteStory(subbedText);
}
void WriteStory(string storyText)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null)
{
return;
}
// Disable quick continue for a short period to prevent accidental taps
quickContinueTimer = 0.8f;
originalStoryText = storyText;
// Hack to avoid displaying partial color tag text
if (storyText.Contains("<"))
{
displayedStoryText = storyText;
}
else
{
// Use a coroutine to write the story text out over time
StartCoroutine(WriteStoryInternal());
}
}
// Coroutine to write story text out over a period of time
IEnumerator WriteStoryInternal()
{
int charactersPerSecond = Game.GetInstance().charactersPerSecond;
// Zero CPS means write instantly
if (charactersPerSecond == 0)
{
displayedStoryText = originalStoryText;
yield break;
}
displayedStoryText = "";
// Make one character visible at a time
float writeDelay = (1f / (float)charactersPerSecond);
float timeAccumulator = 0f;
int i = 0;
while (true)
{
timeAccumulator += Time.deltaTime;
while (timeAccumulator > writeDelay)
{
i++;
timeAccumulator -= writeDelay;
}
if (i >= originalStoryText.Length)
{
displayedStoryText = originalStoryText;
break;
}
else
{
string left = originalStoryText.Substring(0, i + 1);
string right = originalStoryText.Substring(i + 1);
displayedStoryText = left;
displayedStoryText += "<color=#FFFFFF00>";
displayedStoryText += right;
displayedStoryText += "</color>";
}
yield return null;
}
}
public bool FinishedWriting()
{
return (displayedStoryText.Length == originalStoryText.Length);
}
public virtual void OnGUI()
{
if (mode == Mode.Idle)
{
return;
}
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null)
{
return;
}
GUIStyle boxStyle = pageStyle.boxStyle;
GUIStyle headerStyle = pageStyle.GetScaledHeaderStyle();
GUIStyle footerStyle = pageStyle.GetScaledFooterStyle();
GUIStyle sayStyle = pageStyle.GetScaledSayStyle();
GUIStyle optionStyle = pageStyle.GetScaledOptionStyle();
GUIStyle optionAlternateStyle = pageStyle.GetScaledOptionAlternateStyle();
Rect outerRect;
Layout tempLayout;
Game game = Game.GetInstance();
if (mode == Mode.Choose &&
game.centerChooseMenu)
{
// Position the Choose menu in middle of screen
// The width is controlled by game.chooseMenuWidth
// The height is automatically fitted to the text content
Vector2 pageScale = new Vector2(game.chooseMenuWidth, 0.5f);
PageController.ScreenRect screenRect = PageController.CalcScreenRect(pageScale, PageController.PagePosition.Middle);
outerRect = PageController.CalcPageRect(screenRect);
tempLayout = PageController.Layout.FitToMiddle;
}
else
{
outerRect = pageRect;
tempLayout = layout;
}
Rect originalRect = outerRect;
Rect innerRect = CalcInnerRect(outerRect);
// Calculate height of each section
float headerHeight = CalcHeaderHeight(innerRect.width);
float footerHeight = CalcFooterHeight(innerRect.width);
float storyHeight = CalcStoryHeight(innerRect.width);
float optionsHeight = CalcOptionsHeight(innerRect.width);
float contentHeight = headerHeight + footerHeight + storyHeight + optionsHeight;
// Adjust outer rect position based on alignment settings
switch (tempLayout)
{
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.y = originalRect.yMin;
break;
case Layout.FitToMiddle:
outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
outerRect.y = originalRect.center.y - outerRect.height / 2;
break;
case Layout.FitToBottom:
outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
outerRect.y = originalRect.yMax - outerRect.height;
break;
}
innerRect = CalcInnerRect(outerRect);
// Draw box
Rect boxRect = outerRect;
boxRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom);
if (tempLayout == Layout.FullSize)
{
boxRect.height = Mathf.Max(boxRect.height, originalRect.height);
}
GUI.Box(boxRect, "", boxStyle);
// Draw header label
Rect headerRect = innerRect;
headerRect.height = headerHeight;
if (headerHeight > 0)
{
GUI.Label(headerRect, headerText, headerStyle);
}
// Draw say label
Rect storyRect = innerRect;
storyRect.y += headerHeight;
storyRect.height = storyHeight;
GUI.Label(storyRect, displayedStoryText, sayStyle);
// Draw footer label
Rect footerRect = innerRect;
footerRect.y += storyHeight;
footerRect.height = footerHeight;
if (footerHeight > 0)
{
GUI.Label(footerRect, footerText, footerStyle);
}
if (!FinishedWriting())
{
return;
}
// Input handling
if (mode == Mode.Say)
{
// Player can continue by clicking anywhere
if (quickContinueTimer == 0 &&
(Input.GetMouseButtonUp(0) || Input.anyKeyDown) &&
continueAction != null)
{
deferredAction = continueAction;
}
}
else if (mode == Mode.Choose)
{
// Draw option buttons
Rect buttonRect = innerRect;
buttonRect.y += headerHeight + storyHeight;
bool alternateRow = false;
foreach (Option option in options)
{
GUIContent buttonContent = new GUIContent(option.optionText);
buttonRect.height = optionStyle.CalcHeight(buttonContent, innerRect.width);
// Select style for odd/even colored rows
GUIStyle style;
if (alternateRow)
{
style = optionAlternateStyle;
}
else
{
style = optionStyle;
}
alternateRow = !alternateRow;
if (GUI.Button(buttonRect, buttonContent, style))
{
if (option.optionAction != null)
{
// We can't execute the option action yet because OnGUI
// may be called multiple times during a frame, and it's
// not permitted to modify GUI elements within a frame.
// We defer executing the action until OnGUI has completed.
deferredAction = option.optionAction;
break;
}
}
buttonRect.y += buttonRect.height;
}
}
if (Event.current.type == EventType.Repaint)
{
if (deferredAction != null)
{
Game.GetInstance().PlayButtonClick();
Action tempAction = deferredAction;
displayedStoryText = "";
originalStoryText = "";
deferredAction = null;
if (mode == Mode.Choose)
{
options.Clear();
// Reset to idle, but calling action may set this again
mode = Mode.Idle;
CommandQueue commandQueue = Game.GetInstance().commandQueue;
commandQueue.CallCommandMethod(tempAction);
}
else if (mode == Mode.Say )
{
// Reset to idle, but calling action may set this again
mode = Mode.Idle;
// Execute next command
tempAction();
}
}
}
}
float CalcHeaderHeight(float boxWidth)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null ||
mode == Mode.Idle ||
headerText.Length == 0)
{
return 0;
}
GUIStyle headerStyle = pageStyle.GetScaledHeaderStyle();
GUIContent headerContent = new GUIContent(headerText);
return headerStyle.CalcHeight(headerContent, boxWidth);
}
float CalcFooterHeight(float boxWidth)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null ||
mode == Mode.Idle ||
footerText.Length == 0)
{
return 0;
}
GUIStyle footerStyle = pageStyle.GetScaledFooterStyle();
GUIContent headerContent = new GUIContent(headerText);
return footerStyle.CalcHeight(headerContent, boxWidth);
}
float CalcStoryHeight(float boxWidth)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
GUIStyle sayStyle = pageStyle.GetScaledSayStyle();
if (pageStyle == null ||
mode == Mode.Idle ||
originalStoryText.Length == 0)
{
// Allow a space for story even if there's no text
return sayStyle.lineHeight;
}
GUIContent storyContent = new GUIContent(originalStoryText + "\n");
return sayStyle.CalcHeight(storyContent, boxWidth);
}
float CalcOptionsHeight(float boxWidth)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null ||
mode == Mode.Idle ||
options.Count == 0)
{
return 0;
}
// This assumes that the alternate option style is the same height as the regular style
GUIStyle optionStyle = pageStyle.GetScaledOptionStyle();
float totalHeight = 0;
foreach (Option option in options)
{
GUIContent optionContent = new GUIContent(option.optionText);
float optionHeight = optionStyle.CalcHeight(optionContent, boxWidth);
totalHeight += optionHeight;
}
// Add space at bottom
GUIStyle sayStyle = pageStyle.GetScaledSayStyle();
totalHeight += sayStyle.lineHeight;
return totalHeight;
}
// Returns smaller internal box rect with padding style applied
Rect CalcInnerRect(Rect outerRect)
{
PageStyle pageStyle = Game.GetInstance().activePageStyle;
if (pageStyle == null)
{
return new Rect();
}
GUIStyle boxStyle = pageStyle.boxStyle;
Rect innerRect = new Rect(outerRect.x + boxStyle.padding.left,
outerRect.y + boxStyle.padding.top,
outerRect.width - (boxStyle.padding.left + boxStyle.padding.right),
outerRect.height - (boxStyle.padding.top + boxStyle.padding.bottom));
return innerRect;
}
}
}

2
Assets/Fungus/Scripts/PageBounds.cs.meta → Assets/Fungus/Scripts/PageController.cs.meta

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 627f97c837bdf479aa14a90d8ea3a736
guid: 2154cd49b43b3450fb92da231e24e065
MonoImporter:
serializedVersion: 2
defaultReferences: []

2
Assets/Fungus/Scripts/Room.cs

@ -140,7 +140,7 @@ namespace Fungus
}
// Reset Page layout to default setting specified in Game object
game.activePage.SetDefaultPageLayout();
game.pageController.SetDefaultPageLayout();
// 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.

BIN
Assets/FungusExample/Scenes/Example.unity

Binary file not shown.
Loading…
Cancel
Save