I am trying to set up an update cycle for a simple game that is tailored to the observed ones. Top-level components - a model that accepts input commands and makes updates; and a view that displays the received updates and inputs. In isolation, both work fine, the problematic part combines them, as they depend on each other.
With the simplification of the following components:
var view = function (updates) {
return Rx.Observable.fromArray([1,2,3]);
};
var model = function (inputs) {
return inputs.map(function (i) { return i * 10; });
};
The way I put things together is this:
var inputBuffer = new Rx.Subject();
var updates = model(inputBuffer);
var inputs = view(updates);
updates.subscribe(
function (i) { console.log(i); },
function (e) { console.log("Error: " + e); },
function () { console.log("Completed"); }
);
inputs.subscribe(inputBuffer);
That is, I add a topic as a placeholder for the input stream and attach a model to it. Then, after the view is constructed, I pass the actual inputs of the placeholder object, thereby closing the loop.
, -. , , . publish() defer() - ?
: , , . "", , . , , , , . , , - ...
var left = 'left';
var right = 'right';
var flip = function (side) {
if (side === left) {
return right;
} else {
return left;
}
};
var nearby = function (target, radius) {
return function (position) {
var min = target - radius;
var max = target + radius;
return position >= min && position <= max;
};
};
var initScan = function (values, init, updater) {
var initValue = Rx.Observable.return(init);
var restValues = values.scan(init, updater);
return initValue.concat(restValues);
};
var process = function (inputs) {
var update = function(current, input) {
return flip(current);
};
return initScan(inputs, left, update);
};
var display = function (states) {
var clicks = Rx.Observable.interval(800)
.map(function (v) {return (v * 5) % 30; })
.do(function (v) { console.log("Shooting at: " + v)})
.publish();
clicks.connect();
var targetPos = states.map(function (state) {
return state === left ? 5 : 25;
});
return targetPos.flatMapLatest(function (target) {
return clicks
.filter(nearby(target, 10))
.map(function (pos) { return "HIT! (@ "+ pos +")"; })
.do(console.log);
});
};
var feedback = function (process, display) {
var inputBuffer = new Rx.Subject(),
updates = process(inputBuffer),
inputs = display(updates);
inputs.subscribe(inputBuffer);
};
feedback(process, display);