-
Notifications
You must be signed in to change notification settings - Fork 0
2014 04 08 canvas入门
{% include JB/setup %} ##背景 这里主要是我做的一些学习笔记,所以看起来比较乱. #基础
- 元素:
canvas - 2d上下文:
ctx = canvas.getContext('2d') - canvas动画的本质是不停的(requestAnimationFrame)绘制(stroke)和清理(clearRect)
conan
#线
- 方法
ctx.beginPath()定义了一个新的路径绘制动作的开始。 - 方法
ctx.moveTo(0 , 0)为指定点创建了一个新的子路径,这个点就变成了新的上下文点。我们可以把 moveTo() 方法看成用来定位我们的绘图鼠标用的。 - 方法
ctx.lineTo(100, 100)以上下文点为起点,到方法参数中指定的点之间画一条直线。 - 方法
ctx.stroke()为所画的线赋予颜色,并使其可见。如果没有特别的指定颜色的话,则默认使用黑色画直线。 - 属性
context.lineWidth = 5;定义直线宽度(px) - 属性
context.strokeStyle = #dedede定义直线的颜色 - 属性
context.lineGap = [butt, round,square]定义直线断点样式
##画弧线
###圆弧
- 方法
context.arc(x, y, radius, startAngle, endAngle, antiClockwise);每条弧线都需要由中心点、半径、起始弧度、结束 弧度(弧度= 角度 * Math.PI/ 180)和绘图方向(顺时针 false 还是逆时针 true )这几个参数来确定。
###圆角
- 方法
context.arcTo(controlX,controlY,endX,endY,radius);画圆角使用方法 arcTo()此方法需要一个控制点、一个终止点和半径作为必要的参数。
###画二次曲线
- 方法
context.quadraticCurveTo(controlX, controlY, endX, endY);二次曲线使用 quadraticCurveTo()方法来绘制。每条二次曲线要由上下文点(content.moveTo)、一个控制点和一个终止点来定义。
###贝塞尔曲线
- 方法
content.bezierCurveTo(controlX1, controlY1, controlX2, controlY2, endX, endY)。每条二次曲线要由上下文点(content.moveTo)、2个控制点和一个终止点来定义。
###综合路径
- 路径是由多条子路径连接构成的。每条子路径的终止点就将作为新的上下文点。我们可以使用lineTo(), arcTo(), quadraticCurveTo()和 bezierCurveTo()创建新的子路径,子路径的结合使用
content.lineJoin = [miter, round, bevel]。每次要开始画一条路径的时候就要使用 beginPath() 方法
#面
- 要画一个用户自定义的图形,需要创建一个路径,然后用
context.closePath()方法关闭此路径即可。可以使用使用context.fillStyle = 'blue'自定义填充颜色,使用contentText.fille()进行填充。
注意: fill 方法要在 strok 方法之前执行,否则 fill 会覆盖掉 stroke 的一半区域。
首先要使用createLinearGradient方法
var grd = context.createLinearGradient(startX, startY, endX, endY);
grd.addColorStop(offset, color);
context.fillStyle = grd;
context.fill()
方法从上下文对象中创建线性渐变对象,使用对象中的addColorStop指定颜色。
var pattern = context.createPattern(imageObj, repeatOption);
context.fillStyle = pattern;
context.fill();
context.drawImage(imageObj, x, y, width, height);
注意这里需要等到imageObj加载完成之后才能绘制
方法 drawImage() 还可以增加另六个参数来实现对图像的裁剪。这六个参数是, sourceX, sourceY, sourceWidth, sourceHeight, destWidth 和 destHeight。这六个参数对应的含 义可以参阅后面的示意图。
context.drawImage(imageObj, sx, sy, sw, sh, dx, dy, dw, dh);
上面的参数sx,sy和sw,sh可以剪切图片。剪切完了之后可以使用dx, dy, dw, dh等缩放调整位置。
#文字
conText.font = "40px sans-serif";
var fps = "20";
//边缘颜色
conText.strokeStyle = "blue";
//填充颜色
conText.fillStyle = 'yellow';
//边缘的宽度
conText.lineWidth = ".6";
//对齐方向
conText.textAlign = "right"
//内部
conText.fillText('FPS:'+fps.toFixed(2),innerWidth , innerHeight- 50);
//边缘
conText.strokeText('FPS:'+fps.toFixed(2),innerWidth , innerHeight- 50)
#进阶 ##保留当前设置 /* * save() 的作用是在创建剪裁区之前将 canvas 的当前状态保存起来, * 这样在后面就可以恢复上下文对象的原始状态了 */ context.clip(); context.beginPath(); context.arc(x, y, radius, 0, 2 * Math.PI, false); context.save(); onText.shadowColor = "#888"; conText.shadowBlur = "10"; //do some thing //... conText.restore();
//保存
conText.save();
conText.rect( innerWidth - 800, 200, 780, 400);
conText.shadowColor = "#888";
conText.shadowBlur = "10";
conText.fillStyle = "#fefefe";
conText.shadowOffsetX = 10;
conText.shadowOffsetY = 10;
conText.fill();
//恢复
conText.restore();
conText.globalAlpha = ".5";
conText.clip();
conText.globalCompositeOperation = ['source-atop', 'source-in', 'source-out', 'source-over', 'destination-atop', 'destination-in', 'destination-out', 'destination-over', 'ligher', 'darker','xor', 'copy'];
【重要】注意使用另一个canvas元素来组合剪切合并操作,原因是因为会把其他绘制的图像剪切掉。
##tranlate移动 var translateX = innerWidth - 100, translateY = innerHeight - 100; conText.translate(translateX, translateY); conText.fillStyle = "green"; conText.fillRect(0,0, 50, 50); conText.font = "12px sans-serif"; conText.fillText('translate',0, 70); //restore position conText.translate( -translateX, -translateY);
注意:移动的0坐标永远是本身(移动相对于本身),这和DOM操作有所不同的地方。例如移动了10像素(translate(10, 0)),想要移动回来,则必须移动-10px(translate(-10, 0)),而非0像素
##scale缩放 conText.scale(rateX, rateY);//rateX、rateY小于1则是缩小,大于1则是放大 conText.fillRect(100, 100, 100, 100); 注意缩放的是整体canvas里面的内容,而非当前所绘图
##rotate旋转
旋转canvas用的方法是 conText.rotate(angle)。此方法接受一个以弧度为单位的旋转参数,整个canvas将以坐标原点,也就是由 translate()所确定的原点为圆心进行旋转(默认为左上角)。
注意:旋转完成所需绘图后别忘记旋转回来,否则后面的图片也会在旋转中进行
-
无法清除(clearRect)往往是因为未使用beginPath();
-
CANVAS游戏的基本思路:一个总的控制者Stage,调用各个sprite的draw方法,每一个sprite都有自己的left、top、width、height,sprite有一个artist对象负责使用以上参数进行绘制自身, 绘制方法有原生方法broke fill等,以及sprite图标和drawImage方法绘制。 behavio负责修改这些参数形成一个个的行为,一个sprite有多个行为(跳远,爆炸,行走等)
-
draw方法是一个绘制机器,想个发动机一样,不断绘制里面的sprite(只要是visible为true时)
-
任何有动作的个体对象都做成一个sprite,然后将其加入到sprite list进行绘制。
-
2个有密切关联的sprite(豌豆炮手发射炮弹动作,分为豌豆和炮弹),可以通过互相引用关联起来,在其中一个sprite(这里是豌豆)的行为里面定制发射动作,修改另一个sprite的状态(显示、隐藏)
-
行为是可以相互操作的,一个行为可能影响另一个行为,可以把同一个性质的行为抽离独立公用。
-
当需要做一个周期性的行为时(cycle),找到一个极点去判断,例如开始(start index),然后去延迟执行。
-
任何一个动作执行后都保存时间戳,作为下一次的判断点。
-
requestAnimationFrame每次调用第一个参数是一个(time stamp),这个时间戳不是Date.now(),而是距离第一次调用该方法的间隔值(如果是不停执行的情况下),所以第一次调用时是2、30ms左右。
-
将加速度换算成像素加速度,首先将屏幕宽度定义好宽度米(metre)
MW,在获取实际宽度像素(pixed)PW,从而知道比率PW,rate = PW/MW,在使用重力加速度(g = 9.801)计算,最后加速度为g = 9.8 * rate -
动画补间函数是传入一个当前时间占总共运行持续时间(during)的比率(最大为1),返回一个实际运行的距离占总共运行的距离的百分比。这里总共时间是恒定的,当前时间是稳定直线变化的(liner),以时间为参照点计算距离。
-
分为事前判别和事后判别
-
事前是根据现有的帧率计算下一帧的结果,其中当前情况是没有相撞的(ball.bottom <basket.top),下一帧就相撞了(ball.bottom > basket.top)。存在不准确的情况,是用当前的帧率来计算的,可能频率突然变成原来2倍,导致相撞了。所以不精确
-
事后判别是当前是否相撞,他的问题是如果小球速度太快就检测不到,或者穿过很多了(事前检测就是解决这个问题的)。
-
光线投射判别,适合木桶接球的情况,根据2个物体(sprite)2次位置变化的点的射线,相交的点(斜截公式:Y = b*X+m)在其中一个物体相交面距离长度之间,且在2个点相交面的距离小于0,则相撞了。见书籍HTML5 CANVAS核心技术337页。