Open12

マイクラ花火メモ置き場

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

とりあえず万華鏡花火のレシピ

計算式は LifeTime と距離(ブロック)依存性より、多項式近似による二次式を用いる。

x(t) = 0.020595 t^2 - 0.02976 t + C

ただし、C は初期条件(任意定数)
2階微分したら 0.04119 という定数が得られるので、マイクラの世界の花火は 0.04119 [block/tick^2] で等加速度運動してるのが面白い。

ソースコード
using MinecraftConnection;
using MinecraftConnection.Entity;

// マイクラサーバ接続先の設定
string address = "127.0.0.1";
ushort port = 25575;
string pass = "minecraft";
MinecraftCommands command = new MinecraftCommands(address, port, pass);

// メインとなる大玉花火
ushort lifeTime = 30;
Fireworks fireworks = new Fireworks()
{
    LifeTime = lifeTime,
    Type = FireworkType.LargeBall,
    Colors = FireworkOption.RandomColor(),
    FadeColors = new List<FireworkColors> { FireworkColors.WHITE },
};

// 周りを彩るバースト花火
Fireworks BurstFireworks(double x, double y, double z)
{
    Fireworks fireworks = new Fireworks()
    {
        LifeTime = 0,
        Type = FireworkType.Burst,
        Colors = FireworkOption.RandomColor(),
        FadeColors = new List<FireworkColors> { FireworkColors.WHITE },
        Flicker = false,
        Trail = true,
        Motion = new Motion(x, y, z)
    };
    return fireworks;
}

// 多項式近似の計算式(任意定数は各自で調整が必要)
double diff = (0.020595 * lifeTime * lifeTime) - (0.02976 * lifeTime);

// 大玉花火とバースト花火の座標
Position pos = new Position(-516, 64, -205);
Position burstPos = new Position(-516, 64 + diff, -205);

// 大玉花火とバースト花火をそれぞれ打ち上げる
command.SetOffFireworks(pos, fireworks);
command.Wait(1700); // インターバルを置いておく
double val = 1.0;
command.SetOffFireworks(burstPos, BurstFireworks(val, 0, 0));
command.SetOffFireworks(burstPos, BurstFireworks(-val, 0, 0));
command.SetOffFireworks(burstPos, BurstFireworks(0, val, 0));
command.SetOffFireworks(burstPos, BurstFireworks(0, -val, 0));
command.SetOffFireworks(burstPos, BurstFireworks(val, val, 0));
command.SetOffFireworks(burstPos, BurstFireworks(val, -val, 0));
command.SetOffFireworks(burstPos, BurstFireworks(-val, val, 0));
command.SetOffFireworks(burstPos, BurstFireworks(-val, -val, 0));

実行結果

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

空の花火を実装してみた。

IsEmpty プロパティを true にすれば花火なしに軌跡だけ描ける。一本の軌跡を描きたいときに使えそう。

ソースコード
Fireworks fireworks1 = new Fireworks()
{
    LifeTime = 100,
    Motion = new Motion(0.05, 0.5, 0.0),
    IsEmpty = true
};
Fireworks fireworks2 = new Fireworks()
{
    LifeTime = 100,
    Motion = new Motion(-0.05, 0.5, 0.0),
    IsEmpty = true
};

Position pos = new Position(-523, 67, -205);
Position pos2 = new Position(-514, 67, -205);

command.SetOffFireworks(pos, fireworks1);
command.SetOffFireworks(pos2, fireworks2);

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

逆方向もできた。

軌跡に関しても Motion をいじればあらゆる方向へ打ち出せる。

ソースコード
Fireworks fireworks1 = new Fireworks()
{
    LifeTime = 100,
    Motion = new Motion(0.05, -1.0, 0.0),
    IsEmpty = true
};
Fireworks fireworks2 = new Fireworks()
{
    LifeTime = 100,
    Motion = new Motion(-0.05, -1.0, 0.0),
    IsEmpty = true
};
// 以下前スレッドと同じ

MukakinMukakin

キレイ
これができたらどんなエフェクトでも作れそう

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

花火の例

ソースコード
Position pos = new Position(-536, 64, -205);

Fireworks emptyFirewroks(double x, double y, double z)
{
    return new Fireworks()
    {
        LifeTime = 20,
        IsEmpty = true,
        Motion = new Motion(x, y, z)
    };
}

Fireworks smallFirewroks()
{
    return new Fireworks()
    {
        LifeTime = 0,
        Colors = new List<FireworkColors> { FireworkColors.YELLOW },
        FadeColors = new List<FireworkColors> { FireworkColors.ORANGE },
    };
}

for (int i = 0; i < 10; i++)
{
    command.SetOffFireworks(pos.X + 5 * i, pos.Y, pos.Z, emptyFirewroks(0.2, 0.7, 0.0));
    command.SetOffFireworks(pos.X + 5 * i, pos.Y, pos.Z, emptyFirewroks(-0.2, 0.7, 0.0));
    command.Wait(100);
}

command.Wait(300);

for (int i = 0; i < 10; i++)
{
    command.SetOffFireworks(pos.X + 5 * i, pos.Y + 25, pos.Z, smallFirewroks());
}

https://twitter.com/takunology_net/status/1533592405210828802

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

チューリップ型花火(もう少し改良が必要かな)

ソースコード
Position pos = new Position(-540, 74, -205);

Fireworks Leaf(double x, double y, double z)
{
    return new Fireworks()
    {
        LifeTime = 0,
        Type = FireworkType.Burst,
        Colors = new List<FireworkColors> { FireworkColors.LIME },
        Trail = true,
        Motion = new Motion(x, y, z)
    };
}

Fireworks Flower(double x, double y, double z)
{
    return new Fireworks()
    {
        LifeTime = 0,
        Type = FireworkType.Burst,
        Colors = new List<FireworkColors> { FireworkColors.RED },
        Trail = true,
        Motion = new Motion(x, y, z)
    };
}

for (int i = 0; i < 3; i++)
{
    command.SetOffFireworks(pos.X + 25 * i, pos.Y, pos.Z, Leaf(1.3, 0.8, 0));
    command.SetOffFireworks(pos.X + 25 * i, pos.Y, pos.Z, Leaf(-1.3, 0.8, 0));
    command.SetOffFireworks(pos.X + 23 * i, pos.Y - 2, pos.Z, Flower(-0.2, 2.0, 0));
    command.SetOffFireworks(pos.X + 24 * i, pos.Y - 2, pos.Z, Flower(-0.1, 2.0, 0));
    command.SetOffFireworks(pos.X + 25 * i, pos.Y - 2, pos.Z, Flower(0, 2.0, 0));
    command.SetOffFireworks(pos.X + 26 * i, pos.Y - 2, pos.Z, Flower(0.1, 2.0, 0));
    command.SetOffFireworks(pos.X + 27 * i, pos.Y - 2, pos.Z, Flower(0.2, 2.0, 0));
}

https://twitter.com/takunology_net/status/1533595982859948032

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

チューリップ型を少し書き換えてラベンダー風

ソースコード
Position pos = new Position(-540, 74, -205);
Random rand = new Random();

Fireworks Leaf(double x, double y, double z)
{
    return new Fireworks()
    {
        LifeTime = 0,
        Type = FireworkType.Burst,
        Colors = new List<FireworkColors> { FireworkColors.LIME },
        Trail = true,
        Motion = new Motion(x, y, z)
    };
}

Fireworks Flower = new Fireworks()
{
    LifeTime = 0,
    Type = FireworkType.SmallBall,
    Colors = new List<FireworkColors> { FireworkColors.PURPLE }
};

for (int i = 0; i < 3; i++)
{
    command.SetOffFireworks(pos.X + 25 * i, pos.Y, pos.Z, Leaf(1.3, 0.8, 0));
    command.SetOffFireworks(pos.X + 25 * i, pos.Y, pos.Z, Leaf(-1.3, 0.8, 0));
    command.Wait(200);
    for (int j = 0; j < 10; j++)
    {
        command.SetOffFireworks(pos.X + 25 * i + rand.Next(-2, 2), pos.Y + rand.Next(3, 18), pos.Z, Flower);
    }
}

https://twitter.com/takunology_net/status/1533597578175975424

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

結構力技だけどキャラものも作れそう。
これは ネコチャン (=^・^=)

ソースコード
Position pos = new Position(-510, 94, -205);

Fireworks Parts(double x, double y, double z)
{
    return new Fireworks()
    {
        LifeTime = 0,
        Type = FireworkType.Burst,
        Colors = new List<FireworkColors> { FireworkColors.YELLOW },
        Trail = true,
        Motion = new Motion(x, y, z)
    };
}

Fireworks Eyes(double x, double y, double z)
{
    return new Fireworks()
    {
        LifeTime = 0,
        Type = FireworkType.SmallBall,
        Colors = new List<FireworkColors> { FireworkColors.BLUE },
        Trail = true,
        Motion = new Motion(x, y, z)
    };
}

Fireworks Face(double x, double y, double z)
{
    return new Fireworks()
    {
        LifeTime = 5,
        IsEmpty = true,
        Motion = new Motion(x, y, z)
    };
}

Fireworks Face2(double x, double y, double z)
{
    return new Fireworks()
    {
        LifeTime = 20,
        IsEmpty = true,
        Motion = new Motion(x, y, z)
    };
}


for (int i = 0; i < 10; i++)
{
    command.SetOffFireworks(pos.X, pos.Y, pos.Z, Face(-0.2, -1, 0));
    command.SetOffFireworks(pos.X, pos.Y, pos.Z, Face(0.2, -1, 0));
    command.SetOffFireworks(pos.X - 10, pos.Y, pos.Z, Face(-0.2, -1, 0));
    command.SetOffFireworks(pos.X - 10, pos.Y, pos.Z, Face(0.2, -1, 0));
    command.SetOffFireworks(pos.X - 10, pos.Y - 2, pos.Z, Face(0.8, 0, 0));
}

command.SetOffFireworks(pos.X - 14, pos.Y - 6, pos.Z, Face2(0.05, -0.85, 0));
command.SetOffFireworks(pos.X + 3, pos.Y - 6, pos.Z, Face2(-0.05, -0.85, 0));

command.SetOffFireworks(pos.X - 6, pos.Y - 12, pos.Z, Parts(-1.4, -0.2, 0));
command.SetOffFireworks(pos.X - 6, pos.Y - 12, pos.Z, Parts(1.4, -0.2, 0));

command.SetOffFireworks(pos.X - 11, pos.Y - 5, pos.Z + 7, Eyes(0, 0, 2));
command.SetOffFireworks(pos.X, pos.Y - 5, pos.Z + 7, Eyes(0, 0, 2));

https://twitter.com/takunology_net/status/1533606122094882818

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

花火パーティクルを使うと任意の形状を描画できる。pos.X にかかっている 0.1 はゲイン調整のためのパラメータ。pos.Y にかかっている 5 も同様。

例えば sin と cos をプロットすることもできる。

Position pos = new Position(-510, 94, -205);

for (int i = 0; i < 360; i++)
{
    double angle = Math.PI * i / 180;
    command.SendCommand($"particle firework {pos.X - i * 0.1} {pos.Y + Math.Sin(angle) * 5} {pos.Z} 0 0 0 0 1");
    command.SendCommand($"particle firework {pos.X - i * 0.1} {pos.Y - 15 + Math.Cos(angle) * 5} {pos.Z} 0 0 0 0 1");
}

https://twitter.com/takunology_net/status/1533839098821021696

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

とりあえずフーリエ級数展開しとく。x にはラジアンが入る。

f(x) = \sum_{i = 1}^j \frac{{\rm sin}(2j - 1) x}{2j - 1}
ソースコード
for (int i = -360; i <= 360; i++)
{
    double angle = Math.PI * i / 180;
    double val = 0.0;
    for (int j = 1; j <= 20; j++)
    {
        val += Math.Sin((2 * j - 1) * angle) / (2 * j - 1);
    }
    command.SendCommand($"particle firework {pos.X - i * 0.05} {pos.Y + val * 4} {pos.Z} 0 0 0 0 1");
}

j = 5 で近似

j = 10 で近似

j = 20 で近似

たくのろじぃ | Takumi Okawaたくのろじぃ | Takumi Okawa

三角波のフーリエ級数展開

f(x) = \sum_{i = 1}^j \ (-1)^j \ \frac{{\rm sin}(2j - 1) x}{2j - 1}
ソースコード
for (int i = -360; i <= 360; i++)
{
    double angle = Math.PI * i / 180;
    double val = 0.0;
    for (int j = 1; j <= 20; j++)
    {
        if (j % 2 == 0)
        {
            val += Math.Sin((2 * j - 1) * angle) / Math.Pow((2 * j - 1), 2);
        }
        else
        {
            val -= Math.Sin((2 * j - 1) * angle) / Math.Pow((2 * j - 1), 2);
        }
    }
    command.SendCommand($"particle firework {pos.X - i * 0.05} {pos.Y + val * 4} {pos.Z} 0 0 0 0 1");
}

j = 2 で近似

j = 5 で近似

j = 20 で近似