UFRAME
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);
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