mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-07-12 14:03:57 -04:00
Merge remote-tracking branch 'LLK/develop' into develop
This commit is contained in:
parent
ed9623ef4b
commit
0024b209bd
11 changed files with 303 additions and 3 deletions
15
.github/ISSUE_TEMPLATE.md
vendored
Normal file
15
.github/ISSUE_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
### Expected behavior
|
||||
|
||||
_Please describe what should happen_
|
||||
|
||||
### Actual behavior
|
||||
|
||||
_Describe what actually happens_
|
||||
|
||||
### Steps to reproduce
|
||||
|
||||
_Explain what someone needs to do in order to see what's described in *Actual behavior* above_
|
||||
|
||||
### Operating system and browser
|
||||
|
||||
_e.g. Mac OS 10.11.6 Safari 10.0_
|
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
7
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
### Proposed changes
|
||||
|
||||
_Describe what this Pull Request does_
|
||||
|
||||
### Reason for changes
|
||||
|
||||
_Explain why these changes should be made. Please include an issue # if applicable._
|
25
CONTRIBUTING.md
Normal file
25
CONTRIBUTING.md
Normal file
|
@ -0,0 +1,25 @@
|
|||
## Contributing
|
||||
The development of scratch-vm is an ongoing process,
|
||||
and we love to have people in the Scratch and open source communities help us along the way.
|
||||
|
||||
If you're interested in contributing, please take a look at the
|
||||
[issues](https://github.com/LLK/scratch-vm/issues) on this repository.
|
||||
Two great ways of helping are by identifying bugs and documenting them as issues,
|
||||
or fixing issues and creating pull requests. When submitting pull requests please be patient
|
||||
-- it can take a while to find time to review them.
|
||||
The organization and class structures can't be radically changed without significant coordination
|
||||
and collaboration from the Scratch Team, so these types of changes should be avoided.
|
||||
|
||||
It's been said that the Scratch Team spends about one hour of design discussion for every pixel in Scratch,
|
||||
but some think that estimate is a little low. While we welcome suggestions for new features in our
|
||||
[suggestions forum](https://scratch.mit.edu/discuss/1/) (especially ones that come with mockups), we are unlikely to accept PRs with
|
||||
new features that haven't been thought through and discussed as a group. Why? Because we have a strong belief
|
||||
in the value of keeping things simple for new users. To learn more about our design philosophy,
|
||||
see [the Scratch Developers page](https://scratch.mit.edu/developers), or
|
||||
[this paper](http://web.media.mit.edu/~mres/papers/Scratch-CACM-final.pdf).
|
||||
|
||||
Beyond this repo, there are also some other resources that you might want to take a look at:
|
||||
* [Community Guidelines](https://github.com/LLK/scratch-www/wiki/Community-Guidelines) (we find it important to maintain a constructive and welcoming community, just like on Scratch)
|
||||
* [Open Source forum](https://scratch.mit.edu/discuss/49/) on Scratch
|
||||
* [Suggestions forum](https://scratch.mit.edu/discuss/1/) on Scratch
|
||||
* [Bugs & Glitches forum](https://scratch.mit.edu/discuss/3/) on Scratch
|
|
@ -2,6 +2,7 @@
|
|||
#### Scratch VM is a library for representing, running, and maintaining the state of computer programs written using [Scratch Blocks](https://github.com/LLK/scratch-blocks).
|
||||
|
||||
[](https://travis-ci.org/LLK/scratch-vm)
|
||||
[](https://coveralls.io/github/LLK/scratch-vm?branch=develop)
|
||||
[](https://david-dm.org/LLK/scratch-vm)
|
||||
[](https://david-dm.org/LLK/scratch-vm#info=devDependencies)
|
||||
|
||||
|
|
BIN
assets/stage.png
BIN
assets/stage.png
Binary file not shown.
Before ![]() (image error) Size: 1.3 KiB After ![]() (image error) Size: 3.5 KiB ![]() ![]() |
|
@ -13,6 +13,7 @@ h2 {
|
|||
right: 0;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, sans-serif;
|
||||
}
|
||||
#vm-devtools {
|
||||
color: rgb(217,217,217);
|
||||
|
|
|
@ -18,9 +18,11 @@ Scratch3MotionBlocks.prototype.getPrimitives = function() {
|
|||
return {
|
||||
'motion_movesteps': this.moveSteps,
|
||||
'motion_gotoxy': this.goToXY,
|
||||
'motion_goto': this.goTo,
|
||||
'motion_turnright': this.turnRight,
|
||||
'motion_turnleft': this.turnLeft,
|
||||
'motion_pointindirection': this.pointInDirection,
|
||||
'motion_pointtowards': this.pointTowards,
|
||||
'motion_glidesecstoxy': this.glide,
|
||||
'motion_setrotationstyle': this.setRotationStyle,
|
||||
'motion_changexby': this.changeX,
|
||||
|
@ -47,6 +49,26 @@ Scratch3MotionBlocks.prototype.goToXY = function (args, util) {
|
|||
util.target.setXY(x, y);
|
||||
};
|
||||
|
||||
Scratch3MotionBlocks.prototype.goTo = function (args, util) {
|
||||
var targetX = 0;
|
||||
var targetY = 0;
|
||||
if (args.TO === '_mouse_') {
|
||||
targetX = util.ioQuery('mouse', 'getX');
|
||||
targetY = util.ioQuery('mouse', 'getY');
|
||||
} else if (args.TO === '_random_') {
|
||||
var stageWidth = this.runtime.constructor.STAGE_WIDTH;
|
||||
var stageHeight = this.runtime.constructor.STAGE_HEIGHT;
|
||||
targetX = Math.round(stageWidth * (Math.random() - 0.5));
|
||||
targetY = Math.round(stageHeight * (Math.random() - 0.5));
|
||||
} else {
|
||||
var goToTarget = this.runtime.getSpriteTargetByName(args.TO);
|
||||
if (!goToTarget) return;
|
||||
targetX = goToTarget.x;
|
||||
targetY = goToTarget.y;
|
||||
}
|
||||
util.target.setXY(targetX, targetY);
|
||||
};
|
||||
|
||||
Scratch3MotionBlocks.prototype.turnRight = function (args, util) {
|
||||
var degrees = Cast.toNumber(args.DEGREES);
|
||||
util.target.setDirection(util.target.direction + degrees);
|
||||
|
@ -62,6 +84,25 @@ Scratch3MotionBlocks.prototype.pointInDirection = function (args, util) {
|
|||
util.target.setDirection(direction);
|
||||
};
|
||||
|
||||
Scratch3MotionBlocks.prototype.pointTowards = function (args, util) {
|
||||
var targetX = 0;
|
||||
var targetY = 0;
|
||||
if (args.TOWARDS === '_mouse_') {
|
||||
targetX = util.ioQuery('mouse', 'getX');
|
||||
targetY = util.ioQuery('mouse', 'getY');
|
||||
} else {
|
||||
var pointTarget = this.runtime.getSpriteTargetByName(args.TOWARDS);
|
||||
if (!pointTarget) return;
|
||||
targetX = pointTarget.x;
|
||||
targetY = pointTarget.y;
|
||||
}
|
||||
|
||||
var dx = targetX - util.target.x;
|
||||
var dy = targetY - util.target.y;
|
||||
var direction = 90 - MathUtil.radToDeg(Math.atan2(dy, dx));
|
||||
util.target.setDirection(direction);
|
||||
};
|
||||
|
||||
Scratch3MotionBlocks.prototype.glide = function (args, util) {
|
||||
if (!util.stackFrame.timer) {
|
||||
// First time: save data for future use.
|
||||
|
|
|
@ -16,6 +16,7 @@ Scratch3SensingBlocks.prototype.getPrimitives = function() {
|
|||
return {
|
||||
'sensing_touchingcolor': this.touchingColor,
|
||||
'sensing_coloristouchingcolor': this.colorTouchingColor,
|
||||
'sensing_distanceto': this.distanceTo,
|
||||
'sensing_timer': this.getTimer,
|
||||
'sensing_resettimer': this.resetTimer,
|
||||
'sensing_mousex': this.getMouseX,
|
||||
|
@ -37,6 +38,28 @@ Scratch3SensingBlocks.prototype.colorTouchingColor = function (args, util) {
|
|||
return util.target.colorIsTouchingColor(targetColor, maskColor);
|
||||
};
|
||||
|
||||
Scratch3SensingBlocks.prototype.distanceTo = function (args, util) {
|
||||
if (util.target.isStage) return 10000;
|
||||
|
||||
var targetX = 0;
|
||||
var targetY = 0;
|
||||
if (args.DISTANCETOMENU === '_mouse_') {
|
||||
targetX = util.ioQuery('mouse', 'getX');
|
||||
targetY = util.ioQuery('mouse', 'getY');
|
||||
} else {
|
||||
var distTarget = this.runtime.getSpriteTargetByName(
|
||||
args.DISTANCETOMENU
|
||||
);
|
||||
if (!distTarget) return 10000;
|
||||
targetX = distTarget.x;
|
||||
targetY = distTarget.y;
|
||||
}
|
||||
|
||||
var dx = util.target.x - targetX;
|
||||
var dy = util.target.y - targetY;
|
||||
return Math.sqrt((dx * dx) + (dy * dy));
|
||||
};
|
||||
|
||||
Scratch3SensingBlocks.prototype.getTimer = function (args, util) {
|
||||
return util.ioQuery('clock', 'projectTimer');
|
||||
};
|
||||
|
|
|
@ -70,6 +70,18 @@ function Runtime () {
|
|||
this._cloneCounter = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Width of the stage, in pixels.
|
||||
* @const {number}
|
||||
*/
|
||||
Runtime.STAGE_WIDTH = 480;
|
||||
|
||||
/**
|
||||
* Height of the stage, in pixels.
|
||||
* @const {number}
|
||||
*/
|
||||
Runtime.STAGE_HEIGHT = 360;
|
||||
|
||||
/**
|
||||
* Event name for glowing a script.
|
||||
* @const {string}
|
||||
|
|
|
@ -137,9 +137,9 @@ VirtualMachine.prototype.createEmptyProject = function () {
|
|||
stage.costumes.push({
|
||||
skin: '/assets/stage.png',
|
||||
name: 'backdrop1',
|
||||
bitmapResolution: 1,
|
||||
rotationCenterX: 240,
|
||||
rotationCenterY: 180
|
||||
bitmapResolution: 2,
|
||||
rotationCenterX: 480,
|
||||
rotationCenterY: 360
|
||||
});
|
||||
var target2 = stage.createClone();
|
||||
this.runtime.targets.push(target2);
|
||||
|
|
175
test/unit/blocks_operators.js
Normal file
175
test/unit/blocks_operators.js
Normal file
|
@ -0,0 +1,175 @@
|
|||
var test = require('tap').test;
|
||||
var Operators = require('../../src/blocks/scratch3_operators');
|
||||
|
||||
var blocks = new Operators(null);
|
||||
|
||||
test('getPrimitives', function (t) {
|
||||
t.type(blocks.getPrimitives(), 'object');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('add', function (t) {
|
||||
t.strictEqual(blocks.add({NUM1:'1', NUM2:'1'}), 2);
|
||||
t.strictEqual(blocks.add({NUM1:'foo', NUM2:'bar'}), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('subtract', function (t) {
|
||||
t.strictEqual(blocks.subtract({NUM1:'1', NUM2:'1'}), 0);
|
||||
t.strictEqual(blocks.subtract({NUM1:'foo', NUM2:'bar'}), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('multiply', function (t) {
|
||||
t.strictEqual(blocks.multiply({NUM1:'2', NUM2:'2'}), 4);
|
||||
t.strictEqual(blocks.multiply({NUM1:'foo', NUM2:'bar'}), 0);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('divide', function (t) {
|
||||
t.strictEqual(blocks.divide({NUM1:'2', NUM2:'2'}), 1);
|
||||
t.strictEqual(blocks.divide({NUM1:'1', NUM2:'0'}), Infinity); // @todo
|
||||
t.ok(isNaN(blocks.divide({NUM1:'foo', NUM2:'bar'}))); // @todo
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('lt', function (t) {
|
||||
t.strictEqual(blocks.lt({OPERAND1:'1', OPERAND2:'2'}), true);
|
||||
t.strictEqual(blocks.lt({OPERAND1:'2', OPERAND2:'1'}), false);
|
||||
t.strictEqual(blocks.lt({OPERAND1:'1', OPERAND2:'1'}), false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('equals', function (t) {
|
||||
t.strictEqual(blocks.equals({OPERAND1:'1', OPERAND2:'2'}), false);
|
||||
t.strictEqual(blocks.equals({OPERAND1:'2', OPERAND2:'1'}), false);
|
||||
t.strictEqual(blocks.equals({OPERAND1:'1', OPERAND2:'1'}), true);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('gt', function (t) {
|
||||
t.strictEqual(blocks.gt({OPERAND1:'1', OPERAND2:'2'}), false);
|
||||
t.strictEqual(blocks.gt({OPERAND1:'2', OPERAND2:'1'}), true);
|
||||
t.strictEqual(blocks.gt({OPERAND1:'1', OPERAND2:'1'}), false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('and', function (t) {
|
||||
t.strictEqual(blocks.and({OPERAND1:true, OPERAND2:true}), true);
|
||||
t.strictEqual(blocks.and({OPERAND1:true, OPERAND2:false}), false);
|
||||
t.strictEqual(blocks.and({OPERAND1:false, OPERAND2:false}), false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('or', function (t) {
|
||||
t.strictEqual(blocks.or({OPERAND1:true, OPERAND2:true}), true);
|
||||
t.strictEqual(blocks.or({OPERAND1:true, OPERAND2:false}), true);
|
||||
t.strictEqual(blocks.or({OPERAND1:false, OPERAND2:false}), false);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('not', function (t) {
|
||||
t.strictEqual(blocks.not({OPERAND:true}), false);
|
||||
t.strictEqual(blocks.not({OPERAND:false}), true);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('random', function (t) {
|
||||
var min = 0;
|
||||
var max = 100;
|
||||
var result = blocks.random({FROM:min, TO:max});
|
||||
t.ok(result >= min);
|
||||
t.ok(result <= max);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('random - equal', function (t) {
|
||||
var min = 1;
|
||||
var max = 1;
|
||||
t.strictEqual(blocks.random({FROM:min, TO:max}), min);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('random - decimal', function (t) {
|
||||
var min = 0.1;
|
||||
var max = 10;
|
||||
var result = blocks.random({FROM:min, TO:max});
|
||||
t.ok(result >= min);
|
||||
t.ok(result <= max);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('random - int', function (t) {
|
||||
var min = 0;
|
||||
var max = 10;
|
||||
var result = blocks.random({FROM:min, TO:max});
|
||||
t.ok(result >= min);
|
||||
t.ok(result <= max);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('random - reverse', function (t) {
|
||||
var min = 0;
|
||||
var max = 10;
|
||||
var result = blocks.random({FROM:max, TO:min});
|
||||
t.ok(result >= min);
|
||||
t.ok(result <= max);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('join', function (t) {
|
||||
t.strictEqual(blocks.join({STRING1:'foo', STRING2:'bar'}), 'foobar');
|
||||
t.strictEqual(blocks.join({STRING1:'1', STRING2:'2'}), '12');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('letterOf', function (t) {
|
||||
t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:0}), '');
|
||||
t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:1}), 'f');
|
||||
t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:2}), 'o');
|
||||
t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:3}), 'o');
|
||||
t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:4}), '');
|
||||
t.strictEqual(blocks.letterOf({STRING:'foo', LETTER:'bar'}), '');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('length', function (t) {
|
||||
t.strictEqual(blocks.length({STRING:''}), 0);
|
||||
t.strictEqual(blocks.length({STRING:'foo'}), 3);
|
||||
t.strictEqual(blocks.length({STRING:'1'}), 1);
|
||||
t.strictEqual(blocks.length({STRING:'100'}), 3);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('mod', function (t) {
|
||||
t.strictEqual(blocks.mod({NUM1:1, NUM2:1}), 0);
|
||||
t.strictEqual(blocks.mod({NUM1:3, NUM2:6}), 3);
|
||||
t.strictEqual(blocks.mod({NUM1:-3, NUM2:6}), 3);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('round', function (t) {
|
||||
t.strictEqual(blocks.round({NUM:1}), 1);
|
||||
t.strictEqual(blocks.round({NUM:1.1}), 1);
|
||||
t.strictEqual(blocks.round({NUM:1.5}), 2);
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('mathop', function (t) {
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'abs', NUM:-1}), 1);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'floor', NUM:1.5}), 1);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'ceiling', NUM:0.1}), 1);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'sqrt', NUM:1}), 1);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'sin', NUM:1}), 0.01745240643728351);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'cos', NUM:1}), 0.9998476951563913);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'tan', NUM:1}), 0.017455064928217585);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'asin', NUM:1}), 90);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'acos', NUM:1}), 0);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'atan', NUM:1}), 45);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'ln', NUM:1}), 0);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'log', NUM:1}), 0);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'e ^', NUM:1}), 2.718281828459045);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'10 ^', NUM:1}), 10);
|
||||
t.strictEqual(blocks.mathop({OPERATOR:'undefined', NUM:1}), 0);
|
||||
t.end();
|
||||
});
|
Loading…
Add table
Add a link
Reference in a new issue