游戏开发之旅-JavaScript绘制图形
本节是第四讲的第二十二小节,上一节课为大家介绍了Ajax技术,包括XmlHttpRequest对象和FetchAPI的基本用法,本节为大家继续介绍JavaScript绘制图形的方法(Canvas API),有关WebGL的实例请参见视频课程的内容。
网络图形
我们来讨论 HTML 的 多媒体和嵌入式 模块,早先的网页只有单调的文字,后来才引入了图像,起初是通过 元素的方式,后来出现了类似于 background-image 的 CSS 属性和 SVG 图像等方式。然而,这还不够好。当你能够使用 CSS 和 JavaScript 让 SVG 矢量图动起来时,位图却依然没有相应的支持。同时 SVG 动画的可用工具也少得可怜。有效地生成动画、游戏画面、3D场景和其他的需求依然没有满足,而这些在诸如 C++ 或者 Java 等低级语言中却司空见惯。当浏览器开始支持 HTML 画布元素
2D画布基础
以下是绘制图形的基础代码:
var canvas = document.querySelector('.myCanvas');
var width = canvas.width = window.innerWidth;
var height = canvas.height = window.innerHeight;
var ctx = canvas.getContext('2d');
ctx.fillStyle = 'rgb(0, 0, 0)';
ctx.fillRect(0, 0, width, height);
所有绘画操作都离不开 CanvasRenderingContext2D 对象(这里叫做 ctx)。许多操作都需要提供坐标来指示绘图的确切位置,如下图所示,画布左上角的坐标是(0, 0),横坐标(x)轴向右延伸,纵坐标(y)轴向下延伸。
简单矩形
ctx.fillStyle = 'rgb(255, 0, 0)';
ctx.fillRect(50, 50, 100, 150);
画布上将出现一个红色的矩形。其左边和顶边与画布边缘距离均为 50 像素(由前两个参数指定),宽 100 像素、高 150 像素(由后两个参数指定)。
ctx.fillStyle = 'rgba(255, 0, 255, 0.75)';
ctx.fillRect(25, 100, 175, 50);
通过指定半透明的颜色来绘制半透明的图形,比如使用 rgba()。 a 指定了“α 通道”的值,也就是颜色的透明度。值越高透明度越高,底层的内容就越清晰。
描边(stroke)和线条宽度
ctx.strokeStyle = 'rgb(255, 255, 255)';
ctx.strokeRect(25, 25, 175, 200);
ctx.lineWidth = 5;
目前我们绘制的矩形都是填充颜色的,我们也可以绘制仅包含外部框线(图形设计中称为描边)的矩形。你可以使用 strokeStyle 属性来设置描边颜色,使用 strokeRect 来绘制一个矩形的轮廓。默认的描边宽度是 1 像素,可以通过调整 lineWidth 属性的值来修改。
绘制路径
ctx.fillStyle = 'rgb(255, 0, 0)';
ctx.beginPath();
ctx.moveTo(50, 50);
// 绘制路径
ctx.fill();
可以通过绘制路径来绘制比矩形更复杂的图形。路径中至少要包含钢笔运行精确路径的代码以确定图形的形状。画布提供了许多函数用来绘制直线、圆、贝塞尔曲线等等。
一些通用的方法和属性将贯穿以下全部内容:
beginPath():在钢笔当前所在位置开始绘制一条路径。在新的画布中,钢笔起始位置为 (0, 0)。
moveTo():将钢笔移动至另一个坐标点,不记录、不留痕迹,只将钢笔“跳”至新位置。
fill():通过为当前所绘制路径的区域填充颜色来绘制一个新的填充形状。
stroke():通过为当前绘制路径的区域描边,来绘制一个只有边框的形状。
路径也可和矩形一样使用 lineWidth 和 fillStyle / strokeStyle 等功能。
等边三角形
function degToRad(degrees) {
return degrees * Math.PI / 180;
};
ctx.fillStyle = 'rgb(255, 0, 0)';
ctx.beginPath();
ctx.moveTo(50, 50);
ctx.lineTo(150, 50);
var triHeight = 50 * Math.tan(degToRad(60));
ctx.lineTo(100, 50+triHeight);
ctx.lineTo(50, 50);
ctx.fill();
首先绘制一条直线,终点坐标为 (150, 50)。此时路径沿 x 轴向右行走 100 像素。然后利用三角函数来计算等边三角形的高。这里我们要绘制的三角形是朝下的。等边三角形每个角均为 60°,为计算高的值,我们可以将三角形从正中心分割为两个直角三角形,每个直角三角形的三个角分别为 90°、60°、30°。
通过基本三角函数可得:临边长度乘以角的正切等于对边长度。于是可得三角形的高为 50 * Math.tan(degToRad(60))。由于 Math.tan() 接受数值的单位为弧度,于是我们用刚才的 degToRad() 函数将 60° 换算为弧度。有了三角形的高,我们来绘制另一条线,终点坐标为 (100, 50+triHeight)。
画圆
ctx.fillStyle = 'rgb(0, 0, 255)';
ctx.beginPath();
ctx.arc(150, 106, 50, degToRad(0), degToRad(360), false);
ctx.fill();
arc() 函数有六个参数。前两个指定圆心的位置坐标,第三个是圆的半径,第四、五个是绘制弧的起、止角度(给定 0° 和 360° 便能绘制一个完整的圆),第六个是绘制方向(false 是顺时针,true 是逆时针)。
ctx.fillStyle = 'yellow';
ctx.beginPath();
ctx.arc(200, 106, 50, degToRad(-45), degToRad(45), true);
ctx.lineTo(200, 106);
ctx.fill();
将 arc() 的最后一个参数设置为 true,意味着弧将逆时针绘制,也就意味着即使起、止角度分别设置为 -45°、45°,我们还是得到了区域外的一条 270° 的弧。
文本
ctx.strokeStyle = 'white';
ctx.lineWidth = 1;
ctx.font = '36px arial';
ctx.strokeText('Canvas text', 50, 50);
ctx.fillStyle = 'red';
ctx.font = '48px georgia';
ctx.fillText('Canvas text', 50, 150);
fillText() :绘制有填充色的文本。
strokeText():绘制文本外边框(描边)。
这两个函数有三个基本的参数:需要绘制的文字、文本框(顾名思义,围绕着需要绘制文字的方框)左上顶点的X、Y坐标。
还有一系列帮助控制文本渲染的属性:比如用于指定字体族、字号的 font,它的值和语法与 CSS 的 font 属性一致。
在画布上绘制图片
var image = new Image();
image.src = 'flower.png';
ctx.drawImage(image, 20, 20, 185, 175, 50, 50, 185, 175);
第一个参数为图片引用。参数 2、3 表示裁切部分左上顶点的坐标,参考原点为原图片本身左上角的坐标。原图片在该坐标左、上的部分均不会绘制出来。参数 4、5 表示裁切部分的长、宽。参数 6、7 表示裁切部分左上顶点在画布中的位置坐标,参考原点为画布左上顶点。参数 8、9 表示裁切部分在画布中绘制的长、宽。
创建一个循环
ctx.translate(width/2, height/2);
function degToRad(degrees) {
return degrees * Math.PI / 180;
};
var length = 250;
var moveOffset = 20;
for(var i = 0; i < length; i++) {
ctx.fillStyle = 'rgba(' + (255-length) + ', 0, ' + (255-length) + ', 0.9)';
ctx.beginPath();
ctx.moveTo(moveOffset, moveOffset);
ctx.lineTo(moveOffset+length, moveOffset);
var triHeight = length/2 * Math.tan(degToRad(60));
ctx.lineTo(moveOffset+(length/2), moveOffset+triHeight);
ctx.lineTo(moveOffset, moveOffset);
ctx.fill();
length--;
moveOffset += 0.7;
ctx.rotate(degToRad(5));
}
translate(),可用于移动画布的原点,将 canvas 按原始 x点的水平方向、原始的 y点垂直方向进行平移变换。
在每次迭代中:设置 fillStyle 为略透明的紫色渐变色。渐变由每次迭代时 length 值的改变实现。随着循环的运行, length 值逐渐变小,从而使连续的三角形颜色逐渐变亮。
开始路径。
将钢笔移动至坐标 (moveOffset, moveOffset);该变量定义了每次要绘制新三角形时需要移动的距离。
画一条直线,终点坐标为 (moveOffset+length, moveOffset)。即一条长度为 length 与 X 轴平行的线。
计算三角形的高,方法同上。
向三角形底部顶点方向绘制一条直线,然后向三角形的起始点绘制一条直线。
调用 fill() 为三角形填充颜色。
更新次序变量,准备绘制下一个三角形。length 的值减一,使三角形每次迭代都变小一些;小幅增加 moveOffset 的值,使得下一个三角形略微错位;用一个新函数 rotate() 来旋转整块画布,在绘制下个三角形前画布旋转 5°。
以上内容部分摘自视频课程04网页游戏编程JavaScript-22绘制图形,更多示例请参见网站示例。跟着张员外讲编程,学习更轻松,不花钱还能学习真本领。