Canvas俄罗斯方块
写在前面
潜水博客园多年,从未写过博客。最近才注册博客,遂将很久前写的俄罗斯方块分享出来。第一次写博客,不喜勿喷。。。
游戏说明
- 游戏操作:J向左,L向右,I旋转,K快速下降
- 游戏基于HTML canvas开发,请在支持HTML5的浏览器中运行(IE9+, Chrome, Firefox...)
- 目前通过CodePen嵌入到页面中存在一个小BUG,请在页面加载完成后5秒左右在开始游戏(codepen的配置问题,已修复)。
数据结构
- 将整个游戏区域视为一个n*m的二维数组,数组中的每一个元素对应游戏区域中长为h的小正方形。如arr[3][4]对应左上角顶点坐标为(3*h,4*h)边长为h的正方形。数组中元素的值由0或1构成,0表示对应游戏区域没有方块1表示对应游戏区域已有方块。
- 游戏中的图形由若干个小方块构成,每一种图形有4种状态,可通过改变构成图形的小方块的坐标切换图形的状态。每一种图形有一个基点坐标,根据该基点坐标设置对应状态个小方块的坐标。代码如下所示:
var Shape = function () { }; Shape.prototype.Init = function () { this.blocks = []; var random = parseInt(Math.random() * 100); this.status = random % 4; this["st"+this.status]();//random status this.fillStyle = _config.blockColors[random % _config.blockColors.length];//random color } Shape.prototype.Down = function () { this.x += 1; for (var i = 0; i < this.blocks.length; i++) { this.blocks[i].x += 1; } } Shape.prototype.Left = function () { this.y -= 1; for (var i = 0; i < this.blocks.length; i++) { this.blocks[i].y -= 1; } } Shape.prototype.Right = function () { this.y += 1 for (var i = 0; i < this.blocks.length; i++) { this.blocks[i].y += 1; } } Shape.prototype.st0 = function () { };//abstract method Shape.prototype.st1 = function () { }; Shape.prototype.st2 = function () { }; Shape.prototype.st3 = function () { }; Shape.prototype.Rotate = function (i) {//rotate to target status var st = (this.status + i+4) % 4; this.status = st; this["st"+this.status]() }
var Triangle = function (x, y) { this.x = x; this.y = y; this.Init(); }; Triangle.InheritFrom(Shape, null, null); ShapeFactory.AddShape(Triangle); Triangle.prototype.st0 = function () { this.blocks[0] = new Block(this.x - 1, this.y, 1); this.blocks[1] = new Block(this.x, this.y - 1, 1); this.blocks[2] = new Block(this.x, this.y, 1); this.blocks[3] = new Block(this.x, this.y + 1, 1); } Triangle.prototype.st1 = function () { this.blocks[0] = new Block(this.x, this.y + 1, 1); this.blocks[1] = new Block(this.x - 1, this.y, 1); this.blocks[2] = new Block(this.x, this.y, 1); this.blocks[3] = new Block(this.x + 1, this.y, 1); } Triangle.prototype.st2 = function () { this.blocks[0] = new Block(this.x + 1, this.y, 1); this.blocks[1] = new Block(this.x, this.y + 1, 1); this.blocks[2] = new Block(this.x, this.y, 1); this.blocks[3] = new Block(this.x, this.y - 1, 1); } Triangle.prototype.st3 = function () { this.blocks[0] = new Block(this.x, this.y - 1, 1); this.blocks[1] = new Block(this.x + 1, this.y, 1); this.blocks[2] = new Block(this.x, this.y, 1); this.blocks[3] = new Block(this.x - 1, this.y, 1); }
类关系图
游戏中的设计模式
发布订阅模式
用于实现游戏中的事件通知,如得分、游戏结束等。
_events = (function () {//Pub&Sub var topics = {}, uuid = 0, event = function () { this.listen = function (topic, callback) { if (typeof topic !== "string" || typeof callback !== "function") return this; if (!topics[topic]) { topics[topic] = []; } callback.uuid = uuid++; topics[topic].push(callback); return this; }; this.trigger = function (src, topic, data) { if (!topics[topic] || topics[topic].length === 0) return this; var callbacks = topics[topic], i = 0, length = callbacks.length; for (; i < length; i++) { callbacks[i].call(src, data); } return this; }; this.remove = function (topic, callback) { if (!topics[topic] || topics[topic].length === 0) return this; var callbacks = topics[topic], i = 0, length = callbacks.length; for (; i < length; i++) { if (callback.uuid === callbacks[i].uuid) callbacks.splice(i, 1); } return this; }; }; return event; })();
BlockGame.prototype.ListenNewShapeEvents = function (fn) { this.events.listen(_eventEnum.newShape, fn); return this; }
工厂模式
用于随机的创建下一个图形。
var ShapeFactory = (function () {//absolute factory var ShapeArr = []; return { CreateShape: function (x, y) {//create a random shape var random = Math.floor(Math.random() * 100); return new ShapeArr[random % ShapeArr.length](x, y); }, AddShape: function (shape) { ShapeArr.push(shape); } }; })();