mirror of
https://github.com/scratchfoundation/scratch-vm.git
synced 2025-01-08 14:01:58 -05:00
Make "when clicked" blocks target dependent.
This involves adding a new opcode, event_whenstageclicked, and adding a method to the blocks container to update the opcode pair depending on whether the target is the stage. This method is then called in two places: first after the sb2 import parses the blocks (not done in the sb2 parsing itself because no other blocks are target specific) and then again when blocks are shared between targets. Also added tests for the block container method, and a fixture project that tests the opcode splitting on sb2 import.
This commit is contained in:
parent
2b985fa083
commit
140094a7ad
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