Skip to main content

Adding C Blocks

info

This tutorial builds on the dialog blocks added in the Your First Scratch Mod tutorial series.

Simple C Blocks

Let's add this C block:

We will make this block display a confirm prompt repeatedly. Every time the user says Yes, it will run the code within, if the user says No, it will not display the confirm prompt again.

The scratch-blocks definition

scratch-blocks/blocks_vertical/dialogs.js
Blockly.Blocks['dialogs_whileconfirmed'] = {
/**
* @this Blockly.Block
*/
init: function(){
this.jsonInit({
"message0": Blockly.Msg.DIALOGS_WHILECONFIRMED, // while confirmed %1
"message1": "%1",
"args0": [
{
"type": "input_value",
"name": "MESSAGE"
}
],
"args1": [
{
"type": "input_statement",
"name": "SUBSTACK"
}
],
"category": Blockly.Categories.dialogs,
"extensions": ["colours_dialogs", "shape_statement"]
});
}
}

You will notice two differences from a regular block:

  1. message1: The %1 is where the block(s) inside the C block are inserted. Additional uses of this will be explained in the more branches section.
  2. args1: This contains the block input for the branch. A block input is a input_statement.

Don't forget to add the block message DIALOGS_WHILECONFIRMED, which should be while confirmed %1.

The scratch-gui toolbox entry

The block input is left out of the toolbox entry, because there aren't any blocks inside by default. You can copy and modify dialogs_alert for this block.

You can actually insert blocks into the C block by default

If you really want too, you can insert blocks into the C block by default. I'm not sure if there are any practical uses for this, but here is how you can:

scratch-gui/src/lib/make-toolbox-xml.js
<block type="dialogs_whileconfirmed">
<value name="MESSAGE">
<shadow type="text">
<field name="TEXT">${hello}</field>
</shadow>
</value>
<value name="SUBSTACK">
<block type="dialogs_alert">
<value name="MESSAGE">
<shadow type="text">
<field name="TEXT">${hello}</field>
</shadow>
</value>
</block>
</value>
</block>

The scratch-vm implementation

As usual, add the block to the getPrimitives function.

This is the code for the block implementation:

scratch-vm/src/blocks/tutorialmod_dialogs.js
whileConfirmedBlock(args, util){
if(confirm(args.MESSAGE)){
util.startBranch(1, true);
}
}

You might notice two important things about this:

  1. There is no loop in the block.
  2. We are using the util.startBranch function with the arguments 1 and true.

Let's start with the usage of the util.startBranch function. Here is the function's documentation:

scratch-vm/src/engine/block-utility.js
/**
* Start a branch in the current block.
* @param {number} branchNum Which branch to step to (i.e., 1, 2).
* @param {boolean} isLoop Whether this block is a loop.
*/
startBranch (branchNum, isLoop) {
// ...
}

The number 1 tells the Scratch VM to start executing the first branch in the block (in this case, the only branch). The true tells Scratch VM that this block is a loop. Setting isLoop to true doesn't make Scratch VM repeatedly execute the branch. It instead tells Scratch VM to re-execute the C block again after the branch's blocks, which can either do nothing and continue to the next block in the stack or re-execute the branch. This is the reason there is no loop in the function itself.

More branches

Let's now make a random choice C block with three branches. Because this block is random, it will be randomly placed in the dialog blocks category.

This is what the block will look like:

The scratch-blocks definition

scratch-blocks/blocks_vertical/dialogs.js
Blockly.Blocks['dialogs_randomchoice'] = {
/**
* @this Blockly.Block
*/
init: function(){
this.jsonInit({
"message0": Blockly.Msg.DIALOGS_RANDOMCHOICE,
"message1": "%1",
"message2": "%1",
"message3": "%1",
"args1": [
{
"type": "input_statement",
"name": "SUBSTACK"
}
],
"args2": [
{
"type": "input_statement",
"name": "SUBSTACK2"
}
],
"args3": [
{
"type": "input_statement",
"name": "SUBSTACK3"
}
],
"category": Blockly.Categories.dialogs,
"extensions": ["colours_dialogs", "shape_statement"]
});
}
};

You will notice that there are now some more message# and args#, these are the additional branches. You will also notice there is no args0, this is because there is no input box in this block, so it doesn't need it.

Again, don't forget to add the block message DIALOGS_RANDOMCHOICE, which should be random choice.

The scratch-gui toolbox entry

Unlike our other blocks, this block has no inputs, so we can just use this simple one line entry:

scratch-gui/src/lib/make-toolbox-xml.js
<block type="dialogs_randomchoice" />

The scratch-vm implementation

Once again, we must add the block to getPrimitives so Scratch can find our block's implementation.

This will be the implementation of this block:

scratch-vm/src/blocks/tutorialmod_dialogs.js
randomChoice(args, util){
let randomValue = Math.floor(Math.random() * 3 + 1);
util.startBranch(randomValue, false);
}
tip

JavaScript's Math.random() generates floating point numbers between 0 and 1, however never exactly one. MDN has examples on how to use Math.random() to get number in the range you want. In this case, the number is 1, 2 or 3.

randomValue is the branch we want to run and since we only want this block to run once (it isn't a loop), we use false instead of true.

Completed Files

ComponentFileDownload
scratch-blocksblocks_vertical/dialogs.jsdialogs.js
scratch-blocksmsg/messages.jsmessages.js
scratch-guisrc/lib/make-toolbox-xml.jsmake-toolbox-xml.js
scratch-vmsrc/blocks/tutorialmod_dialogs.jstutorialmod_dialogs.js

Scratch commit hashes at the time of this tutorial
scratch-gui:        db1933b2aea9f9dbe51e0ad2d750a2550179314a
scratch-vm: d6420c4c9826d360adee118e0e9e255536be7f7c
scratch-blocks: 686df65cc6b5b3df37dc3204f56f443aa18c5085