mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2024-12-24 06:52:40 -05:00
Merge pull request #992 from paulkaplan/stage-clicked
Make "when clicked" blocks target dependent.
This commit is contained in:
commit
a27ed888d2
8 changed files with 82 additions and 0 deletions
|
@ -32,6 +32,9 @@ class Scratch3EventBlocks {
|
|||
event_whenthisspriteclicked: {
|
||||
restartExistingThreads: true
|
||||
},
|
||||
event_whenstageclicked: {
|
||||
restartExistingThreads: true
|
||||
},
|
||||
event_whenbackdropswitchesto: {
|
||||
restartExistingThreads: true
|
||||
},
|
||||
|
|
|
@ -593,6 +593,21 @@ class Blocks {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Keep blocks up to date after they are shared between targets.
|
||||
* @param {boolean} isStage If the new target is a stage.
|
||||
*/
|
||||
updateTargetSpecificBlocks (isStage) {
|
||||
const blocks = this._blocks;
|
||||
for (const blockId in blocks) {
|
||||
if (isStage && blocks[blockId].opcode === 'event_whenthisspriteclicked') {
|
||||
blocks[blockId].opcode = 'event_whenstageclicked';
|
||||
} else if (!isStage && blocks[blockId].opcode === 'event_whenstageclicked') {
|
||||
blocks[blockId].opcode = 'event_whenthisspriteclicked';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update blocks after a sound, costume, or backdrop gets renamed.
|
||||
* Any block referring to the old name of the asset should get updated
|
||||
|
|
|
@ -31,8 +31,15 @@ class Mouse {
|
|||
// only activate click hat if the mouse up event wasn't
|
||||
// the result of a drag ending
|
||||
if (!wasDragged) {
|
||||
// Activate both "this sprite clicked" and "stage clicked"
|
||||
// They were separated into two opcodes for labeling,
|
||||
// but should act the same way.
|
||||
// Intentionally not checking isStage to make it work when sharing blocks.
|
||||
// @todo the blocks should be converted from one to another when shared
|
||||
this.runtime.startHats('event_whenthisspriteclicked',
|
||||
null, target);
|
||||
this.runtime.startHats('event_whenstageclicked',
|
||||
null, target);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -275,6 +275,9 @@ const parseScratchObject = function (object, runtime, extensions, topLevel) {
|
|||
parseScripts(object.scripts, blocks, addBroadcastMsg, getVariableId, extensions);
|
||||
}
|
||||
|
||||
// Update stage specific blocks (e.g. sprite clicked <=> stage clicked)
|
||||
blocks.updateTargetSpecificBlocks(topLevel); // topLevel = isStage
|
||||
|
||||
if (object.hasOwnProperty('lists')) {
|
||||
for (let k = 0; k < object.lists.length; k++) {
|
||||
const list = object.lists[k];
|
||||
|
|
|
@ -778,6 +778,7 @@ class VirtualMachine extends EventEmitter {
|
|||
for (let i = 0; i < blocks.length; i++) {
|
||||
target.blocks.createBlock(blocks[i]);
|
||||
}
|
||||
target.blocks.updateTargetSpecificBlocks(target.isStage);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
BIN
test/fixtures/when-clicked.sb2
vendored
Normal file
BIN
test/fixtures/when-clicked.sb2
vendored
Normal file
Binary file not shown.
|
@ -746,3 +746,33 @@ test('updateAssetName doesn\'t update name if name isn\'t being used', t => {
|
|||
t.equals(b.getBlock('id1').fields.BACKDROP.value, 'foo');
|
||||
t.end();
|
||||
});
|
||||
|
||||
test('updateTargetSpecificBlocks changes sprite clicked hat to stage clicked for stage', t => {
|
||||
const b = new Blocks();
|
||||
b.createBlock({
|
||||
id: 'originallySpriteClicked',
|
||||
opcode: 'event_whenthisspriteclicked'
|
||||
});
|
||||
b.createBlock({
|
||||
id: 'originallyStageClicked',
|
||||
opcode: 'event_whenstageclicked'
|
||||
});
|
||||
|
||||
// originallySpriteClicked does not update when on a non-stage target
|
||||
b.updateTargetSpecificBlocks(false /* isStage */);
|
||||
t.equals(b.getBlock('originallySpriteClicked').opcode, 'event_whenthisspriteclicked');
|
||||
|
||||
// originallySpriteClicked does update when on a stage target
|
||||
b.updateTargetSpecificBlocks(true /* isStage */);
|
||||
t.equals(b.getBlock('originallySpriteClicked').opcode, 'event_whenstageclicked');
|
||||
|
||||
// originallyStageClicked does not update when on a stage target
|
||||
b.updateTargetSpecificBlocks(true /* isStage */);
|
||||
t.equals(b.getBlock('originallyStageClicked').opcode, 'event_whenstageclicked');
|
||||
|
||||
// originallyStageClicked does update when on a non-stage target
|
||||
b.updateTargetSpecificBlocks(false/* isStage */);
|
||||
t.equals(b.getBlock('originallyStageClicked').opcode, 'event_whenthisspriteclicked');
|
||||
|
||||
t.end();
|
||||
});
|
||||
|
|
|
@ -68,3 +68,26 @@ test('data scoping', t => {
|
|||
t.end();
|
||||
});
|
||||
});
|
||||
|
||||
test('whenclicked blocks imported separately', t => {
|
||||
// This sb2 fixture has a single "whenClicked" block on both sprite and stage
|
||||
const uri = path.resolve(__dirname, '../fixtures/when-clicked.sb2');
|
||||
const file = extract(uri);
|
||||
const json = JSON.parse(file);
|
||||
|
||||
// Create runtime instance & load SB2 into it
|
||||
const rt = new Runtime();
|
||||
sb2.deserialize(json, rt).then(({targets}) => {
|
||||
const stage = targets[0];
|
||||
t.equal(stage.isStage, true); // Make sure we have the correct target
|
||||
const stageOpcode = stage.blocks.getBlock(stage.blocks.getScripts()[0]).opcode;
|
||||
t.equal(stageOpcode, 'event_whenstageclicked');
|
||||
|
||||
const sprite = targets[1];
|
||||
t.equal(sprite.isStage, false); // Make sure we have the correct target
|
||||
const spriteOpcode = sprite.blocks.getBlock(sprite.blocks.getScripts()[0]).opcode;
|
||||
t.equal(spriteOpcode, 'event_whenthisspriteclicked');
|
||||
|
||||
t.end();
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Reference in a new issue