Merge branch 'LLK/master'
This commit is contained in:
commit
ba40cd3396
24 changed files with 764 additions and 698 deletions
|
@ -1,9 +1,16 @@
|
|||
Scratch HTML5 Player
|
||||
# Scratch HTML5 Player
|
||||
|
||||
This project aims to create a Scratch Player in HTML5. Scratch is currently implemented with Actionscript 3 and requires the Flash Player version 10.2. Since Flash does not run on iOS (iPads, iPods, etc) and newer Android devices, we would like to have an HTML5 version to display (but not edit) projects on mobile devices. Scratch projects played in the HTML5 player should look and behave as closely as possible to the way they look and behave when played by the Flash player. We will not be accepting pull requests for new features that don't already exist in the Flash based Scratch project player.
|
||||
|
||||
There are a few github issues created that represent some of the missing features. At this point, the HTML5 player is about 40% complete and can run some simple projects. Running the HTML5 player on your own website, or locally, you will need to have PHP so that the proxy.php file can be used to load assets from the same domain. This is done to be compatible with Javascript security models in today's browsers. To test the HTML5 player against the Flash player you can use the compare.html web page.
|
||||
There are a few github issues created that represent some of the missing features. At this point, the HTML5 player is about 40% complete and can run some simple projects.
|
||||
|
||||
Unimplementable Features on iOS: Image effects for whirl, fisheye, mosaic, and pixelate. Sound and video input for loudness, video motion, and touching colors from the video.
|
||||
|
||||
More documentation will be added as time permits. Thanks for contributing, and Scratch On!
|
||||
|
||||
## Installation
|
||||
|
||||
Running the HTML5 player on your own website, or locally, you will need to have
|
||||
PHP so that the `proxy.php` file can be used to load assets from the same domain. This is done to be compatible with Javascript security models in today's browsers. To test the HTML5 player against the Flash player you can use the compare.html web page.
|
||||
|
||||
See the file `TESTING.md` for more details.
|
45
TESTING.md
Normal file
45
TESTING.md
Normal file
|
@ -0,0 +1,45 @@
|
|||
Running the HTML5 player on your own website, or locally, you will need to have
|
||||
PHP so that the `proxy.php` file can be used to load assets from the same domain. This is done to be compatible with Javascript security models in today's browsers. To test the HTML5 player against the Flash player you can use the compare.html web page.
|
||||
|
||||
# Ubuntu
|
||||
|
||||
If you're using Ubuntu, you can follow the following steps to set up the proxy correctly. You'll need to type the following commands in Terminal.
|
||||
|
||||
Install PHP and Apache for running the proxy file:
|
||||
|
||||
$ sudo apt-get install apache2 php5
|
||||
|
||||
Fork this repository on Github, and then clone it into your home folder somewhere (replacing `<username>` with your Github username):
|
||||
|
||||
$ git clone https://github.com/<username>/scratch-html5
|
||||
|
||||
We'd like to add a new localhost domain, so that we can access the player from our web browser. Something like `scratch.localhost`. Run this command to edit the `/etc/hosts` file:
|
||||
|
||||
$ sudo nano /etc/hosts
|
||||
|
||||
Add the following line:
|
||||
|
||||
127.0.0.1 scratch.localhost
|
||||
|
||||
Use <key>Ctrl-O</key>, <key>Return</key>, <key>Ctrl-X</key> to quit.
|
||||
|
||||
Now we want to add a new Apache configuration for the new domain. Run the following:
|
||||
|
||||
$ cd /etc/apache2/sites-available/
|
||||
$ sudo nano scratch
|
||||
|
||||
And type in the following, replacing `user` with your username, and making sure the `DocumentRoot` matches where you cloned the repository earlier:
|
||||
|
||||
<VirtualHost *:80>
|
||||
ServerName scratch.localhost
|
||||
DocumentRoot /home/user/scratch-html5
|
||||
</VirtualHost>
|
||||
|
||||
Finally, run the following commands to enable the site:
|
||||
|
||||
$ sudo a2ensite scratch
|
||||
$ sudo service apache2 reload
|
||||
|
||||
Now when you go to <http://scratch.localhost/>, the project should play. If you get a "Forbidden" error message, you may need to check the permissions of the folders that the player code is in.
|
||||
|
||||
Now you can go fix bugs in the HTML5 player!
|
|
@ -55,14 +55,16 @@ header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
|
|||
};
|
||||
|
||||
// Pass in the cloud token for the project
|
||||
if(window.getCloudToken)
|
||||
if (window.getCloudToken) {
|
||||
flashvars.cloud_token = encodeURIComponent(getCloudToken());
|
||||
}
|
||||
|
||||
var params = {
|
||||
allowscriptaccess: 'always',
|
||||
allowfullscreen: 'false',
|
||||
wmode: 'direct',
|
||||
menu: 'false'};
|
||||
menu: 'false'
|
||||
};
|
||||
|
||||
var flashPlayer = null;
|
||||
//var swf_url = "http://cdn.scratch.mit.edu/scratchr2/static/Scratch.swf";
|
||||
|
@ -71,7 +73,7 @@ header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
|
|||
"http://cdn.scratch.mit.edu/scratchr2/static/expressInstall.swf",
|
||||
flashvars, params, null, function(e) {
|
||||
$('#flashScratch').css('visibility', 'visible');
|
||||
if(e.success) flashPlayer = e.ref;
|
||||
if (e.success) flashPlayer = e.ref;
|
||||
});
|
||||
|
||||
$('#trigger_green_flag, #greenSlide').click(function() {
|
||||
|
@ -104,7 +106,6 @@ header("Expires: Sat, 26 Jul 1997 05:00:00 GMT"); // Date in the past
|
|||
</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="info">Loading...</div>
|
||||
|
||||
<button id="trigger_green_flag">Green flag</button>
|
||||
|
|
25
js/IO.js
25
js/IO.js
|
@ -33,20 +33,18 @@ var IO = function() {
|
|||
this.asset_suffix = '/get/';
|
||||
this.soundbank_base = 'soundbank/';
|
||||
this.spriteLayerCount = 0;
|
||||
}
|
||||
};
|
||||
|
||||
IO.prototype.loadProject = function(project_id) {
|
||||
var runningIO = this;
|
||||
$.getJSON(this.project_base + project_id + this.project_suffix,
|
||||
function(data) {
|
||||
$.getJSON(this.project_base + project_id + this.project_suffix, function(data) {
|
||||
runningIO.data = data;
|
||||
runningIO.makeObjects();
|
||||
runningIO.loadThreads();
|
||||
runningIO.loadNotesDrums();
|
||||
runtime.loadStart(); // Try to run the project.
|
||||
}
|
||||
);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
IO.prototype.soundRequest = function(sound, sprite) {
|
||||
var request = new XMLHttpRequest();
|
||||
|
@ -63,9 +61,9 @@ IO.prototype.soundRequest = function(sound, sprite) {
|
|||
data[i] = samples[i];
|
||||
}
|
||||
sprite.soundsLoaded++;
|
||||
}
|
||||
};
|
||||
request.send();
|
||||
}
|
||||
};
|
||||
|
||||
IO.prototype.loadNotesDrums = function() {
|
||||
var self = this;
|
||||
|
@ -81,10 +79,10 @@ IO.prototype.loadNotesDrums = function() {
|
|||
var soundBuffer = waveData.readBytes(2 * info.sampleCount);
|
||||
Instr.samples[name] = soundBuffer;
|
||||
Instr.wavsLoaded++;
|
||||
}
|
||||
};
|
||||
request.send();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
IO.prototype.makeObjects = function() {
|
||||
// Create the stage
|
||||
|
@ -92,7 +90,6 @@ IO.prototype.makeObjects = function() {
|
|||
runtime.stage.attach(runtime.scene);
|
||||
runtime.stage.attachPenLayer(runtime.scene);
|
||||
runtime.stage.loadSounds();
|
||||
|
||||
// Create the sprites and watchers
|
||||
$.each(this.data.children.concat(this.data.lists), function i(index, obj) {
|
||||
var newSprite;
|
||||
|
@ -111,7 +108,7 @@ IO.prototype.makeObjects = function() {
|
|||
if (!obj.cmd && !obj.listName)
|
||||
newSprite.loadSounds();
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
IO.prototype.loadThreads = function() {
|
||||
var target = runtime.stage;
|
||||
|
@ -129,7 +126,7 @@ IO.prototype.loadThreads = function() {
|
|||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Returns the number sprite we are rendering
|
||||
// used for initial layering assignment
|
||||
|
@ -137,4 +134,4 @@ IO.prototype.getCount = function() {
|
|||
var rv = this.spriteLayerCount;
|
||||
this.spriteLayerCount++;
|
||||
return rv;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -30,7 +30,7 @@ var Block = function(opAndArgs, optionalSubstack) {
|
|||
this.nextBlock = null;
|
||||
this.tmp = -1;
|
||||
interp.fixArgs(this);
|
||||
}
|
||||
};
|
||||
|
||||
var Thread = function(block, target) {
|
||||
this.nextBlock = block; // next block to run; null when thread is finished
|
||||
|
@ -40,7 +40,7 @@ var Thread = function(block, target) {
|
|||
this.tmp = null; // used for thread operations like Timer
|
||||
this.tmpObj = []; // used for Sprite operations like glide
|
||||
this.firstTime = true;
|
||||
}
|
||||
};
|
||||
|
||||
var Interpreter = function() {
|
||||
// Interpreter state
|
||||
|
@ -54,7 +54,7 @@ var Interpreter = function() {
|
|||
this.yield = false;
|
||||
this.doRedraw = false;
|
||||
this.opCount = 0; // used to benchmark the interpreter
|
||||
}
|
||||
};
|
||||
|
||||
// Utilities for building blocks and sequences of blocks
|
||||
Interpreter.prototype.fixArgs = function(b) {
|
||||
|
@ -66,7 +66,7 @@ Interpreter.prototype.fixArgs = function(b) {
|
|||
if (arg && arg.constructor == Array) {
|
||||
if ((arg.length > 0) && (arg[0].constructor == Array)) {
|
||||
// if first element arg is itself an array, then arg is a substack
|
||||
if(!b.substack) {
|
||||
if (!b.substack) {
|
||||
b.substack = this.makeBlockList(arg);
|
||||
} else {
|
||||
b.substack2 = this.makeBlockList(arg);
|
||||
|
@ -80,7 +80,7 @@ Interpreter.prototype.fixArgs = function(b) {
|
|||
}
|
||||
}
|
||||
b.args = newArgs;
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.makeBlockList = function(blockList) {
|
||||
var firstBlock = null, lastBlock = null;
|
||||
|
@ -91,7 +91,7 @@ Interpreter.prototype.makeBlockList = function(blockList) {
|
|||
lastBlock = b;
|
||||
}
|
||||
return firstBlock;
|
||||
}
|
||||
};
|
||||
|
||||
// The Interpreter proper
|
||||
Interpreter.prototype.stepThreads = function() {
|
||||
|
@ -121,11 +121,11 @@ Interpreter.prototype.stepThreads = function() {
|
|||
}
|
||||
this.currentMSecs = this.timer.time();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.stepActiveThread = function() {
|
||||
// Run the active thread until it yields.
|
||||
if(typeof(this.activeThread) == 'undefined') {
|
||||
if (typeof(this.activeThread) == 'undefined') {
|
||||
return;
|
||||
}
|
||||
var b = this.activeThread.nextBlock;
|
||||
|
@ -149,7 +149,7 @@ Interpreter.prototype.stepActiveThread = function() {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.toggleThread = function(b, targetObj) {
|
||||
var newThreads = [], wasRunning = false;
|
||||
|
@ -161,15 +161,15 @@ Interpreter.prototype.toggleThread = function(b, targetObj) {
|
|||
}
|
||||
}
|
||||
this.threads = newThreads;
|
||||
if(!wasRunning) {
|
||||
if (!wasRunning) {
|
||||
this.startThread(b, targetObj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Interpreter.prototype.startThread = function(b, targetObj) {
|
||||
this.activeThread = new Thread(b, targetObj);
|
||||
this.threads.push(this.activeThread);
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.restartThread = function(b, targetObj) {
|
||||
// used by broadcast; stop any thread running on b, then start a new thread on b
|
||||
|
@ -184,7 +184,7 @@ Interpreter.prototype.restartThread = function(b, targetObj) {
|
|||
if (!wasRunning) {
|
||||
this.threads.push(newThread);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.arg = function(block, index) {
|
||||
var arg = block.args[index];
|
||||
|
@ -193,11 +193,11 @@ Interpreter.prototype.arg = function(block, index) {
|
|||
return arg.primFcn(arg); // expression
|
||||
}
|
||||
return arg;
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.targetSprite = function() {
|
||||
return this.activeThread.target;
|
||||
}
|
||||
};
|
||||
|
||||
// Timer
|
||||
Interpreter.prototype.startTimer = function(secs) {
|
||||
|
@ -206,7 +206,7 @@ Interpreter.prototype.startTimer = function(secs) {
|
|||
this.activeThread.tmp = this.currentMSecs + waitMSecs; // end time in milliseconds
|
||||
this.activeThread.firstTime = false;
|
||||
this.yield = true;
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.checkTimer = function() {
|
||||
// check for timer expiration and clean up if expired. return true when expired
|
||||
|
@ -219,11 +219,11 @@ Interpreter.prototype.checkTimer = function() {
|
|||
this.yield = true;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.redraw = function() {
|
||||
this.doRedraw = true;
|
||||
}
|
||||
};
|
||||
|
||||
// Primitive operations
|
||||
Interpreter.prototype.initPrims = function() {
|
||||
|
@ -231,14 +231,14 @@ Interpreter.prototype.initPrims = function() {
|
|||
this.primitiveTable['whenGreenFlag'] = this.primNoop;
|
||||
this.primitiveTable['whenKeyPressed'] = this.primNoop;
|
||||
this.primitiveTable['whenClicked'] = this.primNoop;
|
||||
this.primitiveTable['if'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b) };
|
||||
this.primitiveTable['doForever'] = function(b) { interp.startSubstack(b, true) };
|
||||
this.primitiveTable['if'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b); };
|
||||
this.primitiveTable['doForever'] = function(b) { interp.startSubstack(b, true); };
|
||||
this.primitiveTable['doForeverIf'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b, true); else interp.yield = true; };
|
||||
this.primitiveTable['doIf'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b); };
|
||||
this.primitiveTable['doRepeat'] = this.primRepeat;
|
||||
this.primitiveTable['doIfElse'] = function(b) { if (interp.arg(b, 0)) interp.startSubstack(b); else interp.startSubstack(b, false, true); };
|
||||
this.primitiveTable['doWaitUntil'] = function(b) { if (!interp.arg(b, 0)) interp.yield = true };
|
||||
this.primitiveTable['doUntil'] = function(b) { if (!interp.arg(b, 0)) interp.startSubstack(b, true) };
|
||||
this.primitiveTable['doWaitUntil'] = function(b) { if (!interp.arg(b, 0)) interp.yield = true; };
|
||||
this.primitiveTable['doUntil'] = function(b) { if (!interp.arg(b, 0)) interp.startSubstack(b, true); };
|
||||
this.primitiveTable['doReturn'] = function(b) { interp.activeThread = new Thread(null); };
|
||||
this.primitiveTable['stopAll'] = function(b) { interp.activeThread = new Thread(null); interp.threads = []; }
|
||||
this.primitiveTable['whenIReceive'] = this.primNoop;
|
||||
|
@ -247,26 +247,26 @@ Interpreter.prototype.initPrims = function() {
|
|||
this.primitiveTable['wait:elapsed:from:'] = this.primWait;
|
||||
|
||||
// added by John:
|
||||
this.primitiveTable['showBubble'] = function(b) { console.log(interp.arg(b, 1)) }
|
||||
this.primitiveTable['timerReset'] = function(b) {interp.timerBase = (new Date()).getTime() }
|
||||
this.primitiveTable['timer'] = function(b) {return ((new Date()).getTime() - interp.timerBase) / 1000 }
|
||||
this.primitiveTable['showBubble'] = function(b) { console.log(interp.arg(b, 1)); };
|
||||
this.primitiveTable['timerReset'] = function(b) { interp.timerBase = Date.now(); };
|
||||
this.primitiveTable['timer'] = function(b) { return (Date.now() - interp.timerBase) / 1000; };
|
||||
|
||||
new Primitives().addPrimsTo(this.primitiveTable);
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.timerBase = (new Date()).getTime();
|
||||
Interpreter.prototype.timerBase = Date.now();
|
||||
Interpreter.prototype.lookupPrim = function(op) {
|
||||
var fcn = interp.primitiveTable[op];
|
||||
if (fcn == null) fcn = function(b) { console.log('not implemented: ' + b.op) }
|
||||
if (fcn == null) fcn = function(b) { console.log('not implemented: ' + b.op); };
|
||||
return fcn;
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.primNoop = function(b) { console.log(b.op); }
|
||||
Interpreter.prototype.primNoop = function(b) { console.log(b.op); };
|
||||
|
||||
Interpreter.prototype.primWait = function(b) {
|
||||
if (interp.activeThread.firstTime) interp.startTimer(interp.arg(b, 0));
|
||||
else interp.checkTimer();
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.primRepeat = function(b) {
|
||||
if (b.tmp == -1) {
|
||||
|
@ -280,14 +280,14 @@ Interpreter.prototype.primRepeat = function(b) {
|
|||
b.tmp = -1;
|
||||
b = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.broadcast = function(b, waitFlag) {
|
||||
var pair;
|
||||
if (interp.activeThread.firstTime) {
|
||||
var receivers = [];
|
||||
var msg = String(interp.arg(b, 0)).toLowerCase();
|
||||
var findReceivers = function (stack, target) {
|
||||
var findReceivers = function(stack, target) {
|
||||
if ((stack.op == "whenIReceive") && (stack.args[0].toLowerCase() == msg)) {
|
||||
receivers.push([stack, target]);
|
||||
}
|
||||
|
@ -310,7 +310,7 @@ Interpreter.prototype.broadcast = function(b, waitFlag) {
|
|||
} else {
|
||||
interp.yield = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.isRunning = function(b) {
|
||||
for (t in interp.threads) {
|
||||
|
@ -319,7 +319,7 @@ Interpreter.prototype.isRunning = function(b) {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
Interpreter.prototype.startSubstack = function(b, isLoop, secondSubstack) {
|
||||
// Start the substack of a control structure command such as if or forever.
|
||||
|
@ -327,9 +327,9 @@ Interpreter.prototype.startSubstack = function(b, isLoop, secondSubstack) {
|
|||
b.isLoop = true;
|
||||
this.activeThread.stack.push(b); // remember the block that started the substack
|
||||
}
|
||||
if(!secondSubstack) {
|
||||
if (!secondSubstack) {
|
||||
this.activeThread.nextBlock = b.substack;
|
||||
} else {
|
||||
this.activeThread.nextBlock = b.substack2;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -33,7 +33,7 @@ var Reporter = function(data) {
|
|||
this.el = null; // jQuery Element for the outer box
|
||||
this.valueEl = null; // jQ element containing the reporter value
|
||||
this.slider = null; // slider jQ element
|
||||
}
|
||||
};
|
||||
|
||||
Reporter.prototype.attach = function(scene) {
|
||||
switch (this.mode) {
|
||||
|
@ -68,13 +68,13 @@ Reporter.prototype.attach = function(scene) {
|
|||
this.valueEl.css('background-color', 'rgb(' + cR + ',' + cG + ',' + cB + ')');
|
||||
this.el.css('display', this.visible ? 'inline-block' : 'none');
|
||||
scene.append(this.el);
|
||||
}
|
||||
};
|
||||
|
||||
Reporter.prototype.update = function() {
|
||||
this.el.css('display', this.visible ? 'inline-block' : 'none');
|
||||
if (!this.visible) return;
|
||||
|
||||
var newValue ='';
|
||||
var newValue = '';
|
||||
var target = runtime.spriteNamed(this.target);
|
||||
switch (this.cmd) {
|
||||
case 'getVar:':
|
||||
|
@ -104,20 +104,21 @@ Reporter.prototype.update = function() {
|
|||
break;
|
||||
}
|
||||
this.valueEl.html(newValue);
|
||||
if (this.mode == 3)
|
||||
if (this.mode == 3) {
|
||||
this.slider.val(parseInt(newValue));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Reporter.prototype.updateLayer = function() {
|
||||
this.el.css('z-index', this.z);
|
||||
}
|
||||
};
|
||||
|
||||
Reporter.prototype.changeSlider = function() {
|
||||
var newValue = parseInt($(this).val());
|
||||
var target = runtime.spriteNamed($(this).attr('data-target'));
|
||||
var variable = $(this).attr('data-var');
|
||||
target.variables[variable] = newValue;
|
||||
}
|
||||
};
|
||||
|
||||
var List = function(data) {
|
||||
this.contents = data.contents;
|
||||
|
@ -171,7 +172,7 @@ List.prototype.attach = function(scene) {
|
|||
this.el.height(this.height);
|
||||
this.el.css('z-index', this.z);
|
||||
this.el.css('display', this.visible ? 'inline-block' : 'none');
|
||||
}
|
||||
};
|
||||
|
||||
List.prototype.update = function(){
|
||||
this.el.css('display', this.visible ? 'inline-block' : 'none');
|
||||
|
@ -191,4 +192,4 @@ List.prototype.update = function(){
|
|||
|
||||
List.prototype.updateLayer = function() {
|
||||
this.el.css('z-index', this.z);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -35,7 +35,7 @@ var Runtime = function() {
|
|||
this.audioPlaying = [];
|
||||
this.notesPlaying = [];
|
||||
this.projectLoaded = false;
|
||||
}
|
||||
};
|
||||
|
||||
// Initializer for the drawing and audio contexts.
|
||||
Runtime.prototype.init = function() {
|
||||
|
@ -44,7 +44,7 @@ Runtime.prototype.init = function() {
|
|||
this.audioContext = new AudioContext();
|
||||
this.audioGain = this.audioContext.createGainNode();
|
||||
this.audioGain.connect(runtime.audioContext.destination);
|
||||
}
|
||||
};
|
||||
|
||||
// Load start waits for the stage and the sprites to be loaded, without
|
||||
// hanging the browser. When the loading is finished, we begin the step
|
||||
|
@ -69,7 +69,7 @@ Runtime.prototype.loadStart = function() {
|
|||
$('#info').html("Loaded!");
|
||||
setInterval(this.step, 33);
|
||||
this.projectLoaded = true;
|
||||
}
|
||||
};
|
||||
|
||||
Runtime.prototype.greenFlag = function() {
|
||||
if (this.projectLoaded) {
|
||||
|
@ -78,7 +78,7 @@ Runtime.prototype.greenFlag = function() {
|
|||
interp.primitiveTable.timerReset();
|
||||
this.startGreenFlags();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Runtime.prototype.stopAll = function() {
|
||||
interp.activeThread = new Thread(null);
|
||||
|
@ -86,10 +86,11 @@ Runtime.prototype.stopAll = function() {
|
|||
stopAllSounds();
|
||||
// Hide reporters
|
||||
for (var s = 0; s < runtime.sprites.length; s++) {
|
||||
if (typeof runtime.sprites[s].hideBubble == 'function')
|
||||
if (typeof runtime.sprites[s].hideBubble == 'function') {
|
||||
runtime.sprites[s].hideBubble();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Step method for execution - called every 33 milliseconds
|
||||
Runtime.prototype.step = function() {
|
||||
|
@ -97,7 +98,7 @@ Runtime.prototype.step = function() {
|
|||
for (var r = 0; r < runtime.reporters.length; r++) {
|
||||
runtime.reporters[r].update();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Stack functions -- push and remove stacks
|
||||
// to be run by the interpreter as threads.
|
||||
|
@ -106,7 +107,7 @@ Runtime.prototype.allStacksDo = function(f) {
|
|||
var stack;
|
||||
for (var i = runtime.sprites.length-1; i >= 0; i--) {
|
||||
var o = runtime.sprites[i];
|
||||
if(typeof(o) == 'object' && o.constructor == Sprite) {
|
||||
if (typeof(o) == 'object' && o.constructor == Sprite) {
|
||||
$.each(o.stacks, function(index, stack) {
|
||||
f(stack, o);
|
||||
});
|
||||
|
@ -115,7 +116,7 @@ Runtime.prototype.allStacksDo = function(f) {
|
|||
$.each(stage.stacks, function(index, stack) {
|
||||
f(stack, stage);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// Hat triggers
|
||||
Runtime.prototype.startGreenFlags = function() {
|
||||
|
@ -123,7 +124,7 @@ Runtime.prototype.startGreenFlags = function() {
|
|||
if (stack.op == 'whenGreenFlag') interp.toggleThread(stack, target);
|
||||
}
|
||||
this.allStacksDo(startIfGreenFlag);
|
||||
}
|
||||
};
|
||||
|
||||
Runtime.prototype.startKeyHats = function(ch) {
|
||||
var keyName = null;
|
||||
|
@ -140,30 +141,30 @@ Runtime.prototype.startKeyHats = function(ch) {
|
|||
if (ch == 32) keyName = "space";
|
||||
|
||||
if (keyName == null) return;
|
||||
var startMatchingKeyHats = function (stack, target) {
|
||||
var startMatchingKeyHats = function(stack, target) {
|
||||
if ((stack.op == "whenKeyPressed") && (stack.args[0] == keyName)) {
|
||||
// Only start the stack if it is not already running
|
||||
if (!interp.isRunning(stack))
|
||||
if (!interp.isRunning(stack)) {
|
||||
interp.toggleThread(stack, target);
|
||||
}
|
||||
}
|
||||
}
|
||||
runtime.allStacksDo(startMatchingKeyHats);
|
||||
}
|
||||
};
|
||||
|
||||
Runtime.prototype.startClickedHats = function(sprite) {
|
||||
function startIfClicked(stack, target) {
|
||||
if(target == sprite && stack.op == "whenClicked") {
|
||||
if(!interp.isRunning(stack))
|
||||
if (target == sprite && stack.op == "whenClicked" && !interp.isRunning(stack)) {
|
||||
interp.toggleThread(stack, target);
|
||||
}
|
||||
}
|
||||
runtime.allStacksDo(startIfClicked);
|
||||
}
|
||||
};
|
||||
|
||||
// Returns true if a key is pressed.
|
||||
Runtime.prototype.keyIsDown = function(ch) {
|
||||
return this.keysDown[ch] || false;
|
||||
}
|
||||
};
|
||||
|
||||
// Sprite named -- returns one of the sprites on the stage.
|
||||
Runtime.prototype.spriteNamed = function(n) {
|
||||
|
@ -176,7 +177,22 @@ Runtime.prototype.spriteNamed = function(n) {
|
|||
}
|
||||
});
|
||||
return selected_sprite;
|
||||
}
|
||||
};
|
||||
|
||||
Runtime.prototype.getTimeString = function(which) {
|
||||
// Return local time properties.
|
||||
var now = new Date();
|
||||
switch (which) {
|
||||
case 'hour': return now.getHours();
|
||||
case 'minute': return now.getMinutes();
|
||||
case 'second': return now.getSeconds();
|
||||
case 'year': return now.getFullYear(); // four digit year (e.g. 2012)
|
||||
case 'month': return now.getMonth() + 1; // 1-12
|
||||
case 'date': return now.getDate(); // 1-31
|
||||
case 'day of week': return now.getDay() + 1; // 1-7, where 1 is Sunday
|
||||
}
|
||||
return ''; // shouldn't happen
|
||||
};
|
||||
|
||||
// Reassigns z-indices for layer functions
|
||||
Runtime.prototype.reassignZ = function(target, move) {
|
||||
|
@ -193,7 +209,7 @@ Runtime.prototype.reassignZ = function(target, move) {
|
|||
if (move == null) {
|
||||
// Move to the front
|
||||
this.sprites.splice(this.sprites.length, 0, target);
|
||||
} else if (oldIndex - move >= 0 && oldIndex - move < this.sprites.length+1) {
|
||||
} else if (oldIndex - move >= 0 && oldIndex - move < this.sprites.length + 1) {
|
||||
// Move to the new position
|
||||
this.sprites.splice(oldIndex - move, 0, target);
|
||||
} else {
|
||||
|
@ -208,4 +224,4 @@ Runtime.prototype.reassignZ = function(target, move) {
|
|||
sprite.updateLayer();
|
||||
newZ++;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
'use strict';
|
||||
|
||||
var runtime, interp, io, iosAudioActive = false;
|
||||
$(function () {
|
||||
$(function() {
|
||||
runtime = new Runtime();
|
||||
runtime.init();
|
||||
|
||||
|
|
106
js/Sprite.js
106
js/Sprite.js
|
@ -22,12 +22,12 @@
|
|||
'use strict';
|
||||
|
||||
var Sprite = function(data) {
|
||||
if(!this.data) {
|
||||
if (!this.data) {
|
||||
this.data = data;
|
||||
}
|
||||
|
||||
// Public variables used for Scratch-accessible data.
|
||||
this.visible = (typeof(this.data.visible) == "undefined") ? true : data.visible;
|
||||
this.visible = typeof(this.data.visible) == "undefined" ? true : data.visible;
|
||||
|
||||
this.scratchX = data.scratchX || 0;
|
||||
this.scratchY = data.scratchY || 0;
|
||||
|
@ -94,7 +94,7 @@ var Sprite = function(data) {
|
|||
|
||||
// Stacks to be pushed to the interpreter and run
|
||||
this.stacks = [];
|
||||
}
|
||||
};
|
||||
|
||||
// Attaches a Sprite (<img>) to a Scratch scene
|
||||
Sprite.prototype.attach = function(scene) {
|
||||
|
@ -109,7 +109,7 @@ Sprite.prototype.attach = function(scene) {
|
|||
sprite.costumesLoaded += 1;
|
||||
sprite.updateCostume();
|
||||
|
||||
$(sprite.textures[c]).css('display', (sprite.currentCostumeIndex == c) ? 'inline' : 'none');
|
||||
$(sprite.textures[c]).css('display', sprite.currentCostumeIndex == c ? 'inline' : 'none');
|
||||
$(sprite.textures[c]).css('position', 'absolute').css('left', '0px').css('top', '0px');
|
||||
$(sprite.textures[c]).bind('dragstart', function(evt) { evt.preventDefault(); })
|
||||
.bind('selectstart', function(evt) { evt.preventDefault(); })
|
||||
|
@ -139,21 +139,20 @@ Sprite.prototype.attach = function(scene) {
|
|||
this.talkBubble.append(this.talkBubbleStyler);
|
||||
|
||||
runtime.scene.append(this.talkBubble);
|
||||
}
|
||||
};
|
||||
|
||||
// Load sounds from the server and buffer them
|
||||
Sprite.prototype.loadSounds = function() {
|
||||
var spr = this;
|
||||
$.each(this.sounds, function (index, sound) {
|
||||
$.each(this.sounds, function(index, sound) {
|
||||
io.soundRequest(sound, spr);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// True when all the costumes have been loaded
|
||||
Sprite.prototype.isLoaded = function() {
|
||||
return (this.costumesLoaded == this.costumes.length
|
||||
&& this.soundsLoaded == Object.keys(this.sounds).length);
|
||||
}
|
||||
return this.costumesLoaded == this.costumes.length && this.soundsLoaded == Object.keys(this.sounds).length;
|
||||
};
|
||||
|
||||
// Step methods
|
||||
Sprite.prototype.showCostume = function(costume) {
|
||||
|
@ -167,33 +166,33 @@ Sprite.prototype.showCostume = function(costume) {
|
|||
this.currentCostumeIndex = costume;
|
||||
}
|
||||
this.updateCostume();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.indexOfCostumeNamed = function(name) {
|
||||
for(var i in this.costumes) {
|
||||
for (var i in this.costumes) {
|
||||
var c = this.costumes[i];
|
||||
if(c['costumeName'] == name) {
|
||||
if (c['costumeName'] == name) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.showCostumeNamed = function(name) {
|
||||
var index = this.indexOfCostumeNamed(name);
|
||||
if(!index) return;
|
||||
if (!index) return;
|
||||
this.showCostume(index);
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.updateCostume = function() {
|
||||
if(!this.textures[this.currentCostumeIndex]) {
|
||||
if (!this.textures[this.currentCostumeIndex]) {
|
||||
this.currentCostumeIndex = 0;
|
||||
}
|
||||
$(this.mesh).css('display', 'none');
|
||||
this.mesh = this.textures[this.currentCostumeIndex];
|
||||
this.updateVisible();
|
||||
this.updateTransform();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.onClick = function(evt) {
|
||||
// TODO - needs work!!
|
||||
|
@ -238,23 +237,24 @@ Sprite.prototype.onClick = function(evt) {
|
|||
$(underElement).click();
|
||||
$(this.mesh).show();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.setVisible = function(v) {
|
||||
this.visible = v;
|
||||
this.updateVisible();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.updateLayer = function() {
|
||||
$(this.mesh).css('z-index', this.z);
|
||||
if (this.talkBubble) this.talkBubble.css('z-index', this.z);
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.updateVisible = function() {
|
||||
$(this.mesh).css('display', (this.visible) ? 'inline' : 'none');
|
||||
if (this.talkBubbleOn)
|
||||
this.talkBubble.css('display', (this.visible) ? 'inline-block' : 'none');
|
||||
}
|
||||
$(this.mesh).css('display', this.visible ? 'inline' : 'none');
|
||||
if (this.talkBubbleOn) {
|
||||
this.talkBubble.css('display', this.visible ? 'inline-block' : 'none');
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.updateTransform = function() {
|
||||
var texture = this.textures[this.currentCostumeIndex];
|
||||
|
@ -305,7 +305,7 @@ Sprite.prototype.updateTransform = function() {
|
|||
}
|
||||
|
||||
this.updateLayer();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.getTalkBubbleXY = function() {
|
||||
var texture = this.textures[this.currentCostumeIndex];
|
||||
|
@ -316,7 +316,7 @@ Sprite.prototype.getTalkBubbleXY = function() {
|
|||
var drawX = this.scratchX + (480 / 2) - rotationCenterX;
|
||||
var drawY = -this.scratchY + (360 / 2) - rotationCenterY;
|
||||
return [drawX + drawWidth, drawY - drawHeight / 2];
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.showBubble = function(text, type) {
|
||||
var xy = this.getTalkBubbleXY();
|
||||
|
@ -329,30 +329,34 @@ Sprite.prototype.showBubble = function(text, type) {
|
|||
|
||||
this.talkBubbleStyler.removeClass('bubble-say');
|
||||
this.talkBubbleStyler.removeClass('bubble-think');
|
||||
if (type == 'say') this.talkBubbleStyler.addClass('bubble-say');
|
||||
else if (type == 'think') this.talkBubbleStyler.addClass('bubble-think');
|
||||
if (type == 'say') {
|
||||
this.talkBubbleStyler.addClass('bubble-say');
|
||||
} else if (type == 'think') {
|
||||
this.talkBubbleStyler.addClass('bubble-think');
|
||||
}
|
||||
|
||||
if (this.visible)
|
||||
if (this.visible) {
|
||||
this.talkBubble.css('display', 'inline-block');
|
||||
}
|
||||
this.talkBubbleBox.html(text);
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.hideBubble = function() {
|
||||
this.talkBubbleOn = false;
|
||||
this.talkBubble.css('display', 'none');
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.setXY = function(x, y) {
|
||||
this.scratchX = x;
|
||||
this.scratchY = y;
|
||||
this.updateTransform();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.setDirection = function(d) {
|
||||
var rotation;
|
||||
d = d % 360
|
||||
if (d < 0) d += 360;
|
||||
this.direction = (d > 180) ? d - 360 : d;
|
||||
this.direction = d > 180 ? d - 360 : d;
|
||||
if (this.rotationStyle == 'normal') {
|
||||
rotation = (this.direction - 90) % 360;
|
||||
} else if (this.rotationStyle == 'leftRight') {
|
||||
|
@ -367,22 +371,22 @@ Sprite.prototype.setDirection = function(d) {
|
|||
}
|
||||
this.rotation = rotation;
|
||||
this.updateTransform();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.setRotationStyle = function(r) {
|
||||
this.rotationStyle = r;
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.getSize = function() {
|
||||
return this.scale * 100;
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.setSize = function(percent) {
|
||||
var newScale = percent / 100.0;
|
||||
newScale = Math.max(0.05, Math.min(newScale, 100));
|
||||
this.scale = newScale;
|
||||
this.updateTransform();
|
||||
}
|
||||
};
|
||||
|
||||
// Move functions
|
||||
Sprite.prototype.keepOnStage = function() {
|
||||
|
@ -398,7 +402,7 @@ Sprite.prototype.keepOnStage = function() {
|
|||
if (myBox.top > edgeBox.bottom) y -= myBox.top - edgeBox.bottom;
|
||||
this.scratchX = x - 240;
|
||||
this.scratchY = 180 - y;
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.getRect = function() {
|
||||
var cImg = this.textures[this.currentCostumeIndex];
|
||||
|
@ -406,7 +410,7 @@ Sprite.prototype.getRect = function() {
|
|||
var y = 180 - this.scratchY - (cImg.height/2.0);
|
||||
var myBox = new Rectangle(x, y, cImg.width, cImg.height);
|
||||
return myBox;
|
||||
}
|
||||
};
|
||||
|
||||
// Pen functions
|
||||
Sprite.prototype.setPenColor = function(c) {
|
||||
|
@ -414,26 +418,29 @@ Sprite.prototype.setPenColor = function(c) {
|
|||
this.penHue = (200 * hsv[0]) / 360 ;
|
||||
this.penShade = 50 * hsv[2]; // not quite right; doesn't account for saturation
|
||||
this.penColorCache = c;
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.setPenHue = function(n) {
|
||||
this.penHue = n % 200;
|
||||
if (this.penHue < 0) this.penHue += 200;
|
||||
this.updateCachedPenColor();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.setPenShade = function(n) {
|
||||
this.penShade = n % 200;
|
||||
if (this.penShade < 0) this.penShade += 200;
|
||||
this.updateCachedPenColor();
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.updateCachedPenColor = function() {
|
||||
var c = Color.fromHSV((this.penHue * 180.0) / 100.0, 1, 1);
|
||||
var shade = (this.penShade > 100) ? 200 - this.penShade : this.penShade; // range 0..100
|
||||
var shade = this.penShade > 100 ? 200 - this.penShade : this.penShade; // range 0..100
|
||||
if (shade < 50) {
|
||||
this.penColorCache = Color.mixRGB(0, c, (10 + shade) / 60.0);
|
||||
} else {
|
||||
this.penColorCache = Color.mixRGB(c, 0xFFFFFF, (shade - 50) / 60);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.stamp = function(canvas, opacity) {
|
||||
var drawWidth = this.textures[this.currentCostumeIndex].width * this.scale;
|
||||
|
@ -447,12 +454,13 @@ Sprite.prototype.stamp = function(canvas, opacity) {
|
|||
canvas.drawImage(this.mesh, -drawWidth/2, -drawHeight/2, drawWidth, drawHeight);
|
||||
canvas.restore();
|
||||
canvas.globalAlpha = 1;
|
||||
}
|
||||
};
|
||||
|
||||
Sprite.prototype.soundNamed = function(name) {
|
||||
if (name in this.sounds && this.sounds[name].buffer)
|
||||
if (name in this.sounds && this.sounds[name].buffer) {
|
||||
return this.sounds[name];
|
||||
else if (name in runtime.stage.sounds && runtime.stage.sounds[name].buffer)
|
||||
} else if (name in runtime.stage.sounds && runtime.stage.sounds[name].buffer) {
|
||||
return runtime.stage.sounds[name];
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
17
js/Stage.js
17
js/Stage.js
|
@ -35,30 +35,27 @@ var Stage = function(data) {
|
|||
this.lineCache = this.lineCanvas.getContext('2d');
|
||||
|
||||
Sprite.call(this, data);
|
||||
}
|
||||
};
|
||||
|
||||
Stage.prototype = Object.create(Sprite.prototype);
|
||||
Stage.prototype.constructor = Stage;
|
||||
|
||||
Stage.prototype.attachPenLayer = function(scene) {
|
||||
if (this.penLayerLoaded)
|
||||
return;
|
||||
if (this.penLayerLoaded) return;
|
||||
this.penLayerLoaded = true;
|
||||
$(this.lineCanvas).css('position', 'absolute');
|
||||
$(this.lineCanvas).css('z-index', '-1');
|
||||
scene.append(this.lineCanvas);
|
||||
}
|
||||
};
|
||||
|
||||
Stage.prototype.isLoaded = function() {
|
||||
return (this.penLayerLoaded
|
||||
&& this.costumesLoaded == this.costumes.length
|
||||
&& this.soundsLoaded == Object.keys(this.sounds).length);
|
||||
}
|
||||
return this.penLayerLoaded && this.costumesLoaded == this.costumes.length && this.soundsLoaded == Object.keys(this.sounds).length;
|
||||
};
|
||||
|
||||
// Pen functions
|
||||
Stage.prototype.clearPenStrokes = function() {
|
||||
this.lineCache.clearRect(0, 0, 480, 360);
|
||||
}
|
||||
};
|
||||
|
||||
Stage.prototype.stroke = function(from, to, width, color) {
|
||||
this.lineCache.lineWidth = width;
|
||||
|
@ -69,4 +66,4 @@ Stage.prototype.stroke = function(from, to, width, color) {
|
|||
this.lineCache.lineTo(to[0] + 240.5, 180.5 - to[1]);
|
||||
this.lineCache.strokeStyle = 'rgb(' + (color >> 16) + ',' + (color >> 8 & 255) + ',' + (color & 255) + ')';
|
||||
this.lineCache.stroke();
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var LooksPrims = function() {}
|
||||
var LooksPrims = function() {};
|
||||
|
||||
LooksPrims.prototype.addPrimsTo = function(primTable) {
|
||||
primTable["show"] = this.primShow;
|
||||
|
@ -47,22 +47,22 @@ LooksPrims.prototype.addPrimsTo = function(primTable) {
|
|||
primTable["say:duration:elapsed:from:"] = function(b) { showBubbleAndWait(b, 'say'); };
|
||||
primTable["think:"] = function(b) { showBubble(b, 'think'); };
|
||||
primTable["think:duration:elapsed:from:"] = function(b) { showBubbleAndWait(b, 'think'); };
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primShow = function(b) {
|
||||
interp.targetSprite().setVisible(true);
|
||||
interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primHide = function(b) {
|
||||
interp.targetSprite().setVisible(false);
|
||||
interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primNextCostume = function(b) {
|
||||
interp.targetSprite().showCostume(interp.targetSprite().currentCostumeIndex + 1);
|
||||
interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primShowCostume = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -88,7 +88,7 @@ LooksPrims.prototype.primShowCostume = function(b) {
|
|||
}
|
||||
}
|
||||
if (s.visible) interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primStartScene = function(b) {
|
||||
var s = runtime.stage;
|
||||
|
@ -113,55 +113,55 @@ LooksPrims.prototype.primStartScene = function(b) {
|
|||
}
|
||||
}
|
||||
if (s.visible) interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primCostumeNum = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
return (s == null) ? 1 : s.currentCostumeIndex + 1;
|
||||
}
|
||||
return s == null ? 1 : s.currentCostumeIndex + 1;
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primChangeSize = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s == null) return;
|
||||
s.setSize(s.getSize() + interp.arg(b, 0));
|
||||
if (s.visible) interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primSetSize = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s == null) return;
|
||||
s.setSize(interp.arg(b, 0));
|
||||
if (s.visible) interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primSize = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s == null) return 100;
|
||||
return s.getSize();
|
||||
}
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primGoFront = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
runtime.reassignZ(s, null);
|
||||
if(s.visible) interp.redraw();
|
||||
}
|
||||
if (s.visible) interp.redraw();
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primGoBack = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
runtime.reassignZ(s, interp.arg(b, 0));
|
||||
if(s.visible) interp.redraw();
|
||||
}
|
||||
if (s.visible) interp.redraw();
|
||||
};
|
||||
|
||||
LooksPrims.prototype.primChangeEffect = function(b) {}
|
||||
LooksPrims.prototype.primChangeEffect = function(b) {};
|
||||
|
||||
LooksPrims.prototype.primSetEffect = function(b) {}
|
||||
LooksPrims.prototype.primSetEffect = function(b) {};
|
||||
|
||||
LooksPrims.prototype.primClearEffects = function(b) {}
|
||||
LooksPrims.prototype.primClearEffects = function(b) {};
|
||||
|
||||
var showBubble = function(b, type) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.showBubble(interp.arg(b, 0), type);
|
||||
}
|
||||
};
|
||||
|
||||
var showBubbleAndWait = function(b, type) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -175,4 +175,4 @@ var showBubbleAndWait = function(b, type) {
|
|||
} else {
|
||||
if (interp.checkTimer()) s.hideBubble();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var MotionAndPenPrims = function() {}
|
||||
var MotionAndPenPrims = function() {};
|
||||
|
||||
MotionAndPenPrims.prototype.addPrimsTo = function(primTable) {
|
||||
primTable['forward:'] = this.primMove;
|
||||
|
@ -52,60 +52,59 @@ MotionAndPenPrims.prototype.addPrimsTo = function(primTable) {
|
|||
|
||||
primTable["stampCostume"] = this.primStamp;
|
||||
primTable["stampTransparent"] = this.primStampTransparent;
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primMove = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
var radians = ((Math.PI * (90 - s.direction)) / 180);
|
||||
var radians = (90 - s.direction) * Math.PI / 180;
|
||||
var d = interp.arg(b, 0);
|
||||
|
||||
moveSpriteTo(s, s.scratchX + (d * Math.cos(radians)),
|
||||
s.scratchY + (d * Math.sin(radians)));
|
||||
if(s.visible) interp.redraw();
|
||||
}
|
||||
moveSpriteTo(s, s.scratchX + d * Math.cos(radians), s.scratchY + d * Math.sin(radians));
|
||||
if (s.visible) interp.redraw();
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primTurnLeft = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
var d = s.direction - interp.arg(b, 0);
|
||||
s.setDirection(d);
|
||||
if(s.visible) interp.redraw();
|
||||
}
|
||||
if (s.visible) interp.redraw();
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primTurnRight = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
var d = s.direction + interp.arg(b, 0);
|
||||
s.setDirection(d);
|
||||
if(s.visible) interp.redraw();
|
||||
}
|
||||
if (s.visible) interp.redraw();
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primSetDirection = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
s.setDirection(interp.arg(b, 0));
|
||||
if(s.visible) interp.redraw();
|
||||
}
|
||||
if (s.visible) interp.redraw();
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primPointTowards = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
var p = mouseOrSpritePosition(interp.arg(b, 0));
|
||||
if ((s == null) || (p == null)) return;
|
||||
if (s == null || p == null) return;
|
||||
var dx = p.x - s.scratchX;
|
||||
var dy = p.y - s.scratchY;
|
||||
var angle = 90 - ((Math.atan2(dy, dx) * 180) / Math.PI);
|
||||
var angle = 90 - Math.atan2(dy, dx) * 180 / Math.PI;
|
||||
s.setDirection(angle);
|
||||
if (s.visible) interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primGoTo = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) moveSpriteTo(s, interp.arg(b, 0), interp.arg(b, 1));
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primGoToSpriteOrMouse = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
var p = mouseOrSpritePosition(interp.arg(b, 0));
|
||||
if ((s == null) || (p == null)) return;
|
||||
if (s == null || p == null) return;
|
||||
moveSpriteTo(s, p.x, p.y);
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primGlide = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -119,16 +118,15 @@ MotionAndPenPrims.prototype.primGlide = function(b) {
|
|||
return;
|
||||
}
|
||||
// record state: [0]start msecs, [1]duration, [2]startX, [3]startY, [4]endX, [5]endY
|
||||
interp.activeThread.tmpObj =
|
||||
[interp.currentMSecs, 1000 * secs, s.scratchX, s.scratchY, destX, destY];
|
||||
interp.activeThread.tmpObj = [interp.currentMSecs, 1000 * secs, s.scratchX, s.scratchY, destX, destY];
|
||||
interp.startTimer(secs);
|
||||
} else {
|
||||
var state = interp.activeThread.tmpObj;
|
||||
if (!interp.checkTimer()) {
|
||||
// in progress: move to intermediate position along path
|
||||
var frac = (interp.currentMSecs - state[0]) / state[1];
|
||||
var newX = state[2] + (frac * (state[4] - state[2]));
|
||||
var newY = state[3] + (frac * (state[5] - state[3]));
|
||||
var newX = state[2] + frac * (state[4] - state[2]);
|
||||
var newY = state[3] + frac * (state[5] - state[3]);
|
||||
moveSpriteTo(s, newX, newY);
|
||||
} else {
|
||||
// finished: move to final position and clear state
|
||||
|
@ -136,27 +134,27 @@ MotionAndPenPrims.prototype.primGlide = function(b) {
|
|||
interp.activeThread.tmpObj = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primChangeX = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) moveSpriteTo(s, s.scratchX + interp.arg(b, 0), s.scratchY);
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primSetX = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) moveSpriteTo(s, interp.arg(b, 0), s.scratchY);
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primChangeY = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.arg(b, 0));
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primSetY = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) moveSpriteTo(s, s.scratchX, interp.arg(b, 0));
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primBounceOffEdge = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -164,7 +162,7 @@ MotionAndPenPrims.prototype.primBounceOffEdge = function(b) {
|
|||
if (!turnAwayFromEdge(s)) return;
|
||||
ensureOnStageOnBounce(s);
|
||||
if (s.visible) interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primSetRotationStyle = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -175,95 +173,94 @@ MotionAndPenPrims.prototype.primSetRotationStyle = function(b) {
|
|||
else if (request == 'left-right') rotationStyle = 'leftRight';
|
||||
else if (request == 'none') rotationStyle = 'none';
|
||||
s.setRotationStyle(rotationStyle);
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primXPosition = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
return (s != null) ? s.scratchX : 0;
|
||||
}
|
||||
return s != null ? s.scratchX : 0;
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primYPosition = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
return (s != null) ? s.scratchY : 0;
|
||||
}
|
||||
return s != null ? s.scratchY : 0;
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primDirection = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
return (s != null) ? s.direction : 0;
|
||||
}
|
||||
return s != null ? s.direction : 0;
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primClear = function(b) {
|
||||
runtime.stage.clearPenStrokes();
|
||||
interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primPenDown = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.penIsDown = true;
|
||||
stroke(s, s.scratchX, s.scratchY, s.scratchX + 0.2, s.scratchY + 0.2);
|
||||
interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primPenUp = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.penIsDown = false;
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primSetPenColor = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.setPenColor(interp.arg(b, 0));
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primSetPenHue = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.setPenHue(interp.arg(b, 0));
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primChangePenHue = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.setPenHue(s.penHue + interp.arg(b, 0));
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primSetPenShade = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.setPenShade(interp.arg(b, 0));
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primChangePenShade = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.setPenShade(s.penShade + interp.arg(b, 0));
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primSetPenSize = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
var w = Math.max(0, Math.min(interp.arg(b, 0), 100));
|
||||
if (s != null) s.penWidth = w;
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primChangePenSize = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
var w = Math.max(0, Math.min(s.penWidth + interp.arg(b, 0), 100));
|
||||
if (s != null) s.penWidth = w;
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primStamp = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
s.stamp(runtime.stage.lineCache, 100);
|
||||
}
|
||||
};
|
||||
|
||||
MotionAndPenPrims.prototype.primStampTransparent = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
var transparency = Math.max(0, Math.min(interp.arg(b, 0), 100));
|
||||
var alpha = 100 - transparency;
|
||||
s.stamp(runtime.stage.lineCache, alpha);
|
||||
}
|
||||
};
|
||||
|
||||
// Helpers
|
||||
var stroke = function(s, oldX, oldY, newX, newY) {
|
||||
runtime.stage.stroke([oldX, oldY],
|
||||
[newX, newY], s.penWidth, s.penColorCache);
|
||||
runtime.stage.stroke([oldX, oldY], [newX, newY], s.penWidth, s.penColorCache);
|
||||
interp.redraw();
|
||||
}
|
||||
};
|
||||
|
||||
var mouseOrSpritePosition = function(arg) {
|
||||
if (arg == "_mouse_") {
|
||||
|
@ -275,7 +272,7 @@ var mouseOrSpritePosition = function(arg) {
|
|||
return new Point(s.scratchX, s.scratchY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
var moveSpriteTo = function(s, newX, newY) {
|
||||
var oldX = s.scratchX;
|
||||
|
@ -283,8 +280,8 @@ var moveSpriteTo = function(s, newX, newY) {
|
|||
s.setXY(newX, newY);
|
||||
s.keepOnStage();
|
||||
if (s.penIsDown) stroke(s, oldX, oldY, s.scratchX, s.scratchY);
|
||||
if ((s.penIsDown) || (s.visible)) interp.redraw();
|
||||
}
|
||||
if (s.penIsDown || s.visible) interp.redraw();
|
||||
};
|
||||
|
||||
var turnAwayFromEdge = function(s) {
|
||||
// turn away from the nearest edge if it's close enough; otherwise do nothing
|
||||
|
@ -298,23 +295,23 @@ var turnAwayFromEdge = function(s) {
|
|||
var d4 = Math.max(0, 360 - r.bottom);
|
||||
// find the nearest edge
|
||||
var e = 0, minDist = 100000;
|
||||
if (d1 < minDist) { minDist = d1; e = 1 }
|
||||
if (d2 < minDist) { minDist = d2; e = 2 }
|
||||
if (d3 < minDist) { minDist = d3; e = 3 }
|
||||
if (d4 < minDist) { minDist = d4; e = 4 }
|
||||
if (d1 < minDist) { minDist = d1; e = 1; }
|
||||
if (d2 < minDist) { minDist = d2; e = 2; }
|
||||
if (d3 < minDist) { minDist = d3; e = 3; }
|
||||
if (d4 < minDist) { minDist = d4; e = 4; }
|
||||
if (minDist > 0) return false; // not touching to any edge
|
||||
// point away from nearest edge
|
||||
var radians = ((90 - s.direction) * Math.PI) / 180;
|
||||
var radians = (90 - s.direction) * Math.PI / 180;
|
||||
var dx = Math.cos(radians);
|
||||
var dy = -Math.sin(radians);
|
||||
if (e == 1) { dx = Math.max(0.2, Math.abs(dx)) }
|
||||
if (e == 2) { dy = Math.max(0.2, Math.abs(dy)) }
|
||||
if (e == 3) { dx = 0 - Math.max(0.2, Math.abs(dx)) }
|
||||
if (e == 4) { dy = 0 - Math.max(0.2, Math.abs(dy)) }
|
||||
var newDir = ((180 * Math.atan2(dy, dx)) / Math.PI) + 90;
|
||||
if (e == 1) { dx = Math.max(0.2, Math.abs(dx)); }
|
||||
if (e == 2) { dy = Math.max(0.2, Math.abs(dy)); }
|
||||
if (e == 3) { dx = 0 - Math.max(0.2, Math.abs(dx)); }
|
||||
if (e == 4) { dy = 0 - Math.max(0.2, Math.abs(dy)); }
|
||||
var newDir = Math.atan2(dy, dx) * 180 / Math.PI + 90;
|
||||
s.direction = newDir;
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
var ensureOnStageOnBounce = function(s) {
|
||||
var r = s.getRect();
|
||||
|
@ -326,4 +323,4 @@ var ensureOnStageOnBounce = function(s) {
|
|||
if (r.bottom > 360) {
|
||||
moveSpriteTo(s, s.scratchX, s.scratchY + (r.bottom - 360));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -26,29 +26,29 @@ var Primitives = function() {}
|
|||
|
||||
Primitives.prototype.addPrimsTo = function(primTable) {
|
||||
// Math primitives
|
||||
primTable["+"] = function(b) { return interp.arg(b, 0) + interp.arg(b, 1) };
|
||||
primTable["-"] = function(b) { return interp.arg(b, 0) - interp.arg(b, 1) };
|
||||
primTable["*"] = function(b) { return interp.arg(b, 0) * interp.arg(b, 1) };
|
||||
primTable["/"] = function(b) { return interp.arg(b, 0) / interp.arg(b, 1) };
|
||||
primTable["%"] = function(b) { return interp.arg(b, 0) % interp.arg(b, 1) };
|
||||
primTable["+"] = function(b) { return interp.arg(b, 0) + interp.arg(b, 1); };
|
||||
primTable["-"] = function(b) { return interp.arg(b, 0) - interp.arg(b, 1); };
|
||||
primTable["*"] = function(b) { return interp.arg(b, 0) * interp.arg(b, 1); };
|
||||
primTable["/"] = function(b) { return interp.arg(b, 0) / interp.arg(b, 1); };
|
||||
primTable["%"] = function(b) { return interp.arg(b, 0) % interp.arg(b, 1); };
|
||||
primTable["randomFrom:to:"] = this.primRandom;
|
||||
primTable["<"] = function(b) { return (interp.arg(b, 0) < interp.arg(b, 1)) };
|
||||
primTable["="] = function(b) { return (interp.arg(b, 0) == interp.arg(b, 1)) };
|
||||
primTable[">"] = function(b) { return (interp.arg(b, 0) > interp.arg(b, 1)) };
|
||||
primTable["&"] = function(b) { return interp.arg(b, 0) && interp.arg(b, 1) };
|
||||
primTable["|"] = function(b) { return interp.arg(b, 0) || interp.arg(b, 1) };
|
||||
primTable["<"] = function(b) { return (interp.arg(b, 0) < interp.arg(b, 1)); };
|
||||
primTable["="] = function(b) { return (interp.arg(b, 0) == interp.arg(b, 1)); };
|
||||
primTable[">"] = function(b) { return (interp.arg(b, 0) > interp.arg(b, 1)); };
|
||||
primTable["&"] = function(b) { return interp.arg(b, 0) && interp.arg(b, 1); };
|
||||
primTable["|"] = function(b) { return interp.arg(b, 0) || interp.arg(b, 1); };
|
||||
primTable["not"] = function(b) { return !interp.arg(b, 0) };
|
||||
primTable["abs"] = function(b) { return Math.abs(interp.arg(b, 0)) };
|
||||
primTable["sqrt"] = function(b) { return Math.sqrt(interp.arg(b, 0)) };
|
||||
|
||||
primTable["\\\\"] = this.primModulo;
|
||||
primTable["rounded"] = function(b) { return Math.round(interp.arg(b, 0)) };
|
||||
primTable["rounded"] = function(b) { return Math.round(interp.arg(b, 0)); };
|
||||
primTable["computeFunction:of:"] = this.primMathFunction;
|
||||
|
||||
// String primitives
|
||||
primTable["concatenate:with:"] = function(b) { return "" + interp.arg(b, 0) + interp.arg(b, 1) };
|
||||
primTable["concatenate:with:"] = function(b) { return "" + interp.arg(b, 0) + interp.arg(b, 1); };
|
||||
primTable["letter:of:"] = this.primLetterOf;
|
||||
primTable["stringLength:"] = function(b) { return interp.arg(b, 0).length };
|
||||
primTable["stringLength:"] = function(b) { return interp.arg(b, 0).length; };
|
||||
|
||||
new VarListPrims().addPrimsTo(primTable);
|
||||
new MotionAndPenPrims().addPrimsTo(primTable);
|
||||
|
@ -60,20 +60,20 @@ Primitives.prototype.addPrimsTo = function(primTable) {
|
|||
Primitives.prototype.primRandom = function(b) {
|
||||
var n1 = interp.arg(b, 0);
|
||||
var n2 = interp.arg(b, 1);
|
||||
var low = (n1 <= n2) ? n1 : n2;
|
||||
var hi = (n1 <= n2) ? n2 : n1;
|
||||
if(low == hi) return low;
|
||||
var low = n1 <= n2 ? n1 : n2;
|
||||
var hi = n1 <= n2 ? n2 : n1;
|
||||
if (low == hi) return low;
|
||||
// if both low and hi are ints, truncate the result to an int
|
||||
if ((Math.floor(low) == low) && (Math.floor(hi) == hi)) {
|
||||
return low + Math.floor(Math.random() * ((hi + 1) - low));
|
||||
if (Math.floor(low) == low && Math.floor(hi) == hi) {
|
||||
return low + Math.floor(Math.random() * (hi + 1 - low));
|
||||
}
|
||||
return (Math.random() * (hi - low)) + low;
|
||||
return Math.random() * (hi - low) + low;
|
||||
}
|
||||
|
||||
Primitives.prototype.primLetterOf = function(b) {
|
||||
var s = interp.arg(b, 1);
|
||||
var i = interp.arg(b, 0) - 1;
|
||||
if ((i < 0) || (i >= s.length)) return "";
|
||||
if (i < 0 || i >= s.length) return "";
|
||||
return s.charAt(i);
|
||||
}
|
||||
|
||||
|
@ -90,12 +90,12 @@ Primitives.prototype.primMathFunction = function(b) {
|
|||
switch(op) {
|
||||
case "abs": return Math.abs(n);
|
||||
case "sqrt": return Math.sqrt(n);
|
||||
case "sin": return Math.sin((Math.PI * n) / 180);
|
||||
case "cos": return Math.cos((Math.PI * n) / 180);
|
||||
case "tan": return Math.tan((Math.PI * n) / 180);
|
||||
case "asin": return (Math.asin(n) * 180) / Math.PI;
|
||||
case "acos": return (Math.acos(n) * 180) / Math.PI;
|
||||
case "atan": return (Math.atan(n) * 180) / Math.PI;
|
||||
case "sin": return Math.sin(n * Math.PI / 180);
|
||||
case "cos": return Math.cos(n * Math.PI / 180);
|
||||
case "tan": return Math.tan(n * Math.PI / 180);
|
||||
case "asin": return Math.asin(n) * 180 / Math.PI;
|
||||
case "acos": return Math.acos(n) * 180 / Math.PI;
|
||||
case "atan": return Math.atan(n) * 180 / Math.PI;
|
||||
case "ln": return Math.log(n);
|
||||
case "log": return Math.log(n) / Math.LN10;
|
||||
case "e ^": return Math.exp(n);
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var SensingPrims = function() {}
|
||||
var SensingPrims = function() {};
|
||||
|
||||
SensingPrims.prototype.addPrimsTo = function(primTable) {
|
||||
primTable['touching:'] = this.primTouching;
|
||||
|
@ -30,9 +30,9 @@ SensingPrims.prototype.addPrimsTo = function(primTable) {
|
|||
|
||||
primTable['getAttribute:of:'] = this.primGetAttribute;
|
||||
|
||||
primTable['timeAndDate'] = this.primTimeDate;
|
||||
primTable['timeAndDate'] = function(b){ return runtime.getTimeString(interp.arg(b, 0)); };
|
||||
primTable['timestamp'] = this.primTimestamp;
|
||||
}
|
||||
};
|
||||
|
||||
SensingPrims.prototype.primTouching = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -51,7 +51,7 @@ SensingPrims.prototype.primTouching = function(b) {
|
|||
if (s2 == null || !s2.visible) return false;
|
||||
|
||||
return spriteHitTest(s, s2);
|
||||
}
|
||||
};
|
||||
|
||||
SensingPrims.prototype.primTouchingColor = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -60,7 +60,7 @@ SensingPrims.prototype.primTouchingColor = function(b) {
|
|||
var color = interp.arg(b, 0);
|
||||
|
||||
return stageColorHitTest(s, color);
|
||||
}
|
||||
};
|
||||
|
||||
SensingPrims.prototype.primColorTouchingColor = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -70,7 +70,7 @@ SensingPrims.prototype.primColorTouchingColor = function(b) {
|
|||
var stageColor = interp.arg(b, 1);
|
||||
|
||||
return stageColorByColorHitTest(s, myColor, stageColor);
|
||||
}
|
||||
};
|
||||
|
||||
var spriteHitTest = function(a, b) {
|
||||
var hitCanvas = document.createElement('canvas');
|
||||
|
@ -91,7 +91,7 @@ var spriteHitTest = function(a, b) {
|
|||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var stageColorHitTest = function(target, color) {
|
||||
var r, g, b;
|
||||
|
@ -123,18 +123,18 @@ var stageColorHitTest = function(target, color) {
|
|||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
var stageColorByColorHitTest = function(target, myColor, otherColor) {
|
||||
var threshold_acceptable = function(a, b, c, x, y, z) {
|
||||
diff_a = Math.abs(a-x);
|
||||
diff_b = Math.abs(b-y);
|
||||
diff_c = Math.abs(c-z);
|
||||
var diff_a = Math.abs(a-x);
|
||||
var diff_b = Math.abs(b-y);
|
||||
var diff_c = Math.abs(c-z);
|
||||
if (diff_a + diff_b + diff_c < 100) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
var targetCanvas = document.createElement('canvas');
|
||||
targetCanvas.width = 480;
|
||||
targetCanvas.height = 360;
|
||||
|
@ -157,22 +157,22 @@ var stageColorByColorHitTest = function(target, myColor, otherColor) {
|
|||
var hitCanvas = document.createElement('canvas');
|
||||
hitCanvas.width = 480;
|
||||
hitCanvas.height = 360;
|
||||
hitCtx = hitCanvas.getContext('2d');
|
||||
var hitCtx = hitCanvas.getContext('2d');
|
||||
$.each(runtime.sprites, function(i, sprite) {
|
||||
if (sprite != target)
|
||||
if (sprite != target) {
|
||||
sprite.stamp(hitCtx, 100);
|
||||
}
|
||||
});
|
||||
|
||||
var hitData = hitCtx.getImageData(0, 0, hitCanvas.width, hitCanvas.height).data;
|
||||
var pxCount = targetData.length;
|
||||
for (var i = 0; i < pxCount; i += 4) {
|
||||
if (threshold_acceptable(targetData[i], targetData[i+1], targetData[i+2], mr, mg, mb)
|
||||
&& threshold_acceptable(hitData[i], hitData[i+1], hitData[i+2], or, og, ob)) {
|
||||
if (threshold_acceptable(targetData[i], targetData[i+1], targetData[i+2], mr, mg, mb) && threshold_acceptable(hitData[i], hitData[i+1], hitData[i+2], or, og, ob)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
SensingPrims.prototype.primKeyPressed = function(b) {
|
||||
var key = interp.arg(b, 0);
|
||||
|
@ -184,7 +184,7 @@ SensingPrims.prototype.primKeyPressed = function(b) {
|
|||
if (key == "down arrow") ch = 40;
|
||||
if (key == "space") ch = 32;
|
||||
return (typeof(runtime.keysDown[ch]) != 'undefined');
|
||||
}
|
||||
};
|
||||
|
||||
SensingPrims.prototype.primDistanceTo = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -193,7 +193,7 @@ SensingPrims.prototype.primDistanceTo = function(b) {
|
|||
var dx = p.x - s.scratchX;
|
||||
var dy = p.y - s.scratchY;
|
||||
return Math.sqrt((dx * dx) + (dy * dy));
|
||||
}
|
||||
};
|
||||
|
||||
SensingPrims.prototype.primGetAttribute = function(b) {
|
||||
var attr = interp.arg(b, 0);
|
||||
|
@ -207,7 +207,7 @@ SensingPrims.prototype.primGetAttribute = function(b) {
|
|||
if (attr == 'size') return targetSprite.getSize();
|
||||
if (attr == 'volume') return targetSprite.volume;
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
SensingPrims.prototype.primTimeDate = function(b) {
|
||||
var dt = interp.arg(b, 0);
|
||||
|
@ -220,13 +220,16 @@ SensingPrims.prototype.primTimeDate = function(b) {
|
|||
if (dt == 'minute') return now.getMinutes();
|
||||
if (dt == 'second') return now.getSeconds();
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
SensingPrims.prototype.primTimestamp = function(b) {
|
||||
var now = new Date(), epoch = new Date(2000,0,1), dst = now.getTimezoneOffset() - epoch.getTimezoneOffset(), msSince = now.getTime() - epoch.getTime();
|
||||
var now = new Date();
|
||||
var epoch = new Date(2000, 0, 1);
|
||||
var dst = now.getTimezoneOffset() - epoch.getTimezoneOffset();
|
||||
var msSince = now.getTime() - epoch.getTime();
|
||||
msSince += (now.getTimezoneOffset() - dst) * 60000;
|
||||
return msSince / 86400000;
|
||||
}
|
||||
};
|
||||
|
||||
// Helpers
|
||||
SensingPrims.prototype.mouseOrSpritePosition = function(arg) {
|
||||
|
@ -239,4 +242,4 @@ SensingPrims.prototype.mouseOrSpritePosition = function(arg) {
|
|||
return new Point(s.scratchX, s.scratchY);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -15,7 +15,7 @@
|
|||
|
||||
'use strict';
|
||||
|
||||
var SoundPrims = function() {}
|
||||
var SoundPrims = function() {};
|
||||
|
||||
SoundPrims.prototype.addPrimsTo = function(primTable) {
|
||||
primTable['playSound:'] = this.primPlaySound;
|
||||
|
@ -34,7 +34,7 @@ SoundPrims.prototype.addPrimsTo = function(primTable) {
|
|||
primTable['changeTempoBy:'] = function(b) { runtime.stage.data.tempoBPM = runtime.stage.data.tempoBPM + interp.arg(b, 0); };
|
||||
primTable['setTempoTo:'] = function(b) { runtime.stage.data.tempoBPM = interp.arg(b, 0); };
|
||||
primTable['tempo'] = function(b) { return runtime.stage.data.tempoBPM; };
|
||||
}
|
||||
};
|
||||
|
||||
var playSound = function(snd) {
|
||||
if (snd.source) {
|
||||
|
@ -64,7 +64,7 @@ var playSound = function(snd) {
|
|||
runtime.audioPlaying.push(snd);
|
||||
snd.source.noteOn(0);
|
||||
return snd.source;
|
||||
}
|
||||
};
|
||||
|
||||
var playDrum = function(drum, secs, client) {
|
||||
var player = SoundBank.getDrumPlayer(drum, secs);
|
||||
|
@ -83,7 +83,7 @@ var playDrum = function(drum, secs, client) {
|
|||
}
|
||||
window.setTimeout(source.finished, secs * 1000);
|
||||
return player;
|
||||
}
|
||||
};
|
||||
|
||||
var playNote = function(instrument, midiKey, secs, client) {
|
||||
var player = SoundBank.getNotePlayer(instrument, midiKey);
|
||||
|
@ -101,7 +101,7 @@ var playNote = function(instrument, midiKey, secs, client) {
|
|||
}
|
||||
window.setTimeout(source.finished, secs * 1000);
|
||||
return player;
|
||||
}
|
||||
};
|
||||
|
||||
var stopAllSounds = function() {
|
||||
var oldPlaying = runtime.audioPlaying;
|
||||
|
@ -121,14 +121,14 @@ var stopAllSounds = function() {
|
|||
oldPlaying[s].finished();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primPlaySound = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s == null) return;
|
||||
var snd = s.soundNamed(interp.arg(b, 0));
|
||||
if (snd != null) playSound(snd);
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primPlaySoundUntilDone = function(b) {
|
||||
var activeThread = interp.activeThread;
|
||||
|
@ -145,11 +145,11 @@ SoundPrims.prototype.primPlaySoundUntilDone = function(b) {
|
|||
} else {
|
||||
interp.yield = true;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var beatsToSeconds = function(beats) {
|
||||
return (beats * 60) / runtime.stage.data.tempoBPM;
|
||||
}
|
||||
return beats * 60 / runtime.stage.data.tempoBPM;
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primPlayNote = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -162,7 +162,7 @@ SoundPrims.prototype.primPlayNote = function(b) {
|
|||
} else {
|
||||
interp.checkTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primPlayDrum = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -175,7 +175,7 @@ SoundPrims.prototype.primPlayDrum = function(b) {
|
|||
} else {
|
||||
interp.checkTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primPlayRest = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -186,28 +186,28 @@ SoundPrims.prototype.primPlayRest = function(b) {
|
|||
} else {
|
||||
interp.checkTimer();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primSetInstrument = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.instrument = interp.arg(b, 0);
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primStopAllSounds = function(b) {
|
||||
stopAllSounds();
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primChangeVolume = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.volume += interp.arg(b, 0);
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primSetVolume = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s != null) s.volume = interp.arg(b, 0);
|
||||
}
|
||||
};
|
||||
|
||||
SoundPrims.prototype.primVolume = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
return (s != null) ? s.volume : 0;
|
||||
}
|
||||
return s != null ? s.volume : 0;
|
||||
};
|
||||
|
|
|
@ -34,7 +34,7 @@ VarListPrims.prototype.addPrimsTo = function(primTable) {
|
|||
primTable['lineCountOfList:'] = this.primListLength;
|
||||
primTable['getLine:ofList:'] = this.primListGetLine;
|
||||
primTable['list:contains:'] = this.primListContains;
|
||||
}
|
||||
};
|
||||
|
||||
// Variable primitive implementations
|
||||
|
||||
|
@ -42,21 +42,23 @@ VarListPrims.prototype.primReadVar = function(b) {
|
|||
var s = interp.targetSprite();
|
||||
if (s == null) return;
|
||||
var targetVar = interp.arg(b, 0);
|
||||
if (targetVar in s.variables)
|
||||
if (targetVar in s.variables) {
|
||||
return s.variables[targetVar];
|
||||
else if (targetVar in runtime.stage.variables)
|
||||
} else if (targetVar in runtime.stage.variables) {
|
||||
return runtime.stage.variables[targetVar];
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primSetVar = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
if (s == null) return;
|
||||
var targetVar = interp.arg(b, 0);
|
||||
if (targetVar in s.variables)
|
||||
if (targetVar in s.variables) {
|
||||
s.variables[targetVar] = interp.arg(b, 1);
|
||||
else if (targetVar in runtime.stage.variables)
|
||||
} else if (targetVar in runtime.stage.variables) {
|
||||
runtime.stage.variables[targetVar] = interp.arg(b, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primChangeVar = function(b) {
|
||||
var s = interp.targetSprite();
|
||||
|
@ -69,7 +71,7 @@ VarListPrims.prototype.primChangeVar = function(b) {
|
|||
runtime.stage.variables[targetVar] = parseFloat(runtime.stage.variables[targetVar]);
|
||||
runtime.stage.variables[targetVar] += interp.arg(b, 1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primHideVar = function(b) {
|
||||
var targetVar = interp.arg(b, 0);
|
||||
|
@ -79,7 +81,7 @@ VarListPrims.prototype.primHideVar = function(b) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primShowVar = function(b) {
|
||||
var targetVar = interp.arg(b, 0);
|
||||
|
@ -89,7 +91,7 @@ VarListPrims.prototype.primShowVar = function(b) {
|
|||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// List primitive implementations
|
||||
|
||||
|
@ -102,20 +104,20 @@ var findList = function(targetSprite, listName) {
|
|||
return runtime.stage.lists[listName].contents;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primReadList = function(b) {
|
||||
var list = findList(interp.targetSprite(), interp.arg(b, 0));
|
||||
if (list) {
|
||||
var allOne = list.map(function(val){return val.length}).reduce(function(old,val){return old+val},0)===list.length;
|
||||
return list.join(allOne?'':' ');
|
||||
var allOne = list.map(function(val) { return val.length; }).reduce(function(old,val) { return old + val; }, 0) === list.length;
|
||||
return list.join(allOne ? '' : ' ');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primListAppend = function(b) {
|
||||
var list = findList(interp.targetSprite(), interp.arg(b, 1));
|
||||
if (list) list.push(interp.arg(b, 0));
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primListDeleteLine = function(b) {
|
||||
var list = findList(interp.targetSprite(), interp.arg(b, 1));
|
||||
|
@ -124,7 +126,7 @@ VarListPrims.prototype.primListDeleteLine = function(b) {
|
|||
if (line == 'all' || list.length == 0) list.length = 0;
|
||||
else if (line == 'last') list.splice(list.length - 1, 1);
|
||||
else if (parseInt(line) - 1 in list) list.splice(parseInt(line) - 1, 1);
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primListInsertAt = function(b) {
|
||||
var list = findList(interp.targetSprite(), interp.arg(b, 2));
|
||||
|
@ -138,7 +140,7 @@ VarListPrims.prototype.primListInsertAt = function(b) {
|
|||
if (position > list.length) return;
|
||||
|
||||
list.splice(position, 0, newItem);
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primListSetLine = function(b) {
|
||||
var list = findList(interp.targetSprite(), interp.arg(b, 1));
|
||||
|
@ -149,16 +151,17 @@ VarListPrims.prototype.primListSetLine = function(b) {
|
|||
if (position == 'last') position = list.length - 1;
|
||||
else if (position == 'random') position = Math.floor(Math.random() * list.length);
|
||||
else position = parseInt(position) - 1;
|
||||
|
||||
if (position > list.length - 1) return;
|
||||
|
||||
list[position] = newItem;
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primListLength = function(b) {
|
||||
var list = findList(interp.targetSprite(), interp.arg(b, 0));
|
||||
if (!list) return 0;
|
||||
return list.length;
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primListGetLine = function(b) {
|
||||
var list = findList(interp.targetSprite(), interp.arg(b, 1));
|
||||
|
@ -169,7 +172,7 @@ VarListPrims.prototype.primListGetLine = function(b) {
|
|||
else if (line == 'last') line = list.length;
|
||||
else if (list.length < line) return 0;
|
||||
return list[line - 1];
|
||||
}
|
||||
};
|
||||
|
||||
VarListPrims.prototype.primListContains = function(b) {
|
||||
var list = findList(interp.targetSprite(), interp.arg(b, 0));
|
||||
|
@ -177,4 +180,4 @@ VarListPrims.prototype.primListContains = function(b) {
|
|||
var searchItem = interp.arg(b, 1);
|
||||
if (parseFloat(searchItem) == searchItem) searchItem = parseFloat(searchItem);
|
||||
return $.inArray(searchItem, list) > -1;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -65,11 +65,11 @@ var NotePlayer = function(wavFileData, originalPitch, loopStart, loopEnd, env) {
|
|||
if (env) {
|
||||
this.attackEnd = env[0] * 44.100;
|
||||
if (this.attackEnd > 0) this.attackRate = Math.pow(33000, 1 / this.attackEnd);
|
||||
this.holdEnd = this.attackEnd + (env[1] * 44.100);
|
||||
this.holdEnd = this.attackEnd + env[1] * 44.100;
|
||||
var decayCount = env[2] * 44100;
|
||||
this.decayRate = (decayCount == 0) ? 1 : Math.pow(33000, -1 / decayCount);
|
||||
this.decayRate = decayCount == 0 ? 1 : Math.pow(33000, -1 / decayCount);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
NotePlayer.prototype = Object.create(SoundDecoder.prototype);
|
||||
NotePlayer.prototype.constructor = NotePlayer;
|
||||
|
@ -79,14 +79,14 @@ NotePlayer.prototype.setNoteAndDuration = function(midiKey, secs) {
|
|||
var pitch = 440 * Math.pow(2, (midiKey - 69) / 12); // midi key 69 is A (440 Hz)
|
||||
this.stepSize = pitch / (2 * this.originalPitch); // adjust for original sampling rate of 22050
|
||||
this.setDuration(secs);
|
||||
}
|
||||
};
|
||||
|
||||
NotePlayer.prototype.setDuration = function(secs) {
|
||||
this.samplesSinceStart = 0;
|
||||
this.samplesRemaining = 44100 * secs;
|
||||
if (!this.isLooped) this.samplesRemaining = Math.min(this.samplesRemaining, this.endOffset / this.stepSize);
|
||||
this.envelopeValue = (this.attackEnd > 0) ? 1 / 33000 : 1;
|
||||
}
|
||||
this.envelopeValue = this.attackEnd > 0 ? 1 / 33000 : 1;
|
||||
};
|
||||
|
||||
NotePlayer.prototype.interpolatedSample = function() {
|
||||
if (this.samplesRemaining-- <= 0) { this.noteFinished(); return 0; }
|
||||
|
@ -99,11 +99,11 @@ NotePlayer.prototype.interpolatedSample = function() {
|
|||
var frac = this.index - i;
|
||||
var curr = this.rawSample(i);
|
||||
var next = this.rawSample(i + 1);
|
||||
var sample = (curr + (frac * (next - curr))) / 100000; // xxx 32000; attenuate...
|
||||
var sample = (curr + frac * (next - curr)) / 100000; // xxx 32000; attenuate...
|
||||
if (this.samplesRemaining < 1000) sample *= (this.samplesRemaining / 1000.0); // relaase phease
|
||||
this.updateEnvelope();
|
||||
return this.envelopeValue * sample;
|
||||
}
|
||||
};
|
||||
|
||||
NotePlayer.prototype.rawSample = function(sampleIndex) {
|
||||
if (sampleIndex >= this.endOffset) {
|
||||
|
@ -112,8 +112,8 @@ NotePlayer.prototype.rawSample = function(sampleIndex) {
|
|||
}
|
||||
var byteIndex = 2 * sampleIndex;
|
||||
var result = (this.soundData[byteIndex + 1] << 8) + this.soundData[byteIndex];
|
||||
return (result <= 32767) ? result : result - 65536;
|
||||
}
|
||||
return result <= 32767 ? result : result - 65536;
|
||||
};
|
||||
|
||||
NotePlayer.prototype.updateEnvelope = function() {
|
||||
// Compute envelopeValue for the current sample.
|
||||
|
@ -125,4 +125,4 @@ NotePlayer.prototype.updateEnvelope = function() {
|
|||
} else if (this.samplesSinceStart > this.holdEnd) {
|
||||
if (this.decayRate < 1) this.envelopeValue *= this.decayRate;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -178,24 +178,24 @@ SoundBank.getNotePlayer = function(instNum, midiKey) {
|
|||
// Return a NotePlayer for the given Scratch 2.0 instrument number (1..21)
|
||||
// and MIDI key (0..127). If the instrument is out of range, use 1.
|
||||
var r = SoundBank.getNoteRecord(instNum - 1, midiKey);
|
||||
var env = (r.length > 5) ? r[5] : null;
|
||||
var env = r.length > 5 ? r[5] : null;
|
||||
return new NotePlayer(Instr.samples[r[1]], SoundBank.pitchForKey(r[2]), r[3], r[4], env);
|
||||
}
|
||||
};
|
||||
|
||||
SoundBank.getNoteRecord = function(instNum, midiKey) {
|
||||
// Get a note record for the given instrument number.
|
||||
if ((instNum < 0) || (instNum >= SoundBank.instruments.length)) instNum = 0;
|
||||
if (instNum < 0 || instNum >= SoundBank.instruments.length) instNum = 0;
|
||||
var keyRanges = SoundBank.instruments[instNum];
|
||||
for (var r = 0; r < keyRanges.length; r++) {
|
||||
var topOfKeyRange = keyRanges[r][0];
|
||||
if (midiKey <= topOfKeyRange) return keyRanges[r];
|
||||
}
|
||||
return keyRanges[keyRanges.length - 1]; // return the note record for the top key range.
|
||||
}
|
||||
};
|
||||
|
||||
SoundBank.pitchForKey = function(midiKey) {
|
||||
return 440 * Math.pow(2, (midiKey - 69) / 12); // midi key 69 is A=440 Hz
|
||||
}
|
||||
};
|
||||
|
||||
SoundBank.getDrumPlayer = function(drumNum, secs) {
|
||||
// Return a NotePlayer for the given drum number.
|
||||
|
@ -210,6 +210,4 @@ SoundBank.getDrumPlayer = function(drumNum, secs) {
|
|||
var player = new NotePlayer(Instr.samples[entry[0]], SoundBank.pitchForKey(60), loopStart, loopEnd, env);
|
||||
player.setNoteAndDuration(60 + entry[1], 0);
|
||||
return player;
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
|
|
@ -61,12 +61,12 @@ var SoundDecoder = function(wavFileData) {
|
|||
if (info.bitsPerSample == 16) this.getSample = this.getSample16Uncompressed;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
SoundDecoder.prototype.noteFinished = function() {
|
||||
// Called by subclasses to force ending condition to be true in writeSampleData()
|
||||
this.bytePosition = this.endOffset;
|
||||
}
|
||||
};
|
||||
|
||||
// Used for Notes and Drums - Web Audio API ScriptProcessorNodes use this
|
||||
// as a callback function to fill the buffers with sample data.
|
||||
|
@ -78,7 +78,7 @@ SoundDecoder.prototype.writeSampleData = function(evt) {
|
|||
var n = this.interpolatedSample();
|
||||
output[i] = n;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// For pre-caching the samples of WAV sounds
|
||||
// Return a full list of samples generated by the decoder.
|
||||
|
@ -90,7 +90,7 @@ SoundDecoder.prototype.getAllSamples = function() {
|
|||
smp = this.interpolatedSample();
|
||||
}
|
||||
return samples;
|
||||
}
|
||||
};
|
||||
|
||||
// Provide the next sample for the buffer
|
||||
SoundDecoder.prototype.interpolatedSample = function() {
|
||||
|
@ -101,11 +101,9 @@ SoundDecoder.prototype.interpolatedSample = function() {
|
|||
this.fraction -= 1.0;
|
||||
}
|
||||
if (this.nextSample == null) { return null; }
|
||||
var out = (this.fraction == 0) ?
|
||||
this.thisSample :
|
||||
this.thisSample + (this.fraction * (this.nextSample - this.thisSample));
|
||||
return (out) / 32768.0;
|
||||
}
|
||||
var out = this.fraction == 0 ? this.thisSample : this.thisSample + this.fraction * (this.nextSample - this.thisSample);
|
||||
return out / 32768.0;
|
||||
};
|
||||
|
||||
// 16-bit samples, big-endian
|
||||
SoundDecoder.prototype.getSample16Uncompressed = function() {
|
||||
|
@ -119,13 +117,13 @@ SoundDecoder.prototype.getSample16Uncompressed = function() {
|
|||
result = null;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
};
|
||||
|
||||
// 8-bit samples, uncompressed
|
||||
SoundDecoder.prototype.getSample8Uncompressed = function() {
|
||||
if (this.bytePosition >= this.info.sampleDataSize) return null;
|
||||
return (this.soundData[this.bytePosition++] - 128) << 8;
|
||||
}
|
||||
};
|
||||
|
||||
/*SoundDecoder.prototype.updateVolume = function() {
|
||||
if (this.client == null) {
|
||||
|
@ -154,8 +152,8 @@ SoundDecoder.prototype.getSampleADPCM = function() {
|
|||
// Note: Handles only one channel, 4-bits/sample.
|
||||
var step = 0, code = 0, delta = 0;
|
||||
|
||||
if (((this.bytePosition % this.adpcmBlockSize) == 0) && (this.lastByte < 0)) { // read block header
|
||||
if (this.bytePosition > (this.info.sampleDataSize - 4)) return null;
|
||||
if (this.bytePosition % this.adpcmBlockSize == 0 && this.lastByte < 0) { // read block header
|
||||
if (this.bytePosition > this.info.sampleDataSize - 4) return null;
|
||||
this.sample = (this.soundData[this.bytePosition + 1] << 8) + this.soundData[this.bytePosition];
|
||||
if (this.sample > 32767) this.sample -= 65536;
|
||||
this.index = this.soundData[this.bytePosition + 2];
|
||||
|
@ -184,7 +182,7 @@ SoundDecoder.prototype.getSampleADPCM = function() {
|
|||
if (this.index > 88) this.index = 88;
|
||||
if (this.index < 0) this.index = 0;
|
||||
// compute and output sample
|
||||
this.sample += ((code & 8) ? -delta : delta);
|
||||
this.sample += code & 8 ? -delta : delta;
|
||||
if (this.sample > 32767) this.sample = 32767;
|
||||
if (this.sample < -32768) this.sample = -32768;
|
||||
return this.sample;
|
||||
|
|
|
@ -19,7 +19,6 @@
|
|||
|
||||
var WAVFile = function() {};
|
||||
|
||||
|
||||
WAVFile.decode = function(waveData) {
|
||||
// Decode the given WAV file data and return an Object with the format and sample data.
|
||||
var result = {};
|
||||
|
@ -75,8 +74,7 @@ WAVFile.decode = function(waveData) {
|
|||
return;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
WAVFile.extractChunk = function(desiredType, data) {
|
||||
// Return the contents of the first chunk of the given type or an empty OffsetBuffer if it is not found.
|
||||
|
@ -93,8 +91,7 @@ WAVFile.extractChunk = function(desiredType, data) {
|
|||
}
|
||||
}
|
||||
return new OffsetBuffer(new ArrayBuffer());
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
WAVFile.dataChunkStartAndSize = function(data) {
|
||||
// Return an array with the starting offset and size of the first chunk of the given type.
|
||||
|
@ -110,4 +107,4 @@ WAVFile.dataChunkStartAndSize = function(data) {
|
|||
}
|
||||
}
|
||||
return [0, 0]; // chunk not found; bad wave file
|
||||
}
|
||||
};
|
||||
|
|
|
@ -29,8 +29,8 @@ Color.fromHSV = function(h, s, v) {
|
|||
var i = Math.floor(h / 60);
|
||||
var f = (h / 60) - i;
|
||||
var p = v * (1 - s);
|
||||
var q = v * (1 - (s * f));
|
||||
var t = v * (1 - (s * (1 - f)));
|
||||
var q = v * (1 - s * f);
|
||||
var t = v * (1 - s * (1 - f));
|
||||
if (i == 0) { r = v; g = t; b = p; }
|
||||
else if (i == 1) { r = q; g = v; b = p; }
|
||||
else if (i == 2) { r = p; g = v; b = t; }
|
||||
|
@ -41,7 +41,7 @@ Color.fromHSV = function(h, s, v) {
|
|||
g = Math.floor(g * 255);
|
||||
b = Math.floor(b * 255);
|
||||
return (r << 16) | (g << 8) | b;
|
||||
}
|
||||
};
|
||||
|
||||
Color.rgb2hsv = function(rgb) {
|
||||
var h, s, v, x, f, i;
|
||||
|
@ -51,18 +51,18 @@ Color.rgb2hsv = function(rgb) {
|
|||
x = Math.min(Math.min(r, g), b);
|
||||
v = Math.max(Math.max(r, g), b);
|
||||
if (x == v) return [0, 0, v]; // gray; hue arbitrarily reported as zero
|
||||
f = (r == x) ? g - b : ((g == x) ? b - r : r - g);
|
||||
i = (r == x) ? 3 : ((g == x) ? 5 : 1);
|
||||
h = ((i - (f / (v - x))) * 60) % 360;
|
||||
f = r == x ? g - b : g == x ? b - r : r - g;
|
||||
i = r == x ? 3 : g == x ? 5 : 1;
|
||||
h = ((i - f / (v - x)) * 60) % 360;
|
||||
s = (v - x) / v;
|
||||
return [h, s, v];
|
||||
}
|
||||
};
|
||||
|
||||
Color.scaleBrightness = function(rgb, scale) {
|
||||
var hsv = Color.rgb2hsv(rgb);
|
||||
scale = Math.max(0, Math.min(scale, 1));
|
||||
return Color.fromHSV(hsv[0], hsv[1], scale * hsv[2]);
|
||||
}
|
||||
};
|
||||
|
||||
Color.mixRGB = function(rgb1, rgb2, fraction) {
|
||||
// Mix rgb1 with rgb2. 0 gives all rgb1, 1 gives rbg2, .5 mixes them 50/50.
|
||||
|
@ -78,7 +78,7 @@ Color.mixRGB = function(rgb1, rgb2, fraction) {
|
|||
var g = ((fraction * g2) + ((1.0 - fraction) * g1)) & 255;
|
||||
var b = ((fraction * b2) + ((1.0 - fraction) * b1)) & 255;
|
||||
return (r << 16) | (g << 8) | b;
|
||||
}
|
||||
};
|
||||
|
||||
Color.random = function() {
|
||||
// return a random color
|
||||
|
@ -86,4 +86,4 @@ Color.random = function() {
|
|||
var s = 0.7 + (0.3 * Math.random());
|
||||
var v = 0.6 + (0.4 * Math.random());
|
||||
return Color.fromHSV(h, s, v);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -19,63 +19,63 @@
|
|||
var OffsetBuffer = function(data) {
|
||||
this.offset = 0;
|
||||
this.ab = data;
|
||||
}
|
||||
};
|
||||
|
||||
// Read various datatypes from the ArrayBuffer, seeking the offset.
|
||||
OffsetBuffer.prototype.readString = function(length) {
|
||||
var str = this.ab2str(this.ab.slice(this.offset, this.offset + length));
|
||||
this.offset += length;
|
||||
return str;
|
||||
}
|
||||
};
|
||||
|
||||
OffsetBuffer.prototype.readInt = function() {
|
||||
var num = this.ab2int(this.ab.slice(this.offset, this.offset + 4));
|
||||
this.offset += 4;
|
||||
return num;
|
||||
}
|
||||
};
|
||||
|
||||
OffsetBuffer.prototype.readUint = function() {
|
||||
var num = this.ab2uint(this.ab.slice(this.offset, this.offset + 4));
|
||||
this.offset += 4;
|
||||
return num;
|
||||
}
|
||||
};
|
||||
|
||||
OffsetBuffer.prototype.readShort = function() {
|
||||
var num = this.ab2short(this.ab.slice(this.offset, this.offset + 2));
|
||||
this.offset += 2;
|
||||
return num;
|
||||
}
|
||||
};
|
||||
|
||||
OffsetBuffer.prototype.readBytes = function(length) {
|
||||
var bytes = this.ab.slice(this.offset, this.offset + length);
|
||||
this.offset += length;
|
||||
return bytes;
|
||||
}
|
||||
};
|
||||
|
||||
// Length of the internal buffer
|
||||
OffsetBuffer.prototype.getLength = function() {
|
||||
return this.ab.byteLength;
|
||||
}
|
||||
};
|
||||
|
||||
// Number of bytes remaining from the current offset
|
||||
OffsetBuffer.prototype.bytesAvailable = function() {
|
||||
return (this.getLength() - this.offset);
|
||||
}
|
||||
return this.getLength() - this.offset;
|
||||
};
|
||||
|
||||
// ArrayBuffer -> JS type conversion methods
|
||||
OffsetBuffer.prototype.ab2str = function(buf) {
|
||||
return String.fromCharCode.apply(null, new Uint8Array(buf));
|
||||
}
|
||||
};
|
||||
|
||||
// These create Javascript Numbers
|
||||
OffsetBuffer.prototype.ab2int = function(buf) {
|
||||
return new Int32Array(buf)[0];
|
||||
}
|
||||
};
|
||||
|
||||
OffsetBuffer.prototype.ab2uint = function(buf) {
|
||||
return new Uint32Array(buf)[0];
|
||||
}
|
||||
};
|
||||
|
||||
OffsetBuffer.prototype.ab2short = function(buf) {
|
||||
return new Int16Array(buf)[0];
|
||||
}
|
||||
};
|
||||
|
|
|
@ -16,7 +16,7 @@
|
|||
var Point = function(x, y) {
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
}
|
||||
};
|
||||
|
||||
var Rectangle = function(x, y, width, height) {
|
||||
this.x = x;
|
||||
|
@ -27,10 +27,8 @@ var Rectangle = function(x, y, width, height) {
|
|||
this.right = x + width;
|
||||
this.top = y;
|
||||
this.bottom = y + height;
|
||||
}
|
||||
};
|
||||
|
||||
Rectangle.prototype.intersects = function(other) {
|
||||
return !(this.left > other.right ||
|
||||
this.right < other.left ||
|
||||
this.top > other.bottom ||
|
||||
this.bottom < other.top);
|
||||
}
|
||||
return !(this.left > other.right || this.right < other.left || this.top > other.bottom || this.bottom < other.top);
|
||||
};
|
||||
|
|
|
@ -21,40 +21,40 @@ var Timer = function() {
|
|||
var trials = [];
|
||||
var last_trial = 0;
|
||||
var start_time = 0;
|
||||
}
|
||||
};
|
||||
|
||||
Timer.prototype.time = function() {
|
||||
return (new Date()).getTime();
|
||||
}
|
||||
return Date.now();
|
||||
};
|
||||
|
||||
Timer.prototype.start = function() {
|
||||
start_time = this.time();
|
||||
}
|
||||
};
|
||||
|
||||
Timer.prototype.stop = function() {
|
||||
end = this.time();
|
||||
last_trial = end - start_time;
|
||||
trials.push(last_trial);
|
||||
}
|
||||
};
|
||||
|
||||
Timer.prototype.count = function() {
|
||||
return trials.length;
|
||||
}
|
||||
};
|
||||
|
||||
Timer.prototype.average = function() {
|
||||
sum = 0;
|
||||
for(i = 0; i < this.count(); i++) {
|
||||
for (i = 0; i < this.count(); i++) {
|
||||
sum += trials[i];
|
||||
}
|
||||
return sum / this.count();
|
||||
}
|
||||
};
|
||||
|
||||
Timer.prototype.print = function(element) {
|
||||
text = "Trial: " + last_trial + "ms" +
|
||||
"<br />\nTrials: " + this.count() + ", Avg: " + this.average() + "ms";
|
||||
if(element) {
|
||||
if (element) {
|
||||
$(element).html(text);
|
||||
} else {
|
||||
console.log(text);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
Reference in a new issue