注目キーワード

逆引きScriptAPI – よく使う関数&スクリプト集【マイクラ統合版】

はじめに

本ページは、ScriptAPIにおいてよく使う関数やスクリプトをまとめることで、コピーしてすぐに使えるようにすることが目的です。もし、「○○がしたいんだけど、どうすればいいの?」、「このスクリプト、よく使うんだけど載ってない」といったご意見・疑問点がありましたら、コメント欄より教えてください。随時追加していきます。

そもそもScriptAPIって何ぞや」という方は、まずはこちらをご覧ください:

Character
結構主観が入っています

手に持っているアイテムを取得

let item = player.getComponent("inventory").container.getItem(player.selectedSlotIndex);
Copied!

この関数を使う機会は結構な頻度であると思います。特に、あるアイテムを所持している時に関数を発火させたり、特定の武器で敵を攻撃したときにエフェクトを付与したりするなど、ゲームシステムを改変するにあたってはこの関数の存在は見逃せません

この関数の使用にあたっては、下の例で示す通り、playerクラスの変数が必要です。

使用例

server.world.afterEvents.entityHitEntity.subscribe(ev => {
    let player = ev.damagingEntity;
    if (player.typeId == "minecraft:player"){
        let weapon = player.getComponent("inventory").container.getItem(player.selectedSlotIndex);
        if(weapon == undefined){return;}
        if(weapon.typeId == "minecraft:diamond_sword"){
            player.sendMessage("ダイアモンドの剣を使いました");
        }
    }
})
Copied!

この例では、プレイヤーが敵に攻撃を当てたときに発火する関数を定義しています。関数内で手に持っている武器を検知し、それがダイアモンドの剣だった場合に「ダイアモンドの剣を使いました」というメッセージを表示しています。

例を見れば明らかですが、weaponがundefinedの場合を明確に区別し、その場合は関数から離脱するようにしています。特に素手であった場合にはweaponがundefinedとなるため、この設定がないと往々にしてエラーを吐く点には注意しましょう。

Character
エラーが出てるとプレイ画面が見づらくなるからね…

現在の体力を検知

let health = player.getComponent("minecraft:health").currentValue;
Copied!

個人的にこれ自体はそれほど頻繁に使うわけではないのですが、あまりに情報が少ないせいで(?)、「やりたいと思った時にできない」ということがしばしば起こり得るのではないかと思います。先ほどと同じようにgetComponent関数で体力自体は検知できるのですが、それを数値の形で取り出そうとするとcurrentValueのプロパティが必要です。ちょっと初見殺し感があるかもしれません笑。

Character
ちなみにplayerじゃなくてもentityクラスなら使えます

使用例

server.system.runInterval(() => {
    for (const player of server.world.getPlayers()) {
        if (player.getComponent("minecraft:health").currentValue <= 6) {
            player.runCommand("effect @s instant_health 1");
        }
    }
},2)
Copied!

これは常時プレイヤーの体力を監視し、もしハートの数が3(体力値が6)以下だったら自動でinstant_healthのエフェクトを付与する例です。このように、プレイヤーの体力に応じて何らかの変化を加えたい、というケースはしばしばあるのではないかと思います。

スコアボードの取得

function get_score(score_name, player_name){
    try{
        const scoreboard = server.world.scoreboard;
        let objective = scoreboard.getObjective(score_name);
        let score = objective.getScore(player_name.scoreboardIdentity);
        if (score != undefined){
            return score;
        }else{
            return NaN;
        }
    } catch{
        return NaN;   //scoreboardが定義されていないかも?
    }
}
Copied!

続いて、スコアボードの名前とプレイヤークラスの変数を引数としてスコアボードの値を返す関数です。私が公式ドキュメントを見た限りではプレイヤーのスコアボードの値を返す関数が存在しないようだったので、自分で作ってしまいました。結構使いますし、重宝すると思います。

Character
スコアボードが存在しなければNnNを返します

ちなみにこの関数の具体的な事項はこちらの記事が詳しいです:

使用例

server.system.runInterval(ev => {
    for (const player of server.world.getAllPlayers()){
        player.runCommand(`give @s[scores={test_score=${get_score("test_score",player)}}] diamond ${get_score("test_score",player)}`);
    }
});
Copied!

これは常時プレイヤーを監視し、スコアボードの値に応じたダイアモンドを与える例です。この関数がなければ、例えば以下のように無数のコマンドを書かなければならないところでした。

give @a[scores={test_score=3}] diamond 3
give @a[scores={test_score=4}] diamond 4
give @a[scores={test_score=5}] diamond 5
give @a[scores={test_score=6}] diamond 6
Copied!

この問題が関数一つで解決するのは非常に意義があることだと思います。

Character
ScriptAPIの強みだなぁって思える瞬間です

インベントリ内のアイテムを取得

function has_item(itemName, player){
    for (let i=0;i<=35;i++){
        if(player.getComponent("minecraft:inventory").container.getSlot(i).typeId == itemName){
            return true;
        }
    }
    return false;
}
Copied!

これは先ほどとは似て非なるものです。アイテムのidとプレイヤークラスの変数を引数とし、インベントリ内に指定のアイテムがあればtrueを、そうでなければfalseを返す関数です。自作の取引システムを構築した際などに、アイテムの有無を検知する手段として使えそうですね。

同様にして、インベントリ内のアイテムの総数をint形式でreturnする関数も作れます:

function get_item_amount(itemName, player){
    let amount = 0
    for (let i=0;i<=35;i++){
        let container_item = player.getComponent("minecraft:inventory").container.getSlot(i)
        try{
            if(container_item.typeId == itemName){
                amount += player.getComponent("minecraft:inventory").container.getSlot(i).amount;
            }   
        }
        catch(error){
            continue;
        }
    }
    return amount;
}
Copied!

このあたりの詳細については、こちらの記事が詳しいです:

Character
結構シンプル。

具体例

server.system.afterEvents.scriptEventReceive.subscribe(ev => {
    if(ev.id == "lq:test"){
        let player = ev.sourceEntity;
        if(has_item("minecraft:apple",player)){
            player.runCommand("say リンゴを持っています");
        }else{
            player.runCommand("say リンゴを持っていません");
        }
    }
})
Copied!

これは「lq:test」というidのscripteventを受け取ったときにリンゴの数を数え、リンゴを持っている時は「リンゴを持っています」と発言し、そうでなければ「リンゴを持っていません」と発言するプログラムです。このように、インベントリ内のアイテムに応じて特定の関数を実行(または実行しない)ことが可能になります。

ちなみに、scripteventについてはこちらで詳しく解説しています。オリジナルのコマンドも作成することができ、非常に便利ですよ~。

Character
リンゴの数を出力する場合も同様です

地下にいるかどうかを判定

function exists_in_underground(player){
    const player_block = player.dimension.getBlock(player.location);
    if (player_block == undefined){return false;}
    let blocks_above = []
    for (let i = player.location.y + 2 ; i <= 255; i++) {
        try{
        blocks_above.push(player.dimension.getBlock({x:player.location.x, y:i, z:player.location.z}));
        }catch{
        }
    }
    for (const block of blocks_above) {
        if (block == undefined){continue;}
        if (block.typeId != "minecraft:air") {
            return true; // 地下
        }
    }
    return false; // 地上
}
Copied!

これは正直使うか微妙なのですが、一応紹介しておきます。ご覧の通り、playerクラスの引数をとってplayerが地下にいればtrueを、そうでなければfalseを返す関数です。

関数を見ていただくとお分かりかと思いますが、playerの頭上にあるブロックを全て取得して配列に格納し、各ブロックについて一つ一つairであるか否かを判定しています。その結果、一つでもairでないブロック(石や土など)が存在すれば、そこは地下であるとみたしてtrueを、そうでなければそこは地上であるとみなしてfalseを返しています。

Character
あるブロックが地表面であるかどうかも、同様の方法で確認できますよ~

UIの表示

function show_form(player){
    const form = new ui.ActionFormData();
    form.title("選択メニュー あなたはどっち派?");
    form.button("マック");
    form.button("マクド");
    form.show(player).then((response) => {
        switch(response.selection){
            case 0:
                player.sendMessage("マックを選択しました。");
                player.runCommandAsync("give @s emerald 1");
                break;
            case 1:
                player.sendMessage("マクドを選択しました。");
                break;
            default:
                player.sendMessage("何も選択していません。");
                break;
        }
    }).catch(error =>
        player.sendMessage("An error occurred: " + error.message)
    );
}
Copied!

これは界隈の人にとっては常識かもしれませんね(笑)。本格的なアドオンを作ろうと思ったらUIの表示は欠かせません。これは、下のように「マクド」と「マック」を選択する、シンプルなUIを表示する関数であり、playerクラスの引数を必要とします

Character
引数に注意!

ちなみに、フォームを表示する場合も、これをすこし変えるだけでOKです。

function show_form(player){
    const form = new ui.ModalFormData();
    form.slider("スライダー",0,100,1,50);
    form.textField("ここにテキストを入力","テキスト");
    form.dropdown("ドロップダウン",["a","b","c"]);
    form.toggle("チェックボックス");
    form.show(player).then(response => {
        if (response.canceled){
            player.sendMessage("キャンセルされました");
            return;
        }
        player.sendMessage("スライダーの値:" + String(response.formValues[0]));
        player.sendMessage("テキストの入力:" + String(response.formValues[1]));
        player.sendMessage("ドロップダウンの選択:" + String(response.formValues[2]));
        player.sendMessage("チェックボックスの状態:" + String(response.formValues[3]));
    })
    .catch(error => {
        player.sendMessage("エラー: " + error.message);
    });
}
Copied!

この関数を使用することで、以下のようにスライダーや各種入力欄が表示されることが確認できるでしょう。操作性の高いアドオンには必須の関数ですね。

使用例

server.world.afterEvents.itemUse.subscribe(ev => {
    if (ev.itemStack.typeId == "minecraft:stick"){
        let player = ev.source;
        show_form(player);
    }
});
Copied!

これは先ほど定義したUIを表示する関数(show_form)を用いて、棒を右クリックしたときにUIを表示するスクリプトの例です。このとき、playerクラスの引数が必要なので、ev.sourceによって棒の使用者を取得しています。

ちなみに、こうしたUIの表示についてはこちらの記事でとても詳しく解説しています:

Character
ちなみにYoutube動画もあります

おしまい

ここまでよく使うスクリプト・関数をまとめてみました。他にもまだまだあると思うので、「これも追加してほしい」というものがありましたら、遠慮なくコメント欄から教えてください。

Character
他の記事もどうぞ~

こちらの記事もどうぞ。

最新情報をチェックしよう!