前談
blockを追加するにもアイテムを追加するにも、非常に重要な要素となったScriptAPIですが、そのScriptAPIを学ぼうにもScriptAPIの基礎となっているJavaScriptの知識がないために、「サンプルを見ても何が書いてあるのかまるで分らない」というような方が多いように感じました。
よって、JavaScriptでよく登場する構文などの基礎知識(へのリンク)をここにまとめておくことで、少しでも敷居が低くなればと思い書き残す次第です。
JavaScriptの基礎
変数・関数
変数
数値や文字列といった単純なデータから、playerやitemstack、それらのリストといった複雑な情報まで、保存して置ける箱のようなものです。
https://techplay.jp/column/1619
let 変数名1; // 上書きされる可能性があるとき使う
var 変数名2; // 二重宣言で思わぬバグにはまることがあるので、できるだけ使わない
const 変数名3; // 宣言時の指定で固定され、上書きされないことを保証したいときに使う
関数(function/method)
関数とは一通りの処理・手続きを手順書にまとめて管理(定義・宣言)し、必要に応じてその手順書を持ってきて作業をする(呼び出し)ようなものです。
これにより、以下のようなメリットを得られます。
・可読性向上
例えば、「球状の範囲内のblockをすべて取得」して「空気なら処理A」「水なら処理B」「マグマなら処理C」「その他且つ岩盤以外なら処理D」ということを関数なしで書くととても長くなり読みにくいですが、「球状の範囲内のblockをすべて取得」「処理A」「処理B」「処理C」「処理D」をそれぞれ関数に切り分けることで、元となった処理では「それらを適切に呼び出すだけ」の短い記述で済みますし、それぞれの関数も役割を分担するので短く済みます。「どこに何が書いてあるか探す」手間が軽減されます。
関数化していない例
const blocks = 中心座標半径を基にした立方体型の範囲を取得して、
blockのリストを確保したのちそのblockのリストに対して中心座標からの距離が半径より短いかを確認することで、
球の内側のblockかを判定し球の内側であれば配列に加える処理;//おそらく20行は超える長すぎる記述!
for( const block of blocks ){
if(block.typeId == "minecraft:air"){
空気ブロックに対して行う処理 // ※ここが100行くらいあるものとして考えてみてください
}else if(block.typeId == "minecraft:water"){
水ブロックに対して行う処理 // ※ここが100行くらいあるものとして考えてみてください
}else if(block.typeId == "minecraft:lava"){
マグマブロックに対して行う処理 // ※ここが100行くらいあるものとして考えてみてください
}else{
その他のブロックに対して行う処理 // ※ここが100行くらいあるものとして考えてみてください
}
}
関数化した例
const blocks = 球状の範囲内のblockすべてを取得(中心座標,範囲);
for( const block of blocks ){
if(block.typeId == "minecraft:air"){
処理A(block);
}else if(block.typeId == "minecraft:water"){
処理B(block);
}else if(block.typeId == "minecraft:lava"){
処理C(block);
}else{
処理D(block);
}
}
function 球状の範囲内のblockすべてを取得(中心座標,範囲){
球状の範囲にあるブロックをすべて取得する処理 //※ここが数十行あるものと考えてください
return 球状の範囲にあるブロックの配列;
}
function 処理A(block){
空気ブロックに対して行う処理 // ※ここが100行くらいあるものとして考えてみてください
}
function 処理B(block){
水ブロックに対して行う処理 // ※ここが100行くらいあるものとして考えてみてください
}
function 処理C(block){
マグマブロックに対して行う処理 // ※ここが100行くらいあるものとして考えてみてください
}
function 処理D(block){
その他のブロックに対して行う処理 // ※ここが100行くらいあるものとして考えてみてください
}
一番上のmainの処理の中身が簡素になり、それぞれの関数も自身が担当する範囲が明らかとなるので「ここでは何をするんだっけ?」と記述中・確認中に混乱することが少なくなります。
・メンテナンス性向上
可読性が向上し責任が分担されることによって、「どこに何が書いてあるのか」「どこに何を書けばいいのか」がわかりやすくなり、改善・修正・更新などが容易になります。
・再利用性向上
関数(手順書)は一度定義してしまえばあちこちから呼び出せるので、毎回いちから記述する必要がなくなります。汎用的な処理などは積極的にくくり出せてあげるのがよいでしょう。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Guide/Functions
// 関数の定義(戻り値なし)
function 関数名1(引数){
関数でやりたいこと
}
// 関数の呼び出し
関数名1(引数);
// 関数の定義(戻り値あり)
function 関数名2(引数){
関数でやりたいこと
return 戻り値;// 実行結果として戻り値が得られる
}
// 関数の呼び出し
let 変数名 = 関数名2(引数);// 戻り値を変数に格納する例
オブジェクト/クラス/インスタンス
オブジェクト
オブジェクトはデータの塊です。
関数を持つこともできます
例えば、三次元座標というオブジェクトは、x座標y座標z座標の情報(property)を一纏めにしたものとなります。
const location3d = {x:x_location,y:y_location,z:z_location};
クラス
クラスは「概念」とか「設計図」のようなものです。
例えば、Entityクラスは三次元座標オブジェクトであったりIDデータであったり、といった様々な情報(property)に加えて、Entityが持つ能力・機能を関数という形で管理しています。
テレポート関数、視線の先のエンティティを取得する関数などですね。
インスタンス
インスタンスとは実体です。
「クラスに基づいて生成されたオブジェクト」と言っても良いでしょう。
ゾンビAのEntity、ゾンビBのEntity、スケルトンCのEntity。これらはすべて、Entityというクラス(設計図)から作られた独立したインスタンスとなります。
基本的に独立(するように設計しているので、ゾンビAに与えたダメージがゾンビBに適用される、というようなことが起こりません。
// Personクラスの定義
class Person {
// コンストラクタ: クラスからオブジェクトを作る際に実行される(する)初期化処理
constructor(name, age) {
this.name = name; // インスタンスのプロパティ
this.age = age;
}
// メソッド: インスタンスに対して呼び出せる関数
greet() {
console.log(`Hello, my name is ${this.name} and I am ${this.age} years old.`);
}
// 年齢を増やすメソッド
haveBirthday() {
this.age += 1;
console.log(`I am now ${this.age} years old.`);
}
}
// Personクラスからインスタンスを生成
const alice = new Person("Alice", 25);
// メソッドを呼び出す
alice.greet(); // "Hello, my name is Alice and I am 25 years old."
alice.haveBirthday(); // "I am now 26 years old."
// 別のインスタンスを生成
const bob = new Person("Bob", 30);
bob.greet(); // "Hello, my name is Bob and I am 30 years old."
配列・リスト・Map
配列とリスト
▼Java(※別言語)での配列とリスト
https://www.kenschool.jp/blog/?p=5308
JavaScriptにはリストが存在せず、Javaにくらべて制約の緩い配列を使って再現します。
https://www.sejuku.net/blog/60444
配列
配列とは同じようなデータをまとめて管理する手段です。
例えば、すべてのプレイヤーのデータが欲しいとき、
const player1 =どうにかして取得する;
const player2 =どうにかして取得する;
const player3 =どうにかして取得する;
const player4 =どうにかして取得する;
...
と一つ一つ変数を定義して管理するのは非常に手間且つ不便です。
そこで、以下のようにひとまとめにして扱います。
const players =どうにかして取得する;
players[0]; // 1人目のデータ
players[1]; // 2人目のデータ
players[2]; // 3人目のデータ
players[3]; // 4人目のデータ
...
Mapオブジェクト
https://qiita.com/chihiro/items/9965cd7eca0380cf288c
Mapとはkeyに対して値を指定し、keyが重複することがないよう保証されたデータ群です。
配列と違い、キーさえわかるのであれば、自分で一々何番目に入れたデータかを覚えておく必要がなくなります。
分岐処理
if
if構文は、条件を満たしたとき、処理を行うことができます。
https://x-tech.pasona.co.jp/media/detail.html?p=2619
if(条件){
実行される処理
}
if(条件) 実行される処理; //処理が短い場合はこのような記述もできます
逆に、itemStackのtypeIdが”minecraft:stick”「ではない」ならという条件の場合、以下のようになります。
if(itemStack.typeId != "minecraft:stick"){
実行される処理
}
if( !(itemStack.typeId == "minecraft:stick") ){
実行される処理
}
!は真偽を反転する意味合いがあるわけですね。
また、今回は等しいかを == によって比較していますが、数値の代償を比較する > や < など、様々な演算子があります。
さらに、複数の条件を満たす必要がある場合や、いずれかの条件だけでよい場合などは以下のように書くことができます。
if(条件1 && 条件2){
両方の条件を満たしたとき実行される処理
}
if( 条件1 || 条件2 ){
どちらかの条件を一方でも満たしたとき(両方満たしていてもよい)に実行される処理
}
if( (条件1 && 条件2) || (条件3 && 条件4) ){
「条件1と条件2の両方」または「条件3と条件4の両方」のどちらかを満たしたときに実行される処理
}
if…else{} else if
条件を「満たしたとき」と「満たさなかった時」の処理を書くことができる構文です。
else ifはどんどん連鎖して書くことができます。
if(条件){
満たしたときの処理
}else{
満たさなかった時の処理
}
if(条件){
満たしたときの処理
}else if(満たさなかった時の追加条件){
満たさなかった時の追加条件を満たしたときの処理
}
switch
Switch文は、分岐が複数にわたり条件の判定元(比較元)が一つのときに、使える条件分岐構文です。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/switch
switch(itemStack.typeId){
case "minecraft:stick":{
棒のときの処理
break;
}
case "minecraft:book":{
本のときの処理
break;
}
default:{
ここまでの判定のどれにも引っかからなかった時の処理
}
}
ちょっと扱いが難しいので、最初はelse ifがたくさん繋がって読みにくいなと感じた時に思い出すくらいのつもりでいいと思います。
繰り返し処理
while
条件を満たしている間繰り返し処理を行い続ける構文です。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/while
while(条件){
条件を満たしている間繰り返す処理
}
do … while
最初に一回実行してから、条件確認を行うwhile構文です。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/do…while
do{
最初に一回実行し、その後は条件を満たしている間繰り返し行う処理
}while(条件)
for
繰り返し毎に更新処理を行い、条件を判定する構文です。
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for
for(初期化処理; 実行条件; 更新処理){
条件を満たしている間繰り返す処理
}
for…in
オブジェクトの中身の要素に対して繰り返し処理を行います。n
暴走しやすい(オブジェクトの関数に対しても繰り返し処理を実行しようとするなど)ので、非推奨。
for…of
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Statements/for…of
文字列や配列など、反復可能オブジェクトに対してそのオブジェクトが想定している手順に従って繰り返し処理を行います。
forEach
https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach
(配列などの)すべての要素に対して処理を行う構文です。
汎用的過ぎて処理内容の全容把握が大変なので、最終手段、などと呼ばれることもあります。nhttps://qiita.com/diescake/items/70d9b0cbd4e3d5cc6fce
後談
メソッドチェーンやtry文、無名関数、コールバック関数など、まだ必要な知識はあるのですが、(それらは一旦呪文のようなものとでも思って見様見真似で記述し)とりあえず上記の基礎知識を覚えておけば、簡単な処理を記述する範囲ではあまり困らないと思います。
慣れてきたら新しい知識を身に着け、ステップアップを目指しましょう。
コメント