[Scratch3.0 拡張機能] 文字からユニコード番号に変換するちょっとしたエクステンションを作る


※ 当ページには【広告/PR】を含む場合があります。
2020/12/16

今回はScratch-guiで拡張機能を自作する企画第二段🎉です。文字もしくは文字列からユニコード(16進数)に変換するための簡単な機能を自作してみましょう。

以前の内容で、Scratch-guiの自作拡張機能(エクステンションブロック)を作成手順を説明した記事はこちらです👇

合同会社タコスキングダム|タコキンのPスクール
【Scratch拡張機能・自作】テキストデータを読み出し・保存するエクステンションを作ろう

Scratchの拡張機能の自作手順の基礎を、テキストを読み出し・書き出しできるような機能の実装を例に解説します。


合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】Scratchを学べるオンライン・駅前プログラミングスクール5選

何かから何かを変換するブロックタイプ ~ レポーター

今回もScratch-guiで拡張機能を自作する手順を具体例で復習・発展させていきたいと思います。

さて、以前もお話したと思いますがスクラッチの拡張機能ブロックにおいては主に以下の4つのブロックタイプをベースに拡張しながら作成することができます。

            
            + コマンドタイプ:
    何かの処理を実行するブロック
+ レポータータイプ:
    文字列や数値を返すブロック
+ ブーリアンタイプ:
    判定を行うブロック
+ ハットタイプ:
    イベントを監視・処理をするブロック
        
今回はレポータータイプの実装に着目しながら、文字からユニコード(16進数)に変換する簡単なブロックを作成を行っていきます。


合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】Scratchをしっかり学ぶためのオススメ書籍まとめ

文字のユニコード番号をコスチューム画像の識別に利用したい

以下のように関連記事のお話ですが、以前の内容までで、フォントファイルから一つ一つのsvg画像を抽出して、スプライトのコスチュームへ割り当てるまでのスクラッチプロジェクトの作成方法を説明していました。

合同会社タコスキングダム|タコキンのPスクール
【Scratch拡張機能・自作】テキストデータを読み出し・保存するエクステンションを作ろう

Scratchの拡張機能の自作手順の基礎を、テキストを読み出し・書き出しできるような機能の実装を例に解説します。

一応フォントが自由に打ち出せるまで動作するスクラッチプログラムに仕上がったのですが、そこから大きな壁にぶち当たりました。

それはフォントの数が大体数千個もあるのに、一つのスプライトに割り当てられるコスチュームの個数はせいぜい100個くらいがブラウザ内でサクサク動くための上限みたいな問題です。

この問題を回避するためには、複数のスプライトにフォント画像を分割しながら割り当てて、文字ごとに対応するコスチュームを表示できればなんとか動くのでは...という一つのアイディアが浮かびました。

でもフォント画像を仕分けるとしても、文字をどういった規則で分割して、各スプライトから探しだそうか?といった課題が出てきました。

そこで解決案として、文字にはユニコード識別番号というものがあるので、これを利用することでフォント画像の区分け整理と検索ができるのではないか...そうだ文字からユニコードを表示させるエクステンションを作りましょう、というのが今回のお話です。


合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】Scratchを学べるオンライン・駅前プログラミングスクール5選

Scratch3エクステンションの作成

では今回のスクラッチ用自作エクステンションの具体的な実装手順を細かく見ていきましょう。

エクステンションのブロック表紙絵とアイコン画像

まずは2つのサイズ指定された画像を準備する決まりなので以下の図のように作成しました。

大きいほうの画像(600x372)を
str2unicode.png

合同会社タコスキングダム|タコキンのPスクール

そして小さい方(80x80)を
str2unicode-small.pngとして、

合同会社タコスキングダム|タコキンのPスクール

プロジェクトの中の
scratch-gui/src/lib/libraries/extensions/str2unicodeというフォルダーを作って保存しておきます。

ブロックアイコンはスクラッチの画像エディタで40x40の正方形範囲に収まるサイズに作成して書き出ししておきます。

合同会社タコスキングダム|タコキンのPスクール

保存したアイコンsvgは例によって
こちらのサイトでbase64化をしておきましょう。

index.jsxの中身を修正

scratch-gui/src/lib/libraries/extensions`scratch-gui/src/lib/libraries/extensions`のindex.jsxが全てのエクステンションを操作するGUIのエンドポイントになりますので、ここに今回作成するstr2unicodeエクステンションを新しく登録しておきます。

            
            import React from 'react';
import {FormattedMessage} from 'react-intl';

//...中略

//👇先程作った画像までのリソースパスを定義
import str2unicodeURL from './str2unicode/str2unicode.png';
import str2unicodeIconURL from './str2unicode/str2unicode-small.png';

export default [
    ///...中略
    //👇拡張機能を追加登録
    {
        name: '文字からユニコードへ変換',
        extensionId: 'str2unicode',
        iconURL: str2unicodeURL,
        insetIconURL: str2unicodeIconURL,
        description: (
            <FormattedMessage
                defaultMessage="文字からユニコードを調べます"
                description="Description for the 'Str2Unicode' extension"
                id="gui.extension.str2unicode.description"
            />
        ),
        featured: true
    }
];
        

拡張機能の中身を実装

次はエクステンション本体の実装を行います。

scratch-vm/src/extensions以下に新しいフォルダをエクステンションに対応した名前で作ります。

ここでは
scratch3_str2unicodeというフォルダ名にしておきます。

メインファイルのindex.jsを同フォルダ内に新規作成・追加しておきましょう。

エクステンションのサンプルコードの雛形は以下のようになりますのでこれをコピーして利用してもらってもよいと思います。

index.jsのテンプレートの書き方は
こちらのサイトを参考してください。

            
            const ArgumentType = require('../../extension-support/argument-type');
const BlockType = require('../../extension-support/block-type');
const Cast = require('../../util/cast');
const log = require('../../util/log');

// 👇先程作成したアイコン画像
const commonSvgIcon = 'data:image/svg+xml;base64,PHN2ZyB2ZXJzaW9uPSIxLjEiIHZpZXdCb3g9IjAgMCAzOC4zMDIgMzguNDc1IiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPgogPGcgdHJhbnNmb3JtPSJ0cmFuc2xhdGUoLTE5Mi44OCAtMTcyLjU0KSI+CiAgPGcgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjMDAwMDAwIiBzdHJva2UtZGFzaGFycmF5PSIiIHN0cm9rZS1taXRlcmxpbWl0PSIxMCIgc3Ryb2tlLXdpZHRoPSIuNSIgc3R5bGU9Im1peC1ibGVuZC1tb2RlOm5vcm1hbCIgZGF0YS1wYXBlci1kYXRhPSd7ImlzUGFpbnRpbmdMYXllciI6dHJ1ZX0nPgogICA8cGF0aCBkPSJtMTkzLjEzIDIxMC43NnYtMzcuOTc1aDM3LjgwMnYzNy45NzV6Ii8+CiAgPC9nPgogPC9nPgogPHBhdGggZD0ibTE5LjgyOCAxNi41NzItNi40ODgyLTAuNDI2MjYtNC41ODkyIDQuNjA2Mi0xLjU5OTYtNi4zMDIzLTUuNzk4OS0yLjk0MTIgNS40OTk2LTMuNDY4OCAxLjAwNTMtNi40MjQgNC45OTg1IDQuMTU4NSA2LjQyMDItMS4wMjkxLTIuNDEwNCA2LjAzODl6IiBzdHlsZT0iZmlsbDojZDQ1NTAwO3N0cm9rZS1saW5lY2FwOnJvdW5kO3N0cm9rZS1saW5lam9pbjpyb3VuZDtzdHJva2Utd2lkdGg6MS40O3N0cm9rZTojMDAwMDAwIi8+CiA8cGF0aCBkPSJtMjkuMjYgMzYuOTcxYy0xLjgxNzYtMS43NDUzLTMuNjM1Mi0zLjQ5MDUtNS40NTI3LTUuMjM1OC0yLjUwMDEgMC4yMjYzNC01LjAwMDIgMC40NTI2OC03LjUwMDQgMC42NzkwMiAxLjA4NTUtMi4yNzQ5IDIuMTcxMS00LjU0OTggMy4yNTY2LTYuODI0Ny0wLjk5MDkzLTIuMzIxOS0xLjk4MTktNC42NDM4LTIuOTcyOC02Ljk2NTcgMi40ODg1IDAuMzM5MzEgNC45NzcgMC42Nzg2MiA3LjQ2NTQgMS4wMTc5IDEuODg3Ny0xLjY2MTQgMy43NzU0LTMuMzIyNyA1LjY2MzEtNC45ODQxIDAuNDUyNDMgMi40ODQ2IDAuOTA0ODYgNC45NjkyIDEuMzU3MyA3LjQ1MzggMi4xNTc2IDEuMjk1MSA0LjMxNTIgMi41OTAzIDYuNDcyOCAzLjg4NTQtMi4yMDg5IDEuMTk2My00LjQxNzcgMi4zOTI1LTYuNjI2NiAzLjU4ODgtMC41NTQyMyAyLjQ2MTgtMS4xMDg1IDQuOTIzNi0xLjY2MjcgNy4zODU0eiIgc3R5bGU9ImZpbGw6I2IyNTVhMTtzdHJva2UtbGluZWNhcDpyb3VuZDtzdHJva2UtbGluZWpvaW46cm91bmQ7c3Ryb2tlLXdpZHRoOjEuNDtzdHJva2U6IzAwMDAwMCIvPgogPGcgdHJhbnNmb3JtPSJyb3RhdGUoLTQwLjA2MikiIHN0eWxlPSJmaWxsOiMwMDAwMDAiIGFyaWEtbGFiZWw9IuaWh+WtlyI+CiAgPHBhdGggZD0ibTkuNTMyOCAyMi43ODdoLTEuNDA1OGMtMC4wMjcwNzQtMC45MDIxNiAxLjE5NzItMC40Mjc3NyAxLjgxMzUtMC41MjgxOGgxLjMzNTh2LTEuNDU3NWMxLjIzMjYtMC4yMjIzNS0wLjAzMDUyIDIuMDYzNSAxLjQ1NjcgMS40NTc1aDIuMzcxNmMwLjA4Mzk5IDEuMTMxNy0xLjgxMTItMC4wOTUxOC0xLjczMiAxLjE2NDIgMC4wMDQ4IDAuOTM2MS0xLjI2NjkgMS43NzM3LTEuMDIxMiAyLjUxMDkgMC42NzI4OCAwLjY2NDM1IDIuMjYwNCAwLjgzMjIxIDIuNjE2MyAxLjMyMTYtMC4zNTE1MiAwLjkyNTA3LTEuMjg2IDAuMDEzMS0xLjg5OS0wLjE2Mzk1LTAuNzgzNzUtMC4zMTM5NS0xLjQwNS0xLjM3NzktMi4wOTgyLTAuMzc1NjMtMC43NDMzMSAwLjI3NzgzLTIuMDIwOSAxLjYwMjUtMi42NDg1IDAuODE0NjUtMC41MTE1NC0wLjU5NzU2IDEuMTQ5OS0wLjQxNTggMS40NTgyLTAuODI1MjIgMC43MDk3Ny0wLjM1NjUxIDIuMDI1OS0wLjg1NDMzIDAuOTExNDItMS41ODk1LTAuNTE0ODktMC43MDM0MS0wLjg4OTgxLTEuNTAxOS0xLjE1ODctMi4zMjg5em0wLjYxMTU4IDBjMC4zMjcxMyAwLjgzNDI2IDAuODgxMjQgMi4zMjQxIDEuNjMyNyAyLjQzNzcgMC40MDkwOC0wLjYwNjI4IDEuMzk0LTIuMDI3NCAwLjkwOTk5LTIuNDM3N2gtMi41NDI3eiIgc3R5bGU9ImZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtzdHJva2Utd2lkdGg6LjM4MTI0Ii8+CiAgPHBhdGggZD0ibTIwLjAyOSAyMS43MzloMi45OTgzdjEuNjQwMWMtMC45ODA0NCAwLjM0OTE3LTAuMjE0NTMtMS42MzU2LTEuMzk3LTEuMTI3NC0xLjUyLTJlLTMgLTMuMDM5OSA1LjM2ZS00IC00LjU1OTktNS4zNGUtNHYxLjEyNzhjLTAuODEzNjIgMC4yODM2My0xLjAwMzMtMS45MzczLTAuMDk4MDQtMS42NDAxaDIuNDM3MXYtMS4xMTU5YzAuNzA0MzItMC4yNzM5MyAwLjY3MTE5IDAuNzAyMjMgMC42MTk1MiAxLjExNnptMC4wNTU2IDIuODQzNGMwLjIwMzM5IDAuODAzNjUgMS4zMTQxIDAuMjgyNCAxLjk3MDMgMC40MDkwNGgxLjI3NDNjMC4wMjcwNyAwLjkwMjE2LTEuMTk3MiAwLjQyNzc3LTEuODEzNSAwLjUyODE4aC0xLjM4NzRjLTAuMTQ1MzQgMC44MjA4NCAwLjQ1MTIzIDIuMTYxOC0wLjY4MzU0IDIuNDczNC0wLjkyNzc4IDAuMjg0MzMtMS41Njc5LTAuNzc4MzYtMC4zMDg4OC0wLjY1ODkxIDAuNzUxODQtMC4yNDI1NSAwLjI2NDc0LTEuMDQyMiAwLjM4MDg1LTEuNjA5IDAuMDUyOTktMC40MTMwMi0wLjYwNDU0LTAuMTE1NTEtMC44NzQ2Ni0wLjIwNTQyaC0yLjQ2MTJjLTAuMDI3MDctMC45MDIxNiAxLjE5NzItMC40Mjc3NyAxLjgxMzUtMC41MjgxOGgxLjQ4NjdjLTAuNTk3OTgtMC44NjI4NSAyLjIwMzMtMS4zNjA3IDAuNTgyMjUtMS40MTQ0LTAuODEwNTYtMC4xNTM2Ni0yLjEyODQgMC4yOTIzMS0yLjYwNzEtMC4yMjk5MSAwLjM3OTY4LTAuNjA1MzkgMS4yNzIyLTAuMjE0NTIgMS44OTktMC4zMDk1OWgyLjQ0NWMwLjI0MzA4IDAuOTk1Ny0xLjE5MjkgMS4wNDM0LTEuNzE1NiAxLjU0NDh6IiBzdHlsZT0iZm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO3N0cm9rZS13aWR0aDouMzgxMjQiLz4KIDwvZz4KIDxnIHRyYW5zZm9ybT0icm90YXRlKDUxLjYwNikiIHN0eWxlPSJmaWxsOiMwMDAwMDAiIGFyaWEtbGFiZWw9IjB4ZGRkZCI+CiAgPHBhdGggZD0ibTE3Ljk0NSA3Ljg1NjJjLTEuMTc5MyAwLjM1NDc1LTAuOTMzODIgMS44NC0wLjkxMDM1IDIuNzc3OSAwLjUzMTggMS40OTc0IDIuMjYzNiAwLjM2NDMyIDEuODU4OC0wLjkwMjk5LTAuMDA4NS0wLjY2ODgyLTAuMTAwNjgtMS43ODM2LTAuOTQ4NDctMS44NzQ5em0wLTAuNDcwOTFjMS40NzMgMC4wNzk1OTQgMS43MDA3IDEuOTI4OSAxLjQ5NTQgMy4wNzc5LTAuMDc2NSAxLjI5MDktMS44ODc2IDIuMTE0MS0yLjYzMTMgMC44NTE0My0wLjYxMTI5LTEuMTAzOS0wLjU4MTMxLTIuNzIyNCAwLjMxMzYyLTMuNjY2NiAwLjIyNzMzLTAuMTg5OTIgMC41Mjg1LTAuMjc2NiAwLjgyMjIyLTAuMjYyNjR6IiBzdHlsZT0iZm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO3N0cm9rZS13aWR0aDouMzIyOTEiLz4KICA8cGF0aCBkPSJtMjMuMTc1IDguNTYyNmMtMC4zOTczMyAwLjUzNDY4LTAuNzk0NjYgMS4wNjk0LTEuMTkyIDEuNjA0IDAuNDE3OTMgMC41NjQxMSAwLjgzNTg2IDEuMTI4MiAxLjI1MzggMS42OTIzLTAuOTIxNjQgMC41NTA3NC0xLjI3MDEtMS45MzQ2LTIuMDQ4Ni0wLjY4Ny0wLjE3MzM0IDAuNzEwNzUtMS4zOTA0IDAuOTQ0NzQtMC42NDYyLTAuMDM2MTEgMS4wMTA5LTAuNjY5MTkgMC41NTEtMS41MTc3LTAuMTI1MDktMi4yMTQ0LTAuNjA3MzYtMC45NzI2NyAwLjk5MTMgMC4xNTE2NiAxLjE4ODkgMC41ODMwMSAwLjY0MzA0IDAuMDY4MDQ0IDAuNjM4MTQtMS4zMjggMS41NjkyLTAuOTQxOXoiIHN0eWxlPSJmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7c3Ryb2tlLXdpZHRoOi4zMjI5MSIvPgogIDxwYXRoIGQ9Im0yNi4xNzEgOS4wNjI5di0xLjc4MzZjMS4wNDU0IDAuMjI0ODEgMC4zODE4NiAxLjY2NyAwLjU0MTU0IDIuNDk4OXYyLjA4MDdjLTAuOTcwMjktMC40MzQ3Ny0yLjI1ODQgMC42NzMzMy0yLjgxMi0wLjc5MjU5LTAuNTgxOTktMS4wNjQ4IDAuMjA3MjMtMi44NTkxIDEuNTY2Ni0yLjU1MjcgMC4yOTY0NSAwLjA3NzA3NyAwLjU1NTc5IDAuMjgxNzIgMC43MDM5MiAwLjU0OTI4em0tMS44NDU0IDEuMTUwOGMtMC4zODAzIDEuNjgwNCAyLjUzMjggMS40MTMyIDEuOTIwMi0wLjI1NDktMC4yODE1NC0xLjM0MTctMi4xMjc0LTEuMjM2Ni0xLjkyMDIgMC4yNTQ5eiIgc3R5bGU9ImZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtzdHJva2Utd2lkdGg6LjMyMjkxIi8+CiAgPHBhdGggZD0ibTI5Ljk5NyA5LjA2Mjl2LTEuNzgzNmMxLjA0NTQgMC4yMjQ4MSAwLjM4MTg2IDEuNjY3IDAuNTQxNTQgMi40OTg5djIuMDgwN2MtMC45NzAyOS0wLjQzNDc3LTIuMjU4NCAwLjY3MzMzLTIuODEyLTAuNzkyNTktMC41ODE5OS0xLjA2NDggMC4yMDcyMy0yLjg1OTEgMS41NjY2LTIuNTUyNyAwLjI5NjQ1IDAuMDc3MDc3IDAuNTU1NzkgMC4yODE3MiAwLjcwMzkyIDAuNTQ5Mjh6bS0xLjg0NTQgMS4xNTA4Yy0wLjM4MDMgMS42ODA0IDIuNTMyOCAxLjQxMzIgMS45MjAyLTAuMjU0OS0wLjMzOTA0LTEuMzM5OS0yLjA3MzYtMS4yNzQ4LTEuOTIwMiAwLjI1NDl6IiBzdHlsZT0iZm9udC1mZWF0dXJlLXNldHRpbmdzOm5vcm1hbDtmb250LXZhcmlhbnQtY2Fwczpub3JtYWw7Zm9udC12YXJpYW50LWxpZ2F0dXJlczpub3JtYWw7Zm9udC12YXJpYW50LW51bWVyaWM6bm9ybWFsO3N0cm9rZS13aWR0aDouMzIyOTEiLz4KICA8cGF0aCBkPSJtMzMuODIzIDkuMDYyOXYtMS43ODM2YzEuMDQ1NCAwLjIyNDgxIDAuMzgxODYgMS42NjcgMC41NDE1NCAyLjQ5ODl2Mi4wODA3Yy0wLjk3MDI5LTAuNDM0NzctMi4yNTg0IDAuNjczMzMtMi44MTItMC43OTI1OS0wLjU4MjA0LTEuMDY0OCAwLjIwNzM1LTIuODU5MyAxLjU2NjctMi41NTI2IDAuMjk2NDggMC4wNzY5NDEgMC41NTU1MyAwLjI4MTc4IDAuNzAzNzIgMC41NDkyem0tMS44NDU0IDEuMTUwOGMtMC4zODAzIDEuNjgwNCAyLjUzMjggMS40MTMyIDEuOTIwMi0wLjI1NDktMC4zMzkwNC0xLjMzOTktMi4wNzM2LTEuMjc0OC0xLjkyMDIgMC4yNTQ5eiIgc3R5bGU9ImZvbnQtZmVhdHVyZS1zZXR0aW5nczpub3JtYWw7Zm9udC12YXJpYW50LWNhcHM6bm9ybWFsO2ZvbnQtdmFyaWFudC1saWdhdHVyZXM6bm9ybWFsO2ZvbnQtdmFyaWFudC1udW1lcmljOm5vcm1hbDtzdHJva2Utd2lkdGg6LjMyMjkxIi8+CiAgPHBhdGggZD0ibTM3LjY1IDkuMDYyOXYtMS43ODM2YzEuMDQ1NCAwLjIyNDgxIDAuMzgxODYgMS42NjcgMC41NDE1NCAyLjQ5ODl2Mi4wODA3Yy0wLjk3MDI5LTAuNDM0NzctMi4yNTg0IDAuNjczMzMtMi44MTItMC43OTI1OS0wLjU4MTk5LTEuMDY0OCAwLjIwNzIzLTIuODU5MSAxLjU2NjYtMi41NTI3IDAuMjk2NDUgMC4wNzcwNzcgMC41NTU3OSAwLjI4MTcyIDAuNzAzOTIgMC41NDkyOHptLTEuODQ1NCAxLjE1MDhjLTAuMzgwMyAxLjY4MDQgMi41MzI4IDEuNDEzMiAxLjkyMDItMC4yNTQ5LTAuMzM5MDQtMS4zMzk5LTIuMDczNi0xLjI3NDgtMS45MjAyIDAuMjU0OXoiIHN0eWxlPSJmb250LWZlYXR1cmUtc2V0dGluZ3M6bm9ybWFsO2ZvbnQtdmFyaWFudC1jYXBzOm5vcm1hbDtmb250LXZhcmlhbnQtbGlnYXR1cmVzOm5vcm1hbDtmb250LXZhcmlhbnQtbnVtZXJpYzpub3JtYWw7c3Ryb2tlLXdpZHRoOi4zMjI5MSIvPgogPC9nPgo8L3N2Zz4K';

const blockIconURI = commonSvgIcon;
const menuIconURI = commonSvgIcon;

class Scratch3Str2Unicode {
    constructor (runtime) {
        this.runtime = runtime;
    }

    getInfo () {
        return {
            id: 'str2unicode',
            name: 'String To Unicode#',
            menuIconURI: menuIconURI,
            blockIconURI: blockIconURI,
            blocks: [
                {
                    opcode: 'writeLog',
                    blockType: BlockType.COMMAND,
                    text: 'log [TEXT]',
                    arguments: {
                        TEXT: {
                            type: ArgumentType.STRING,
                            defaultValue: "hello"
                        }
                    }
                },
                {
                    opcode: 'getBrowser',
                    text: 'browser',
                    blockType: BlockType.REPORTER
                }
            ],
            menus: {
            }
        };
    }

    writeLog (args) {
        const text = Cast.toString(args.TEXT);
        log.log(text);
    }

    getBrowser () {
        return navigator.userAgent;
    }
}

module.exports = Scratch3Str2Unicode;
        

scratch-vmの拡張機能リストに追加

新しく作成したエクステンションをScratch3へ組み込むには、エクステンションの機能を統括しているプログラムコードであるscratch-vm/src/extension-support/extension-manager.jsを編集します。

変更の内容は単純で、builtinExtensionsのメンバーフィールドにエクステンションの名前で関数登録をするだけです。

            
            const dispatch = require('../dispatch/central-dispatch');
const log = require('../util/log');
const maybeFormatMessage = require('../util/maybe-format-message');

const BlockType = require('./block-type');

// These extensions are currently built into the VM repository but should not be loaded at startup.
// TODO: move these out into a separate repository?
// TODO: change extension spec so that library info, including extension ID, can be collected through static methods

const builtinExtensions = {
    //...中略
    //👇新規エクステンションのindex.jsのパスで登録
    str2unicode: () => require('../extensions/scratch3_str2unicode')
};

//...以下略
        

エクステンションの動作確認

ではここまでで正常にビルドできるかscratch-guiのフォルダに入り、ローカルサーバーモードを立ち上げてみます。

            
            $ npm start
#OR
$ yarn start
        
サーバー起動後http://localhost:8601にアクセスし、Scratch3の画面で拡張機能が新しく見えていたら正しく登録されています。

合同会社タコスキングダム|タコキンのPスクール

codePointAtメソッド

ここからは文字からユニコードの16進数ID番号に変換するための機能を作成します。

Unicodeはすべての文字に対してID番号が付けられています。この文字に対する一意のIDのことをコードポイント(符号位置)と呼びます。

このコードポイントはStringクラスのcodePointAtメソッドで読み出したり、逆にfromCodePointメソッドでコードポイントから文字列に変換したりすることができます。

            
            // "あ"のコードポイントを取得
console.log("あ".codePointAt(0)); // => 12354
        
codePointAtは10進法の整数を返しますので、これを16進法表記にするには続けてtoString(16)メソッドを付けてあげます。

            
            // "あ"のコードポイントを取得
console.log("あ".codePointAt(0)).toString(16); // => 3042
        

文字からコードポイントを返すスクラッチブロック

ではようやく本題であった文字からユニコードのコードポイントを16進法で返すエクステンションを作成します。

先程テンプレートだけで作成していた
scratch-vm/src/extensions/scratch3_str2unicode/index.jsを以下のように編集します。

            
            const ArgumentType = require('../../extension-support/argument-type');

///...略

class Scratch3Str2Unicode {
    ///...略
    getInfo () {
        return {
            id: 'str2unicode',
            ///...略
            blocks: [
                ///...略
                //👇①レポータータイプの(引数あり)関数を定義
                {
                    opcode: 'getCodePoint',
                    text: '文字>コードポイント [STR]',
                    blockType: BlockType.REPORTER,
                    arguments: {
                        STR: {
                            type: ArgumentType.STRING,
                            defaultValue: 'あ'
                        }
                    }
                }
            ],
        ///...略
        };
    }

    //👇②文字をコードポイントに変換するレポーター
    getCodePoint (args) {
        //👇STRで定義していた引数を受け取る
        const text = Cast.toString(args.STR);
        //👇文字からポイントコードポイントへ変換して返す
        return text.codePointAt(0).toString(16);
    }
}
///...以下略
        
編集したポイントはソースコード内の①と②の部分です。

なお、スクラッチのエクステンションは以下の4つの種類の型のどれかでプログラミングしていくスタイルですので、今回の用途ではレポーターブロックで構成するべき機能になりました。

            
            + COMMAND:
    関数を実行するブロック。
    引数を定義して利用することも可能
+ REPORTER:
    特定の文字列や数値などを返すブロック。
    引数を与えて利用することもできる
+ BOOLEAN:
    判定に特化したブロック。
    true/falseのどちらかを返す。
    引数を与えて真偽を判断して返すことも可能。
+ HAT:
    エクステンションのコード内部の変数(true/false)を監視して、
    trueのときにだけ処理を実行するブロック。
    イベントのトリガーとして利用できる
        
これらの詳しい使い方はこちらの方のサイトで言及されていますのでご参照ください。

ではこのブロックを使ってみます。

プロジェクトをビルド・実行するといかのように正常に動作すると成功です。

合同会社タコスキングダム|タコキンのPスクール


合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】Scratchをしっかり学ぶためのオススメ書籍まとめ

まとめ

今回はScratch-guiで拡張機能を自作する方法の復習と合わせて、文字からユニコード(16進数)に変換する簡単なブロックをレポータータイプで作成しました。

そして、このエクステンションブロックを何に使うと、文字のユニコードの数字からプログラム内部の適当な場所に配置したフォントSVGを選択するために利用する予定です。

一体どういう実装になるのかは後日ブログ内容で解説していきたいと思います。

スクラッチプログラムでフォント操作に興味を持たれている(?)方はご期待して次回までお待ちください。

参考サイト

文字列とUnicode

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

これからの"地方格差"なきプログラミング教育とは何かを考えながら、 地方密着型プログラミング学習関連テーマの記事を不定期で独自にブログ発信しています。

合同会社タコスキングダム|タコキンのPスクール【Pschool厳選】お子様に通わせたいロボットプログラミング教室&教材・学習サービスまとめ