火をともす

火は煙と同じ要領でできる。

火粒.png
Fire


class 火クラス
{
  method 火クラス()
  {
  }

  method OnEnter()
  {
    int $number = 0;
    while(true)
    {
      string $name = "火粒"+String($number++);
      ThreadCreate(call=@火粒スレッド(name=$name));
      wait 50;
    }
  }

  method 火粒スレッド(string $name)
  {
    CreateImage(name=$name
      , sx=100%, sy=100%, ox="Center", oy="Middle", alpha=0%
      , angle=rand_range(0,359), image="火粒.png", blend="Add");
    Enter(to=$name);

    int   $range = 5;
    int   $angle = 90+rand_range(-$range,$range);
    float $rad = radian(Float($angle));
    float $radius = 500.0;
    float $x = $radius*cos($rad);
    float $y = -$radius*sin($rad);
    int   $time = 1500;

    Move(to=$name, time=$time, x=$x, y=$y, step="AccSin");
    Zoom(to=$name, time=$time, sx=50%, sy=50%);
    Opaque(to=$name, time=100, alpha=50%, step="DecSin");
    wait 100;
    Opaque(to=$name, time=$time-100, alpha=0%, step="DecSin");
    WaitDecor(to=$name);
    Delete(to=$name);
  }
}

method Main()
{
  CreateColor(name="背景", w=1280, h=720, color=black);
  Enter(to="背景");

  CreateObject(name="火", x=1280/2, y=720/2+150, class=@火クラス());
  Enter(to="火");
}
YouTube Preview Image

煙がだんだん減速しながら広がっていくのに対して
火はだんだん加速しながら狭まっていく感じにする。

火粒が融合して艶かしい不思議なかんじになっているが
これは合成モードを”Add”(加算)にしている効果だ。
加算合成の画像同士を近づけるとひっついたかんじになるのが加算合成の特徴である。

さて、やはりこれだけでは単純すぎるのでまた工夫してみる。
火元を動かせるようにする。


class 火クラス
{
  method 火クラス()
  {
    CreateNode(name="火元");
  }

  method OnEnter()
  {
    int $number = 0;
    float $old_x;
    float $old_y;
    while(true)
    {
      // 火元が前回の位置から動いていたらハードモードに設定
      decor $target = GetDecor("火元");
      float $tx = $target.GetPosX();
      float $ty = $target.GetPosY();
      bool $hard = ($old_x != $tx || $old_y != $ty);
      operate $old_x = $tx;
      operate $old_y = $ty;

      string $name = "火粒"+String($number++);
      ThreadCreate(call=@火粒スレッド(name=$name, tx=$tx, ty=$ty, hard=$hard));

      // ハードモードなら発生間隔を詰める
      wait $hard ? 10 : 50;
    }
  }

  method 火粒スレッド(string $name, float $tx, float $ty, bool $hard)
  {
    CreateImage(name=$name
      , x=$tx, y=$ty
      , sx=100%, sy=100%, ox="Center", oy="Middle", alpha=0%
      , angle=rand_range(0,359), image="火粒.png", blend="Add");
    Enter(to=$name);

    int   $range = $hard ? 30 : 5;
    int   $angle = 90+rand_range(-$range,$range);
    float $rad = radian(Float($angle));
    float $radius = 500.0;
    float $x = $tx+$radius*cos($rad);
    float $y = $ty-$radius*sin($rad);
    int   $time = 1500;

    Move(to=$name, time=$time, x=$x, y=$y, step="AccSin");
    Zoom(to=$name, time=$time, sx=50%, sy=50%);
    Opaque(to=$name, time=100, alpha=50%, step="DecSin");
    wait 100;
    Opaque(to=$name, time=$time-100, alpha=0%, step="DecSin");
    WaitDecor(to=$name);
    Delete(to=$name);
  }
}

method Main()
{
  CreateColor(name="背景", w=1280, h=720, color=black);
  Enter(to="背景");

  CreateObject(name="火", x=1280/2, y=720/2+150, class=@火クラス());
  Enter(to="火");
  wait 2000;
  Move(to="火/火元", x=-500, time=1000, step="AccSig");
  wait 1000;
  Move(to="火/火元", x=500, time=2000, step="AccSig");
  wait 2000;
  Move(to="火/火元", x=0, y=-200, time=1000, step="AccSig");
  wait 1000;
  Move(to="火/火元", x=-500, y=0, time=1000, step="AccSig");
  wait 1000;
  Move(to="火/火元", x=0, y=0, time=1000, step="AccSig");
  wait 1000;
}
YouTube Preview Image

まず”火元”という名のノードデーカーを作成している。
そしてそのノードデーカーの位置を基準に火粒を発生させるようにしている。
するとノードデーカーを動かすことで、火粒の発生位置を動かすことができるようになる。
…といった寸法だ。

GetDecor関数はデーカーへの参照を得る関数で、
この参照を通してデーカーの様々な状態値を得ることができる。

ハードモードなる判定をしているが、
これは火が移動した時に火の見た目がおかしくなるのを防ぐ細工だ。
この火のエフェクトは火粒がある程度密集していることで火のように見せかけているが
火元がすばやく移動すると、火粒が密集せず散らばってまばらになってしまい、
個々の火粒がはっきりと見え、火のように見えなくなってしまう。

そこで火元が移動する時だけ火粒の発生間隔をつめるようにしている。
これは奇しくも現実の火をすばやく動かすと酸素を多く取り込んで強く燃え上がるのに似ている。
またさらに動いた時の風によるぶれを表現するために火粒の散り具合を上げるなどしている。

火のエフェクトというのは原理は簡単でも調整がすごく難しい…


Leave a Reply

*