diff --git a/Assets/Example.meta b/Assets/Example.meta new file mode 100644 index 00000000..53478fb4 --- /dev/null +++ b/Assets/Example.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 19f5178ee50b34817a7cdafbda2ce166 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Example/Scenes.meta b/Assets/Example/Scenes.meta new file mode 100644 index 00000000..0a120a12 --- /dev/null +++ b/Assets/Example/Scenes.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 695c2b87de46948719d8d25616c55ad0 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Example/Scenes/Example.unity b/Assets/Example/Scenes/Example.unity new file mode 100644 index 00000000..3e20077f Binary files /dev/null and b/Assets/Example/Scenes/Example.unity differ diff --git a/Assets/Example/Scenes/Example.unity.meta b/Assets/Example/Scenes/Example.unity.meta new file mode 100644 index 00000000..a293dfc5 --- /dev/null +++ b/Assets/Example/Scenes/Example.unity.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 5a6b6f6f9c1684498b25f6f41ef56995 +DefaultImporter: + userData: diff --git a/Assets/Example/Scripts.meta b/Assets/Example/Scripts.meta new file mode 100644 index 00000000..79acb382 --- /dev/null +++ b/Assets/Example/Scripts.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 48785157e076a44009fad585c2ab2735 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Example/Scripts/MenuRoom.cs b/Assets/Example/Scripts/MenuRoom.cs new file mode 100644 index 00000000..5023ac59 --- /dev/null +++ b/Assets/Example/Scripts/MenuRoom.cs @@ -0,0 +1,27 @@ +using UnityEngine; +using System.Collections; +using Fungus; + +public class MenuRoom : Room +{ + public Room writingRoom; + public Room viewRoom; + + void OnEnter() + { + AddOption("1. Writing a story with Pages", MoveToWriting); + AddOption("2. Controlling the camera with Views", MoveToViews); + Choose("Choose an example"); + } + + void MoveToWriting() + { + MoveToRoom(writingRoom); + } + + void MoveToViews() + { + MoveToRoom(viewRoom); + } + +} diff --git a/Assets/Example/Scripts/MenuRoom.cs.meta b/Assets/Example/Scripts/MenuRoom.cs.meta new file mode 100644 index 00000000..f8b9e3e8 --- /dev/null +++ b/Assets/Example/Scripts/MenuRoom.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 8f3838e29c03e4ebf9a232fb00d4dffb +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Example/Scripts/ViewRoom.cs b/Assets/Example/Scripts/ViewRoom.cs new file mode 100644 index 00000000..10ce59c4 --- /dev/null +++ b/Assets/Example/Scripts/ViewRoom.cs @@ -0,0 +1,44 @@ +using UnityEngine; +using System.Collections; +using Fungus; + +public class ViewRoom : Room +{ + public Room menuRoom; + + public View mainView; + public View logoView; + public View toadstoolView; + + void OnEnter() + { + SetView(mainView); + + AddOption("Lets look at the logo", LookLogo); + AddOption("That's a nice toadstool over there", LookToadstool); + AddOption("Back to menu", MoveToMenu); + + Choose("Wanna move the camera?"); + } + + void MoveToMenu() + { + MoveToRoom(menuRoom); + } + + void LookLogo() + { + PanToView(logoView, 2f); + Wait(2); + PanToView(mainView, 2f); + Call(OnEnter); + } + + void LookToadstool() + { + FadeToView(toadstoolView, 2f); + Say("Now that is a pretty mushroom"); + Say("Hey - let's go look at that logo"); + Call(LookLogo); + } +} diff --git a/Assets/Example/Scripts/ViewRoom.cs.meta b/Assets/Example/Scripts/ViewRoom.cs.meta new file mode 100644 index 00000000..1b368148 --- /dev/null +++ b/Assets/Example/Scripts/ViewRoom.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b17df452ec8b34e1ea67b7ff2c46579b +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Example/Scripts/WritingRoom.cs b/Assets/Example/Scripts/WritingRoom.cs new file mode 100644 index 00000000..e87954ea --- /dev/null +++ b/Assets/Example/Scripts/WritingRoom.cs @@ -0,0 +1,77 @@ +using UnityEngine; +using System.Collections; +using Fungus; + +public class WritingRoom : Room +{ + // This is a reference to the menu room so we can transition back to the menu using MoveToRoom() + public Room menuRoom; + + // 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. + void OnEnter() + { + // Sets the title text on the page + Title("The Mushroom"); + + // Each Say() command writes one line of text, followed by a continue button + Say("One day a mushroom grew in the forest"); + Say("What am I doing here he wondered?"); + Say("I think I will wait for a while and see if something happens."); + + // Wait for a few seconds + Wait(3); + + // Set the title text to the empty string to remove the page title + Title(""); + + Say("..."); + Say("Hmmm. Nothing seems to be happening."); + + // Add a couple of user options + // The first parameter is the option text + // The second parameter is the method to call if the user selects the option + // You can add as many options as you like + AddOption("Go to sleep", GoToSleep); + AddOption("Produce spores", ProduceSpores); + + // Display all the previously added options, with a text prompt + Choose("Whatever will I do?"); + } + + void GoToSleep() + { + // Check to see if a game flag has been set + // You can also use GetCounter & GetInventory to get other types of values. + if (GetFlag("spawned")) + { + Say("I am feeling rather sleepy after all that spawning!"); + Say("Yawn! Good night world!"); + + // Leave the current room and enter the menu room + MoveToRoom(menuRoom); + } + else + { + Say("I'm not feeling tired. I'm a fresh mushroom!"); + Say("Maybe I should spawn some spores?"); + + // Use Call() to call another method whenever you want. + Call(ProduceSpores); + } + } + + void ProduceSpores() + { + Say("Yeah! I feel like doing some sporing!"); + Say("Wow - look at all these spores! COOL!"); + + // Sets a game flag which we check above in GoToSleep + SetFlag("spawned", true); + + AddOption("So tired. I sleep now.", GoToSleep); + AddOption("No way! More spores!", ProduceSpores); + + Choose("What will I do now?"); + } +} diff --git a/Assets/Example/Scripts/WritingRoom.cs.meta b/Assets/Example/Scripts/WritingRoom.cs.meta new file mode 100644 index 00000000..2bd02b37 --- /dev/null +++ b/Assets/Example/Scripts/WritingRoom.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 79047217eeb604324b501728ce6c43b2 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus.meta b/Assets/Fungus.meta new file mode 100644 index 00000000..b8729a60 --- /dev/null +++ b/Assets/Fungus.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 72452d0189a95436fb93c2ec54d83801 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Fungus/Editor.meta b/Assets/Fungus/Editor.meta new file mode 100644 index 00000000..324319b9 --- /dev/null +++ b/Assets/Fungus/Editor.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: b7cb2aa1c114f44b89b82bc527e85bab +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Fungus/Editor/GameEditor.cs b/Assets/Fungus/Editor/GameEditor.cs new file mode 100644 index 00000000..99a92ab9 --- /dev/null +++ b/Assets/Fungus/Editor/GameEditor.cs @@ -0,0 +1,44 @@ +using UnityEditor; +using UnityEngine; +using System.Collections; + +namespace Fungus +{ + [CustomEditor (typeof(Game))] + public class GameEditor : Editor + { + private void OnSceneGUI() + { + GameEditor.DrawRoomNames(); + } + + static public void DrawRoomNames() + { + Handles.color = Color.white; + Handles.BeginGUI(); + + // Show labels for each room + Room[] rooms = GameObject.FindObjectsOfType(); + + foreach (Room room in rooms) + { + if (!room.renderer) + { + continue; + } + + Bounds bounds = room.renderer.bounds; + Vector3 pos = new Vector3(bounds.min.x, bounds.max.y, 0); + + GUIStyle style = new GUIStyle(GUI.skin.label); + style.normal.textColor = new Color(1,1,1); + style.fontSize /= 2; + Rect boxRect = HandleUtility.WorldPointToSizedRect(pos, new GUIContent(room.name), style); + boxRect.y -= boxRect.height * 1.5f; + GUI.Box(boxRect, room.name, style); + } + + Handles.EndGUI(); + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Editor/GameEditor.cs.meta b/Assets/Fungus/Editor/GameEditor.cs.meta new file mode 100644 index 00000000..7267527f --- /dev/null +++ b/Assets/Fungus/Editor/GameEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 5464e5745a4da462795a6f6f5b112962 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Editor/PageEditor.cs b/Assets/Fungus/Editor/PageEditor.cs new file mode 100644 index 00000000..5287d4ca --- /dev/null +++ b/Assets/Fungus/Editor/PageEditor.cs @@ -0,0 +1,98 @@ +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(); + 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; + } + } +} diff --git a/Assets/Fungus/Editor/PageEditor.cs.meta b/Assets/Fungus/Editor/PageEditor.cs.meta new file mode 100644 index 00000000..49d26ab2 --- /dev/null +++ b/Assets/Fungus/Editor/PageEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: dce33924cf6804b2c94d17784a6037d1 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Editor/RoomEditor.cs b/Assets/Fungus/Editor/RoomEditor.cs new file mode 100644 index 00000000..73b3798f --- /dev/null +++ b/Assets/Fungus/Editor/RoomEditor.cs @@ -0,0 +1,16 @@ +using UnityEditor; +using UnityEngine; +using System.Collections; + +namespace Fungus +{ + [CustomEditor (typeof(Room))] + [CanEditMultipleObjects] + public class RoomEditor : Editor + { + private void OnSceneGUI() + { + GameEditor.DrawRoomNames(); + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Editor/RoomEditor.cs.meta b/Assets/Fungus/Editor/RoomEditor.cs.meta new file mode 100644 index 00000000..c343ab3b --- /dev/null +++ b/Assets/Fungus/Editor/RoomEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 0314fe408508a4b25afa76f65378a427 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Editor/ViewEditor.cs b/Assets/Fungus/Editor/ViewEditor.cs new file mode 100644 index 00000000..cd2672f7 --- /dev/null +++ b/Assets/Fungus/Editor/ViewEditor.cs @@ -0,0 +1,90 @@ +using UnityEditor; +using UnityEngine; +using System.Collections; +using System.Collections.Generic; +using Fungus; + +[CanEditMultipleObjects] +[CustomEditor (typeof(View))] +public class ViewEditor : Editor +{ + void OnSceneGUI () + { + View t = target as View; + if (t.enabled) + { + EditViewBounds(); + } + + if (GUI.changed) + { + EditorUtility.SetDirty(target); + } + } + + void EditViewBounds() + { + View t = target as View; + + DrawView(t); + + Vector3 pos = t.transform.position; + float viewSize = t.viewSize; + + Vector3 newViewPos = Handles.PositionHandle(pos, Quaternion.identity); + + t.transform.position = newViewPos; + + Vector3[] handles = new Vector3[2]; + handles[0] = pos + new Vector3(0, -viewSize, 0); + handles[1] = pos + new Vector3(0, viewSize, 0); + + for (int i = 0; i < 2; ++i) + { + Vector3 newPos = Handles.FreeMoveHandle(handles[i], + Quaternion.identity, + HandleUtility.GetHandleSize(pos) * 0.1f, + Vector3.zero, + Handles.CubeCap); + if (newPos != handles[i]) + { + t.viewSize = Mathf.Abs(newPos.y - pos.y); + break; + } + } + } + + public static void DrawView(View view) + { + Vector3 pos = view.transform.position; + float viewSize = view.viewSize; + + // Draw 2:1 aspect ratio box + { + float height = viewSize; + float width = height * (2f / 1f); + + Vector3[] verts = new Vector3[4]; + verts[0] = pos + new Vector3(-width, -height, 0); + verts[1] = pos + new Vector3(-width, height, 0); + verts[2] = pos + new Vector3(width, height, 0); + verts[3] = pos + new Vector3(width, -height, 0); + + Handles.DrawSolidRectangleWithOutline(verts, new Color(1,1,1,0f), new Color(0,1,0,0.25f) ); + } + + // Draw 4:3 aspect ratio box + { + float height = viewSize; + float width = height * (4f / 3f); + + Vector3[] verts = new Vector3[4]; + verts[0] = pos + new Vector3(-width, -height, 0); + verts[1] = pos + new Vector3(-width, height, 0); + verts[2] = pos + new Vector3(width, height, 0); + verts[3] = pos + new Vector3(width, -height, 0); + + Handles.DrawSolidRectangleWithOutline(verts, new Color(1,1,1,0f), new Color(0,1,0,1) ); + } + } +} diff --git a/Assets/Fungus/Editor/ViewEditor.cs.meta b/Assets/Fungus/Editor/ViewEditor.cs.meta new file mode 100644 index 00000000..b3d7b040 --- /dev/null +++ b/Assets/Fungus/Editor/ViewEditor.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 66d37e0778b8a4bf9a5e498dc37467cf +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Fonts.meta b/Assets/Fungus/Fonts.meta new file mode 100644 index 00000000..c5ec497b --- /dev/null +++ b/Assets/Fungus/Fonts.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: 9baefe3bcf2e94f17b5feaeb1c07e77e +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Fungus/Fonts/open-sans.meta b/Assets/Fungus/Fonts/open-sans.meta new file mode 100644 index 00000000..f547af41 --- /dev/null +++ b/Assets/Fungus/Fonts/open-sans.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: eb92cb8aa27394dbd87cb00161e162e8 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Fungus/Fonts/open-sans/Apache License.txt b/Assets/Fungus/Fonts/open-sans/Apache License.txt new file mode 100755 index 00000000..989e2c59 --- /dev/null +++ b/Assets/Fungus/Fonts/open-sans/Apache License.txt @@ -0,0 +1,201 @@ +Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. \ No newline at end of file diff --git a/Assets/Fungus/Fonts/open-sans/Apache License.txt.meta b/Assets/Fungus/Fonts/open-sans/Apache License.txt.meta new file mode 100644 index 00000000..d2855e10 --- /dev/null +++ b/Assets/Fungus/Fonts/open-sans/Apache License.txt.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 3e4f39b0883694bc1b7f6f8d0117fd68 +TextScriptImporter: + userData: diff --git a/Assets/Fungus/Fonts/open-sans/OpenSans-Regular.ttf b/Assets/Fungus/Fonts/open-sans/OpenSans-Regular.ttf new file mode 100755 index 00000000..db433349 Binary files /dev/null and b/Assets/Fungus/Fonts/open-sans/OpenSans-Regular.ttf differ diff --git a/Assets/Fungus/Fonts/open-sans/OpenSans-Regular.ttf.meta b/Assets/Fungus/Fonts/open-sans/OpenSans-Regular.ttf.meta new file mode 100644 index 00000000..ecba2ee3 --- /dev/null +++ b/Assets/Fungus/Fonts/open-sans/OpenSans-Regular.ttf.meta @@ -0,0 +1,14 @@ +fileFormatVersion: 2 +guid: a19d04f08ff4046d891ffab76afcc3b1 +TrueTypeFontImporter: + serializedVersion: 2 + fontSize: 16 + forceTextureCase: -2 + characterSpacing: 1 + characterPadding: 0 + includeFontData: 1 + use2xBehaviour: 0 + fontNames: [] + customCharacters: + fontRenderingMode: 0 + userData: diff --git a/Assets/Fungus/Prefabs.meta b/Assets/Fungus/Prefabs.meta new file mode 100644 index 00000000..051de10a --- /dev/null +++ b/Assets/Fungus/Prefabs.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: dd60c6b3baeb0475db2ac8ac965401c4 +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Fungus/Prefabs/Game.prefab b/Assets/Fungus/Prefabs/Game.prefab new file mode 100644 index 00000000..b02be275 Binary files /dev/null and b/Assets/Fungus/Prefabs/Game.prefab differ diff --git a/Assets/Fungus/Prefabs/Game.prefab.meta b/Assets/Fungus/Prefabs/Game.prefab.meta new file mode 100644 index 00000000..5938e7f9 --- /dev/null +++ b/Assets/Fungus/Prefabs/Game.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: f6e5e4b8124614271beca06a1d6c67c2 +NativeFormatImporter: + userData: diff --git a/Assets/Fungus/Prefabs/Page.prefab b/Assets/Fungus/Prefabs/Page.prefab new file mode 100644 index 00000000..4a67bee8 Binary files /dev/null and b/Assets/Fungus/Prefabs/Page.prefab differ diff --git a/Assets/Fungus/Prefabs/Page.prefab.meta b/Assets/Fungus/Prefabs/Page.prefab.meta new file mode 100644 index 00000000..e3e66556 --- /dev/null +++ b/Assets/Fungus/Prefabs/Page.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: ec557b5a76ab94961964394b8511fc9b +NativeFormatImporter: + userData: diff --git a/Assets/Fungus/Prefabs/Room.prefab b/Assets/Fungus/Prefabs/Room.prefab new file mode 100644 index 00000000..f58d8ab6 Binary files /dev/null and b/Assets/Fungus/Prefabs/Room.prefab differ diff --git a/Assets/Fungus/Prefabs/Room.prefab.meta b/Assets/Fungus/Prefabs/Room.prefab.meta new file mode 100644 index 00000000..7fa08f64 --- /dev/null +++ b/Assets/Fungus/Prefabs/Room.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: 6e8f8f59ed030466b99184bf0fb44954 +NativeFormatImporter: + userData: diff --git a/Assets/Fungus/Prefabs/View.prefab b/Assets/Fungus/Prefabs/View.prefab new file mode 100644 index 00000000..3feae427 Binary files /dev/null and b/Assets/Fungus/Prefabs/View.prefab differ diff --git a/Assets/Fungus/Prefabs/View.prefab.meta b/Assets/Fungus/Prefabs/View.prefab.meta new file mode 100644 index 00000000..3bef4078 --- /dev/null +++ b/Assets/Fungus/Prefabs/View.prefab.meta @@ -0,0 +1,4 @@ +fileFormatVersion: 2 +guid: e0d427add844a4d9faf970a3afa07583 +NativeFormatImporter: + userData: diff --git a/Assets/Fungus/Scripts.meta b/Assets/Fungus/Scripts.meta new file mode 100644 index 00000000..6d227248 --- /dev/null +++ b/Assets/Fungus/Scripts.meta @@ -0,0 +1,5 @@ +fileFormatVersion: 2 +guid: f9ded1304c85a430bbc6c65f025cf4dc +folderAsset: yes +DefaultImporter: + userData: diff --git a/Assets/Fungus/Scripts/Button.cs b/Assets/Fungus/Scripts/Button.cs new file mode 100644 index 00000000..53349f19 --- /dev/null +++ b/Assets/Fungus/Scripts/Button.cs @@ -0,0 +1,48 @@ +using UnityEngine; +using System.Collections; + +namespace Fungus +{ + // Simple button handler class. + // When the user taps on the button, the named method is called on ancestor game objects (if it exists). + [RequireComponent (typeof (SpriteController))] + [RequireComponent (typeof (Collider2D))] + public class Button : MonoBehaviour + { + public string methodName; + + public bool autoDisable = true; + + SpriteController spriteController; + + void Start() + { + spriteController = GetComponent(); + } + + void OnMouseUpAsButton() + { + if (methodName == "") + { + return; + } + + // Ignore button press if button is not fully visible + if (!spriteController.isShown) + { + return; + } + + Game game = Game.GetInstance(); + + game.ResetCommandQueue(); + gameObject.SendMessageUpwards(methodName, SendMessageOptions.RequireReceiver); + game.ExecuteCommandQueue(); + + if (autoDisable) + { + gameObject.SetActive(false); + } + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Button.cs.meta b/Assets/Fungus/Scripts/Button.cs.meta new file mode 100644 index 00000000..372a2258 --- /dev/null +++ b/Assets/Fungus/Scripts/Button.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 1fe346be2e3e54b0b8ec94f09bb152a4 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Scripts/CameraController.cs b/Assets/Fungus/Scripts/CameraController.cs new file mode 100644 index 00000000..04460e3d --- /dev/null +++ b/Assets/Fungus/Scripts/CameraController.cs @@ -0,0 +1,199 @@ +using UnityEngine; +using System; +using System.Collections; +using Fungus; + +namespace Fungus +{ + // Controller for main camera. + // Supports several types of camera transition including snap, pan & fade. + public class CameraController : MonoBehaviour + { + Action onArriveAction; + + float moveDuration; + float moveTimer; + float startSize; + float endSize; + Vector3 startPos; + Vector3 endPos; + + Camera mainCamera; + + void Start() + { + GameObject cameraObject = GameObject.FindGameObjectWithTag("MainCamera"); + if (cameraObject == null) + { + Debug.LogError("Failed to find game object with tag 'MainCamera'"); + return; + } + mainCamera = cameraObject.GetComponent(); + if (mainCamera == null) + { + Debug.LogError("Failed to find camera component"); + return; + } + + Reset(); + } + + public Texture2D fadeTexture; + + public float fadeAlpha = 1f; + + void OnGUI() + { + int drawDepth = -1000; + + if (fadeAlpha < 1f) + { + // 1 = scene fully visible + // 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), fadeTexture); + } + } + + public void Fade(float targetAlpha, float fadeDuration, Action fadeAction) + { + StartCoroutine(FadeInternal(targetAlpha, fadeDuration, fadeAction)); + } + + public void FadeToView(View view, float fadeDuration, Action fadeAction) + { + // Fade out + Fade(0f, fadeDuration / 2f, delegate { + + // Snap to new view + PanToView(view, 0f, null); + + // Fade in + Fade(1f, fadeDuration / 2f, delegate { + if (fadeAction != null) + { + fadeAction(); + } + }); + }); + } + + IEnumerator FadeInternal(float targetAlpha, float fadeDuration, Action fadeAction) + { + float startAlpha = fadeAlpha; + float timer = 0; + + while (timer < fadeDuration) + { + float t = timer / fadeDuration; + timer += Time.deltaTime; + + t = Mathf.Clamp01(t); + + fadeAlpha = Mathf.Lerp(startAlpha, targetAlpha, t); + yield return null; + } + + fadeAlpha = targetAlpha; + + if (fadeAction != null) + { + fadeAction(); + } + } + + void Reset() + { + moveDuration = 0; + moveTimer = 0; + startSize = 0; + endSize = 0; + startPos = Vector3.zero; + endPos = Vector3.zero; + onArriveAction = null; + } + + public void SnapToView(View view) + { + PanToView(view, 0, null); + } + + public void PanToView(View view, float duration, Action arriveAction) + { + Reset(); + + if (duration == 0f) + { + // Move immediately + mainCamera.orthographicSize = view.viewSize; + mainCamera.transform.position = view.transform.position; + SetCameraZ(); + if (arriveAction != null) + { + arriveAction(); + } + } + else + { + moveDuration = duration; + onArriveAction = arriveAction; + moveTimer = 0; + startSize = mainCamera.orthographicSize; + endSize = view.viewSize; + startPos = mainCamera.transform.position; + endPos = view.transform.position; + } + } + + // Position camera so sprite is centered and fills the screen + public void CenterOnSprite(SpriteRenderer spriteRenderer) + { + Sprite sprite = spriteRenderer.sprite; + Vector3 extents = sprite.bounds.extents; + float localScaleY = spriteRenderer.transform.localScale.y; + mainCamera.orthographicSize = extents.y * localScaleY; + + Vector3 pos = spriteRenderer.transform.position; + mainCamera.transform.position = new Vector3(pos.x, pos.y, 0); + SetCameraZ(); + } + + void Update () + { + if (moveDuration == 0f) + { + return; + } + + moveTimer += Time.deltaTime; + + bool arrived = false; + if (moveTimer > moveDuration) + { + moveTimer = moveDuration; + arrived = true; + } + + float t = moveTimer / moveDuration; + + mainCamera.orthographicSize = Mathf.Lerp(startSize, endSize, Mathf.SmoothStep(0f, 1f, t)); + mainCamera.transform.position = Vector3.Lerp(startPos, endPos, Mathf.SmoothStep(0f, 1f, t)); + SetCameraZ(); + + if (arrived) + { + if (onArriveAction != null) + { + onArriveAction(); + } + Reset(); + } + } + + void SetCameraZ() + { + mainCamera.transform.position = new Vector3(mainCamera.transform.position.x, mainCamera.transform.position.y, -10f); + } + } +} diff --git a/Assets/Fungus/Scripts/CameraController.cs.meta b/Assets/Fungus/Scripts/CameraController.cs.meta new file mode 100644 index 00000000..319781b7 --- /dev/null +++ b/Assets/Fungus/Scripts/CameraController.cs.meta @@ -0,0 +1,9 @@ +fileFormatVersion: 2 +guid: efb7bb24722d4469bbd789bd2e01db19 +MonoImporter: + serializedVersion: 2 + defaultReferences: + - fadeTexture: {fileID: 2800000, guid: f6c7b1f3a78a24703b70c746d8b9c768, type: 3} + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Scripts/CommandQueue.cs b/Assets/Fungus/Scripts/CommandQueue.cs new file mode 100644 index 00000000..a32bc8eb --- /dev/null +++ b/Assets/Fungus/Scripts/CommandQueue.cs @@ -0,0 +1,54 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Fungus +{ + // Manages a sequential list of commands. + // When a command completes, the next command is popped from the queue and exectuted. + public class CommandQueue : MonoBehaviour + { + [HideInInspector] + public CameraController cameraController; + + public void Start() + { + cameraController = Game.GetInstance().GetComponent(); + } + + // Base class for commands used with the CommandQueue + public abstract class Command + { + public abstract void Execute(CommandQueue commandQueue, Action onComplete); + } + + List commandList = new List(); + + public void AddCommand(Command command) + { + commandList.Add(command); + } + + public void Reset() + { + StopAllCoroutines(); + commandList.Clear(); + } + + public void Execute() + { + if (commandList.Count == 0) + { + return; + } + + Command command = commandList[0]; + + command.Execute(this, delegate { + commandList.RemoveAt(0); + Execute(); + }); + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/CommandQueue.cs.meta b/Assets/Fungus/Scripts/CommandQueue.cs.meta new file mode 100644 index 00000000..dff861e3 --- /dev/null +++ b/Assets/Fungus/Scripts/CommandQueue.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 6727650fe2095478c9d180eac7ba0d2f +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Scripts/Commands.cs b/Assets/Fungus/Scripts/Commands.cs new file mode 100644 index 00000000..c89bd8ad --- /dev/null +++ b/Assets/Fungus/Scripts/Commands.cs @@ -0,0 +1,463 @@ +using UnityEngine; +using System; +using System.Collections; +using System.Collections.Generic; + +namespace Fungus +{ + // 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(); + } + 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) + { + commandQueue.StartCoroutine(WaitCoroutine(duration, onComplete)); + } + + IEnumerator WaitCoroutine(float duration, Action onComplete) + { + yield return new WaitForSeconds(duration); + if (onComplete != null) + { + 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) + { + commandQueue.cameraController.SnapToView(view); + Game.GetInstance().activeView = view; + + // Set the first page component found (if any) as the active page + Page page = view.gameObject.GetComponentInChildren(); + 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 title text displayed at the top of the active page + public class TitleCommand : CommandQueue.Command + { + string titleText; + + public TitleCommand(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.SetTitle(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.GetInstance().MoveToRoom(room); + + // MoveToRoom always resets the command queue so no need to call onComplete + } + } + + // Sets a global boolean flag value + public class SetFlagCommand : CommandQueue.Command + { + string key; + bool value; + + public SetFlagCommand(string _key, bool _value) + { + key = _key; + value = _value; + } + + public override void Execute(CommandQueue commandQueue, Action onComplete) + { + Game.GetInstance().SetFlag(key, value); + if (onComplete != null) + { + onComplete(); + } + } + } + + // Sets a global integer counter value + public class SetCounterCommand : CommandQueue.Command + { + string key; + int value; + + public SetCounterCommand(string _key, int _value) + { + key = _key; + value = _value; + } + + public override void Execute(CommandQueue commandQueue, Action onComplete) + { + Game.GetInstance().SetCounter(key, value); + if (onComplete != null) + { + onComplete(); + } + } + } + + // Sets a global inventory count value + public class SetInventoryCommand : CommandQueue.Command + { + string key; + int value; + + public SetInventoryCommand(string _key, int _value) + { + key = _key; + value = _value; + } + + public override void Execute(CommandQueue commandQueue, Action onComplete) + { + Game.GetInstance().SetInventory(key, value); + if (onComplete != null) + { + onComplete(); + } + } + } + + // Fades a sprite to a given alpha value over a period of time + public class FadeSpriteCommand : CommandQueue.Command + { + SpriteController spriteController; + float targetAlpha; + float fadeDuration; + Vector2 slideOffset = Vector2.zero; + + public FadeSpriteCommand(SpriteController _spriteController, + float _targetAlpha, + float _fadeDuration, + Vector2 _slideOffset) + { + if (_spriteController == null) + { + Debug.LogError("Sprite controller must not be null."); + return; + } + + spriteController = _spriteController; + targetAlpha = _targetAlpha; + fadeDuration = _fadeDuration; + slideOffset = _slideOffset; + } + + public override void Execute(CommandQueue commandQueue, Action onComplete) + { + spriteController.SlideFade(targetAlpha, fadeDuration, slideOffset); + if (onComplete != null) + { + onComplete(); + } + } + } + + // Plays the named animation on a object with a SpriteController component + public class PlayAnimationCommand : CommandQueue.Command + { + SpriteController spriteController; + string animationName; + + public PlayAnimationCommand(SpriteController _spriteController, + string _animationName) + { + if (_spriteController == null) + { + Debug.LogError("Sprite controller must not be null."); + return; + } + + spriteController = _spriteController; + animationName = _animationName; + } + + public override void Execute(CommandQueue commandQueue, Action onComplete) + { + spriteController.PlayAnimation(animationName); + 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) + { + commandQueue.cameraController.PanToView(view, duration, delegate { + + Game game = Game.GetInstance(); + game.activeView = view; + + // 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(); + 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) + { + commandQueue.cameraController.FadeToView(view, duration, delegate { + + Game game = Game.GetInstance(); + game.activeView = view; + + // 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(); + if (defaultPage) + { + game.activePage = defaultPage; + } + + if (onComplete != null) + { + onComplete(); + } + }); + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Commands.cs.meta b/Assets/Fungus/Scripts/Commands.cs.meta new file mode 100644 index 00000000..9ad6db1a --- /dev/null +++ b/Assets/Fungus/Scripts/Commands.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: b221bfbeec06a47aab4bce90937db5e8 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Scripts/FixedHeightSprite.cs b/Assets/Fungus/Scripts/FixedHeightSprite.cs new file mode 100644 index 00000000..2263d826 --- /dev/null +++ b/Assets/Fungus/Scripts/FixedHeightSprite.cs @@ -0,0 +1,34 @@ +using UnityEngine; +using System.Collections; + +namespace Fungus +{ + // Adjusts the scale of a sprite to fit into a fixed number of vertical world units + // This helps to keep room sprites neatly organised in the editor. + [ExecuteInEditMode] + public class FixedHeightSprite : MonoBehaviour + { + public float height = 2f; + + public void Update() + { + if (!Application.isPlaying) + { + SpriteRenderer spriteRenderer = renderer as SpriteRenderer; + if (!spriteRenderer || !spriteRenderer.sprite) + { + return; + } + + transform.position = new Vector3(transform.position.x, transform.position.y, 0); + transform.rotation = Quaternion.identity; + + float spriteHeight = spriteRenderer.sprite.bounds.extents.y * 2; + + float scale = height / spriteHeight; + + transform.localScale = new Vector3(scale, scale, 1f); + } + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/FixedHeightSprite.cs.meta b/Assets/Fungus/Scripts/FixedHeightSprite.cs.meta new file mode 100644 index 00000000..25ef11a6 --- /dev/null +++ b/Assets/Fungus/Scripts/FixedHeightSprite.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 09bfb0dc7847247568d08205da364d93 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Scripts/Game.cs b/Assets/Fungus/Scripts/Game.cs new file mode 100644 index 00000000..8c341eba --- /dev/null +++ b/Assets/Fungus/Scripts/Game.cs @@ -0,0 +1,178 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace Fungus +{ + // Manages movement between rooms and global game state + [RequireComponent (typeof (CommandQueue))] + [RequireComponent (typeof (CameraController))] + public class Game : MonoBehaviour + { + public bool showLinks = true; + + public Room activeRoom; + + [HideInInspector] + public View activeView; + + [HideInInspector] + public Page activePage; + + public GameState state = new GameState(); + + protected Dictionary stringTable = new Dictionary(); + + private static Game instance; + + CameraController cameraController; + + CommandQueue commandQueue; + + public float fadeDuration = 1f; + + public string continueText = "Continue"; + + public int charactersPerSecond = 60; + + public static Game GetInstance() + { + if (!instance) + { + instance = GameObject.FindObjectOfType(typeof(Game)) as Game; + if (!instance) + { + Debug.LogError("There must be one active Game object in your scene."); + } + } + + return instance; + } + + public virtual void Start() + { + cameraController = GetComponent(); + commandQueue = GetComponent(); + + if (activeRoom == null) + { + // Pick first room found if none is specified + activeRoom = GameObject.FindObjectOfType(typeof(Room)) as Room; + } + + if (activeRoom != null) + { + MoveToRoom(activeRoom); + } + } + + public Room GetCurrentRoom() + { + return GetInstance().activeRoom; + } + + public void ResetCommandQueue() + { + commandQueue.Reset(); + } + + public void ExecuteCommandQueue() + { + commandQueue.Execute(); + } + + public void MoveToRoom(Room room) + { + if (room == null) + { + Debug.LogError("Failed to move to room. Room must not be null."); + return; + } + + // Fade out screen + cameraController.Fade(0f, fadeDuration / 2f, delegate { + + if (activeRoom != null) + { + activeRoom.Leave(); + } + + activeRoom = room; + + activeRoom.Enter(); + + // Fade in screen + cameraController.Fade(1f, fadeDuration / 2f, null); + }); + } + + public void Restart() + { + // TODO: Reload scene + } + + public void ClearFlags() + { + state.ClearFlags(); + } + + public bool GetFlag(string key) + { + return state.GetFlag(key); + } + + public void SetFlag(string key, bool value) + { + state.SetFlag(key, value); + } + + public void ClearCounters() + { + state.ClearCounters(); + } + + public int GetCounter(string key) + { + return state.GetCounter(key); + } + + public void SetCounter(string key, int value) + { + state.SetCounter(key, value); + } + + public void ClearInventory() + { + state.ClearInventory(); + } + + public int GetInventory(string key) + { + return state.GetInventory(key); + } + + public void SetInventory(string key, int value) + { + state.SetInventory(key, value); + } + + public void ClearStringTable() + { + stringTable.Clear(); + } + + public string GetString(string key) + { + if (stringTable.ContainsKey(key)) + { + return stringTable[key]; + } + return ""; + } + + public void SetString(string key, string value) + { + stringTable[key] = value; + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/Game.cs.meta b/Assets/Fungus/Scripts/Game.cs.meta new file mode 100644 index 00000000..be458afc --- /dev/null +++ b/Assets/Fungus/Scripts/Game.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 05e21cf853d714e3ab419e2573b64951 +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Scripts/GameState.cs b/Assets/Fungus/Scripts/GameState.cs new file mode 100644 index 00000000..65aa87b7 --- /dev/null +++ b/Assets/Fungus/Scripts/GameState.cs @@ -0,0 +1,88 @@ +using UnityEngine; +using System.Collections; +using System.Collections.Generic; + +namespace Fungus +{ + // Manages the global state information for the game + // This is implemented as a separate class to support saving and loading game state easily. + public class GameState + { + protected Dictionary flags = new Dictionary(); + + protected Dictionary counters = new Dictionary(); + + protected Dictionary inventory = new Dictionary(); + + public GameState DeepClone() + { + GameState clone = new GameState(); + + foreach (string key in flags.Keys) + clone.flags[key] = flags[key]; + foreach (string key in counters.Keys) + clone.counters[key] = counters[key]; + foreach (string key in inventory.Keys) + clone.inventory[key] = inventory[key]; + + return clone; + } + + public void ClearFlags() + { + flags.Clear(); + } + + public bool GetFlag(string key) + { + if (flags.ContainsKey(key)) + { + return flags[key]; + } + return false; + } + + public void SetFlag(string key, bool value) + { + flags[key] = value; + } + + public void ClearCounters() + { + counters.Clear(); + } + + public int GetCounter(string key) + { + if (counters.ContainsKey(key)) + { + return counters[key]; + } + return 0; + } + + public void SetCounter(string key, int value) + { + counters[key] = value; + } + + public void ClearInventory() + { + inventory.Clear(); + } + + public int GetInventory(string key) + { + if (inventory.ContainsKey(key)) + { + return inventory[key]; + } + return 0; + } + + public void SetInventory(string key, int value) + { + inventory[key] = value; + } + } +} \ No newline at end of file diff --git a/Assets/Fungus/Scripts/GameState.cs.meta b/Assets/Fungus/Scripts/GameState.cs.meta new file mode 100644 index 00000000..c2ccc75c --- /dev/null +++ b/Assets/Fungus/Scripts/GameState.cs.meta @@ -0,0 +1,8 @@ +fileFormatVersion: 2 +guid: 2420b605a4ce1443bba29d71d694429c +MonoImporter: + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: diff --git a/Assets/Fungus/Scripts/Page.cs b/Assets/Fungus/Scripts/Page.cs new file mode 100644 index 00000000..02e22b92 --- /dev/null +++ b/Assets/Fungus/Scripts/Page.cs @@ -0,0 +1,331 @@ +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 transitiong to that View will automatically activate the Page. + [ExecuteInEditMode] + public class Page : MonoBehaviour + { + public Bounds pageBounds = new Bounds(Vector3.zero, new Vector3(0.25f, 0.25f, 0f)); + + // The font size for title, say and option text is calculated by dividing the screen height + // by the number of allowed rows for each type of text. This gives a consistent font size + // regardless of the device resolution. + public int titleRows = 20; + public int sayRows = 25; + public int optionRows = 25; + + public GUIStyle titleStyle; + public GUIStyle sayStyle; + public GUIStyle optionStyle; + public GUIStyle boxStyle; + + string titleText = ""; + + string originalStoryText = ""; + string displayedStoryText = ""; + + Action deferredAction; + + public enum Mode + { + Idle, + Say, + Choose + }; + + Mode mode = Mode.Idle; + + class Option + { + public string optionText; + public Action optionAction; + + public Option(string _optionText, Action _optionAction) + { + optionText = _optionText; + optionAction = _optionAction; + } + } + + List