Canvas绘制雨滴之setInterval与setTimeout(一)

绘制雨滴时,目前大多数的程序中,雨滴的原型有属性update。对于雨滴的移动move进行了原型外的function操作。并使用数组下标的方式对雨滴实例进行定位实现move。

那么,倘若move是固定在每一个雨滴的程序,是否意味着,可以将move也写为雨滴原型中的属性。下面进行了实验:

<!doctype html>
<html lang="en">
 <head>
  <meta charset="UTF-8">
  <meta name="Generator" content="EditPlus®">
  <meta name="Author" content="">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>雨滴下落1</title>
  <style>
  body{margin:0;}
  #rain{display:block;
  background-color:black;}
  </style>
 </head>
 <body>
  <canvas id="rain"></canvas>
  <script>
  /*
	1.获取
		1.1 设置canvas宽高
		1.2 获取窗口宽高
		1.3 当窗口大小变化时,改变canvas宽高
	2.绘制雨滴
	3.多个雨滴
	3.雨滴降落
*/
	//1.设置canvas大小
	var can=document.getElementById("rain");//为can元素设置宽高,而不是画布getcontext
	//var can=document.getContext(canva);
	var w=window.innerWidth;//使用全局变量保存宽高,减少访问,便于调用
	var h=window.innerHeight;//属性名字为inner-width/height
	can.width=w;
	can.height=h;
	window.οnresize=function(){
		w=window.innerWidth;
		h=window.innerHeight;//需要重新为w,h赋值
		can.width=w;
		can.height=h;
		}
	//2.绘制雨滴
	//绘制一滴
	/*
	function random(min,max){
		return Math.random()*(max-min)+min;
	}
	var x=random(0,w);
	var y=0;//起点
	var canContent=can.getContext("2d");//画布
	//初始位置绘制
	canContent.fillStyle="rgb(0,255,255)";
	canContent.fillRect(x,y,5,20);//雨滴
	//移动--动画
	function draw(){
		canContent.fillStyle="rgba(0,0,0,0.01)";
		canContent.fillRect(0,0,w,h);//毛玻璃
		canContent.fillStyle="rgb(0,255,255)";
		canContent.fillRect(x,y++,5,20);//雨滴位置变化
	}
	setInterval(draw,1000/60);
	
	*/
		

	function random(min,max){
		return Math.random()*(max-min)+min;
	}
	
	function Rain(){};
	var canContent=can.getContext("2d");
	Rain.prototype={
		init:function(){
			//参数
			this.x=random(0,w);
			this.y=0;//起点
			this.l=random(0.8*h,0.9*h);//下落高度
			this.v=random(4,5);//下落速度
			this.r=1;//水花的初始半径
			this.vr=random(1,2);//半径扩大的速度
			this.rmax=random(50,60);//开始变透明的半径
			this.a=1;//初始透明度
			this.va=0.98;//透明度的变化
			this.amin=0.2;
		},
		draw:function(){
			//绘制
			//.1绘制下落
			if(this.y<this.l){
				canContent.fillStyle="rgb(0,255,255)";
				canContent.fillRect(this.x,this.y,2,20);//雨滴位置变化
			}else{
			//.2绘制水花
				canContent.strokeStyle="rgba(0,255,255,"+this.a+")";//
				//"rgba(0,255,255,this.a)";//会出错,读取字符串,无法获得变量变化值
				canContent.beginPath();
				canContent.arc(this.x,this.y,this.r,0,2*Math.PI,false);
				canContent.stroke();
			}
		},
		update:function(){
			//更新坐标值,并绘制
			//.1下落过程的坐标更新
			if(this.y<this.l){
				this.y+=this.v;
			}else{
			//.2水花过程的坐标更新(坐标不变,半径变化,透明度变化)
			//更新后绘制雨滴:
				
				/*
				透明度的变化取决于半径大小
				this.r+=this.vr;
				if(this.r<this.rmax){
					this.a*=this.va;
				}else{
					this.init();
				}
				}
				*/
				//透明度的变化取决于半径大小,半径大小取决于透明度大小
				if(this.a>this.amin){
						this.r+=this.vr;
						if(this.r>this.rmax){
							this.a*=this.va;//乘更自然
						}
					}
					else{
						this.init();//透明度变了的话,回到天上
					}
				}
				this.draw();
				console.log(this);
				
		},
		move:function(){//将move添加在原型属性中
		//移动显示:覆盖不透明度不同的层数,并不断在新的位置绘制雨滴,所形成的
			canContent.fillStyle="rgba(0,0,0,0.05)";
			canContent.fillRect(0,0,w,h);//毛玻璃
			console.log("move"+this);
			this.update();
			setInterval(this.move,1000/60);//this的指向
			//console.log("thisismove");
		}
	}


//创建30个
for(var i=0;i<30;i++){
    setTimeout(createRain,300*i);//隔300*i ms执行一次createRain
}//同时创建30个setTimeout,但每个setTimeout开始执行的时间不同

function createRain(){
	var rain=new Rain();
	rain.init();
	rain.draw();
	rain.move();
}


//不能在函数体内写setInterval
//所有的计算与渲染必须在16ms内完成???
//在第0秒就开始执行
//setInterval(hanshu,10ms);
//每个一段时间就执行setInterval中的函数,插到堆栈中,会打断整个任务的运行
//假设10mm运行一次interval,而若调用的"hanshu"程序19ms才运行完,那么会抛弃第二次的interval,即造成丢帧
//运行主体:window;只有window才能调用setInterval,注意this指向因此不存在this.update
//替代


//请问:如果move是在跟着元素创建中的属性,那么可否在prototype中运行?

  </script>
 </body>
</html>


运行发现出现错误显示为this.update()不存在
查找资料与视频讲解,了解到:
setInterval函数的特殊性:
setInterval(codeFunc,timeInterval)
①此命令将会,在JS最初运行的时间t=0ms时就开始运行,并在运行栈中插入固定的位置,意味着每间隔timeInterval秒就执行一次。
②要求在时间间隔timeInterval内执行完毕所有的codeFunc
③命令的主体只能是window
在上述程序中,当要求执行setInterval时,对rain实例进行操作,此时时间为1000/60ms,而rain至少在300ms时才被创建,因此此时的命令没有操作的对象。
另外,setInterval有一个缺点是容易造成丢帧。原因是:
//setInterval(rain.move,1000/60);//此时还没有rain//在第0秒就开始执行

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

picoasis

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值