zoukankan      html  css  js  c++  java
  • Canvas俄罗斯方块

    写在前面

    潜水博客园多年,从未写过博客。最近才注册博客,遂将很久前写的俄罗斯方块分享出来。第一次写博客,不喜勿喷。。。

    游戏说明

    1. 游戏操作:J向左,L向右,I旋转,K快速下降
    2. 游戏基于HTML canvas开发,请在支持HTML5的浏览器中运行(IE9+, Chrome, Firefox...)
    3. 目前通过CodePen嵌入到页面中存在一个小BUG,请在页面加载完成后5秒左右在开始游戏(codepen的配置问题,已修复)。

    数据结构

    1. 将整个游戏区域视为一个n*m的二维数组,数组中的每一个元素对应游戏区域中长为h的小正方形。如arr[3][4]对应左上角顶点坐标为(3*h,4*h)边长为h的正方形。数组中元素的值由0或1构成,0表示对应游戏区域没有方块1表示对应游戏区域已有方块。
    2. 游戏中的图形由若干个小方块构成,每一种图形有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);
        }
    图形子类(L)

    类关系图

    游戏中的设计模式

    发布订阅模式

    用于实现游戏中的事件通知,如得分、游戏结束等。

    _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);
                }
            };
        })();
    工厂模式

    游戏效果

    See the Pen JGodp by victor zhang (@viczha) on CodePen.

  • 相关阅读:
    StackExchange.Redis 实现SetNx
    线程与进程基础
    K8s 命令基础
    MYSQL 5.7 alter table 小记
    Java Transient 关键字小记
    Java Functional Programming
    NetGear R6400 刷华硕小记
    datagrip bug 小记
    Spring 的历史
    IdentityServer4系列之中文文档及实际项目经验分享
  • 原文地址:https://www.cnblogs.com/viczha/p/3542951.html
Copyright © 2011-2022 走看看