Merge pull request #104 from tmickel/feature/io

VM "I/O devices"; clock, mouse as demo
This commit is contained in:
Tim Mickel 2016-08-16 15:59:14 -04:00 committed by GitHub
commit fd5d85ed73
8 changed files with 151 additions and 2 deletions

View file

@ -88,6 +88,24 @@ window.onload = function() {
workspace.reportValue(data.id, data.value);
});
// Feed mouse events as VM I/O events.
document.addEventListener('mousemove', function (e) {
var rect = canvas.getBoundingClientRect();
var coordinates = {
x: e.clientX - rect.left - rect.width / 2,
y: e.clientY - rect.top - rect.height / 2
};
window.vm.postIOData('mouse', coordinates);
});
canvas.addEventListener('mousedown', function (e) {
window.vm.postIOData('mouse', {isDown: true});
e.preventDefault();
});
canvas.addEventListener('mouseup', function (e) {
window.vm.postIOData('mouse', {isDown: false});
e.preventDefault();
});
// Run threads
vm.start();

View file

@ -0,0 +1,43 @@
function Scratch3SensingBlocks(runtime) {
/**
* The runtime instantiating this block package.
* @type {Runtime}
*/
this.runtime = runtime;
}
/**
* Retrieve the block primitives implemented by this package.
* @return {Object.<string, Function>} Mapping of opcode to Function.
*/
Scratch3SensingBlocks.prototype.getPrimitives = function() {
return {
'sensing_timer': this.getTimer,
'sensing_resettimer': this.resetTimer,
'sensing_mousex': this.getMouseX,
'sensing_mousey': this.getMouseY,
'sensing_mousedown': this.getMouseDown
};
};
Scratch3SensingBlocks.prototype.getTimer = function (args, util) {
return util.ioQuery('clock', 'projectTimer');
};
Scratch3SensingBlocks.prototype.resetTimer = function (args, util) {
util.ioQuery('clock', 'resetProjectTimer');
};
Scratch3SensingBlocks.prototype.getMouseX = function (args, util) {
return util.ioQuery('mouse', 'getX');
};
Scratch3SensingBlocks.prototype.getMouseY = function (args, util) {
return util.ioQuery('mouse', 'getY');
};
Scratch3SensingBlocks.prototype.getMouseDown = function (args, util) {
return util.ioQuery('mouse', 'getIsDown');
};
module.exports = Scratch3SensingBlocks;

View file

@ -77,7 +77,14 @@ var execute = function (sequencer, thread) {
startBranch: function (branchNum) {
sequencer.stepToBranch(thread, branchNum);
},
target: target
target: target,
ioQuery: function (device, func, args) {
// Find the I/O device and execute the query/function call.
if (runtime.ioDevices[device] && runtime.ioDevices[device][func]) {
var devObject = runtime.ioDevices[device];
return devObject[func].call(devObject, args);
}
}
});
// Deal with any reported value.

View file

@ -3,12 +3,17 @@ var Sequencer = require('./sequencer');
var Thread = require('./thread');
var util = require('util');
// Virtual I/O devices.
var Clock = require('../io/clock');
var Mouse = require('../io/mouse');
var defaultBlockPackages = {
'scratch3_control': require('../blocks/scratch3_control'),
'scratch3_event': require('../blocks/scratch3_event'),
'scratch3_looks': require('../blocks/scratch3_looks'),
'scratch3_motion': require('../blocks/scratch3_motion'),
'scratch3_operators': require('../blocks/scratch3_operators')
'scratch3_operators': require('../blocks/scratch3_operators'),
'scratch3_sensing': require('../blocks/scratch3_sensing')
};
/**
@ -43,6 +48,11 @@ function Runtime (targets) {
*/
this._primitives = {};
this._registerBlockPackages();
this.ioDevices = {
'clock': new Clock(),
'mouse': new Mouse()
};
}
/**

View file

@ -101,6 +101,17 @@ VirtualMachine.prototype.animationFrame = function () {
this.runtime.animationFrame();
};
/**
* Post I/O data to the virtual devices.
* @param {?string} device Name of virtual I/O device.
* @param {Object} data Any data object to post to the I/O device.
*/
VirtualMachine.prototype.postIOData = function (device, data) {
if (this.runtime.ioDevices[device]) {
this.runtime.ioDevices[device].postData(data);
}
};
/*
* Worker handlers: for all public methods available above,
* we must also provide a message handler in case the VM is run
@ -140,6 +151,9 @@ if (ENV_WORKER) {
case 'animationFrame':
self.vmInstance.animationFrame();
break;
case 'postIOData':
self.vmInstance.postIOData(messageData.device, messageData.data);
break;
default:
if (e.data.id == 'RendererConnected') {
//initRenderWorker();

16
src/io/clock.js Normal file
View file

@ -0,0 +1,16 @@
var Timer = require('../util/timer');
function Clock () {
this._projectTimer = new Timer();
this._projectTimer.start();
}
Clock.prototype.projectTimer = function () {
return this._projectTimer.timeElapsed() / 1000;
};
Clock.prototype.resetProjectTimer = function () {
this._projectTimer.start();
};
module.exports = Clock;

33
src/io/mouse.js Normal file
View file

@ -0,0 +1,33 @@
var MathUtil = require('../util/math-util');
function Mouse () {
this._x = 0;
this._y = 0;
this._isDown = false;
}
Mouse.prototype.postData = function(data) {
if (data.x) {
this._x = data.x;
}
if (data.y) {
this._y = data.y;
}
if (typeof data.isDown !== 'undefined') {
this._isDown = data.isDown;
}
};
Mouse.prototype.getX = function () {
return MathUtil.clamp(this._x, -240, 240);
};
Mouse.prototype.getY = function () {
return MathUtil.clamp(-this._y, -180, 180);
};
Mouse.prototype.getIsDown = function () {
return this._isDown;
};
module.exports = Mouse;

View file

@ -51,6 +51,14 @@ VirtualMachine.prototype.getPlaygroundData = function () {
this.vmWorker.postMessage({method: 'getPlaygroundData'});
};
VirtualMachine.prototype.postIOData = function (device, data) {
this.vmWorker.postMessage({
method: 'postIOData',
device: device,
data: data
});
};
VirtualMachine.prototype.start = function () {
this.vmWorker.postMessage({method: 'start'});
};