从零开始开发一款H5小游戏(一) 重温canvas的基础用法

@fwon 2016-07-06 09:29:02发表于 fwon/blog

本系列文章对应游戏代码已开源 escape game

初衷

从萌发写一个小游戏的想法到完成游戏开发用了大概一周的业余时间。这个过程积累了一些经验,也算是参透了一些游戏开发的原理。在这里打算写一个系列教程,讲述怎样从零开始开发一款小游戏。让新者少走弯路,快速入手。也能让自己总结反思,发现问题。

在开始介绍如何写游戏前有必要重温一下canvas。它是本游戏的地基,建房子要快,首先地基要牢固。

Canvas
Canvas 对一个做前端的人来说再熟悉不过,html5中新增的这个功能为网页创造了无限可能,极大促进了网页富应用的开发。
而canvas对于大部分前端来说又是陌生的。
可以说在写这个游戏之前,我只是模糊地记得canvas的一些功能,以及经常在网上看到的酷炫高大上的基于canvas实现的效果,但自己绝对答不出canvas有哪些API,以及它们的具体使用方法。毕竟自己平时没做过类似的活动页,在大厂里这些工作一般都是让UED部门给承包了。

好了,废话不多说,进入主题。

在开始之前建议读一遍MDN的教程,如果有《犀牛书》也可以看第21章关于canvas图形编程一节。

里面几个概念需要说一下。
context上下文:

var canvas = document.getElementById('canvas');
var cxt = canvas.getContext('2d');

我们的图形并不是直接花在canvas上的,而是要通过getContext首先获得这个画板的上下文。传入的2d参数则表示我们创建的是一个2d的画布。后面所有的绘画都是直接操作cxt这个画布对象。

这个画布对象的全称是 CanvasRenderingContext2D,上面实现了很多绘制方法。具体用到可以参考这里

API虽然多,但是道理只有一个,万变不离其宗。

现实中我们画一个东西一般要有以下几个步骤:

  1. 准备画布
  2. 选择画笔
  3. 选择颜料
  4. 画出轮廓
  5. 填充颜色

而实际上CanvasRenderingContext2D API的设计也是大概遵循这样一个步骤,每一步都会最终影响画出来的图案。
我们可以将所有绘制分为两大类,一类是线,一类是面。线使用的API一般以stroke开头,面的API是以fill开头。

画一条线:

var c=document.getElementById("canvas");
var cxt=c.getContext("2d");                     //准备画布
cxt.lineWidth = 5;                              //选择画笔
cxt.strokeStyle = "red";                        //选择颜料
cxt.moveTo(10,10);                              //...
cxt.lineTo(150,50);                             //...
cxt.lineTo(10,50);                              //画出轮廓
cxt.stroke();                                   //填充颜色

效果图:
roadmap.path

画一个三角形面

var c=document.getElementById("canvas");
var cxt=c.getContext("2d");                     //准备画布
cxt.lineWidth = 5;                              //选择画笔
cxt.fillStyle = "red";                          //选择颜料
cxt.moveTo(10,10);                              //...
cxt.lineTo(150,50);                             //...
cxt.lineTo(10,50);                              //画出轮廓
cxt.fill();                                     //填充颜色

效果图:
roadmap.path

只要将stroke的地方换成fill, 就变成图形面的填充。而这里的lineWidth其实是可以省略的,它的默认值是1。

为了方便,CanvasRenderingContext2D为我们提供了一些简单的API,不需要使用moveTo和lineTo一条线段一条线段绘制。最重要的有几个:

arc: 画圆

cxt.arc(x, y, radius, startAngle, endAngle, anticlockwise);

fillRectstrokeRect: 画矩形

cxt.fillRect(x, y, width, height)           //填充图形
cxt.strokeRect(x, y, width, height)         //不填充图形

fillText: 写字

cxt.fillText(text, x, y [, maxWidth])

当然CanvasRenderingContext2D还有更多丰富的API,但是基本都是基于上面5个步骤衍生出来的。基础开发中很少会使用到,可以用时再查阅文档。

为了能在一张画图上绘制多个图形而互不影响,CanvasRenderingContext2D提供了
beginPathclosePath

beginPath 用于在开始绘制一个独立图形的时候声明,在beginPath之后定义的画笔,颜料都不会影响到画图中的其他图形。可以看到下面的两条路径,各自定义了strokeStyle, 但是互不影响。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");

//第一条路径
ctx.beginPath();
ctx.strokeStyle = 'blue';
ctx.moveTo(20,20);
ctx.lineTo(200,20);
ctx.stroke();

//第二条路径
ctx.beginPath();
ctx.strokeStyle = 'green';
ctx.moveTo(20,20);
ctx.lineTo(120,120);
ctx.stroke();

效果图:
roadmap.path

closePath 用于方便地将首尾两个点连接起来,形成一个封闭的图形,而不必手动调用lineTo闭合图形。 例如上方的三角形线段可以这样用:

var c=document.getElementById("canvas");
var cxt=c.getContext("2d");
cxt.moveTo(10,10);
cxt.lineTo(150,50);
cxt.lineTo(10,50);
cxt.closePath();
cxt.stroke();

效果图:
roadmap.path

上面详细介绍的几个简单的API已经足够开发一个简单的游戏了。而如何使游戏界面更丰富炫酷,则需要用到更多的辅助方法。我们将在游戏中用到时再做具体介绍。

关于canvas的基础就温习到这,下一篇文章将进入本游戏的开发。敬请期待
《从零开始开发一款H5小游戏(二) 创造游戏的世界,启动发动机》