キンチョウの夏、その2(忘れたころに)JavaScriptで花火
計算との分離を目標に書きました。
爆発直前の処理は、打ち上げ前にやるべきだよなぁ〜
ちゅっとだけ落下しながらフェードアウト。
コードはへなちょこだが、風情は出てきたか!?
<!DOCTYPE html> <title>Hanabi</title> <style type="text/css"> body { background : #000; } h1 { color : #440; float: left} </style> <body> <h1>Hanabi</h1> <script type="text/javascript"> (function () { //@cc_on var MAX = 3, stock = [ ], CHAR_LIST = [ '●', '○', '◎', '*', '※', '・', '☆', '∴' ], COLOR_LIST = [ [ 255, 0, 0 ], [ 0, 255, 0 ], [ 0, 0, 255 ], [ 255, 255, 0 ], [ 255, 0, 255 ], [ 0, 255, 255 ], [ 255, 255, 255], [ 255, 128, 0 ], [ 128, 255, 0 ], [ 0, 128, 255 ], [ 255, 0, 128 ], [ 0, 255, 128 ], [ 128, 0, 255 ] ], // ランダム整数 randomInt = function ( n, b ) { return (b || 0) + Math.random () * n |0 }, // ランダム配色 randomColor = function ( ) { return COLOR_LIST[ randomInt( COLOR_LIST.length ) ]; }, // ランダム火玉文字 randomStar = function ( ) { return CHAR_LIST[ randomInt( CHAR_LIST.length ) ]; }, //____________________________ // パーツ追加 append = function ( parts ) { for( var i = 0, p; p = parts[i++]; this.appendChild( p.materialt ) ); }, // 動く move = function ( ) { for( var i = 0, p, f; p = this.parts[ i++ ]; ) f = f | this.motion.call(p) return f }, // パーツ削除 remove = function ( parts ) { for( var i = 0, p; p = parts[ i++ ]; ) p.materialt.parentNode.removeChild( p.materialt ); }, // パーツを描画 draw = function ( parts ) { for( var i = 0, p, s; p = parts[ i++ ]; ) { s = p.materialt.style; s.top = (p.position.y |0) + 'px'; s.left = (p.position.x |0) + 'px'; s.color = 'rgb(' + (p.color[0]|0) + ',' + (p.color[1]|0) + ',' + (p.color[2]|0) + ')'; } }, //____________________________ // func のループ開始 start = function ( func ) { var that = this; this.timerId = setInterval( function () { func.call( that ) }, 30); }, // ループ処理終了 stop = function ( flag ) { this.timerId && clearInterval( this.timerId ); return this.timerId = null }, //____________________________ // 打ち上げの高さ計算 motion1 = function ( ) { var y = this.option[3], h = this.position.y -= Math.floor( ( this.position.y - y ) / 20 ) + 2; return y > h; }, // 爆発の後の花火の位置を計算 motion2 = function ( ) { var c = this.color, a = this.option[2]; this.position.x += (this.option[0] *= 0.8); this.position.y += (this.option[1] *= 0.8) + 0.4; this.color = [ c[0] += a[0], c[1] += a[1], c[2] += a[2] ]; }, // ゆっくりと消えてゆく motion3 = function ( ) { this.position.y += 0.2; this.color[0] -= 10 < this.color[0] ? 10: 0; this.color[1] -= 10 < this.color[1] ? 10: 0; this.color[2] -= 10 < this.color[2] ? 10: 0; }, //____________________________ // 発射 fire = function ( ) { move.call( this ) ? stage2.call( this ): draw( this.parts ); }, // 消滅 extinction = function ( ) { if (0 == --this.life) { stop.call( this ); remove( [ { materialt: this.screen } ] ); } else { move.call ( this ); draw ( this.parts ); } }, // 爆発 explosion = function ( ) { if (0 == --this.life) { stop.call( this ); this.motion = motion3; this.life = 25; start.call( this, extinction ); } else { move.call ( this ); draw ( this.parts ); } } // 爆発前処理 function stage2 ( ) { stop.call( this ); var ball = this.parts[0]; var wa = 7, // 花火の輪の数 v = 1, u = 2 / ball.option[2] * Math.PI, // 高速化のために計算 w = ball.option[1] / this.life, c = ball.materialt.cloneNode( true ), cr = ( ball.option[0][0] - ball.color[0] ) / this.life, // red:色の変化の差分を計算 cg = ( ball.option[0][1] - ball.color[1] ) / this.life, // green: cb = ( ball.option[0][2] - ball.color[2] ) / this.life, // blue: j, d, r, t, q; remove( this.parts ); this.parts = [ ]; this.motion = motion2; while( --wa ) { // 外側から内側へと計算 v *= 1.4; // 花火の輪の間隔 d = 0; // 角度(単位はちがうけど) r = w / v; // 花火の半径 q = ball.option[2] / v; // 内側になるほど、点の数を減らす t = u * v; // 次の角度を高速化のために計算 c.firstChild.nodeValue = randomStar(); // 火の点の文字 for( j = 0; j < q; j++ ) { this.parts.push( { materialt : c.cloneNode( true ), position : { x: ball.position.x, y: ball.position.y }, color : [ ball.color[0], ball.color[1], ball.color[2] ], option : [ Math.sin( d ) * r, Math.cos( d ) * r, [ cr, cg, cb ] ] } ); d += t; // 次の角度 } } append.call( this.screen, this.parts ); start.call( this, explosion ); } //____________________________ // 表示領域を取得 var getViewSize = function (doc) { /*@if(1) var v = doc.compatMode == 'CSS1Compat' ? doc.documentElement: doc.body; return [ v.clientWidth, v.clientHeight ]; @else@*/ var v = doc.defaultView; return [ v.innerWidth, v.innerHeight ]; /*@end@*/ }; // 花火の打ち上げ環境整備 var create = function ( x, y, size, volume, sColor, eColor, life ) { var i = MAX, obj, screen, ball, vsize = getViewSize( this ); if( 'undefined' === typeof x ) x = randomInt( vsize[0] ); if( 'undefined' === typeof y ) y = randomInt( vsize[1] ); if( 'undefined' === typeof size ) size = randomInt( 1800, 800 ); if( 'undefined' === typeof volume ) volume = randomInt( 24, 24 ); if( 'undefined' === typeof sColor ) sColor = randomColor(); if( 'undefined' === typeof eColor ) eColor = randomColor(); if( 'undefined' === typeof life ) life = randomInt( 20, 20 ); while( i-- ) { if( obj = stock[i] ) if( obj.life ) continue; screen = this.createElement( 'div' ); screen.style.position = 'absolute'; this.body.appendChild( screen ); ball = this.createElement ( 'span' ), ball.appendChild( this.createTextNode( '・' ) ); ball.style.position = 'absolute'; stock[i] = obj = { // オブジェクト(領域・部品・動き)を作って call する screen : screen, // DIV parts : [ { materialt : ball, position : { x: x, y: vsize[1] -10 }, color : sColor, option : [ eColor, size, volume, y ] } ], life : life, motion : motion1 // }; append.call( screen, obj.parts ); start.call( obj, fire ); break; } }; //____________________________ var init = function ( view ) { var win = view || window, doc = view.document, onClick = function (e) { /*@if(1) var d = doc.compatMode == 'CSS1Compat' ? doc.documentElement: doc.body; create.call( doc, e.clientX + d.scrollLeft, e.clientY + d.scrollTop ); @else@*/ create.call( doc, e.pageX, e.pageY ); /*@end@*/; }, onUnload = function (e) { doc./*@if(1) detachEvent('on'+ @else@*/ removeEventListener(/*@end@*/ 'click', onClick, false ); win./*@if(1) detachEvent('on'+ @else@*/ removeEventListener(/*@end@*/ 'unload', onUnload, false ); MAX = randomStar = getViewSize = set = start = explosion = create = init = null; }; doc./*@if(1) attachEvent('on'+@else@*/ addEventListener(/*@end@*/ 'click', onClick, false ); win./*@if(1) attachEvent('on'+@else@*/ addEventListener(/*@end@*/ 'unload', onUnload, false ); }; this.Hanabi = { init: init }; })(); Hanabi.init( this ); </script>
覚えてるもんね〜絶対答えないよ〜〜だ!
http://oshiete.goo.ne.jp/qa/5983961.html
いつもながら、考えがハチャメチャに見える
スタイルシートのルールをかえるだけだろう!?