3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

 夏だけじゃなく、最近は冬にもクリスマスやカウントダウンのイベントで花火が上がること、多いですよね?
 そして、お祝いと言えば、やはり花火です!
 なでしこ20周年を締めくくるのにふさわしいネタと言えるでしょう。

 というわけで、過去作を雑に使いまわしつつ、一日目の電光掲示板で得た知見をもとに改良したりなんだりします。

かこのいぶつ

 花火はずっと以前に一度作りました。
 元ネタは、これでした。

 クジラ飛行机氏の記事ですが、なでしこさんじゃなくてJavaScriptの記事でしたので、うっ、チョットなに言ってるかわかんにゃい💧️とか、アルファベットのコードぐあいわるい😵️とかなりつつ作ったものでした。

通常花火

 ちゃんとした移植ではありません。
 なんか、イメージで!
 あんまよくわかんないけど、ようするに前に紙吹雪作った時みたいに、花火の火花いっこいっこに辞書型変数で設定を作って、画面更新時実行で全部描画するのを繰り返せばいいんでしょ!? とゆう😅️

 夏の花火大会は、その後色数を増やしたり花火の種類を増やしたりしたことでゴチャッとしているので、当初の状態がコチラ。

# キャンバスの準備
変数 [キャンバス幅,キャンバス高さ,背景色][400,400,黒色]
描画中キャンバス「幅」キャンバス幅DOM属性設定
描画中キャンバス「高さ」キャンバス高さDOM属性設定
背景描画
●背景描画
    背景色塗り色設定
    [0,0,キャンバス幅,キャンバス高さ]四角描画
ここまで

# 宣言
花火データ空配列
粒子データ{"x":100,"y":100,"半径":2,"色":赤色,"透明度":1,"重力":0.05}
粒子数100
前時間時間ミリ秒取得

# 花火粒子の位置や透明度を更新
●(粒子を経過時間で)花火更新
    粒子["x"]粒子["vx"]*経過時間だけ増やす
    粒子["y"]粒子["vy"]*経過時間だけ増やす
    粒子["vy"]粒子["重力"]*経過時間だけ増やす
    粒子["透明度"]0.01*経過時間だけ減らす
    粒子["半径"]0.05*経過時間だけ減らす
    粒子["時間"]経過時間だけ増やす
    もし粒子["半径"]ならば粒子["半径"]
    もし粒子["透明度"]ならば粒子["透明度"]
ここまで

●花火描画
    # 経過時間を計算
    今時間時間ミリ秒取得
    経過時間(今時間-前時間)/100
    前時間今時間
    # キャンバスをクリア
    背景描画
    # 各粒子を更新して描画
    総粒子数花火データ要素数
    花火データ要素数
        粒子花火データ[総粒子数-回数]# 消失した粒子を削除するため逆順で回す
        粒子経過時間花火更新
        粒子["透明度"](粒子["色"]RGB分解)カラーコードRGBA
        塗り色設定線色設定
        [粒子["x"],粒子["y"]]粒子["半径"]円描画
        # 半径が0か透明度が0になった粒子は削除
        もし(粒子["透明度"]0)また(粒子["半径"]0)ならば花火データ総粒子数-回数配列削除
    ここまで
    「花火描画」画面更新時実行
ここまで

# 花火色候補の色定数。
定数 赤色「#FF0000」
定数 橙色「#ffa500」
定数 金色「#ffd700」
定数 黄色「#ffff00」

定数 空色「#87ceeb」
定数 薄桃色「#ffb6c1」
定数 薄緑色「#90ee90」
定数 矢車菊色「#6495ed」

●(xyへ)花火打ち上げ
    変数 花火色配列[[赤色,金色,黄色,橙色],[空色,薄桃色,薄緑色,矢車菊色]]
    変数 [cx,cy]xy
    粒子色配列花火色配列[(花火色配列要素数)乱数]
    粒子数
        粒子粒子データ配列複製
        粒子["x"]cx粒子["y"]cy
        粒子["色"]粒子色配列[(粒子色配列要素数)乱数]
        粒子["半径"]3乱数+1
        粒子["速度"]30乱数/10+1
        粒子["角度"](PI*2度変換)乱数
        粒子["vx"]COS(粒子["角度"])*粒子["速度"]
        粒子["vy"]SIN(粒子["角度"])*粒子["速度"]
        花火データ粒子配列追加
    ここまで
ここまで
#-------------------------------------------------
「花火描画」画面更新時実行
0.3秒毎には
    cxキャンバス幅乱数
    cyキャンバス高さ乱数
    [cx,cy]花火打ち上げ
ここまで
#-------------------------------------------------
//「#RRGGBB」→[R,G,B]
●(色を|色の)RGB分解
 分色とは変数分色空配列
 「#」「0x」置換
 整数変換
 からまで繰り返す
  分色[]%256
  (-分色[])/256
 ここまで
 分色戻る
ここまで
// (0~1)と[R,G,B]→「RGBA(R,G,B,A)」
●(透明度とrgbの)カラーコードRGBA
 「RGBA({rgb[0]},{rgb[1]},{rgb[2]},{透明度})」戻る
ここまで
#-------------------------------------------------

乱数

 なでしこさんの乱数とJavaScriptのMath.random()は、違います。
 なでしこさんの乱数は、0からA-1までのいずれかの整数を適当に返すものです。なので、6の乱数+1とかすれば、簡単にサイコロが作れます👍️
 ところがMath.random()は、0以上1未満の範囲で浮動小数点の擬似乱数を返すんだって。知ってたけどわかってなかった。
 3の乱数+1じゃ、粒子のサイズは1,2,3の三種類しかないわけですよ🤣️
 ピクセルに小数はないでしょって思ってたんだけど、サブピクセルってものがあるラシイ。

 とはいえ、そんなに細かくったってしょうがないだろうから、100の乱数/100*2+1とかでどうだろう・・・?🤔️
 「Math.random()」をJS実行とかすれば、まったく同様にすることもできますが、ま、いいでしょ💧️

 JavaScriptはもちろん、乱数と言えば0~1という言語は結構多いと思うので、なでしこさんにもあっていいと思うんだけど。
 って話、どっかで聞いたような気がすると思ったら、過去のアドベントカレンダーにこんなのありました!

 小数乱数ね👍️

透明度

 描画中コンテキストのglobalAlphaとゆうものを知りませんでしたんで、花火に使う色は全て、なでしこさんの色定数を使わずにカラーコードで定義して、透明度を加えてrgba形式にしています。

型物花火

 これは、花火の粒子を作っていません。
 丸点線で星やハートやスマイルマーク🙂を描いているだけです。

●(粒子の)型物花火描画
    r粒子["サイズ"]
    粒子["半径"]*2線太さ設定「round」線端形状設定
    [1,r/粒子["元半径"]]破線パターン設定
    キャンバス状態保存
    [粒子["x"],粒子["y"]]描画起点設定
    粒子["傾き"]描画回転
    粒子["型物"]条件分岐
        「星」ならば5[0,0]r星描画ここまで
        「ハート」ならば[0-r,0-r,r*2,r*2]ハート描画ここまで
        「スマイル」ならば
            [0,0]r円描画
            [0,0](20ラジアン変換)から(170ラジアン変換)までr/2円弧描画
            [r/3*-1,r/3*-1]r/20円描画
            [r/3,r/3*-1]r/20円描画
        ここまで
    ここまで
    キャンバス状態復元
ここまで

 なでしこの描画命令に、線端の形状(lineCap)や破線パターンの設定(setLineDash())を変更するものはありませんが、ワタクシどうしても点線が描きたい! とか、扇形描きたい! とか、v1ではできる角丸四角をv3でもぜったいに描きたい! とかとかいろいろあって、プラグイン(ライブラリ)を作っています。

 花火のためだけに、星とハートもしゅっと描けるようにしました🤣️

昇竜

 打ち上げ時にシュルシュルと尾を引くやつです。
 今回の改良点にある、背景を薄くして残像を残すということを知らなかったので、さっきまで自分がいたとこに尻尾の粒子を置いてくる、ということをしています。
 また、ただ残像を残しただけではシュルシュル感が出ないので、ランダムに左右に少し振っています。
 さいんこさいんのじゅもんで、らせんを描くようにしてみたらどうじゃろうとも思うたが、ワタクシの能力とセンスが不足で、変な感じにしかならなかったような記憶が~😥️
 今回の改良でもリベンジはせず💧️

改良します

 オブジェクトプロパティ構文など使って、今風な感じで1から作り直そうかとも思いましたが、時間とやる気が不足なため、過去の遺物にそのままいろいろ付け足しマス😅️

  • 祝 なでしこ 20周年! の文字花火
  • 花火の粒子が尾を引くようにする
  • 花火の粒子のキラキラ感を出す
  • 打ち上げ時の昇龍に角度を付ける

 こんなところです。

文字花火

 これはもう完全に一日目の電光掲示板と同様に、描画した文字からドットを作成しています。
 それを花火の粒子にしているだけ!

テキスト「祝 なでしこ 20周年!」
文字幅画面幅*1.2切り捨て
フォントサイズ80文字幅/(テキスト文字数)最小値
フォント「bold {フォントサイズ}px sans-serif」

文字用[0,0]キャンバス作成//領域を確保しない
文字用.可視オフ
文字用.幅属性文字幅
文字用.高さ属性画面高さ/2
フォント描画フォント設定

黒色塗り色設定
[0,0,文字幅,画面高さ]四角描画
白色塗り色設定
描画中コンテキスト.textAlign「center」
[文字幅/2,画面高さ/4]テキスト文字描画

色データ[0,0,文字幅,画面高さ/2]色データ取得

文字花火データ空配列
粒子間隔フォントサイズ/12切り捨て
y0から画面高さまで粒子間隔ずつ増やし繰り返す
    x0から文字幅まで粒子間隔ずつ増やし繰り返す
        ID(y*文字幅+x)*4
        もし色データ[ID]128ならば文字花火データ{"種別":"文字","tx":x-(文字幅-画面幅)/2,"ty":y,"透明度":1,"重力":0.09,"時間":0}配列追加
    ここまで
ここまで

 描画中コンテキストのtextAligncenterに設定すると、文字幅取得して計算する必要もなく描画位置に指定したxを中心にして中央寄せで文字描画出来るんですね❗️
 描画中コンテキスト奥が深い・・・

花火の粒子が尾を引く(残像)

 検索すると、背景描画時に描画中コンテキストにglobalAlphaを設定するか、背景色自体を透明度のついたものにするかといったところのようです。
 これらも、電光掲示板の消灯LEDを描画するときに学びました。

 ようするに背景のほうを半透明にして、前の描画が透けて見えるようにすることで残像を残すということですね。
 ただこの方法だと、しだれ柳のように長く尾を引く花火と、牡丹のように点状の粒子が丸く広がる花火を共存させることは出来ず不満が残りますが、今回はとりあえず折角なのでglobalAlphaを採用してみます。

 また、これを機に前述した花火の粒子のほうの透明度も、こちらに変えました。
 それにより、花火の色に、なでしこの色定数がフツーに使えるようになり、追加の色定数もカラーネームにしてみました。

●背景描画
    夜空色塗り色設定線色設定
    描画中コンテキスト.globalAlpha0.15
    [0,0,画面幅,画面高]四角描画
ここまで

 あまり残像が残りすぎると、文字花火や型物が変な感じになるのでほどほどの設定に。
 実際、型物のスマイル🙂は、尾を引くととてもそうは見えなくなってしまうのでやめました。
 ワタクシ本当は、しだれ柳が一番好きなんですけどね~😅

キラキラ感(明滅)

 周期的に粒子の透明度を変化させることでキラキラ✨💍✨明滅して見えるようにします。

 こんなかんじ。

# 花火打ち上げ時
粒子["明滅速度"]100乱数/100*0.2+0.05

# 花火更新時
粒子["透明度"]SIN(時間ミリ秒取得*粒子["明滅速度"])絶対値

 ただ、型物花火はただの点線なので、すべての点が同じタイミングでチカチカしてしまい不都合なので明滅はさせず、色が変わる感じにしました。

 また、花火描画時に、

 # 花火描画
描画中コンテキスト.globalCompositeOperation「lighter」

 とゆうじゅも~ん。
 globalCompositeOperationは、画像の合成演算や色の混合演算の方法を設定できるプロパティで、lighterは、色値加算で重なった部分は明るくなります。キラキラ感が増します✨️

 背景を塗るときには、元のsource-overに戻します。

昇龍の角度

 前は単純にyの値だけを変化させていたので、全部打ち上げ位置の真下からまっすぐ真上に上がっていましたが、イマイチかっこよくないので角度を付けました。

 二点間の途中座標を求めるじゅもーん!

xt = x  + (x2 - x) * t
yt = y  + (y2 - y) * t

 tは、(0=出発点)〜(1=到着点)で進行度を指定します。

移動元[100,300]
移動先[200,50]

黒色塗り色設定黒色線色設定
移動元円描画移動先円描画

赤色塗り色設定赤色線色設定
20
    進行度回数/20
    移動元から移動先まで進行度途中座標計算
    それ2円描画
ここまで

●(xyからxy2までtで|xy2までのtを)途中座標計算
    変数[x,y]xy
    変数[x2,y2]xy2
    xtx+(x2-x)*t
    yty+(y2-y)*t
    [xt,yt]戻す
ここまで

二点間の距離.png
 
 こんなかんじ?

できました🎆️

花火小.gif

おわります

 皆様のご尽力により、なでしこ20周年のアドベントカレンダー、無事に全て埋めることが出来ました!
 参加してくださった方はもちろん、読んでくださった方々もありがとうございました!!

3
2
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?