前面两节,我们已经对《五子飞》有个初步的认识,对走棋路线也有了基本的了解,现在里沃特继续跟大家分享HTML页面,另外把棋盘棋子也画出来。
演示地址:http://www.lyout.com/projects/fiveflychess/FiveflyChess3.htm
HTML页面非常简单:
<!DOCTYPE html> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <title>五子飞</title> <style type="text/css"> .fiveflychess { margin-left: auto; margin-right: auto; } </style> <script language="javascript" type="text/javascript" src="http://common.cnblogs.com/script/jquery.js"></script> <script language="javascript" type="text/javascript" src="canvas.js"></script> <script language="javascript" type="text/javascript" src="FiveflyChess.js"></script> </head> <body style="text-align: center;"> <canvas id="fiveflychess" class="fiveflychess" width="800" height="600"> Your brower is not support canvas! </canvas> <script language="javascript" type="text/javascript"> $(document).ready(function () { var chesspanel = $("#fiveflychess"); var ffc = new GameChess(); ffc.start(chesspanel); }); </script> </body> </html>
其中,jquery.js 被调用的函数不多,完全可以自行实现,但为了省时间,就用它处理了。canvas.js 是一个简单的在 html5 Canvas 上画图的类,实现了画圆、线、文字、圆角矩形、填充矩形、空心矩形、球等一些比较基础的函数。有时候没必要做一个小游戏还加载一些大型的框架:
var Canvas = { // 画圆弧路径 drawArc: function (c, x, y, r, a1, a2, anticlockwise) { c.arc(x, y, r, a1 * Math.PI / 180, a2 * Math.PI / 180, anticlockwise); }, // 画两条射线相切的的圆弧 drawArcTo: function (c, x1, y1, x2, y2, o1, o2, r) { c.moveTo(x1, y1); c.arcTo(o1, o2, x2, y2, r); }, // 画线 drawLine: function (c, strokestyle, lw, x1, y1, x2, y2) { c.strokeStyle = strokestyle; c.lineWidth = lw; c.beginPath(); c.moveTo(x1, y1); c.lineTo(x2, y2); c.closePath(); c.stroke(); }, // 画文字 drawText: function (c, text, x, y, fillstyle) { c.fillStyle = fillstyle; c.fillText(text, x, y); }, // 画个圆角矩形 drawRoundRect: function (c, strokestyle, x1, y1, x2, y2, r, fillstyle) { c.strokeStyle = strokestyle; c.fillStyle = fillstyle; c.beginPath(); c.moveTo(x1 + r, y1); c.lineTo(x2 - r, y1); c.quadraticCurveTo(x2, y1, x2, y1 + r); c.lineTo(x2, y2 - r); c.quadraticCurveTo(x2, y2, x2 - r, y2); c.lineTo(x1 + r, y2); c.quadraticCurveTo(x1, y2, x1, y2 - r); c.lineTo(x1, y1 + r); c.quadraticCurveTo(x1, y1, x1 + r, y1); c.fill(); c.stroke(); }, // 画填充矩形 drawFillRect: function (c, strokestyle, lw, x1, y1, x2, y2, fillstyle) { c.fillStyle = fillstyle; c.fillRect(x1, y1, x2 - x1, y2 - y1); if (lw > 0) this.drawRect(c, strokestyle, lw, x1, y1, x2, y2); }, // 画空心矩形 drawRect: function (c, strokestyle, lw, x1, y1, x2, y2) { c.strokeStyle = strokestyle; c.lineWidth = lw; c.beginPath(); c.moveTo(x1 - lw / 2, y1); c.lineTo(x2, y1); c.lineTo(x2, y2); c.lineTo(x1, y2); c.lineTo(x1, y1 - lw / 2); c.stroke(); }, // 画线 drawLine: function (c, strokestyle, lw, x1, y1, x2, y2) { c.strokeStyle = strokestyle; c.lineWidth = lw; c.beginPath(); c.moveTo(x1, y1); c.lineTo(x2, y2); c.closePath(); c.stroke(); }, // 画只有边的球 drawCircleStroke: function (c, strokestyle, lw, x, y, r) { c.strokeStyle = strokestyle; c.lineWidth = lw; c.beginPath(); this.drawArc(c, x, y, r, 0, 360, true); c.closePath(); c.stroke(); }, // 画填充有边的球 drawCircleFill: function (c, strokestyle, lw, x, y, r, fillstyle) { c.strokeStyle = strokestyle; c.lineWidth = lw; c.fillStyle = fillstyle; c.beginPath(); this.drawArc(c, x, y, r, 0, 360, true); c.closePath(); c.fill(); c.stroke(); }, // 画球 drawBall: function (c, x, y, r, fillstyle) { c.fillStyle = fillstyle; c.beginPath(); this.drawArc(c, x, y, r, 0, 360, true); c.closePath(); c.fill(); }, // 判断点是否在某个区块内 inRegion: function (p, r) { if (p[0] > r[0] && p[0] < r[2] && p[1] > r[1] && p[1] < r[3]) { return true; } else { return false; } }, //判断两个矩形对象是否重合 coincide: function (a, b) { if (this.inRegion([a[0], a[1]], b)) return true; if (this.inRegion([a[0], a[3]], b)) return true; if (this.inRegion([a[2], a[1]], b)) return true; if (this.inRegion([a[2], a[3]], b)) return true; if (this.inRegion([b[0], b[1]], a)) return true; if (this.inRegion([b[0], b[3]], a)) return true; if (this.inRegion([b[2], b[1]], a)) return true; if (this.inRegion([b[2], b[3]], a)) return true; return false; }, getContext: function (el) { if (!(el && el.length && el.length > 0)) { return null; } return (function () { if (el[0].getContext) { var c = el[0].getContext("2d"); if (c) { return c; } } return null; })(); } };
现在我们看看怎么把棋盘和棋子画出来:
/// <reference path="../common/jquery.js" /> /// <reference path="../common/canvas.js" /> var Player = { A: 0, B: 1, None: -1 }; function Size(w, h) { this.w = w; this.h = h; } function Point(x, y, index) { this.x = x; this.y = y; this.index = index; } function Bounds(x, y, w, h) { this.x = x; this.y = y; this.w = w; this.h = h; this.toArray = function () { return [this.x, this.y, this.w, this.h]; }; this.toArrayXY = function () { return [this.x, this.y, this.x + this.w, this.y + this.h]; }; } function Chess(player) { this.player = player; this.point = new Point(-1, -1, -1); this.bounds = new Bounds(-1, -1, -1, -1); this.moveTo = function (chess) { chess.player = this.player; this.player = Player.None; }; } function GameChess() { // 可走的路线 this.lines = [ [ 0, 1, 2, 3, 4], [ 5, 6, 7, 8, 9], [10, 11, 12, 13, 14], [15, 16, 17, 18, 19], [20, 21, 22, 23, 24], [ 0, 5, 10, 15, 20], [ 1, 6, 11, 16, 21], [ 2, 7, 12, 17, 22], [ 3, 8, 13, 18, 23], [ 4, 9, 14, 19, 24], [ 0, 6, 12, 18, 24], [ 4, 8, 12, 16, 20], [ 2, 6, 10], [ 2, 8, 14], [10, 16, 22], [14, 18, 22] ]; this.cpc = 0; // 单方初始棋子数 this.ctc = 0; // 棋子可走的点数 this.chesses = []; // 棋子(包含空棋子) this.chessarray = null; // 多选棋子 this.chessreplace = []; // 被替换的棋子 this.chesssize = new Size(32, 32); // 棋子大小 this.panel = null; // 作画的画板 this.width = 0; // 画板宽度 this.height = 0; // 画板高度 this.chessblack = new Image(); // 黑棋子图片 this.chesswhite = new Image(); // 白棋子图片 this.imagestate = 0; // 棋子图片加载状态 this.imagetimer = null; // 判断棋子图片加载的时钟 this.currentIndex = -1; // 当前棋子 this.currentPlayer = Player.B; // 当前玩家是哪一方 this.computerPlayer = Player.A; // 电脑是哪一方 this.computerUsed = true; // 是否与电脑对弈 this.player = Player.B; // 轮到谁玩了 this.timetimer = null; // 倒计时 this.timecount = 30; // 每步30秒 this.winner = Player.None; // 谁赢了 this.isover = false; // 是否结束了 // 初始配置 this.init = function () { this.chesses = []; this.cpc = 5; this.ctc = Math.pow(this.cpc, 2); var i; // 分配棋子 for (i = 0; i < this.cpc; i++) { this.chesses.push(new Chess(Player.A)); } for (i = this.cpc; i < this.ctc - this.cpc; i++) { this.chesses.push(new Chess(Player.None)); } for (i = this.ctc - this.cpc; i < this.ctc; i++) { this.chesses.push(new Chess(Player.B)); } for (i = 0; i < this.ctc; i++) { this.chesses[i].point = new Point(i % this.cpc, parseInt(i / this.cpc, 10), i); } }; this.play = function () { this.replay(); }; // 重玩,重置所有棋子 this.replay = function () { this.isover = false; this.changePlayer(); var i; // 分配棋子 for (i = 0; i < this.cpc; i++) { this.chesses[i].player = Player.A; } for (i = this.cpc; i < this.ctc - this.cpc; i++) { this.chesses[i].player = Player.None; } for (i = this.ctc - this.cpc; i < this.ctc; i++) { this.chesses[i].player = Player.B; } for (i = 0; i < this.ctc; i++) { this.chesses[i].point = new Point(i % this.cpc, parseInt(i / this.cpc, 10), i); } }; this.changePlayer = function () { this.timecount = 30; }; // 获取索引号 this.getIndex = function (pDest, pSrc) { var t1 = typeof (pDest), t2 = typeof (pSrc); var i1 = -1, i2 = -1; if ((t1 == "number") && (t2 == "number")) { i1 = pDest; i2 = pSrc; } else if ((t1 == "object") && (t2 == "object")) { i1 = pDest.index || -1; i2 = pSrc.index || -1; } if (i1 >= 0 && i1 < this.ctc) { return { destIndex: i1, srcIndex: i2 }; } return false; }; // 得到对方是哪个玩家 this.getAnotherPlayer = function (player) { return player == Player.A ? Player.B : Player.A; }; this.paint = function () { var i; var cw = this.width > this.height ? this.height : this.width; // 画棋盘 Canvas.drawRoundRect(this.panel, "#225C21", 0, 0, this.width, this.height, 5, "#225C21"); Canvas.drawFillRect(this.panel, "#000000", 1, 20, 20, cw - 20, cw - 20, "#E8BC7D"); Canvas.drawRect(this.panel, "#000000", 5, 50, 50, cw - 50, cw - 50); var startp = 58; var w = cw - startp * 2; var h = cw - startp * 2; for (i = 0; i < this.cpc; i++) { Canvas.drawLine(this.panel, "#000000", 1, startp + i * w / (this.cpc - 1), startp, startp + i * w / (this.cpc - 1), cw - startp); } for (i = 0; i < this.cpc; i++) { Canvas.drawLine(this.panel, "#000000", 1, startp, startp + i * h / (this.cpc - 1), cw - startp, startp + i * h / (this.cpc - 1)); } // 长对角线 Canvas.drawLine(this.panel, "#000000", 1, startp, startp, cw - startp, cw - startp); Canvas.drawLine(this.panel, "#000000", 1, startp, cw - startp, cw - startp, startp); // 短对角线 Canvas.drawLine(this.panel, "#000000", 1, startp, startp + (this.cpc - 1) / 2 * h / (this.cpc - 1), startp + (this.cpc - 1) / 2 * w / (this.cpc - 1), startp); Canvas.drawLine(this.panel, "#000000", 1, startp, startp + (this.cpc - 1) / 2 * h / (this.cpc - 1), startp + (this.cpc - 1) / 2 * w / (this.cpc - 1), cw - startp); Canvas.drawLine(this.panel, "#000000", 1, startp + (this.cpc - 1) / 2 * w / (this.cpc - 1), cw - startp, cw - startp, startp + (this.cpc - 1) / 2 * h / (this.cpc - 1)); Canvas.drawLine(this.panel, "#000000", 1, startp + (this.cpc - 1) / 2 * w / (this.cpc - 1), startp, cw - startp, startp + (this.cpc - 1) / 2 * h / (this.cpc - 1)); Canvas.drawRect(this.panel, "#000000", 2, startp, startp, cw - startp, cw - startp); if (this.imagestate == 2) { if (this.imagetimer) { clearInterval(this.imagetimer); this.imagetimer = null; } var b; // 画棋子 for (i = 0; i < this.chesses.length; i++) { this.chesses[i].bounds = new Bounds(startp + this.chesses[i].point.x * w / (this.cpc - 1) - this.chesssize.w / 2, startp + this.chesses[i].point.y * h / (this.cpc - 1) - this.chesssize.h / 2, this.chesssize.w, this.chesssize.h); switch (this.chesses[i].player) { case Player.A: this.panel.drawImage(this.chessblack, this.chesses[i].bounds.x, this.chesses[i].bounds.y, 32, 32); break; case Player.B: this.panel.drawImage(this.chesswhite, this.chesses[i].bounds.x, this.chesses[i].bounds.y, 32, 32); break; default: break; } } } // 画棋子 }; this.repaint = function () { this.panel.clearRect(0, 0, this.width, this.height); this.paint(); }; this.start = function (el) { this.init(); this.width = el.width(); this.height = el.height() this.panel = Canvas.getContext(el); if (this.panel != null) { var t = this; // 加载棋子图片 $(this.chessblack).load(function () { t.imagestate++; }); $(this.chesswhite).load(function () { t.imagestate++; }); this.chessblack.src = "chessblack.png"; this.chesswhite.src = "chesswhite.png"; if (this.imagestate < 2) { this.paint(); } this.imagetimer = setInterval(function () { if (t.imagestate == 2) { t.repaint(); t.play(); } }, 100); return true; } return false; }; }
怎么样?熟悉javascript的伙伴应该看起来没什么难度吧:)
这节我们就讲到这里,下次里沃特再跟大家分享怎么分析和处理“移动棋子”、“夹一个”和“挑一对”,敬请期待。
HTML5+JS 《五子飞》游戏实现(一)规则
HTML5+JS 《五子飞》游戏实现(二)路线分析和资源准备
HTML5+JS 《五子飞》游戏实现(四)夹一个和挑一对
HTML5+JS 《五子飞》游戏实现(五)移动棋子
HTML5+JS 《五子飞》游戏实现(六)鼠标响应与多重选择