【C#】マイクラでイ゛オ゛ナ゛ズン゛!してみた

イクラの世界で「魔法が使えたらなぁ...」なんて思ったことありませんか?

例えば、クリーパーやTNTを使えば爆発させることが出来ますし、ウィッチやポーションを使えば状態異常を付与することができます。他にも、雷を落とすことだって可能です。

可能なら、やってみましょう。イ゛オ゛ナ゛ズン゛!(睡眠不足)

こちら、参考画像になります。

f:id:takunology:20210824143624p:plain

準備

1. マイクラで爆発パーティクルを作る

TNTやクリーパーが爆発するとき、爆風のパーティクルが表示されますが、あれは単なるパーティクルで当たり判定はありません。当たり判定は小さなドット(正確にはある座標)にのみ存在しており、ある空間内におけるMobにピンポイントでダメージを与えています。

まずはパーティクル作りから始めます。(.NET 5 のコンソールアプリで作ってから、動作確認後に Functions を使用します。)

1.1 導入

このブログでは何度も紹介しているマイクラ用のパッケージを導入します。

www.nuget.org

あとは using MinecraftConnection して MinecraftCommandsインスタンスを生成してください。

1.2 パーティクルの発生

パーティクルを呼び出すには particle コマンドを使用します。

particle <名前> <位置(x, y, z)> <距離(x, y, z)> <速度> <総数> <モード> <表示者>
オプション 説明
名前 パーティクルの種類
位置 パーティクルを発生させる位置(x, y, z)有効範囲は 32 まで
距離 空間上の基準点(位置)との差で、大きいほど広がる
速度 パーティクルのアニメーション速度(爆発は大きさを表す)
総数 パーティクルの数
モード force または normal から選択する(省略可能)
表示者 パーティクルを表示させるプレイヤー(省略可能)

距離を大きくすると、パーティクルが発生する位置が広がります。逆に小さくして総数を増やすと密なパーティクルになります。

例えば、爆発のパーティクルを作るにはこのコマンドを実行します。

execute at @e[type=zombie] run particle explosion_emitter ~ ~ ~ 1 1 1 1 5

@e でエンティティを指定しますが、[type=] をつけることで対象を絞ることが出来ます。この例ではゾンビを対象にしているので、ワールドに存在するゾンビたちに爆発パーティクルを表示するようなコマンドになります。また、距離に関しては 1 あたり 8 ブロック分広がります。つまり、1×1×1に設定されているので体積 8 の範囲で爆発する位置がランダムに指定されます。

f:id:takunology:20210824141728p:plain

これを応用して、様々な敵にパーティクルを適用させるプログラムを書いてみます。

using MinecraftConnection;

namespace ConsoleApps
{
    class Program
    {
        static string address = "127.0.0.1";
        static ushort port = 25575;
        static string pass = "minecraft";
        static MinecraftCommands commands = new MinecraftCommands(address, port, pass);

        static void Main(string[] args)
        {
            for (int i = 0; i < 2; i++)
            {
                PrticleEntity("explosion_emitter");
                commands.Wait(50);
            }
        }

        //敵エンティティにパーティクルを出す
        static void PrticleEntity(string name)
        {
            double dx = 0.5, dy = 1, dz = 0.5;
            double speed = 1.0;
            int count = 5;
            var Mob = new string[]
            {
                "creeper",
                "zombie",
                "skeleton",
                "slime",
                "bat",
                "spider",
                "cave_spider",
                "witch",
                "pillager"
            };

            foreach(var type in Mob)
            {
                commands.SendCommand($"execute at @e[type={type}] run particle {name} ~ ~ ~ {dx} {dy} {dz} {speed} {count}");
            }
        }
    }
}

次に、プレイヤーのパーティクルを作ります。魔法を使うのならばせっかくなので、エンチャント文字となんかキラキラしたやつをつけてみましょう。

//キラキラパーティクルを出す
static void PrticleComposter(int x, int y, int z)
{
    string name = "composter";
    double dx = 1.0, dy = 0, dz = 1.0;
    double speed = 1.0;
    int count = 20;
    commands.SendCommand($"particle {name} {x} {y} {z} {dx} {dy} {dz} {speed} {count}");
}

//もやもやパーティクルを出す
static void PrticleEffect(int x, int y, int z)
{
    string name = "effect";
    double dx = 0.5, dy = 0, dz = 0.5;
    double speed = 1.0;
    int count = 10;
    commands.SendCommand($"particle {name} {x} {y} {z} {dx} {dy} {dz} {speed} {count}");
}

//エンチャントパーティクルを出す
static void PrticleEnchant(int x, int y, int z)
{
    string name = "enchant";
    double dx = 1.0, dy = 0, dz = 1.0;
    double speed = 2.0;
    int count = 10;
    commands.SendCommand($"particle {name} {x} {y} {z} {dx} {dy} {dz} {speed} {count}");
}

これらのパーティクルはすぐに消えてしまうので、反復処理で繰り返すとそれっぽいアニメーションになります。

static void Main(string[] args)
{
    for (int i = 0; i < 40; i++)
    {
        var data = commands.GetPlayerData("takunology");
        PrticleEnchant(data.PositionX, data.PositionY, data.PositionZ);
        PrticleComposter(data.PositionX, data.PositionY, data.PositionZ);
        PrticleDust(data.PositionX, data.PositionY, data.PositionZ, 1, 0.4, 0, 1);
        commands.Wait(50);
    }
}

こんな感じで呼び出すと良いかと...。

2. ダメージを与える

次に、対象のMobにダメージを与えます。ダメージを与えるには effect コマンドの即時ダメージ効果を付与します。ただし、注意しないといけないのは、ゾンビとスケルトンは即時ダメージではなく即時回復でないとダメージを与えられません。それ以外の Mob は即時ダメージでダメージが与えられます。なので、これらを条件分岐する必要があります。

即時回復のコマンド

effect give <エンティティ> instant_health <時間> <強さ>

即時ダメージのコマンド

effect give <エンティティ> instant_damage <時間> <強さ>

いい感じにプログラムにまとめます。(コレクションではなく配列でも良かったですね。)

static void Attack()
{
    var Mob = new string[]
            {
                "creeper",
                "zombie",
                "skeleton",
                "slime",
                "bat",
                "spider",
                "cave_spider",
                "witch",
                "pillager"
            };

    foreach (var type in Mob)
    {
        if (type == "zombie" || type == "skeleton")
        {
            commands.SendCommand($"effect give @e[type={type}] instant_health 1 1");
        }
        else
        {
            commands.SendCommand($"effect give @e[type={type}] instant_damage 1 1");
        }
    }
}

3. 実行結果

実行結果はツイッターに載せました。爆発のパーティクルが表示されながらMobにダメージを与えます。動画では2発目を当てているので、倒しています。なお、ウィッチはポーション回復してしまうので、なにか対策が必要ですね。ダメージ量に関しては、instant_damage のオプションを変えることで調整可能です。

ちなみに、これに音声認識をつけて「イ゛オ゛ナ゛ズン゛!」と詠唱して魔法攻撃出来ないかを模索中です。(できたら記事にします。)

参考サイト

パーティクルの効果は色々変更できるので、参考先からご覧ください。

minecraft.fandom.com

www.digminecraft.com

イベントのお知らせ

2021年8月27日(金)20:00 より、MS Tech Camp #10 を開催します!
今回は Azure Functions の .NET ランタイムとC#プログラミングを使用して、Minecraft で花火を打ち上げます。 Azure Functions や マイクラプログラミング(C#)に興味のある方、ぜひご参加ください!(Minecraft Java 版でも統合版でもご参加いただけます)

mspjp.connpass.com

夏の思い出に「マイクラ花火」いかがでしょうか?