inosyanのブログ

プログラム関連の話題を中心に掲載します

【マイクラMakeCode】JavaScriptからプログラムブロックへ切り替える時の罠

f:id:inosyan:20181013115034j:plain

 プログラムを書いたら、できるだけたくさんの人に見てもらいましょう。みんなで作品を共有すれば、きっとますます楽しくなるでしょう。 

 MakeCode1(メイクコード)は、子供たちがプログラムを学習するためのアプリです。子供たちの多くはプログラムブロック2を使っています。もしあなたがプログラムブロックを使わずJavaScriptで書いたとしても、プログラムブロックでも見れるようにしておいた方が親切です。 

「あれ? JavaScriptとプログラムブロックはボタンを押すだけで簡単に切り替わるんじゃないの?」と思うかもしれません。
確かに切り替えは簡単にできるのですが、気をつけたほうが良いことがいくつかあります。でも心配ありません。そんなに難しいことではないですよ。

「;(セミコロン)」が消える

 JavaScriptからプログラムブロックに切り替えたあと、再びJavaScriptに切り替えると、元のコードから少し変化することがあります。

 例えば、次のような、単純な足し算をするコードをプログラムブロックに切り替えます。

player.onChat("add", function (a, b) {
    player.say(a + " + " + b + " = " + (a + b));
})

 プログラムプロックに切り替えると、このように見えます。JavaScriptと同じ内容ですね。

f:id:inosyan:20181013115053g:plain

 再びJavaScriptに切り替えると、コードはつぎのようになります。

player.onChat("add", function (a, b) {
    player.say("" + a + " + " + b + " = " + (a + b))
})

 はじめのコードと見比べてみてください。すこし変化しているのに気づきましたか? 

 文末の「;(セミコロン)」が消えてますね。 セミコロンは、プログラム文がそこで終わることを明示的に示すために書くもので、文末にはこれを書きます。 この決まり事は、他の言語だと必須の場合もありますが、JavaScriptは寛容な言語なので、あってもなくても動きます。

 セミコロンがあった方が良いのかどうかについては、いろんな意見があり、どちらが良いとはここでは書きませんが、 プログラムブロックとの切り替えをするのであれば、セミコロンは書かない方が良いでしょう。

文字列の連結の先頭が変数だった場合、変数の前に「""(空文字)」が足される

 上の2つの違いをもう一度よく見比べてみてください。 a の前に 「""(空文字)」 が足されていますね。 プログラムブロックからJavaScriptに切り替える際、文字連結の先頭が変数だった場合、空文字が足されてしまうようです。

"" + a

 その状態から、改行するなど少し編集を加えてからプログラムブロックに切り替えます。(MakeCodeはユーザーが手を加えないとプログラムブロックを更新してくれないので)

f:id:inosyan:20181013115109g:plain

 プログラムブロック上でも「""」が足されてしまいました。この状態からJavaScriptに切り替えても、これ以上は変化しないようです。文字列連結の先頭は変数ではなく文字列を入れるようにすれば、このような変化は起きないようです。

 自分の書いたコードが勝手に別の形に変化してしまうのは気持ちわるいので、できればはじめから変化しないような書き方をしたいものです。

「 '(シングルクォート)」や「 `(バッククォート)」は「 "(ダブルクォート)」に置き換えられる

 JavaScriptでは、文字列を囲む記号として「"」の他に「'」や「`」が使えます。しかしプログラムからJavaScriptに切り替えると、「"」に置き換えられます。

例えば

    player.say('' + a + ' + ' + b + ' = ' + (a + b))

    player.say(`` + a + ` + ` + b + ` = ` + (a + b))

は、プログラムブロックに切り替えたあとJavaScriptに戻すと、

    player.say("" + a + " + " + b + " = " + (a + b))

になってしまいます。

バッククォートで変数を囲むとプログラムブロックに変化しない

 文字列を囲むだけなら、通常は「"」や「'」を使います。「 `(バッククォート)」は、変数もいっしょに囲みたい時に使います。 例えば

a + " + " + b + " = " + (a + b)

`${a} + ${b} = ${a + b}`

と書くことができまます。このほうがプログラムとして見やすいですね。

ですが、このJavaScript

player.onChat("add", function (a, b) {
    player.say(`${a} + ${b} = ${a + b}`)
})

プログラムブロックに切り替えると

f:id:inosyan:20181013115138g:plain

このように、バッククォートで囲んだ部分がコードのまま表示されてしまいます。 バッククォートで変数を含むとプログラムブロックに変化しないようです。

 これ以外にも、ブロックに置き換えられないコードは、そのままの形でプログラムブロック上に表示されてしまいます。まだコードの書き方を知らない人が見たら、意味がわからず混乱してしまうでしょう。

別の関数の引数でも、同じ名前のものはグローバル変数3になってしまう

 例えば、足し算のプログラムの他に、引き算のプログラムを作ったとします。引数 a, b はそのまま使い回し、符号だけを変えます。

player.onChat("add", function (a, b) {
    player.say("" + a + " + " + b + " = " + (a + b))
})
player.onChat("subtract", function (a, b) {
    player.say("" + a + " - " + b + " = " + (a - b))
})

 これをプログラムブロックに変えるとこうなります。

f:id:inosyan:20181013115151g:plain

 さらにこれをJavaScriptに変えると、このようになります。

let a = 0
let b = 0
player.onChat("add", function (a, b) {
    player.say("" + a + " + " + b + " = " + (a + b))
})
player.onChat("subtract", function (a, b) {
    player.say("" + a + " - " + b + " = " + (a - b))
})

プログラムブロックからJavaScriptに切り替えた結果、コードの最初のほうに、2つの変数

let a = 0
let b = 0

が作られました。

 足し算のチャットコマンドの a と b は、引き算の a と b とは別のものですし、それぞれのハンドラの中でしか使われない変数なので、グローバル変数ではありません。 つまり、足し算や引き算のa, b と、let で定義している a, b は関係ありません。

 複数のチャットコマンドで引数の名前が同じだと、この現象がおきるようです。必要のないグローバル変数が作られるのは気持ちわるいので、これを避けるために、変数にそれぞれ違う名前をつけます。 例えば、足し算用の a と b は addA と addB, 引き算用の a と b は、subA, subB という名前にします。

player.onChat("add", function (addA, addB) {
    player.say("" + addA + " + " + addB + " = " + (addA + addB))
})
player.onChat("subtract", function (subA, subB) {
    player.say("" + subA + " - " + subB + " = " + (subA - subB))
})

f:id:inosyan:20181013115209g:plain

 これなら、プログラムブロックからJavaScriptに戻ってきてもグローバル変数が作られることはありません。

結局どうすれば良いのか

 どうやら、プログラムブロックとJavaScriptとは、完璧な切り替えが可能というわけではなさそうです。切り替えてもJavaScriptのコードが崩れないようにするためには、制約があるみたいです。

 でもそのために、制約を気にしながらコードを書くのは違うと思います。プログラムは自由に好きなように書いたほうが楽しいです。

 切り替えをしない前提で書いてしまうというのも一つの方法です。自分しか使わないのであればそれでもいいです。しかし、作品を公開するのであれば、プログラムブロックを使う人にも配慮したいものです。

 解決策は「カスタムブロック4を作る」です。

 カスタムブロックのコードは別のファイルに書くことができるので、複雑なコードはカスタムブロックに書いて、メインのファイルにはカスタムブロックを呼び出すだけのコードを書くのです。それであれば、メインファイルはシンプルなコードにできるので、プログラムブロックに切り替えてもJavaScriptが崩れることはありません。それにプログラムブロックを見ている人にも配慮できます。

 カスタムブロックの作り方については、次回ご紹介したいと思います。


  1. MakeCode(メイクコード)とは、子供向けに開発されたプログラミング学習用のアプリ。パズルのピースのようなブロックをならべてプログラミングできるビジュアルプログラミングと、JavaScript(TypeScript)でのコーディングを両方サポートしているのが特等。マインクラフトと接続し、ゲーム内の操作をプログラミングできる。

  2. プログラムブロックとは、ビジュアルプログラムでつかうパズルのピースのような形のブロックのこと。一般的にはブロックと呼ぶが、マインクラフトのゲーム内のブロックと区別するため、ここではそう呼ぶ。

  3. グローバル変数とは、プログラム中のどこからでも参照できる変数のこと。便利な反面、どの処理からも値を変更できるためバグが起きると原因を特定しづらくなる。

  4. カスタムブロックとは、ユーザーが定義したプログラムブロックのこと。JavaScript(TypeScript)で書くことができ、他のプログラムブロックと同じようにならべて使うことも、JavaScriptから呼び出すこともできる。