示例#1
0
    public override void GetContent(IDocumentationBuilder _)
    {
        base.GetContent(_);

        _.CodeSnippet("var player = this.CreatePlayer()");
        _.Title2("Creating a ViewModel with the Extension Method");
        _.Paragraph("In uframe 1.6 there is an extension method for creating any viewmodel that will use the correct controller to create it.");
        _.CodeSnippet("this.CreateViewModel<PlayerViewModel>()");
        _.Paragraph("This method will resolve the controller and invoke the associated controller's 'Create' method.");
        _.Paragraph("It is important that you use this method because the controller will initialize the commands on the viewmodel to point to the correct handlers on itself.");
        _.Break();

        _.Title2("Initialization Inside Controllers");
        _.Paragraph("Typically you will use the relevant Controller's Initialize{ElementName} function to initialize " +
                    "a newly created ViewModel with default values and references.  It's a great place to subscribe to " +
                    "state changes and \"scene property\" changes, or possibly track a list of ViewModel instances when " +
                    "acting similarly to a manager.");



        _.Break();
        _.Title2("Initialization Inside Views");
        _.Paragraph("For convenience, you also have the option of Initializing a ViewModel from a particular View, by checking Initialize ViewModel on the View.  This is particularly useful when setting up a scene before runtime or creating prefabs.");

        _.Break();
        _.AlsoSeePages(typeof(ViewModelManagers));
    }
示例#2
0
    public override void GetContent(IDocumentationBuilder _)
    {
        base.GetContent(_);

        var graph = new ScaffoldGraph();
        var node  = graph.BeginNode <SceneTypeNode>("UIScene").EndNode() as SceneTypeNode;

        _.Paragraph("Scene Types exist on the root game object of a scene. These components need to live on the root game-object of the scene. This allows uFrame to know what scene has been loaded and to keep a reference for removing this scene when needed.");


        _.Title2("Generated Scene Types");
        _.Paragraph("The scene type is a mono behaviour that will go on your root scene object.  This allows uFrame to associate a game object so it can easily be destroyed when you want to unload a scene.  This also allows uFrame to listen for when the scene has actually been loaded.");
        _.Break();
        _.TemplateExample <SceneTemplate, SceneTypeNode>(node, true);
        _.Break();
        _.Title2("Generated Scene Loaders");
        _.Paragraph("A scene loader is generated for every scene type that exists in the graph.");
        _.Paragraph("The scene loader lives as a gameobject on the uFrame Kernel, when the same corresponding 'Scene Type' has been loaded," +
                    " the scene loader will get a reference to the scene type and allow you to load it accordingly.  This gives very fine grained " +
                    "control on how scenes are loaded and unloaded.");
        _.Break();
        _.TemplateExample <SceneLoaderTemplate, SceneTypeNode>(node, true);


        _.AlsoSeePages(typeof(UsingSceneLoaders));
    }
示例#3
0
    public override void GetContent(IDocumentationBuilder _)
    {
        base.GetContent(_);
        _.Paragraph("The uFrame Kernel is an essential piece of uFrame, it handles loading scenes, systems and services.  " +
                    "The kernel is nothing more than a prefab with these types of components attached to it in an organized manner.");



        _.ImageByUrl("http://i.imgur.com/5Rg2X25.png");

        _.Paragraph("In the image above you can see the scene 'BasicsProjectKernelScene'.  This scene will always always contain the 'BasicsProjectKernel' " +
                    "prefab and any other things that need to live throughout the entire lifecycle of your application.");
        _.Paragraph("Important Note: All SystemLoaders, Services, and SceneLoaders are MonoBehaviours attached their corresponding child game-objects in the kernel prefab.");

        _.Note(
            "Whenever a scene begins, uFrame will ensure that the kernel is loaded, if it hasen't been loaded it will delay " +
            "its loading mechanism until the kernel has been loaded. This is necessary because you might initialize ViewModels, deserialize them...etc so the view should not bind until that data is ready.");

        _.Break();

        _.Title2("Scaffolding The Kernel");
        _.Paragraph("For convenience uFrame 1.6 makes the process of creating the kernel very easy and straightforward.  " +
                    "By pressing the Scaffold/Update Kernel button it will create a scene, and a prefab with all of the types created by the uFrame designer.  " +
                    "You can freely modify the kernel, and updating it will only add anything that is not there.");
        _.Break();

        _.Title2("Boot Order");
        _.ImageByUrl("http://i.imgur.com/L5CC8q8.png");


        _.Title2("The Game Ready Event");
        _.Paragraph("Once the kernal has loaded, it will publish the event 'GameReadyEvent'.  This event ensures that everything is loaded and bindings have properly taken place on views.");
    }
示例#4
0
    public override void GetContent(IDocumentationBuilder _)
    {
        base.GetContent(_);
        _.Paragraph("The uFrame Kernel is an essential piece of uFrame, it handles loading scenes, systems and services.  " +
                    "The kernel is nothing more than a prefab with these types of components attached to it in an organized manner.");

        _.ImageByUrl("http://i.imgur.com/5Rg2X25.png");

        _.Paragraph("In the image above you can see the scene 'BasicsProjectKernelScene'.  This scene will always always contain the 'BasicsProjectKernel' " +
                    "prefab and any other things that need to live throughout the entire lifecycle of your application.");
        _.Paragraph("Important Note: All SystemLoaders, Services, and SceneLoaders are MonoBehaviours attached their corresponding child game-objects in the kernel prefab.");

        _.Note(
            "Whenever a scene begins, uFrame will ensure that the kernel is loaded, if it hasen't been loaded it will delay " +
            "its loading mechanism until the kernel has been loaded. This is necessary because you might initialize ViewModels, deserialize them...etc so the view should not bind until that data is ready.");

        _.Break();

        _.Title2("Scaffolding The Kernel");
        _.Paragraph("For convenience uFrame 1.6 makes the process of creating the kernel very easy and straightforward.  " +
                    "By pressing the Scaffold/Update Kernel button it will create a scene, and a prefab with all of the types created by the uFrame designer.  " +
                    "You can freely modify the kernel, and updating it will only add anything that is not there.");
        _.Break();

        _.Title2("Boot Order");
        _.ImageByUrl("http://i.imgur.com/L5CC8q8.png");

        _.Title2("The Game Ready Event");
        _.Paragraph("Once the kernal has loaded, it will publish the event 'GameReadyEvent'.  This event ensures that everything is loaded and bindings have properly taken place on views.");
    }
示例#5
0
 public override void GetContent(IDocumentationBuilder _)
 {
     base.GetContent(_);
     _.Paragraph("By default uFrame keeps up with viewmodels for us.  It maintains a manager for each type of viewmodel you create.");
     _.Paragraph("To access these managers, you can inject them into controllers and services using the following code.");
     _.Break();
     _.CodeSnippet("[Inject] public IViewModelManager<MyViewModel> MyViewModelsManager { get; set; }");
     _.Break();
     _.Note("Important Note: By default every element controller already generates manager properties just like the above example for the associated element's viewmodel.");
 }
示例#6
0
        private static void ImportantMethods(IDocumentationBuilder _)
        {
            _.Title2("Execution Order");
            _.Paragraph("There are actually several different entry points on generated Views.  The usual order is:");
            _.Title3("For Views instantiated at runtime");
            _.Paragraph("Awake > OnEnable > PreBind > Bind > AfterBind > InitializeViewModel > Start > Update loop begins");
            _.Title3("For Views existing \"SceneFirst\" before runtime");
            _.Paragraph(
                "Awake > OnEnable > CreateModel > InitializeViewModel > Start (before base call) > PreBind > Bind > AfterBind > Start (after base call)");

            _.Title3("When Destroying an object");
            _.Paragraph(
                "OnDisable > OnDestroy (before base.OnDestroy() call) > UnBind > OnDestroy (after base.OnDestroy() call)");
            _.Break();
            _.Break();
            _.Title2("Help, my bindings have stopped working!");
            _.Paragraph(
                "There are a few methods that ALWAYS need their base.Method() calls intact, otherwise uFrame can easily  produce unexpected results.");
            _.Paragraph("These methods include a majority of the overridden standard Unity methods:");
            _.Paragraph(" - Awake(), Start(), OnEnable(), OnDisable(), OnDestroy(), Update(), LateUpdate()");
            _.Paragraph(" - PreBind(), Bind(), AfterBind(), UnBind(), InitializeViewModel()");
            _.Break();
            _.Break();
            _.Title2("Important Methods");
            _.Paragraph(
                "When looking for more clarity on how uFrame builds upon Monobehaviour, it can be fairly useful to look through ViewBase.cs, as this is what all uFrame Views inherit from.");

            _.Title3("PreBind()");
            _.Paragraph("This happens before the View begins creating bindings to its given ViewModel.");
            _.Break();

            _.Title3("Bind()");
            _.Paragraph(
                "This is where the View actually creates property bindings, collection bindings, and command bindings to the given ViewModel.  The base.Bind() call will automatically create the bindings specified in the uFrame diagram for this specific View type.  If you have any further manual bindings you need to do, this can be a good place to implement them.");
            _.Break();

            _.Title3("AfterBind()");
            _.Paragraph("This is called immediately after the View creates bindings to its ViewModel.");
            _.Break();

            _.Title3("CreateModel()");
            _.Paragraph(
                "This is when SceneFirst Views request a proper ViewModel from the scene's Dependency Container.  For the most part, this should be left alone.");
            _.Break();

            _.Title3("InitializeViewModel()");
            _.Paragraph(
                "On a View, when the Initialize ViewModel option is checked in the inspector, this is where the base.InitializeViewModel() call will set the ViewModel's properties to the values of the View's matching properties (which are underscored in code on the View).  This will usually never need to be overridden.");
            _.Break();

            _.Title3("Awake(), Start(), OnEnable(), OnDisable(), OnDestroy(), Update(), LateUpdate()");
            _.Paragraph(
                "These are all the same as their Unity counterparts, and must retain their base calls if you override them, in order for uFrame to function properly.");
            _.Break();
        }
示例#7
0
        private static void ImportantMethods(IDocumentationBuilder _)
        {
            _.Title2("Execution Order");
            _.Paragraph("There are actually several different entry points on generated Views.  The usual order is:");
            _.Title3("For Views instantiated at runtime");
            _.Paragraph("Awake > OnEnable > PreBind > Bind > AfterBind > InitializeViewModel > Start > Update loop begins");
            _.Title3("For Views existing \"SceneFirst\" before runtime");
            _.Paragraph(
                "Awake > OnEnable > CreateModel > InitializeViewModel > Start (before base call) > PreBind > Bind > AfterBind > Start (after base call)");

            _.Title3("When Destroying an object");
            _.Paragraph(
                "OnDisable > OnDestroy (before base.OnDestroy() call) > UnBind > OnDestroy (after base.OnDestroy() call)");
            _.Break();
            _.Break();
            _.Title2("Help, my bindings have stopped working!");
            _.Paragraph(
                "There are a few methods that ALWAYS need their base.Method() calls intact, otherwise uFrame can easily  produce unexpected results.");
            _.Paragraph("These methods include a majority of the overridden standard Unity methods:");
            _.Paragraph(" - Awake(), Start(), OnEnable(), OnDisable(), OnDestroy(), Update(), LateUpdate()");
            _.Paragraph(" - PreBind(), Bind(), AfterBind(), UnBind(), InitializeViewModel()");
            _.Break();
            _.Break();
            _.Title2("Important Methods");
            _.Paragraph(
                "When looking for more clarity on how uFrame builds upon Monobehaviour, it can be fairly useful to look through ViewBase.cs, as this is what all uFrame Views inherit from.");

            _.Title3("PreBind()");
            _.Paragraph("This happens before the View begins creating bindings to its given ViewModel.");
            _.Break();

            _.Title3("Bind()");
            _.Paragraph(
                "This is where the View actually creates property bindings, collection bindings, and command bindings to the given ViewModel.  The base.Bind() call will automatically create the bindings specified in the uFrame diagram for this specific View type.  If you have any further manual bindings you need to do, this can be a good place to implement them.");
            _.Break();

            _.Title3("AfterBind()");
            _.Paragraph("This is called immediately after the View creates bindings to its ViewModel.");
            _.Break();

            _.Title3("CreateModel()");
            _.Paragraph(
                "This is when SceneFirst Views request a proper ViewModel from the scene's Dependency Container.  For the most part, this should be left alone.");
            _.Break();

            _.Title3("InitializeViewModel()");
            _.Paragraph(
                "On a View, when the Initialize ViewModel option is checked in the inspector, this is where the base.InitializeViewModel() call will set the ViewModel's properties to the values of the View's matching properties (which are underscored in code on the View).  This will usually never need to be overridden.");
            _.Break();

            _.Title3("Awake(), Start(), OnEnable(), OnDisable(), OnDestroy(), Update(), LateUpdate()");
            _.Paragraph(
                "These are all the same as their Unity counterparts, and must retain their base calls if you override them, in order for uFrame to function properly.");
            _.Break();
        }
示例#8
0
 public override void GetContent(IDocumentationBuilder _)
 {
     base.GetContent(_);
     _.Paragraph("Although uFrame does its best to support and guide you to the creation of better games, it is extremely important to realize that the implementation is still always left to you.  While uFrame tries to separate things clearly, there are still countless ways you can circumvent and break the patterns put in place.  The most common violation is through mixing core game logic with representation logic, where some poor developer has created a nightmare trying to access fields on Views from Controllers or other Views.  These separations exist for a reason, so one puzzle piece can content itself with handling its own functionality and not worry how other pieces are handling themselves.");
     _.Break();
     _.Paragraph("There are also many situations with multiple valid solutions, and it all depends on how you decide to arrange your implementation.  When prototyping, many things are forgivable and easily redesigned as the project evolves and features are settled on.  It's very easy to bind/subscribe to properties in order to initiate logic, but you should always consider from where you want that logic handled.  For example, imagine something odd happens and your RobotEnemy suddenly stops working correctly.  If all of your modifications are done in RobotEnemyController, then you've only got one place to look for the problem.  If you've allowed any parent, or child, or practically anything with a reference to RobotEnemy, to make modifications to it, then you've got more places to check...");
     _.Break();
     _.Paragraph(" Above all, stick to the separation of Controller <-> ViewModel <- View.");
     _.Paragraph(" - Controllers handle the layer of core game logic,");
     _.Paragraph(" - ViewModels are effectively the data layer,");
     _.Paragraph(" - and Views are the presentation layer, handling how the game is displayed and represented in Unity.");
 }
示例#9
0
    public override void GetContent(IDocumentationBuilder _)
    {
        base.GetContent(_);
        _.Title2("What is it?");
        _.Paragraph("Controllers dictate the rules of your game and, like ViewModels, they do not inherit from Unity's Monobehaviour.  As they only handle logic, there only ever needs to be one Controller for each type of ViewModel.  For example, when a PlayerViewModel performs the PickupItem command, the PlayerController would simply need to know which PlayerViewModel to execute that command logic on, and the logic remains the same whether there are 4 players or one.");

        _.Paragraph(" A controller is designed to implement the data-driven logic and rules behind an element " +
                    "and could be considered just a \"group\" of commands for a view-model. " +
                    "The Designer has enough information about an element to implement most of the controller itself " +
                    "In most instances, you only need to apply the logic and rules to each method.  ");

        _.Break();



        _.Title2("Best Practices");
        _.Paragraph("When implementing controllers, think of the element as its own little section of your world, " +
                    "if you want your element to interact or be visible to the entire world, publish events as " +
                    "necessary in your command controller methods.");
        _.Paragraph("To understand this idea a bit more, take a look at the following diagram.");
        _.ImageByUrl("http://i.imgur.com/KbPL9bw.png");
        _.Paragraph("So in the diagram above, on the EnemyHit command handler, we publish the command as 'global' event.  This means that services can be your general connection layer that make various elements work together.");
        _.Title3("But why should I do this?");
        _.Paragraph("Imagine you create a Player element, if it lives entirely on its own (no dependencies on other controllers, services..etc), you can re-use the element in another game and implement services to connect them together.");
        _.Break();
        _.Break();

        _.Title2("The Setup Method");
        _.Paragraph("The setup method is an implementation of the ISystemService interface, this means that all controllers are ultimately services, they do not derive from monobehaviour.  This means you can easily listen to any kind of event on a controller, as well as publish them.");
        _.Title3("Important Note");
        _.Paragraph("You must be careful when listening to events in controllers that use inheritance. For instance, if you have an elementA controller, and a derived elementB controller, and in the setup method you are listening to event 'C', then beth element A and element B will be listening to the same event.  In some cases this may be wanted behaviour, but its important to understand.");
        _.Break();
        _.Break();
        _.Title2("The Initialize Method");
        _.Paragraph("The initialize Method in a controller can be used to initialize an Element's ViewModel (similar to how it might be initialized in the inspector of a View). It is a great place to subscribe to 'Scene Properties'.");
        _.Title2("Command Handlers");
        _.Paragraph("Every command that is outlined on an element, in the Element Designer, will have a corresponding method in a controller (assuming the diagram is saved).  ");
        _.Paragraph("There are a few things to notice when looking at the code example below:");
        _.Paragraph(" - The \"FPSWeaponController\" is derived from \"FPSWeaponControllerBase\", which is generated by the designer.");
        _.Paragraph(" - All of these methods are overrides, because the base class has implemented an empty \"virtual method\" for each command.");
        _.Paragraph(" - The reload method has an IEnumerator result type, because is it is marked as a yield command (indicated by the yellow marker).  This can be achieved by right-clicking on a command and checking \"Is Yield Command\". It is used for simulating a co-routine.");
        _.Paragraph(" - In each method we are simply processing rules by reading and modifying the FPSWeaponViewModel's instance data .");
        _.ShowGist("7bba5439faf0b46efa61", "FPSWeaponController.cs");
    }
示例#10
0
 public override void GetContent(IDocumentationBuilder _)
 {
     base.GetContent(_);
     _.Paragraph("uFrame, specifically created for the Unity game engine, uses a pattern-based framework called MVVM (Model View ViewModel). It is designed to provide developers with the visual editing tools, code structure and knowledge to develop games faster and more efficiently. This \"frame of mind\" for creating games is different than what most Unity developers are used to, but once understood the possibilities of where an idea can go are limitless. So, let's jump right into the \"uFrame of mind\"! ");
     _.Title2("Making things simple");
     _.Paragraph("Far too often game development begins with throwing a bunch of random game objects and components together and then retrofitting code in hopes of creating a masterpiece. Teams fail to focus on the basic concepts first and are left with trying to assemble pieces of a project that don't quite fit together. Doesn't make much sense does it?");
     _.Paragraph("uFrame simplifies things by separating out the essential and peripheral parts of the Unity's component model. It eliminates the visual noise (user-interface, HUD, transformers, positions, rotations, working with geometry, shaders, pathfinders, mouse events etc.) that can overwhelm and discourage many developers, and allows them to initially focus on the core logic.");
     _.Paragraph("uFrame does this with the use of Elements . Each element in a game has different parts, which consists of the ViewModel, Controller, View and possibly the View Component. A ViewModel serves as interface between the visual entities and logic of the game. These entities include properties (Score, Ammo, etc.), collections (Players, Environments etc.), and commands (PlayerHit, Upgrade etc.). A Controller works with a ViewModel to initialize and modify data when a command is invoked and/or interaction occurs between an event and the user. ");
     _.Break();
     _.Title2("Always Consider Portability.");
     _.Paragraph("In uFrame, both the Controller and the ViewModel are \"portable\" parts of a game. This means taking them outside of Unity and putting them into a separate environment, such as a terminal application or web server, will never be an issue. In fact, this is essential to providing proper support for the extended features of uFrame and is enforced by the Element Designer (which limit the types that are available). This should always be taken into consideration when developing or extending Controllers or ViewModels. ");
     _.Note("Even if a game doesn't need portability it is still good to think in these terms. uFrame is built around this concept, which allows each piece to fit together more naturally.");
     _.Break();
     _.Title2("Making The Noise Sing.");
     _.Paragraph("The other two parts of the element, the View and the View Component, connect the game logic with the visual noise. They are the key components that connect Unity to the Controllers and ViewModels, bringing the game to life. A View Component can read and modify the real-time data of a ViewModel, but isn't necessary for every element. It is only meant to provide an extra level of extendibility when needed. A View (which is technically a View Component, but with a larger role) binds to an element's data so that it's notified when something is changed. When these changes occur, it directs the View Component to execute the appropriate action. Views also execute the commands of events and interactions that occur in the scene (e.g. Collision, MouseClick, Hover). ");
     _.Break();
     _.Title2("Naming Things.");
     _.Paragraph("When creating elements, particularly element commands, it's important to think about how things are being named. For instance, if a player can pick up an item when a game object collides with it and when the player clicks on it, then a developer would want to create a label such as \"PickUpItem\", that describes both commands. This would more broadly explain its function and allow for items to be collected in a different way, if the developer so chooses.  ");
     _.Break();
 }
 public override void GetContent(IDocumentationBuilder _)
 {
     base.GetContent(_);
     _.ImageByUrl("http://i.imgur.com/2G5Amgx.png");
     _.Paragraph("ViewComponents can be used for a wide variety of things, and are meant to provide a further level of extensibility to Views.  They are derived from MonoBehaviour, and require a View in order to function.  A ViewComponent will bind to the same ViewModel instance to which its corresponding View is bound.  In essence, they are extremely simplistic, offering these things:");
     _.Paragraph(" - Access to a particular View to which it is bound ");
     _.Paragraph("   - Access to that specific ViewModel instance");
     _.Paragraph(" - Matching execute methods for the corresponding View's commands");
     _.Paragraph(" - Awake, Bind, and Unbind methods ");
     _.Paragraph("   - These can be used to implement manual bindings where desired, among other things");
     _.Break();
     _.Paragraph("While entirely optional, there are a lot of creative uses for ViewComponents, including interchangeable behaviours, toggleable logic, and even extending logical ownership for a View.");
     _.Break();
     _.Paragraph("For example, we'll outline a scenario where you wish to have a system that detects hit damage to specific player body parts in an FPS game, in order to have damage multipliers.  In the example diagram below, we have separated out ViewComponents for each type of body part.");
     _.ImageByUrl("http://i.imgur.com/wNxFcQt.png");
     _.Paragraph("On the Player GameObject, we would attach the PlayerView.  Assuming that we have a rigged character model parented to that Player GameObject, we would want to set up Colliders on the joint references of each of the corresponding body parts, similar to the screenshot below:");
     _.ImageByUrl("http://i.imgur.com/GuwVQzf.png");
     _.Paragraph("We can either add ViewComponents at runtime, or assign them directly to each Collider individually:");
     _.ImageByUrl("http://i.imgur.com/RX8hZeY.png");
     _.Paragraph("Once this is done, we simply need to add a short piece of code to each ViewComponent to detect collisions and execute TakeDamage, something like:");
     _.ShowGist("2c2c6ca621f91280b693","PlayerArmComponent.cs");
     _.Paragraph("So now with similar code on all of our body part GameObjects, they will each provide separate collision checks for individual body parts.  If a body part is hit by a bullet GameObject with a BulletView on it, the damage of that BulletViewModel instance will be passed, along with the type of body part hit, to the TakeDamage command on the PlayerController.");
 }
示例#12
0
    public override void GetContent(IDocumentationBuilder _)
    {
        base.GetContent(_);

        var graph = new ScaffoldGraph();
        var node = graph.BeginNode<SceneTypeNode>("UIScene").EndNode() as SceneTypeNode;
        _.Paragraph("Scene Types exist on the root game object of a scene. These components need to live on the root game-object of the scene. This allows uFrame to know what scene has been loaded and to keep a reference for removing this scene when needed.");

        _.Title2("Generated Scene Types");
        _.Paragraph("The scene type is a mono behaviour that will go on your root scene object.  This allows uFrame to associate a game object so it can easily be destroyed when you want to unload a scene.  This also allows uFrame to listen for when the scene has actually been loaded.");
        _.Break();
        _.TemplateExample<SceneTemplate, SceneTypeNode>(node, true);
        _.Break();
        _.Title2("Generated Scene Loaders");
        _.Paragraph("A scene loader is generated for every scene type that exists in the graph.");
        _.Paragraph("The scene loader lives as a gameobject on the uFrame Kernel, when the same corresponding 'Scene Type' has been loaded," +
                    " the scene loader will get a reference to the scene type and allow you to load it accordingly.  This gives very fine grained " +
                    "control on how scenes are loaded and unloaded.");
        _.Break();
        _.TemplateExample<SceneLoaderTemplate, SceneTypeNode>(node, true);

        _.AlsoSeePages(typeof(UsingSceneLoaders));
    }
 public override void GetContent(IDocumentationBuilder _)
 {
     base.GetContent(_);
     _.ImageByUrl("http://i.imgur.com/2G5Amgx.png");
     _.Paragraph("ViewComponents can be used for a wide variety of things, and are meant to provide a further level of extensibility to Views.  They are derived from MonoBehaviour, and require a View in order to function.  A ViewComponent will bind to the same ViewModel instance to which its corresponding View is bound.  In essence, they are extremely simplistic, offering these things:");
     _.Paragraph(" - Access to a particular View to which it is bound ");
     _.Paragraph("   - Access to that specific ViewModel instance");
     _.Paragraph(" - Matching execute methods for the corresponding View's commands");
     _.Paragraph(" - Awake, Bind, and Unbind methods ");
     _.Paragraph("   - These can be used to implement manual bindings where desired, among other things");
     _.Break();
     _.Paragraph("While entirely optional, there are a lot of creative uses for ViewComponents, including interchangeable behaviours, toggleable logic, and even extending logical ownership for a View.");
     _.Break();
     _.Paragraph("For example, we'll outline a scenario where you wish to have a system that detects hit damage to specific player body parts in an FPS game, in order to have damage multipliers.  In the example diagram below, we have separated out ViewComponents for each type of body part.");
     _.ImageByUrl("http://i.imgur.com/wNxFcQt.png");
     _.Paragraph("On the Player GameObject, we would attach the PlayerView.  Assuming that we have a rigged character model parented to that Player GameObject, we would want to set up Colliders on the joint references of each of the corresponding body parts, similar to the screenshot below:");
     _.ImageByUrl("http://i.imgur.com/GuwVQzf.png");
     _.Paragraph("We can either add ViewComponents at runtime, or assign them directly to each Collider individually:");
     _.ImageByUrl("http://i.imgur.com/RX8hZeY.png");
     _.Paragraph("Once this is done, we simply need to add a short piece of code to each ViewComponent to detect collisions and execute TakeDamage, something like:");
     _.ShowGist("2c2c6ca621f91280b693", "PlayerArmComponent.cs");
     _.Paragraph("So now with similar code on all of our body part GameObjects, they will each provide separate collision checks for individual body parts.  If a body part is hit by a bullet GameObject with a BulletView on it, the damage of that BulletViewModel instance will be passed, along with the type of body part hit, to the TakeDamage command on the PlayerController.");
 }
示例#14
0
        public override void GetContent(IDocumentationBuilder _)
        {
            base.GetContent(_);

            _.Paragraph("System loaders are used to setup the uFrame Runtime with any dependencies it might need before the game begins.");
            _.Break();


            _.Title2("Custom System Loaders");
            _.Paragraph("In some cases creating a custom system loader can be very useful for different environments.  e.g. Dev Environment, Production Environment..etc");
            _.Paragraph("To create a custom system loader, derive from SystemLoader, override the load method, and add it to the kernel.");
            _.Break();
            _.Break();
            _.Title2("Generated System Loaders From Subsystems");
            _.Paragraph("All subsystem nodes inside a project will generate a 'SystemLoader'. These register an instance of every element " +
                        "controller that lives inside of it, as well as any 'Instances' defined on it.");

            _.Break();

            var graph = new ScaffoldGraph();
            InstancesReference instance;

            graph.BeginNode <SubsystemNode>(Name)
            .AddItem <InstancesReference>("MyInstance", out instance);

            var subsystem = graph.EndNode();

            graph.BeginNode <ElementNode>("Player");
            var playerNode = graph.EndNode();

            graph.PushFilter(subsystem);
            graph.SetItemLocation(playerNode, new Vector2(10f, 10f));

            instance.SourceIdentifier = playerNode.Identifier;

            _.TemplateExample <SystemLoaderTemplate, SubsystemNode>(subsystem as SubsystemNode, true, "Load");
        }
 protected override void Introduction(IDocumentationBuilder _)
 {
     _.Paragraph("The purpose of this tutorial is to teach you how to publish events to the scene service for unloading, and loading of scene types.");
     _.Break();
 }
示例#16
0
    public override void GetContent(IDocumentationBuilder _)
    {
        base.GetContent(_);


        _.Paragraph("So if you've made games in Unity before, you may have noticed how easy " +
                    "it is to end up with a mess of components with heavy dependencies.  Unit " +
                    "testing is impossible.  Adding/removing properties or changing the game " +
                    "logic of one component may break components on one, two, or half a dozen " +
                    "other Gameobjects and/or UI elements.  It can easily become a nightmare.");
        _.Break();
        _.Paragraph("In uFrame, an emphasis is placed on separating out the pieces of your game " +
                    "into certain categories (often referred to as \"layers\"), based on this hybrid" +
                    " MVCVM pattern.  The reasoning behind this is to help enforce separation of concerns, " +
                    "and allow you to quickly split things into these categories and think about them " +
                    "up-front.  These parts are defined as:");
        _.ImageByUrl("http://i.imgur.com/oVunJef.png");
        _.Paragraph(" - ViewModels: The objects, including properties and available commands");
        _.Paragraph(" - Controllers: The rules, where you implement logic of commands");
        _.Paragraph(" - Views: The visual/auditory representation of your objects in a game engine environment");
        _.Break();
        _.Paragraph("It gets a little more complicated with the actual implementation, but the chart above " +
                    "is the core concept.  Ideas are always theoretical.  The idea of your game and everything" +
                    " that defines it should technically be able to exist in any environment, whether it's a " +
                    "game engine, a console app, or a physical board game.  A player takes damage and health " +
                    "is decremented; this concept can be represented any number of ways, as a UI health gauge, " +
                    "a damage printout message in a console, or loss of health tokens from a board game player.");
        _.Break();
        _.Break();
        _.Paragraph(
            "In the previous example the Player would be a ViewModel, an object in your game, with a " +
            "Health property.  There would most likely be a TakeDamage command defined in the " +
            "PlayerController, which would handle the rule of decrementing the playerViewModel's Health." +
            "  When the value changes on the Health property, you may have it trigger a view binding on " +
            "the PlayerHUDView which updates a health gauge according to this new value.  The fun part is " +
            "that all it takes to trigger this chain of events is something like:");

        _.CodeSnippet("ExecuteCommand(playerVM.TakeDamage, 10); // player takes 10 damage");
        _.Paragraph("This command can be executed from any controller, or any view that has access to that " +
                    "particular PlayerViewModel instance, usually through some kind of interaction, such as a " +
                    "collision with spikes or an enemy's weapon.  Furthermore, it is important to make a " +
                    "distinction of game logic (which goes on the Controller layer of the design) and " +
                    "visual/auditory/engine-specific logic (which belongs on the View layer).");
        _.Break();
        _.Paragraph("Instead of an EnemyView detecting that it has hit the PlayerView, taking its PlayerViewModel " +
                    "instance, and executing the TakeDamage command on it directly from that EnemyView, it's " +
                    "important to make the distinction that this is game logic and belongs in the Controller " +
                    "layer.  The correct approach that most follows the MVCVM pattern would be to implement " +
                    "some kind of AttackPlayer command on the Enemy element, and pass the playerViewModel of " +
                    "the PlayerView that the EnemyView has hit.");
        _.ShowGist("2db6ead6cc89deb81a5e", "EnemyView, Hit was detected");
        _.Paragraph("Now that you're handling the game logic properly on the Controller layer, the actual logic " +
                    "is no longer dependent on that specific view, and is available to anything that tells the" +
                    " EnemyViewModel to AttackPlayer.");

        _.ShowGist("f79b3de4126c75d5bb03", "Enemy and Player Controllers Command Logic");
        _.Break();
        _.Paragraph("As you can see, there's a method to the madness.  Separating the core logic and state " +
                    "from the \"Monobehaviour\" side of things allows any number of Views to use this data. " +
                    " Under the hood, uFrame manages the state and helps centralize logic.  Everything else " +
                    "is just an expression of that state, a Player getting attacked or taking damage and " +
                    "losing health.");
    }
 protected override void Introduction(IDocumentationBuilder _)
 {
     _.Paragraph("The purpose of this tutorial is to teach you how to publish events to the scene service for unloading, and loading of scene types.");
     _.Break();
 }