UFRAME

m

UFrame1p5

2DGameExample

MainDiagram

_DesignerFiles

<io>

UFrame

io_ViewModel.cs

dpad

(computed properties)

(boolean only)

(dpad)

bool

Compute{NameofProperty}

(dpad_SM)

(transitions)

(states)

io_Controller.cs

(Code)

Controller Code Connects ViewModel -> View relationships

Instantiates

Child ViewModels

Subscribes

ViewModel Property

??? Commands

Implements

Untiy3D

io_View.cs

(scene properties)

dpad

(code)

// calculates on each update

<T> Calculate{NameOfProperty}(){ ... }

if(GetInput.Event){ dpad == dir.left}

// GetInputObservable???

IObservable<T>

GetCalculate{NameOfProperty}AsObservable(){ ... }

//only invokes if postion has changed

return PositionAsObservable.Select(p=>CalculatevPos());

//only invokes every x seconds

return PositionAsObservable.Sample(TimeSpan.FromSeconds(1.0f)).Select(p=>CalculatevPos());

(binding)

(statemachine)

(code)

void

On{NameofState}

Spike.cs

//arbitrary Unity Script Object

<LevelRoot>

(prop)

<playerElement>

(properties)

int

numCoin

(command)

PickupCoin

OnHit

playerElementController.cs

void

PickupCoin( playerElementViewModel player) { ... }

player.numCoin++;

OnHit( playerElementViewModel player) { ... }

if(character.bInvulnerable==true){ return; }

//return without damage is character not eligible for damage

character.lives--;

if(character.lives <= 0){ character.bAlive=false; }

//if no lives left die => gameover

else{ ... }

character.bInvulnerable = true;

//character no longer eligible for damage

Observable.Timer(TimeSpan.FromMilliseconds(1500)).Subscribe( ... );

//subscribe to event 1500 ms from now

//couroutine???

l => {character.bInvulnerable = false;}

//change state to be eligible for damage in function called at 1500ms

//what is l???

playerElementView.cs

void

Bind(){ ... }

base.Bind();

//handle coin collision

this.BindViewTriggerWith<CoinView>(event, lambda);

(event)

CollisionEventType.Enter

(lambda)

coinview =>{ ... }

ExecutePickupCoin();

coinview.ExecutePickup();

//handle spike collision

this.BindComponentCollisionWith<Spikes>(event, lambda);

(event)

CollisionEventType.Enter

(lambda)

_ =>{ ... }

ExecuteOnHit();

(collections)

<coinElement>

(command)

Pickup

//??? Pickup command is never implemented...only a placeholder to subscribe to

ADVANCED:

UF_Asteroids

LevelSceneManager

LevelSystem

(instances)

LevelManagerViewModel

LevelManager

(elements)

LevelManager

(config)

(prop)

PlayerShipViewModel

Player

//Why is this ViewModel type as prop

Vector3

SpawnPoint

bool

GameOver

string

NotificationText

(collections)

Asteroid

Asteroids

//And this is Asteroid type; not AsteroidViewModel???

(commands)

void

RestartLevel

string

ShowNotification

(scripts)

(controller)

LevelManagerController.cs

public

override

void

(viewmodel)

LevelManagerViewModel.cs

public

override

int

ComputeScore(){ ... }

(view)

LevelManagerView.cs

(sys)

PowerUpSystem

Asteroid

PlayerShip

WeaponSystem

(abstract)

BaseWeapon

(prop)

float

FireRate

(collections)

BaseProjectiles

Projectiles

(commands)

Fire

(elements)

BasicLaser

(controllers)

BasicLaserController.cs

(var)

public

LaserBoltController

LaserBoltController { get; set; }

[Inject]

//wth is this?

//!!! must have prefab in Resources/LaserBolt !!!

(func)

public

override

void

InitializeBasicLaser(BasicLaserViewModel basicLaser) { ... }

Fire(BaseWeaponViewModel baseWeapon){ ... }

base.Fire(baseWeapon);

var laser = LaserBoltController.CreateLaserBolt();

//where is CreateLaserBolt defined???

baseWeapon.Projectiles.Add(laser);

laser.Hit.Subscribe(_ => { baseWeapon.ParentPlayerShip.AsteroidsDestroyed++; }).DisposeWith(laser);

//adds +1 asteroid point to parent of weapon on hit

laser.Destroy.Subscribe(_ => { baseWeapon.Projectiles.Remove(laser); }).DisposeWith(laser);

//on laser destroyed, remove from projectile list

baseWeapon.ParentPlayerShip.IsAliveProperty.Where(isAlive => !isAlive).Subscribe(_ => { laser.Destroy.Execute(null); }).DisposeWith(baseWeapon);

???

//destroys laser when ship dies. Also disposes of weapons???

(view)

BasicLaserView.cs

(var)

public

Transform

spawnPoint;

(func)

public

override

ViewBase

CreateProjectilesView(BaseProjectileViewModel item){ ... }

var laser = base.CreateProjectilesView(item);

laser.transform.position = spawnPoint.position;

// move to spawn position

return laser;

BaseProjectile

(elements)

LaserBolt

(view)

LaserBoltView.cs

(func)

public

override

void

Bind(){ ... }

GetComponent<Rigidbody>().velocity = transform.forward * 10;

//for firing this bolt should be rotated by emitter

this.transform.rotation = this.ParentView.transform.rotation;

//What if no parent view???

this.BindComponentTriggerWith<AsteroidView>(CollisionEventType.Enter, asteroidView =>{ ... }).DisposeWith(this);

r

//asteroid should be responsible for destroying himself//this creates null exceptions later becouse it executes in the same time as the binding from the asteroid view//and creates a race condition where we get null exception for parent level manager in asteroid, becouse we have //a subscription to destroy command from level manager where the asteroid is removed from collection//asteroidView.ExecuteDestroy();

this.ExecuteHit();

this.ExecuteDestroy();

Observable.Interval(TimeSpan.FromMilliseconds(10000)).Subscribe(x =>{ ... }).DisposeWith(this);

if (this != null){ this.ExecuteDestroy(); }

ExecuteDestroy() { ... }

//executes command in controller

base.ExecuteDestroy();

Destroy(this.gameObject);

//why do this in both???

DestroyExecuted() { ... }

//executes after controller command is executed

base.DestroyExecuted();

Destroy(this.gameObject);

<controllers>

//THERE ARE TWO OVERIDABLE FUNCTIONS FOR EACH COMMAND !!!!!!!
//EXECUTE{CNAME} => Executes comand in the controller !
//{CNAME}EXECUTED => Executed after controller command is executed !

(exe/call syntax)

(own)

view

this.Execute{CommandName};

(other)

view

this.ExecuteCommand(vm.command[ , arg]);

(ex:)

TurretViewModel turret = null;

this.ExecuteCommand(turret.Kill);

controller

this.ExecuteCommand(vm.command[ , arg]);

//HOW TO SPAWN

(unity)

(Resource/)

UF_PLAYER

UF_PLAYER_Player2

gLEVELController.cs

[Inject]

(Prefab)

//MUST

Resources folder with settings

Exact same name as Controller

Ex:

UF_PLAYERController

prefab => "UF_PLAYER"

Else:

How to inject variant prefabs???

Must also have variant Controller ???

NO

(Controller)

???

public

override

void

SpawnPlayer (gLEVELViewModel gLEVEL, Vector3 arg){ ... }

//init ViewModel values here

gLEVELView.cs

public

override

ViewBase CreateplayersView(UF_PLAYERViewModel item) { ... }

var _gPlayer_ = base.CreateplayersView(item).GetComponent<UF_PLAYERView>();

//intercept/get player instancedView

//searches Resource Folder for "UF_PLAYER" prefab

(else)

var _gPlayer_ = this.InstantiateView("UF_PLAYER_Player2", item).GetComponent<UF_PLAYERView>();

//searches Resources Folder for "UF_PLAYER_Player2" prefab

//if in subfolder "Resources/Char" then "Char/UF_PLAYER2"

???

this.transform.InitializeView(_gPlayer_.name, (ViewModel) item, _gPlayer_.gameObject, _gPlayer_.name);

//does something string manip that BossPool needs???

_gPlayer_.InitializeData(item);

//takes inspector information and applies it to the viewmodel

_gPlayer_.transform.position = this.playerSpawnPoint.position;

//position playerView

return _gPlayer_;

//must return view

//CAN BE OVERRIDEN BY

unity view Initialization/Initialize ViewModel

(UF_PLAYER NOT gLEVEL)

base.SpawnPlayer(gLEVEL, arg);

var player = this.UF_PLAYERController.CreateUF_PLAYER();

gLEVEL.players.Add(player);

(uFRAME)

(element)

(viewModel)

Collections

UF_PLAYER

players

<views>

public

override

void

Bind(){ ... }

(input)

UpdateAsObservable().Where(_ => Input.GetKey(KeyCode.R)).Subscribe(_ => { this.ExecuteRestartLevel(); });

??? On input keyCode.R, restart level ???

this.BindInputButton(LevelManager.RestartLevel, "Restart", InputButtonEventType.ButtonDown);

//NOTE: this requires that we setup input button restart in Edit -> Project Settings -> Input

<viewModels>

(Unity)

(View)

(InspectorSettings)

bool

Force Resolve

Save & Load

Inject This View

Initialize View Model

//Overrides what gets set in controller initialization

//Can cause instance errors

string

Id

OVERVIEW

Rx

r

Essentially Rx is built upon the foundations of the Observer pattern. .NET already exposes some other ways to implement the Observer pattern such as multicast delegates or events (which are usually multicast delegates). Multicast delegates are not ideal however as they exhibit the following less desirable features;In C#, events have a curious interface. Some find the += and -= operators an unnatural way to register a callbackEvents are difficult to composeEvents don't offer the ability to be easily queried over timeEvents are a common cause of accidental memory leaksEvents do not have a standard pattern for signaling completionEvents provide almost no help for concurrency or multithreaded applications. e.g. To raise an event on a separate thread requires you to do all of the plumbingRx looks to solve these problems. Here I will introduce you to the building blocks and some basic types that make up Rx.

m