diff --git a/Assets/Fungus/Prefabs/Game.prefab b/Assets/Fungus/Prefabs/Game.prefab index 86069123..1dabbf3e 100644 Binary files a/Assets/Fungus/Prefabs/Game.prefab and b/Assets/Fungus/Prefabs/Game.prefab differ diff --git a/Assets/Fungus/Scripts/Commands/PageCommands.cs b/Assets/Fungus/Scripts/Commands/PageCommands.cs index 4fc458da..99946bfa 100644 --- a/Assets/Fungus/Scripts/Commands/PageCommands.cs +++ b/Assets/Fungus/Scripts/Commands/PageCommands.cs @@ -43,25 +43,19 @@ namespace Fungus */ public class SetPageRect : CommandQueue.Command { - float x1; - float y1; - float x2; - float y2; + Page.ScreenRect screenRect; Page.Layout layout; - public SetPageRect(float _x1, float _y1, float _x2, float _y2, Page.Layout _layout) + public SetPageRect(Page.ScreenRect _screenRect, Page.Layout _layout) { - x1 = _x1; - y1 = _y1; - x2 = _x2; - y2 = _y2; + screenRect = _screenRect; layout = _layout; } public override void Execute(CommandQueue commandQueue, Action onComplete) { Page page = Game.GetInstance().activePage; - page.SetPageRect(x1, y1, x2, y2); + page.pageRect = Page.CalcPageRect(screenRect); page.layout = layout; if (onComplete != null) diff --git a/Assets/Fungus/Scripts/Game.cs b/Assets/Fungus/Scripts/Game.cs index dfcc8ade..8067d7af 100644 --- a/Assets/Fungus/Scripts/Game.cs +++ b/Assets/Fungus/Scripts/Game.cs @@ -73,7 +73,26 @@ namespace Fungus */ public float autoHideButtonDuration = 5f; - float autoHideButtonTimer; + /** + * Default screen position for Page when player enters a Room. + */ + public Page.PagePosition defaultPagePosition; + + /** + * Default width and height of Page as a fraction of screen height [0..1] + */ + public Vector2 defaultPageScale = new Vector2(0.75f, 0.25f); + + /** + * Automatically center the Page when player is choosing from multiple options. + */ + public bool centerChooseMenu = true; + + /** + * Width of Page as a fraction of screen width [0..1] when automatically centering a Choose menu. + * This setting only has an effect when centerChooseMenu is enabled. + */ + public float chooseMenuWidth = 0.5f; /** * Global dictionary of integer values for storing game state. @@ -105,6 +124,8 @@ namespace Fungus [HideInInspector] public float fadeAlpha = 0f; + float autoHideButtonTimer; + static Game instance; /** @@ -174,7 +195,7 @@ namespace Fungus if (manualPanTexture) { Rect rect = new Rect(Screen.width - manualPanTexture.width, - 0, + Screen.height - manualPanTexture.height, manualPanTexture.width, manualPanTexture.height); GUI.DrawTexture(rect, manualPanTexture); @@ -188,7 +209,7 @@ namespace Fungus if (continueTexture) { Rect rect = new Rect(Screen.width - continueTexture.width, - 0, + Screen.height - manualPanTexture.height, continueTexture.width, continueTexture.height); GUI.DrawTexture(rect, continueTexture); diff --git a/Assets/Fungus/Scripts/GameController.cs b/Assets/Fungus/Scripts/GameController.cs index 6d5377eb..f2eb5fd5 100644 --- a/Assets/Fungus/Scripts/GameController.cs +++ b/Assets/Fungus/Scripts/GameController.cs @@ -205,6 +205,12 @@ namespace Fungus commandQueue.AddCommand(new Command.SetPageBounds(pageBounds, pageLayout)); } + public static void SetPageRect(Page.ScreenRect screenRect, Page.Layout pageLayout = Page.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). @@ -218,8 +224,12 @@ namespace Fungus */ public static void SetPageRect(float x1, float y1, float x2, float y2, Page.Layout pageLayout = Page.Layout.FullSize) { - CommandQueue commandQueue = Game.GetInstance().commandQueue; - commandQueue.AddCommand(new Command.SetPageRect(x1, y1, x2, y2, pageLayout)); + Page.ScreenRect screenRect = new Page.ScreenRect(); + screenRect.x1 = x1; + screenRect.y1 = y1; + screenRect.x2 = x2; + screenRect.y2 = y2; + SetPageRect(screenRect, pageLayout); } /** @@ -231,14 +241,8 @@ namespace Fungus */ 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); + Page.ScreenRect screenRect = Page.CalcScreenRect(new Vector2(scaleX, scaleY), Page.PagePosition.Top); + SetPageRect(screenRect, pageLayout); } /** @@ -247,7 +251,8 @@ namespace Fungus */ public static void SetPageTop() { - SetPageTop(0.75f, 0.25f, Page.Layout.FullSize); + Vector2 pageScale = Game.GetInstance().defaultPageScale; + SetPageTop(pageScale.x, pageScale.y, Page.Layout.FullSize); } /** @@ -259,15 +264,8 @@ namespace Fungus */ 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); + Page.ScreenRect screenRect = Page.CalcScreenRect(new Vector2(scaleX, scaleY), Page.PagePosition.Middle); + SetPageRect(screenRect, pageLayout); } /** @@ -276,7 +274,8 @@ namespace Fungus */ public static void SetPageMiddle() { - SetPageMiddle(0.5f, 0.5f, Page.Layout.FitToMiddle); + Vector2 pageScale = Game.GetInstance().defaultPageScale; + SetPageMiddle(pageScale.x, pageScale.y, Page.Layout.FitToMiddle); } /** @@ -288,14 +287,8 @@ namespace Fungus */ 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); + Page.ScreenRect screenRect = Page.CalcScreenRect(new Vector2(scaleX, scaleY), Page.PagePosition.Bottom); + SetPageRect(screenRect, pageLayout); } /** @@ -304,7 +297,8 @@ namespace Fungus */ public static void SetPageBottom() { - SetPageBottom(0.75f, 0.25f, Page.Layout.FullSize); + Vector2 pageScale = Game.GetInstance().defaultPageScale; + SetPageBottom(pageScale.x, pageScale.y, Page.Layout.FullSize); } /** @@ -321,10 +315,10 @@ namespace Fungus /** * Obsolete! Use Header() instead. */ - [System.Obsolete("use Header() instead")] + [System.Obsolete("use SetHeader() instead")] public static void Title(string titleText) { - Header(titleText); + SetHeader(titleText); } /** @@ -333,7 +327,7 @@ namespace Fungus * 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. */ - public static void Header(string headerText) + public static void SetHeader(string headerText) { CommandQueue commandQueue = Game.GetInstance().commandQueue; commandQueue.AddCommand(new Command.SetHeader(headerText)); @@ -345,7 +339,7 @@ namespace Fungus * 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. */ - public static void Footer(string footerText) + public static void SetFooter(string footerText) { CommandQueue commandQueue = Game.GetInstance().commandQueue; commandQueue.AddCommand(new Command.SetFooter(footerText)); diff --git a/Assets/Fungus/Scripts/Page.cs b/Assets/Fungus/Scripts/Page.cs index d27dbdf4..ebd9d187 100644 --- a/Assets/Fungus/Scripts/Page.cs +++ b/Assets/Fungus/Scripts/Page.cs @@ -14,7 +14,30 @@ namespace Fungus [ExecuteInEditMode] public class Page : MonoBehaviour { - /// Page alignment options + /// 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. @@ -27,28 +50,35 @@ namespace Fungus FitToBottom } - /// Page position within bounds when display height is less than bounds height. + /// Controls layout of content within Page rect. public Layout layout = Layout.FullSize; - string headerText = ""; - string footerText = ""; - - string displayedStoryText = ""; - string originalStoryText = ""; - - Action deferredAction; - Action continueAction; - + /// 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 = ""; + + Action deferredAction; + Action continueAction; + class Option { public string optionText; @@ -65,27 +95,86 @@ namespace Fungus float quickContinueTimer; - Rect pageRect; // Screen space rect for Page in pixels + /** + * 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; + } /** - * Set the screen rect in normalized screen space coords. - * The origin is at the top left of the screen. + * Calculates a screen rect in normalized screen space coordinates in one of the 'standard' Page positions (top, middle, bottom). */ - public void SetPageRect(float x1, float y1, float x2, float y2) + public static ScreenRect CalcScreenRect(Vector2 pageScale, PagePosition pagePosition) { - pageRect.xMin = Screen.width * x1; - pageRect.yMin = Screen.height * y1; - pageRect.xMax = Screen.width * x2; - pageRect.yMax = Screen.height * y2; + float width = Mathf.Clamp01(pageScale.x); + float height = Mathf.Clamp01(pageScale.y); - // 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); + 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; } - public virtual void Update() + /** + * 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) { @@ -227,7 +316,28 @@ namespace Fungus GUIStyle optionStyle = pageStyle.GetScaledOptionStyle(); GUIStyle optionAlternateStyle = pageStyle.GetScaledOptionAlternateStyle(); - Rect outerRect = pageRect; + 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 @@ -238,7 +348,7 @@ namespace Fungus float contentHeight = headerHeight + footerHeight + storyHeight + optionsHeight; // Adjust outer rect position based on alignment settings - switch (layout) + switch (tempLayout) { case Layout.FullSize: outerRect.height = Mathf.Max(outerRect.height, contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom)); @@ -246,15 +356,15 @@ namespace Fungus break; case Layout.FitToTop: outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom); - outerRect.y = pageRect.yMin; + outerRect.y = originalRect.yMin; break; case Layout.FitToMiddle: outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom); - outerRect.y = pageRect.center.y - outerRect.height / 2; + outerRect.y = originalRect.center.y - outerRect.height / 2; break; case Layout.FitToBottom: outerRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom); - outerRect.y = pageRect.yMax - outerRect.height; + outerRect.y = originalRect.yMax - outerRect.height; break; } @@ -263,9 +373,9 @@ namespace Fungus // Draw box Rect boxRect = outerRect; boxRect.height = contentHeight + (boxStyle.padding.top + boxStyle.padding.bottom); - if (layout == Layout.FullSize) + if (tempLayout == Layout.FullSize) { - boxRect.height = Mathf.Max(boxRect.height, pageRect.height); + boxRect.height = Mathf.Max(boxRect.height, originalRect.height); } GUI.Box(boxRect, "", boxStyle); diff --git a/Assets/Fungus/Scripts/PageBounds.cs b/Assets/Fungus/Scripts/PageBounds.cs index 2c651fa5..41802bba 100644 --- a/Assets/Fungus/Scripts/PageBounds.cs +++ b/Assets/Fungus/Scripts/PageBounds.cs @@ -31,13 +31,14 @@ namespace Fungus Vector2 tl = Camera.main.WorldToScreenPoint(topLeft); Vector2 br = Camera.main.WorldToScreenPoint(bottomRight); - float x1 = (tl.x / Screen.width); - float y1 = 1f - (tl.y / Screen.height); - float x2 = (br.x / Screen.width); - float y2 = 1f - (br.y / Screen.height); + 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.SetPageRect(x1, y1, x2, y2); + page.pageRect = Page.CalcPageRect(screenRect); page.layout = layout; } } diff --git a/Assets/Fungus/Scripts/Room.cs b/Assets/Fungus/Scripts/Room.cs index 573a834e..e73d7db0 100644 --- a/Assets/Fungus/Scripts/Room.cs +++ b/Assets/Fungus/Scripts/Room.cs @@ -139,9 +139,8 @@ namespace Fungus button.SetAlpha(0f); } - // Default to bottom aligned Page rect - game.activePage.SetPageRect(0.125f, 0.75f, 0.875f, 1f); - game.activePage.layout = Page.Layout.FullSize; + // Reset Page layout to default setting specified in Game object + game.activePage.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. diff --git a/Assets/FungusExample/Scenes/Example.unity b/Assets/FungusExample/Scenes/Example.unity index c1d0782e..f92e8654 100644 Binary files a/Assets/FungusExample/Scenes/Example.unity and b/Assets/FungusExample/Scenes/Example.unity differ diff --git a/Assets/FungusExample/Scripts/MenuRoom.cs b/Assets/FungusExample/Scripts/MenuRoom.cs index fd87515d..acc67937 100644 --- a/Assets/FungusExample/Scripts/MenuRoom.cs +++ b/Assets/FungusExample/Scripts/MenuRoom.cs @@ -13,10 +13,12 @@ public class MenuRoom : Room void OnEnter() { + SetPageMiddle(); + AddOption("Writing a story with Pages", MoveToWritingRoom); AddOption("Controlling the camera with Views", MoveToViewRoom); AddOption("Sprites and Animations", MoveToSpriteRoom); - AddOption("Parallax scrolling effects", MoveToParallaxRoom); + AddOption("Manual pan and parallax", MoveToParallaxRoom); AddOption("Using Buttons", MoveToButtonsRoom); AddOption("Playing music and sound effects", MoveToAudioRoom); Choose("Choose an example"); diff --git a/Assets/FungusExample/Scripts/PageRoom.cs b/Assets/FungusExample/Scripts/PageRoom.cs index 65a17fbf..e0a53f9c 100644 --- a/Assets/FungusExample/Scripts/PageRoom.cs +++ b/Assets/FungusExample/Scripts/PageRoom.cs @@ -17,24 +17,22 @@ public class PageRoom : Room void OnEnter() { // Sets the header text on the page - Header("The Mushroom"); + SetHeader("The Mushroom"); // Each Say() command writes one line of text, followed by a continue button - SetPageTop(); Say("One day in the forest, a mushroom grew."); - - SetPageMiddle(); Say("What am I doing here he wondered?"); - SetPageBottom(); + SetPageTop(); Say("I think I will wait for a while and see if something happens."); // Wait for a few seconds Wait(3); // Set the header text to the empty string to remove the page title - Header(""); + SetHeader(""); + SetPageBottom(); Say("..."); Say("Hmmm. Nothing seems to be happening."); @@ -81,7 +79,7 @@ public class PageRoom : Room // Set the default style with background box texture SetPageStyle(defaultStyle); - // Sets a game flag which we check above in GoToSleep + // Sets a global value flag which we check above in GoToSleep SetValue("spawned"); AddOption("So tired. I sleep now.", GoToSleep); diff --git a/Assets/FungusExample/Scripts/ParallaxRoom.cs b/Assets/FungusExample/Scripts/ParallaxRoom.cs index b166c972..b27a2df6 100644 --- a/Assets/FungusExample/Scripts/ParallaxRoom.cs +++ b/Assets/FungusExample/Scripts/ParallaxRoom.cs @@ -8,21 +8,31 @@ using Fungus; public class ParallaxRoom : Room { - public View mainView; - public View zoomView; + public View viewA; + public View viewB; + + public Button menuButton; public Room menuRoom; void OnEnter() { - SetView(mainView); + SetView(viewA); Say("Let's zoom in!"); - PanToView(zoomView, 2); + PanToView(viewB, 2); Say("Oooh! Nice parallax!"); - PanToView(mainView, 2); - Say("Mmmm... purdy!"); + PanToView(viewA, 2); + Say("Now you have a go!"); + Say("Swipe the screen to pan around."); + + ShowButton(menuButton, OnHomeButtonClicked); + StartManualPan(viewA, viewB, 0f); + } + + void OnHomeButtonClicked() + { MoveToRoom(menuRoom); } -} +} \ No newline at end of file