<!DOCTYPE html> |
< html > |
< head > |
< meta charset = "utf-8" /> |
< title ></ title > |
< meta charset = "utf-8" > |
< title >3D烟花</ title > |
< style > |
html,body{ |
margin:0px; |
width:100%; |
height:100%; |
overflow:hidden; |
background:#000; |
} |
#canvas{ |
width:100%; |
height:100%; |
} |
</ style > |
</ head > |
< body > |
< canvas id = "canvas" width = "825" height = "631" ></ canvas >< script > |
function initVars(){ |
pi=Math.PI; |
ctx=canvas.getContext("2d"); |
canvas.width=canvas.clientWidth; |
canvas.height=canvas.clientHeight; |
cx=canvas.width/2; |
cy=canvas.height/2; |
playerZ=-25; |
playerX=playerY=playerVX=playerVY=playerVZ=pitch=yaw=pitchV=yawV=0; |
scale=600; |
seedTimer=0;seedInterval=5,seedLife=100;gravity=.02; |
seeds=new Array(); |
sparkPics=new Array(); |
s="https://cantelope.org/NYE/"; |
for(i=1;i<=10;++i){ |
sparkPic=new Image(); |
sparkPic.src=s+"spark"+i+".png"; |
sparkPics.push(sparkPic); |
} |
sparks=new Array(); |
pow1=new Audio(s+"pow1.ogg"); |
pow2=new Audio(s+"pow2.ogg"); |
pow3=new Audio(s+"pow3.ogg"); |
pow4=new Audio(s+"pow4.ogg"); |
frames = 0; |
} |
function rasterizePoint(x,y,z){ |
var p,d; |
x-=playerX; |
y-=playerY; |
z-=playerZ; |
p=Math.atan2(x,z); |
d=Math.sqrt(x*x+z*z); |
x=Math.sin(p-yaw)*d; |
z=Math.cos(p-yaw)*d; |
p=Math.atan2(y,z); |
d=Math.sqrt(y*y+z*z); |
y=Math.sin(p-pitch)*d; |
z=Math.cos(p-pitch)*d; |
var rx1=-1000,ry1=1,rx2=1000,ry2=1,rx3=0,ry3=0,rx4=x,ry4=z,uc=(ry4-ry3)*(rx2-rx1)-(rx4-rx3)*(ry2-ry1); |
if(!uc) return {x:0,y:0,d:-1}; |
var ua=((rx4-rx3)*(ry1-ry3)-(ry4-ry3)*(rx1-rx3))/uc; |
var ub=((rx2-rx1)*(ry1-ry3)-(ry2-ry1)*(rx1-rx3))/uc; |
if(!z)z=.000000001; |
if(ua>0&&ua< 1 &&ub>0&&ub< 1 ){ |
return { |
x:cx+(rx1+ua*(rx2-rx1))*scale, |
y:cy+y/z*scale, |
d:Math.sqrt(x*x+y*y+z*z) |
}; |
}else{ |
return { |
x:cx+(rx1+ua*(rx2-rx1))*scale, |
y:cy+y/z*scale, |
d:-1 |
}; |
} |
} |
function spawnSeed(){ |
seed = new Object(); |
seed.x=-50+Math.random()*100; |
seed.y = 25 ; |
seed.z=-50+Math.random()*100; |
seed.vx=.1-Math.random()*.2; |
seed.vy=-1.5;//*(1+Math.random()/2); |
seed.vz=.1-Math.random()*.2; |
seed.born = frames ; |
seeds.push(seed); |
} |
function splode(x,y,z){ |
t = 5 +parseInt(Math.random()*150); |
sparkV = 1 +Math.random()*2.5; |
type = parseInt (Math.random()*3); |
switch(type){ |
case 0: |
pic1 = parseInt (Math.random()*10); |
break; |
case 1: |
pic1 = parseInt (Math.random()*10); |
do{ pic2 = parseInt (Math.random()*10); }while(pic2==pic1); |
break; |
case 2: |
pic1 = parseInt (Math.random()*10); |
do{ pic2 = parseInt (Math.random()*10); }while(pic2==pic1); |
do{ pic3 = parseInt (Math.random()*10); }while(pic3==pic1 || pic3==pic2); |
break; |
} |
for( m = 1 ;m<t;++m){ |
spark = new Object(); |
spark.x =x; spark.y =y; spark.z =z; |
p1 = pi *2*Math.random(); |
p2 = pi *Math.random(); |
v = sparkV *(1+Math.random()/6) |
spark.vx = Math .sin(p1)*Math.sin(p2)*v; |
spark.vz = Math .cos(p1)*Math.sin(p2)*v; |
spark.vy = Math .cos(p2)*v; |
switch(type){ |
case 0: spark.img = sparkPics [pic1]; break; |
case 1: |
spark.img = sparkPics [parseInt(Math.random()*2)?pic1:pic2]; |
break; |
case 2: |
switch(parseInt(Math.random()*3)){ |
case 0: spark.img = sparkPics [pic1]; break; |
case 1: spark.img = sparkPics [pic2]; break; |
case 2: spark.img = sparkPics [pic3]; break; |
} |
break; |
} |
spark.radius = 25 +Math.random()*50; |
spark.alpha = 1 ; |
spark.trail = new Array(); |
sparks.push(spark); |
} |
switch(parseInt(Math.random()*4)){ |
case 0: pow = new Audio(s+"pow1.ogg"); break; |
case 1: pow = new Audio(s+"pow2.ogg"); break; |
case 2: pow = new Audio(s+"pow3.ogg"); break; |
case 3: pow = new Audio(s+"pow4.ogg"); break; |
} |
d = Math .sqrt((x-playerX)*(x-playerX)+(y-playerY)*(y-playerY)+(z-playerZ)*(z-playerZ)); |
pow.volume = 1 .5/(1+d/10); |
pow.play(); |
} |
function doLogic(){ |
if(seedTimer<frames){ |
seedTimer = frames +seedInterval*Math.random()*10; |
spawnSeed(); |
} |
for( i = 0 ;i<seeds.length;++i){ |
seeds[i].vy+=gravity; |
seeds[i].x+=seeds[i].vx; |
seeds[i].y+=seeds[i].vy; |
seeds[i].z+=seeds[i].vz; |
if(frames-seeds[i].born>seedLife){ |
splode(seeds[i].x,seeds[i].y,seeds[i].z); |
seeds.splice(i,1); |
} |
} |
for(i=0;i< sparks.length ;++i){ |
if(sparks[i].alpha>0 && sparks[i].radius>5){ |
sparks[i].alpha-=.01; |
sparks[i].radius/=1.02; |
sparks[i].vy+=gravity; |
point=new Object(); |
point.x=sparks[i].x; |
point.y=sparks[i].y; |
point.z=sparks[i].z; |
if(sparks[i].trail.length){ |
x=sparks[i].trail[sparks[i].trail.length-1].x; |
y=sparks[i].trail[sparks[i].trail.length-1].y; |
z=sparks[i].trail[sparks[i].trail.length-1].z; |
d=((point.x-x)*(point.x-x)+(point.y-y)*(point.y-y)+(point.z-z)*(point.z-z)); |
if(d>9){ |
sparks[i].trail.push(point); |
} |
}else{ |
sparks[i].trail.push(point); |
} |
if(sparks[i].trail.length>5)sparks[i].trail.splice(0,1); |
sparks[i].x+=sparks[i].vx; |
sparks[i].y+=sparks[i].vy; |
sparks[i].z+=sparks[i].vz; |
sparks[i].vx/=1.075; |
sparks[i].vy/=1.075; |
sparks[i].vz/=1.075; |
}else{ |
sparks.splice(i,1); |
} |
} |
p=Math.atan2(playerX,playerZ); |
d=Math.sqrt(playerX*playerX+playerZ*playerZ); |
d+=Math.sin(frames/80)/1.25; |
t=Math.sin(frames/200)/40; |
playerX=Math.sin(p+t)*d; |
playerZ=Math.cos(p+t)*d; |
yaw=pi+p+t; |
} |
function rgb(col){ |
var r = parseInt((.5+Math.sin(col)*.5)*16); |
var g = parseInt((.5+Math.cos(col)*.5)*16); |
var b = parseInt((.5-Math.sin(col)*.5)*16); |
return "#"+r.toString(16)+g.toString(16)+b.toString(16); |
} |
function draw(){ |
ctx.clearRect(0,0,cx*2,cy*2); |
ctx.fillStyle="#ff8"; |
for(i=-100;i< 100 ;i+=3){ |
for(j=-100;j<100;j+=4){ |
x = i ; z = j ; y = 25 ; |
point = rasterizePoint (x,y,z); |
if(point.d!=-1){ |
size = 250 /(1+point.d); |
d = Math .sqrt(x * x + z * z); |
a = 0 .75 - Math.pow(d / 100, 6) * 0.75; |
if(a>0){ |
ctx.globalAlpha = a; |
ctx.fillRect(point.x-size/2,point.y-size/2,size,size); |
} |
} |
} |
} |
ctx.globalAlpha=1; |
for(i=0;i< seeds.length ;++i){ |
point = rasterizePoint (seeds[i].x,seeds[i].y,seeds[i].z); |
if(point.d!=-1){ |
size = 200 /(1+point.d); |
ctx.fillRect(point.x-size/2,point.y-size/2,size,size); |
} |
} |
point1 = new Object(); |
for( i = 0 ;i<sparks.length;++i){ |
point = rasterizePoint (sparks[i].x,sparks[i].y,sparks[i].z); |
if(point.d!=-1){ |
size = sparks [i].radius*200/(1+point.d); |
if(sparks[i].alpha<0)sparks[i] .alpha = 0 ; |
if(sparks[i].trail.length){ |
point1.x =point.x; |
point1.y =point.y; |
switch(sparks[i].img){ |
case sparkPics[0] :ctx.strokeStyle = "#f84" ;break; |
case sparkPics[1] :ctx.strokeStyle = "#84f" ;break; |
case sparkPics[2] :ctx.strokeStyle = "#8ff" ;break; |
case sparkPics[3] :ctx.strokeStyle = "#fff" ;break; |
case sparkPics[4] :ctx.strokeStyle = "#4f8" ;break; |
case sparkPics[5] :ctx.strokeStyle = "#f44" ;break; |
case sparkPics[6] :ctx.strokeStyle = "#f84" ;break; |
case sparkPics[7] :ctx.strokeStyle = "#84f" ;break; |
case sparkPics[8] :ctx.strokeStyle = "#fff" ;break; |
case sparkPics[9] :ctx.strokeStyle = "#44f" ;break; |
} |
for( j = sparks [i].trail.length-1;j>=0;--j){ |
point2=rasterizePoint(sparks[i].trail[j].x,sparks[i].trail[j].y,sparks[i].trail[j].z); |
if(point2.d!=-1){ |
ctx.globalAlpha=j/sparks[i].trail.length*sparks[i].alpha/2; |
ctx.beginPath(); |
ctx.moveTo(point1.x,point1.y); |
ctx.lineWidth=1+sparks[i].radius*10/(sparks[i].trail.length-j)/(1+point2.d); |
ctx.lineTo(point2.x,point2.y); |
ctx.stroke(); |
point1.x=point2.x; |
point1.y=point2.y; |
} |
} |
} |
ctx.globalAlpha=sparks[i].alpha; |
ctx.drawImage(sparks[i].img,point.x-size/2,point.y-size/2,size,size); |
} |
} |
} |
function frame(){ |
if(frames>100000){ |
seedTimer=0; |
frames=0; |
} |
frames++; |
draw(); |
doLogic(); |
requestAnimationFrame(frame); |
} |
window.addEventListener("resize",()=>{ |
canvas.width=canvas.clientWidth; |
canvas.height=canvas.clientHeight; |
cx=canvas.width/2; |
cy=canvas.height/2; |
}); |
initVars(); |
frame();</ script > |
</ body > |
</ html > |
初级程序员
by: MMCCEE 发表于:2020-08-15 18:39:02 顶(4) | 踩(2) 回复
回复评论