Canvasで花火を打ち上げる(まだ書きかけ)
http://jsdo.it/babu_baboo/Oj11
iPadで連打すると意外に綺麗な花火が打ち上がる
大曲の花火大会は見たことが無いけれど、
こりゃ〜洋野町の花火大会より好いんじゃないかい?!
<!DOCTYPE html> <meta charset="UTF-8"> <title>N個の点を持つ球体。それはこの夏の花火につながる?!まだ書きかけ</title> <style> body { color: white; background: black; } </style> <body> <canvas width="1000" height="700"></canvas> <script> (function () { //球体の n個の点を生成。rは半径 function Sphere (n, r) { var A = Math.asin; var C = Math.cos; var S = Math.sin; var G = (Math.sqrt (5) + 1) / 4; var B = n + 0.5; var D = Math.PI * 2 * (G - 1); var R = [ ]; if ('undefined' === typeof r) r = 1; for (var a, b, c, d = -n; d < n; d += 2) R.push([ (b = C (a = A (d / B)) * r) * C (c = D * d), b * S (c) , S (a) * r ]); return R; // [[x0, y0, z0], .. , [xn, yn, zn]] } //花火を生成 function Hanabi (point, vector, color, kayaku, gain) { this.point = point; this.vector = vector; this.color = color; this.kayaku = kayaku; this.gain = gain; } //花火の燃焼中 function diffusion () { var i, p, v; var k = this.kayaku + Math.random() * 2; var vector = this.vector; for (i = 0; p = this.point[i]; i += 1) { v = vector[i]; this.point[i][0] += v[0] * k; this.point[i][1] += v[1] * k + 2; this.point[i][2] += v[2] * k; } this.kayaku *= this.gain; return (this.kayaku > .1); } function initPoint (_) { return [this.x-0, this.y-0, this.z-0]; } function create (n, color, kayaku, gain, offset3D) { offset3D.y = Math.random () * 200 + 500; var vector = Sphere (n); var point = [ ]; var i, I = vector.length; for (i = 0; i < I; i += 1) { point.push([offset3D.x, offset3D.y, offset3D.z, color]); } var obj = new Hanabi (point, vector, color , kayaku || 100, gain || .99); return obj; } Hanabi.prototype.diffusion = diffusion; Hanabi.create = create; this.HANABI = Hanabi; }) (); //___________ //花火師職人を雇う (function (hanabi) { var HColor = [//そのうち花火の種類のオブジェクトを作れ 'RGB(255,50,50)', 'RGB(255,100,0)', 'RGB(255,200,50)', 'RGB(255,255,100)','RGB(255,0,50)', 'RGB(255,0,150)', 'RGB(200,0,255)', 'RGB(0,255,0)', 'RGB(100,255,30)','RGB(0,200,255)' ]; var int = Math.floor; var rnd = Math.random; //花火師職人を雇用する function Hanabisi (offset3D, hosiMin, hosiMax) { this.offset3D = offset3D; //立ち位置 this.hosiMin = hosiMin; //扱える花火の星の最低数 this.hosiMax = hosiMax; //最大数 } function bomb (hanabi) {//花火の爆発 return hanabi.diffusion (); } function getHosi (hanabi) {//花火の星の座標を返す return hanabi.point; } function admiring () {//花火師が夜空を見上げる Hanabisi.LIST = Hanabisi.LIST.filter (bomb);//燃焼中のものだけ集める return Array.prototype.concat.apply ([ ], Hanabisi.LIST.map (getHosi));//一次元配列化 } function fire (event) {//花火の発射(click handler) var e = event.target; var n = int (rnd () * (this.hosiMax - this.hosiMin)) + this.hosiMin; //星の数 var c = HColor[int (rnd () * HColor.length)]; var k = rnd () * 20 + 10; var g = .9; var tmp = {//試しに立ち位置をランダムにする x: int (rnd () * 600) - 300, y: 0, z: int (rnd () * -200) }; var h = hanabi.create (n, c, k, g, tmp /*this.offset3D*/); Hanabisi.LIST.push (h); } function create (tatiiti, hosiMin, hosiMax) { if ('undefined' === typeof tatiiti) tatiiti = {x: 0, y: 0, z: 0}; return new Hanabisi (tatiiti, hosiMin || 30, hosiMax || 300); } Hanabisi.prototype.list = [ ]; Hanabisi.prototype.admiring = admiring; Hanabisi.prototype.handleEvent = fire; Hanabisi.create = create; Hanabisi.LIST = [ ]; this.HANABISI = Hanabisi; }) (HANABI); //___________ //Canvas をコントロールするためのオブジェクト (function () { function Ctx (canvas, ctx, width, height, offset, distance) { this.canvas = canvas; this.ctx = ctx; this.width = width; this.height = height; this.offset = offset; this.distance = distance; } //夜空を好きな色で染める function clsScreen (rgba) { this.ctx.fillStyle = rgba ? rgba: 'rgb(0,0,0)'; this.ctx.fillRect (0,0, this.width, this.height); } //夜空に光を放つ function pset (aryPoint) { var i, z, a; var x = [ ], y = [ ], c = [ ]; var d = this.distance, cx = this.offset.x, cy = this.offset.y; var ctx = this.ctx; for (i = 0; a = aryPoint[i]; i += 1) { z = - (d - a[2]) / d; ctx.fillStyle = a[3]; ctx.fillRect (cx + a[0] * z, cy - a[1] * z, 2, 2);//大きさも考えろよ } } //Canvasコントローラを作る function create (canvas, offset, distance) { var ctx = canvas.getContext ('2d'); var width = canvas.width; var height = canvas.height; var offset_default = { x: width / 2, y: height / 2}; var distance_default = 10000; var p; if ('undefined' === typeof offset) offset = offset_default; else for (p in offset_default) //標準設定で上書き if (offset_default.hasOwnProperty (p)) if (! offset.hasOwnProperty (p)) offset[p] = offset_default[p]; return new Ctx (canvas, ctx, width, height, offset, distance || distance_default); } //___________ Ctx.prototype.clsScreen = clsScreen; Ctx.prototype.pset = pset; Ctx.create = create; this.CTX = Ctx; })(); //___________ //アニメーションの環境か? if ('undefined' === typeof window.requestAnimationFrame) { window.requestAnimationFrame = window.requestAnimationFrame || window.webkitRequestAnimationFrame|| window.mozRequestAnimationFrame || window.oRequestAnimationFrame || window.msRequestAnimationFrame || function (callback, that) { var tmpFunc = function () { var timestamp = +(new Date); //(new Date).getTime (); callback (timestamp); //callback.call (that, timestamp); }; window.setTimeout (tmpFunc, Math.floor (1000/60)); }; } var canvas = document.querySelector ('canvas'); var hanabisi = HANABISI.create (); var yozora = CTX.create (canvas, {y: -300}); canvas.addEventListener ('click', hanabisi, false); canvas.addEventListener ('touchstart', hanabisi, false); //___________ //アニメーションの実行 function demo () { yozora.clsScreen ('rgba(0,0,0,.1)'); yozora.pset (hanabisi.admiring ()); requestAnimationFrame (demo); } demo (); </script>