类别 全部 - controller - functions - commands

作者:Mike Ton 9 年以前

1761

Unity 3D : uFrame

The document describes the uFrame framework within Unity3D, focusing on the functionalities of controllers. Controllers are composed of commands that operate at an abstract level, managing various tasks within a game.

Unity 3D : uFrame

Unity3D : uFrame

OverviewOLD

UFRAME
ROAD MAP

Exportable

Subsystema and Elements

Plug-ins API

Networking

Anatomy

Scene State Saving & Loading

WIP

Subsystems

"Real Time" Properties

Element Code Generation

Multi Instance Elements

*

(ElementController.cs)

public override void Spawn(BirdViewModel bird){ ... }

bird.Parent{NameofElementParent=="Game"}.birds.Add(newBird);

Must be instanced through UFRAME

Not Unity Editor

Else

Shared Reference!!!

base.SpawnBird(bird);

var newBird = this.Create{Element=="Bird"}();

newBird.mForce = 6;

(Required either)

It is explicitly marked as "Has Multiple Instances", via right-click to see it.

Collections : MyGamePlayer[] Players

There is a collection property from another element, somewhere in the diagram, with the same type of property.

Sharing ViewModels.

Multi-Player game

This can easily be accomplished using "Force Resolve"

This type of game element will have a collection of players, but most likely will need easy access to the local player

A case where a single instance needs to be shared among others while still allowing multiple instances

Single Instance Elements

Setting up the Inspector of a View doesn't require any information about accessing the Instance. uFrame has already done this when it generated the code for this element by generating a default "Identifier" for it.

Subscribing to "Real Time" Properties

Using The Initialize Method

Generated Controllers

Implementing Commands

Binding Handlers

"Real Time" Handlers

View Component Generation

Accessing Views From Other Views

Collection Bindings

ViewModel Property Bindings

Property Bindings

Generated Views

Sharing View Models

Instantiating Views

View Inspector

SceneManager

Extending Scene Managers

Loading a Scene Dynamically

Extending Scene Manager Settings

Generated Scene Managers

Inspector Options

Creating Scenes with SceneManagers

Creating Scene Transitions

SceneLoad/Boot

Then call the Start SceneManager's setup in Unity scene inspector option

The OnLoaded Method

After all of this has been completed the OnLoaded method will be called

There isn't much to note about its implementation because it doesn't have one. It is simply for your own use to know when everything has been properly loaded and the game is ready to begin.

The RequestViewModel Method

Bind

After a view has received it's view-model from the scene manager, the Bind method on the view will be called which will appropriately wire up the various binding methods to the property and collection change events.

Note: When using uFrame InstantiateView method you can pass in a ViewModel directly in which it will skip this method entirely.

??? This Method == Bind or RequestViewModel

InitializeData

Call the Initialize{ElementName} on the controller passing the reference to the view-model

Anything applied in this method will override anything that has been set in the inspector

This gives the controller the ultimate initialization power.

Last step before returning the requested view-model it will invoke "InitializeData" on the view

maps the properties specified in the view's inspector directly to the view-model

Save & Load

"Persistable View" dictionary

final step it will check if the view is marked as "Save & Load"

If true, it will add it to a separated "PersitableViews" dictionary that can easily be iterated and serialized for saving and loading a scenes state.

(function)

This allows any view-model to be located very easily by its identifier.

//This is why when you set the same identifier or "ResolveName" on two different views they will get the same instance of the view-model and thus both re-act as the view-model properties and collections change

This method will always ensure that the view-model exists in the context.

Then the method will take the identifier, search for it in the context first

then in the dependency container

and if nothing is found it will create a new one

This method provides view-models to all of the views in a scene on load.

The view will pass itself, the controller it should use, as well as the identifier for the view-model as well.

The Load Method

During this load method coroutines execution the Scene is also loading.

When each view loads it will call RequestViewModel on the SceneManager.

This is a great place to create any root views (if any) that need to be dynamically instantiated when the scene loads.

This is also a great place to load a serialized state of a game. (See: Scene State Saving & Loading )

WIP:

Scene State Saving & Loading

After the setup method is called by the game-manager.

It will then call the load method coroutine that is also on the SceneManager.

public override void Setup() { ... }

Container.RegisterInstance(SetupViewModel(MyElementController,"MyElement"));

// "SetupViewModel" == Simply a helper method for creating Single-Instance View-Models.

//This method will create the ViewModel and assign it the appropriate controller passed in the first argument if it doesn't already exist.

Container.InjectAll();

So when we register the instance of this controller. The container will scan it looking for properties with inject attribute. If it finds a property with the inject attribute it will "Resolve" a registered instance based on the type of the property.

You could easily create your own properties and mark them with the [Inject] attribute and they will work the same way controllers do as long as you have registered it in the Setup method before the base.Setup() line is executed.

// Inject all the controllers at once

Container.Resolve();

//Will return the same instance of the controller we registered

//Controller, in its own form is a Singleton

//Registering a single instance of a controller

Container.RegisterInstance(this.MyElementController, false);

this.MyElementController = new MyElementController() { Container = Container, Context = Context };

// Register every controller defined in the subsystems that are connected to the scene manager in the designer

//We register these controllers in the setup method because it is important that they are ready to be used as unity loads the views and GameObjects in the scene.

public override void Setup(){ ... }

base.Setup();

//The base call because uFrame generates the basic bootstrapper for you

The first thing to load in uFrame...

When the GameManager loads it makes sure that it is the first instance to load

If it's not the first instance then it will transfer the properties of itself to the current instance and then destroy itself

This happens because of its predefined "Script Execution Order"

API

Class Reference

A controller is a group of commands usually to provide an abstract level Inheritance diagram for Controller:

Functions

Protected

Public

(Send an event to our game)

UnityEngine.Coroutine StartCoroutine (IEnumerator routine)

ModelPropertyBinding SubscribeToProperty< TViewModel, TBindingType > (TViewModel source, P< TBindingType > sourceProperty, Action< TViewModel, TBindingType > changedAction)

void StopCoroutine (string name)

void StopAllCoroutines ()

abstract

Initialize (ViewModel viewModel)

virtual

ViewModel

Create ()

Create a new ViewModel. This will generate a Unique Identifier for the VM. If this is a specific instance use the

overload and pass an identifier.

(Create an empty view-model . Note: This method does not wire up the view-model to this controller and only instantiates an associated view-model.)

CreateEmpty ()

Create an empty view-model . Note: This method does not wire up the view-model to this controller and only instan-

tiates an associated view-model.

CreateEmpty (string identifier)

Create an empty view-model with the specified identifer. Note: This method does not wire up the view-model to this

controller.

Create (string identifier)

Creates a new ViewModel with a specific identifier. If it already exists in the SceneContext it will return that instead

//if exist in scene, will return that instead

UI

F2

rename

F1

hide/show help

ctrl

mouse

connect

File

BuildSettings

ALL SCENE INVOLVED IN TRANSITIONS MUST BE ADDED TO BUILD SETTINGS

mtonFlapper

Resources

Does "Resources" name matter ???

Tested : NO

GamePipe

PrefabName == Uframe Collection Class Type

Hiearchy

(gameObj)

(entity)

_Pipes(collection parent)

GamePipe(view prefab)

Manual

?? Point to Prefab ??

Auto

matches name of Resource Prefab

(bg)

Ground

(menus)

???(whencreated)

Insert String of Unity Scene : SceneToTransitionTo.unity

if fail generate, find script and reimport

Nodes
Sub Systems

({SubSystemName}Views.designer.cs)

({SubSystemName}Controllers.designer.cs)

public abstract class {ElementName}ControllerBase : Controller {}

{ ... }

public virtual {ElementName}ViewModel Create{ElementName}(){}

({SubSystemName}.designer.cs)

Elements

connect : ctrl + drag

collapse :

output

(objconfig)

Is Template ??

Doesn't live in scene

Template elements views are eligible to be base views

abstract element

Allows functionality for anything inherited from it

Has Multiple instances??

ModelView

(implemented by Controller)

(namestring must match)

GamePipe[] Pipes

??? Collection : class == class[]

SceneFirst

Transform

Container

(Prefab)

COLLECTION TYPE STRING SHOULD == RESOURCE PREFAB STRING

GamePipe currentPipe

(link to GamePipe)

Can not link directly else single access.!

delegate to parent element

`

{ElementName}ViewModel.cs

???

{ElementName}View.cs

NOTE :

Accessing Views from other Views

Element View is better to Regenerate than to rename.

(UI)

(addToSelection)

GameOverView

(addToScene)

(config)

View Components

View Bindings

Behaviours

2-Way Properties

(real time properties)

(removing binding)

manually delete okay

(adding binding)

(unity)

(GameObject)

??? WON'T SPAWN IN SCENE WITHOUT BINDING

Macro: WRITES NEW BIND FUNCTION AT TOP OF CLASS

ONLY WRITES

Can not automatically delete existing function

Regardless of what is there; multiple function possible; creates collision

(io)

Listener

{PropertyName}Changed( ??? )

currentItemChanged(){}

Caller

Execute{CommandName}()

ExecutePlay()

Execute keyword + function(Play)

if exists in connected controller; launches ->

{ElementName}Controller.cs

Play()

??? must pass view object ???

public override void Play(myViewModel viewObj)

(implements ModelView)

???(associated elements...view are linked by their controllers.)

{ElementName} == only ONE instance of this!

(singleton)

LogMessage.nameofProperty

public override void InitializeLogMessage(LogMessageViewModel logMessage) { ... }

public class LogMessageController : LogMessageControllerBase { ... }

Scene Managers

myGameSceneManager

TransitionSceneCmd

Commands from direct subsystem descendent???

func

???Single element only???

create scene

myGame.unity

generates

_SceneManager

_GameManager

initializes all linked elements

The Setup Method

Scene Loading/Booting

GameManager

The first thing to load in uFrame is the GameManager. This happens because of its predefined "Script Execution Order". When the GameManager loads it makes sure that it is the first instance to load. If it's not the first instance then it will transfer the properties of itself to the current instance and then destroy itself.

Then the GameManager will begin by calling the "Start" SceneManger's setup method that is specified in the "Start" property located on the GameManger's inspector options. Before we got much further lets examine this setup method.

FlappyBird

Unity
Project
Scene
UFrame
Code

(path)

(data)

Controller

(vars)

{ControllerName}.{VarName}

(cmds)

Execute{CmdName}

(display)

View

(Instantiating Views By Name )

return InstantiateView(pill.Type == PillType.Blue?"Pill_Blue":"Pill_Red",pill);

(Instantiating Views With Prefabs)

public partial class EmergencyGameView{ ... }

return InstantiateView(pill.Type == PillType.Blue ? _BluePillPrefab : _RedPillPrefab, pill);

public GameObject _RedPillPrefab;

public GameObject _BluePillPrefab;

(Instantiating Views With Just A ViewModel)

In this code all thats passed is a view-model. When a prefab name or prefab gameobject is not passed it will attempt to find the prefab based on the ViewModel type using {ViewModelTypeName} and removing "ViewModel" from that type name. This is managed by uFrame's "ViewResolver" class.

public override ViewBase CreatePillsView (PillViewModel pill){ ... }

return InstantiateView( pill);

(accessing)

(All Child Views Dynamically)

foreach (var childView in ChildViews){ ... }

Debug.Log(childView.ViewModelObject);

(The Parent View)

public override void AfterBind(){ ... }

Debug.Log(this.ParentView);

(A View From A Collision, Gameobject, Transform, Or Component)

public void OnCollisionEnter(Collider colliderObject){ ... }

Debug.Log(view.ViewModelObject);

var view = collider.GetView();

MonoBehaviour

(Pipe)

ExecutePassed();

if (Pipe.ParentmtonFlapperGame.State == mtonFlapperState.Playing){ ... }

xform.position -= Vector3.right * Pipe.ParentmtonFlapperGame.ScrollSpeed * Time.deltaTime ;

(Bird)

public

void

OnTriggerEnter2D(Collider2D other){ ... }

Update(){ ... }

FixedUpdate(){ ... }

Vector3

_Velocity

bool

_DidFlap

public override void StateChanged(BirdState value) { ... }

if(value == BirdState.Alive){ ... }

xform.position = new Vector3(0.0f, 0.0f, 0.0f);

(mtonFlapperGame)

public void Update(){ ... }

xform.position -= Vector3.right * mtonFlapperGame.ScrollSpeed * Time.deltaTime;

if(mtonFlapperGame.State == mtonFlapperState.Playing){ ... }

if(xform.position.x <= -20.0f){ ... }

xform.position = new Vector3(21.111f, -5.3f, -0.1f);

(mono)

public void Update(){ ... }

if(mtonFlapperGame.State == mtonFlapperState.Menu || mtonFlapperGame.State == mtonFlapperState.GameOver){ ... }

if(Input.GetKeyDown(KeyCode.B)){ ... }

Execute{playerSpawn}(_playerVM);

if(Input.GetMouseButtonDown(0)){ ... }

ExecutePlay();

private

IO_mtonViewModel

_ioVM

BirdViewModel

_playerVM

(mvc)

(bindings)

(pipes)

public override void PipesRemoved(PipeViewBase item) { ... }

public override void PipesAdded(PipeViewBase item) { ... }

public override ViewBase CreatePipesView(PipeViewModel value) { ... }

(properties)

public override void playerChanged(BirdViewModel value) { ... }

_playerVM = value;

public override void StateChanged(mtonFlapperState value) { ... }

public void Passed(){ ... }

public override void Hit(BirdViewModel bird){ ... }

mtonFlapperGameController.GameOver();

Bird.State = BirdState.Dead;

EX:

(cleanup)

public override void GameOver(){ ... }

StopAllCoroutines();

(spawn)

public override void playerSpawn(BirdViewModel bird){ ... }

bird.Parent{mtonFlapperGame}.birds.Add(newBird);

// birds == Bird[] property of {mtonFlapperGame}

//!!! MUST ADD new entry to exist in scene

newBird.mForce = bird.mForce * 0.5f;

// uses values from passed in BirdViewModel instance

var newBird = new BirdViewModel(BirdController);

// Also : var newBird = BirdController.CreateBird();

public IEnumerator SpawnPipes(){ ... }

while(mtonFlapperGame.State == mtonFlapperState.Playing){ ... }

yield return new WaitForSeconds(mtonFlapperGame.PipeSpawnSpeed);

mtonFlapperGame.Pipes.Add(new PipeViewModel(PipeController));

(init)

public override void Play(){ ... }

StartCoroutine(SpawnPipes());

Diagram

(SubSystem)

Game

mtonFlapperGame

GroundView

mtonFlapperGameView

(Bindings)

(collections)

(Pipes)

PipesRemoved

PipesAdded

CreatePipesView

StateChanged

playerSpawn

Collections

Pipe

pipes*

PipeView

Bird

birds*

BirdView

Commands

flapVelocity

maxSpeed

BirdState

Properties

(sys)

float

ScrollSpeed

PipeSpawnSpeed

Gravity

int

Score

enum

MtonFlapperState

State

Playing

Menu

(SceneManager)

mtonFlapperManager

Transitions

Hit

Play

GameOver

From direct child ??

?? All Commands pathed to this node ??

UFRAME : OVERVIEW

UFRAME : 1.5