Uploaded:2023/01/01 Latest-Update:2023/01/01

アドオン作成 - Molang 上級

目次は右上の「≡」から!
用途

アドオンの色んなところで色んな「値」を指定しますが、指定する値が動的であってほしいこともあります。 たとえば、残りHPに応じて見た目や色が変化するなどといったシチュエーションにも、1つの「値」として「Molang」を使って表すことができます。

しかし、Molangはどこでも使えるわけではなく、値の種類としてMolangでの指定が許されている場所でのみ使うことができます。

演算子と関数

● 基本的な演算子

記号概要
+足し算
-引き算
*掛け算
/割り算
!AAではない
A && BAかつB
A || BAまたはB
x < axはaより小さい
x <= axはaであるまたはaより小さい
x >= axはaであるまたはaより大きい
x > axはaより大きい
x == yxとyは等しい
x != yxとyは等しくない

● カッコ

カッコ (・)を使って演算の順序をコントロールします。

● 三項演算子

?の前に条件式を書き、後ろにコロン( : )を挟んで返す値を指定します。条件が真ならコロンの前の値、偽なら後ろの値になります。
たとえば以下の式は100を返します。

(1 < 2)? 2 : 0

● 数学関数

記号概要
math.abs(x)xの絶対値
math.acos(x)xのアークコサイン
math.asin(x)xのアークサイン
math.atan(x)xのアークタンジェント
math.atan2(x, y)x/yのアークタンジェント
math.ceil(x)xを下回らない最小の整数
math.clamp(x, a, b)xがaより小さいとa、bより大きいとb、間ならx
math.cos(x)xの余弦
math.die_roll(n, a, b)n個のa~bのランダムな小数の合計
math.die_roll_integer(n, a, b)n個のa~bのランダムな整数の合計
math.exp(x)ネイピア数が底の指数関数
math.floor(x)xを越えない最大の整数
math.hermite_blend(x)3x²-2x³(エルミート補間) xは0~1
math.lerp(x)
math.lerprotate(x)
math.ln(x)xの自然対数
math.max(a, b)aとbの大きいほう
math.min(a, b)aとbの小さいほう
math.min_angle(x)-180°~180°の角度に変換
math.mod(x, k)xをkで割ったあまり
math.pi円周率
math.pow(x, a)xのa乗
math.random(a, b)a~bのランダムな小数
math.random_integer(a, b)a~bのランダムな整数
math.round(x)xの四捨五入
math.sin(x)xの正弦
math.sqrt(x)xの正の平方根
math.trunc(x)xの小数点以下切り捨て
変数と複雑表現

Molangでは変数を定義することができます。変数名は必ず variable.(省略形: v.)から始まるようにしてください。

variable.my_var = 1.0;

変数定義の式は複雑表現(Complex Expression)となり、式の終わりに必ずセミコロン( ; )を書かないといけません。

● return文

Molangを書く場所は、一部のフィールドを除いて何らかの「値」を返す必要があるはずですが、変数を定義すると定義するだけして何も値を返しません。 そこで、最終的にどんな値を返すのか指定するのがreturn文です。

variable.my_var = 1.0; return 2.0;

● 一時的な変数

temp.(省略形: t.)で始まる変数は一時的な変数として定義されます。 variable変数は別の場所からアクセスできますが、temp変数は定義されたその場所からしかアクセスできません。

● 定数

定数はcontext.(省略形: c.)で始まる名前で定義します。variable変数やtemp変数と違って一度定義したら中身を変更できません。

クエリ関数

Molangは演算できることが強みではありますが、多くのクリエイターがMolangを重宝しているのは「Molangで特殊な値を取得できる」ことがあるからでもあります。
クエリ関数は、ゲーム内の様々な値を取得するための関数です。これがあることによって、エンティティがアニメーションしたりイベントの条件をMolangで書くことが実用的になったりします。

query.body_x_rotation > 90

クエリ名は必ず query.(省略形: q.)で始まります。

クエリ関数の種類は大量にあるので、一覧はここでは紹介せず各自リファレンスを参照してもらうこととします。

● 上級者の知識

ゲーム内にある様々な「値」を取得するのがクエリ関数だと説明しましたが、実はvariable変数にそういった値が入っていることがあります。 つまり、内部で定義されている(ハードコードされている)がクエリ関数と同様に扱えるvariable変数があるということです。

Null合体演算子

??の前にある変数が未定義(Null)だった場合、後ろの数が採用されます。 たとえば、以下の例は v.xが未定義なら 0.0を、定義されていたら v.xの値をそのまま返します。

(v.x ?? 0.0)
ブラケット表記

特にloopやfor_eachで { }を使って一連のステートメントを1つのグループにまとめることができます。以下の例では v.mooが0より大きいときカッコ内の処理をするというものです。

(v.moo > 0) ? { v.x = math.sin(q.life_time * 45); v.x = v.x * v.x + 17.3; t.sin_x = math.sin(v.x); v.x = t.sin_x * t.sin_x + v.x * v.x; v.x = math.sqrt(v.x) * v.x * math.pi; } return (v.x ?? 0);
loop

loopの中に書いた式を指定した回数だけ処理します。

v.x = 1; v.y = 1; loop(10, { t.x = v.x + v.y; v.x = v.y; v.y = t.x; }); return v.y;

上記の例はフィボナッチ数列の第11項(87)を返します。

● break

breakを使って条件に応じて繰り返し処理を抜け出すことができます。以下の例では、 v.yが20より大きくなるとloopの処理を抜けます(最終的な値は21)。

v.x = 1; v.y = 1; loop(10, { t.x = v.x + v.y; v.x = v.y; v.y = t.x; (v.y > 20) ? break; }); return v.y;

● continue

continueを使って条件に応じて処理をスキップすることができます。以下の例では v.xが5より大きいときの処理はスキップされます(最終的な値は6)。

v.x = 0; loop(10, { (v.x > 5) ? continue; v.x = v.x + 1; }); return v.x;

for_each

たとえば、クエリ関数 q.get_nearby_entitiesはエンティティの配列を返します。 for_eachはそのような配列の要素それぞれに対して処理を行うことができます。以下の例では周囲4マス以内のブタの数を返します。

v.x = 0; for_each(t.pig, q.get_nearby_entities(4, 'minecraft:pig'), { v.x = v.x + 1; }); return v.x;

● breakとcontinue

for_eachでもloopのようにbreakとcontinueを使うことができます。

矢印演算子

いくつかのクエリ関数またはtemp/entity/context変数は別のエンティティへの参照を格納していることがあります。

プレイヤーに関するJSONの中で q.is_on_fireを使うと「プレイヤーが炎上状態かどうか」が取得できます。 もし、定義した変数 v.pigがワールド内にいる、ある1匹のブタへの参照を格納していたならば、

v.pig -> q.is_on_fire

という式をそのブタに関係ないJSONで書いても、この式は「(その)ブタが炎上状態かどうか」を示すことになります。

● 実用例

v.x = 0; for_each(v.pig, q.get_nearby_entities(4, 'minecraft:pig'), { v.x = v.x + (v.pig -> q.get_relative_block_state(0, -1, 0, 'flammable')); }); return v.x;

この式はプレイヤーのJSONに書かれているとします。
まず、プレイヤーの周囲4マス以内にいるブタを取得します。1匹ずつ v.pigに格納して、for_each内の式の処理をします。最終的にこの式はそれらのブタのうち何匹の足元が "flammable"タグをもったブロックだったのかを返します。

Molangで扱う「値」の型のほとんどは数です。特に、真偽値も数で表されることに注意してください。 エンティティや文字列など数でない値を扱うのはまれです。

● 真偽値

クエリ関数から真偽値が渡されるときは、trueが1.0、falseが0.0となります。 逆に、0.0以下の数はfalse、それ以外の数はtrueとして扱われます。

● 文字列

MolangはJSONでは文字列として扱われるため、 " "で囲まれているので、Molangの値としての文字列は ' 'で囲みます。

また、Molangの文字列に対して使える演算子は ==!=のみです。

演算の優先度

以下の表の上が優先度最大です

演算処理概要
論理否定否定!
乗算・除算掛け算*・割り算/
加算・減算足し算+・引き算-
比較演算(不等号)不等号 < <= > >=
比較演算(等号) 等号== !=
論理積AND(かつ)&&
論理和OR(または)||
三項演算三項演算子? :(入れ子になっている場合は右から左に評価する)
Null合体演算Null合体演算子??
ストラクト

クエリ関数などで取得した値はしばしば深層データをもっていることがあります。ドット( . )でプロパティ名をつなげるとその深層データにアクセスできます。

v.location.x = 1; v.location.y = 2; v.location.z = 3; v.another_mobs_location = v.another_mob_set_elsewhere -> v.location;

以下はその他の例です。どれも返す値は1.23になります。

v.cowcow.friend = v.pigpig; v.pigpig -> v.test.a.b.c = 1.23; return v.cowcow.friend -> v.test.a.b.c;
v.cowcow.friend = v.pigpig; v.pigpig -> v.test.a.b.c = 1.23; v.moo = v.cowcow.friend -> v.test; return v.moo.a.b.c;
v.cowcow.friend = v.pigpig; v.pigpig -> v.test.a.b.c = 1.23; v.moo = v.cowcow.friend -> v.test.a; return v.moo.b.c;
v.cowcow.friend = v.pigpig; v.pigpig -> v.test.a.b.c = 1.23; v.moo = v.cowcow.friend -> v.test.a.b; return v.moo.c;
v.cowcow.friend = v.pigpig; v.pigpig -> v.test.a.b.c = 1.23; v.moo = v.cowcow.friend -> v.test.a.b.c; return v.moo;
©2023 Rinca Hayamine