door Mike Ton 9 jaren geleden
1772
Meer zoals dit
Exportable
Subsystema and Elements
Plug-ins API
Networking
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" == 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"
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
F2
rename
F1
hide/show help
ctrl
mouse
connect
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
({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 { ... }
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.
(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());
(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 ??