javascript代码实例教程-javascrpit开发连连看记录-小游戏

发布时间:2019-01-28 发布网站:脚本宝典
脚本宝典收集整理的这篇文章主要介绍了javascript代码实例教程-javascrpit开发连连看记录-小游戏脚本宝典觉得挺不错的,现在分享给大家,也给大家做个参考。
小宝典致力于为广大程序猿(媛)提供高品质的代码服务,请大家多多光顾小站,小宝典在此谢过。 首先就是熟悉连连看的规则,为此还专门下载了一个app感受了一下,规则简单的说就是:找到两个相同的图标,但是之前的连线不能大于条线;

    其次就要准备棋盘的UI设计和结构的成型,这块儿我直接使用了@墨尘的设计;

    再次就看是思考js里需要哪些功能:

初始化棋盘

绑定连线事件

处理连线的核心逻辑:判断是否可以连线

成功、失败提示等其他功能

    最后完善细节基本上就搞定了。

 

    下面详细介绍一下实现连连看核心功能的一些想法:

    第一:初始化棋盘

        初始化棋盘的时候,需要一些原始数据,页面才能知道哪里需要展现什么。我这里一共有45个不同的图标,那么所有的数据都是从这45个数据中获取,这个地方遇到的问题是:怎么能保证每个图标出现是偶数个?我的做法是随机去除总个数一般的数据,然后每个数据存入两次,这样就能保证每个图标都是偶数个。

       

 

/**

  * 获取数据

  * @param {Number} total 获取个数,默认整个棋盘需要的棋子数

  * @returns {Array} 源数据

  */

 getRandomData: function(total) {

  total = total || this.cols * this.rows;

  VAR halfTotal = total/2;

  var pieces = [];

  for(var i = 0; i < halfTotal; i++) {

   //保证每个元素都是成双的

   var num = Math.floor(Math.random() * 45);

   pieces.push(num);

   pieces.push(num);

  }

  return pieces;

 }

  

 

        在展示数据的时候,需要时随机布局,这个时候我想到了数组的sort方法,可以创建规则进行排序,如果我的排序规则是随机的呢?是不是这样展示的时候就是随机的呢。当然可能还有更加好的随机做法,也希望可以分享给我。

      

 

/**

 * 随机排序算法

 * @returns {number} -1或1

 */

randomSort: function() {

 return Math.random() > 0.5 ? -1 : 1;

}

  

 

        这样基本上就可以初始化一个随机排序的棋盘了。

 

    第二:绑定连线事件

        这个相对比较简单,需要注意的是,只有在点击两个点的时候才能进行判断是否可以连接,并且保证同时处于选中状态的不能超过两个。

 

    第三:连线的核心逻辑

            经过分析,所有的连线情况无非就是三种情况:连线没有拐点、连线只有一个拐点、连线有两个拐点

            连线没有拐点:

            这个很简单,这种情况就是两个点(x,y)和(m,n),两点必须同行或者同列,再通过一个循环就能知道两个能不能连起来了,伪代码大概是这样:

            

 

//假设方法名是 dealOneLine(x,y,m,n)

            if(x == m || y == n) {

                // y == n 是从x轴方向开始遍历

                if(x ==m) {

                    for(i = mixY; i<=maxY;i++) {

                        //判断是否能连通

                    }

                }

            }

  

 

            一个拐点:

            这种情况,必须得保证两点不是同行或者同列,这个时候只要检测要使得两点连通并且只能有一个拐点的话,这个拐点只有两个(x,n)和(m, y),所以就变成了带上这两个虚拟的点,能不能成功连通,伪代码是这样的:

            

 

//假设方法名是  oneFoldPoint(x,y,m,n)

            if(this.dealOneLine(x, y, x, n) && this.dealOneLine(x, n, m, n)) {

// console.LOG(&#39;纵向一个折点');

   }else if(this.dealOneLine( m, y, m, n) && this.dealOneLine( x, y, m, y)) {

// console.log('横向一个折点');

    return this.isSamePic();

   }

  

 

            两个拐点:

            这种情况,可以理解为出发地能不能到达目的地,将一个点作为不动点,另外一点寻找正确的路径找到不动点。所以这个动点就得通过遍历上线左右四个方向找到适合自己路径。每移动一次,就得使用OneFoldPoint判断是否可以通过一个拐点连通,如果可以直接返回,如果不能连通就再移动。

            基本上这些就是连连看比较核心的算法了。在一块儿我们的讨论的过程中,@宁宁提到了两外一个思路,就是分别遍历(x,y)和(m,n)四个方向,找到可以连通的路径。这个我没有去实现,但是感觉可以行的通。(做这个小游戏的一好处已经体现出来了,感觉非常好)

 

       最后就是一些辅助功能,如:连接成功或是失败怎么表现、过关成功和失败处理、倒计时处理等等,这些都比较常规,也比较简单,这里就不再赘述了~

 

        交流过程中,@尊杰也提到了一些安全方面的问题,如:通过提供的接口,机器进行过关;我这里没有进行处理,倒是需要考虑的地方。@jedmeng提到,可以将逻辑、数据和UI进行分离,各自完成各自的逻辑,相互直接不能有太多影响,这个想法会在以后的开发中多多考虑这方面的问题。还存在一个问题就是:我可以记录路径,但是不能顺序记录路径,导致不能进行画线,我初步分析了一下,应该是我的算法没有办法准确的记录路径~这个@墨尘实现了,他跟我的算法不太一样,想了解的可以看这里。

 

        这里是实现连连看的源码:

       

 

/**

 * LinkGame 360产品连连看

 * @author 黑MAO

 * @time 2014-7-24

 * @desription 描述

 */

(function() {

 'use strict';

  

 var isError = false;

 var clickTimes = 0;

 var timer = null;

 var pointOne = {

  x: 0,

  y: 0

 };

 var pointTwo = {

  x: 0,

  y: 0

 };

 var levelSum = 1;

  

 /**

  * LinkGame构造函数

  * @param {Number} rows 行数

  * @param {Number} cols 列数

  */

 function LinkGame(rows, cols) {

  if((rows && rows%2 != 0) && (rows && rows%2 != 0)) {

   isError = true;

  }

  this.rows = rows || 6;

  this.cols = cols || 7;

 }

  

 $.extend(LinkGame.PRototyPE, {

  /**

   * 初始化函数

   * @param {Boolean} restart 是否是重新初始化

   * @param {Number} total 总倒计时时间,默认值200s

   * @param {Number} level 等级,默认是levelSum

   */

  inIT: function(restart, total, level) {

   total = total || 200;

   this.total = total;

   levelSum = level || levelSum;

   if(isError) return;

   this.restart = restart || false;

   this.initGameBoard();

   this.initEvent();

   //初始化时间条

   this.startTime(total, 300);

   this.setLevel(levelSum);

  },

  

  //初始化棋盘

  initGameBoard: function() {

   var $gameBoard = $('.game-board');

   this.restart && $gameBoard.htML('');

   for(var y = 1; y <= this.rows; y++) {

    for(var x = 1; x <= this.cols; x++) {

     this.renderHtml(x, y);

    }

   }

   this.fillBoardData();

  },

  

  //重新初始化棋盘

  rebuildGameBoard: function() {

   var $items = $('.game-board').find('.item');

   this.fillBoardData($items.length);

  },

  

  //初始化事件

  initEvent: function() {

   var self = this;

   var $gameBoard = $('.game-board');

  

   $gameBoard.find('.item').on('click', function(e) {

    e.preventDefault();

    var pos = $(this).data('pos').split('_');

    clickTimes++;

    if(clickTimes > 2) return;

    if(pointOne.x > 0 || pointOne.y > 0) {

     pointTwo.x = pos[0];

     pointTwo.y = pos[1];

     $(this).addClass('current-one');

    }else {

     pointOne.x = pos[0];

     pointOne.y = pos[1];

     $(this).addClass('current-two');

    }

    self.dealGame(this);

   });

  },

  

  /**

   * 渲染棋子

   * @param {Number} x 横坐标

   * @param {Number} y 纵坐标

   */

  renderHtml: function(x, y) {

   var $gameBoard = $('.game-board');

   var left= 15+(x-1)*79;

   var top = 15+(y-1)*79;

   var pos = x + '_' + y;

   var $item = $('<p data-pos="' + pos + '" class="item pos' + pos + '" data-status="1"><p class="u"></p></p>');

   $gameBoard.append($item);

   $item.css({

    top: top,

    left: left

   });

  },

  

  /**

   * 填充数据

   * @param {Number} total 棋子总个数

   */

  fillBoardData: function(total) {

   var sourceArr = this.getRandomData(total).sort(this.randomSort);

   var $gameBoard = $('.game-board');

   $.each(sourceArr, function(i, value) {

    var classname = 'p'+value;

    var pos = $gameBoard.find('.item').eq(i).data('pos')

    $gameBoard.find('.item').eq(i).data('pic', className).removeClass()

     .addClass(className)

     .addClass('item')

     .addClass('pos' + pos);

   });

  },

  

  /**

   * 获取源数据

   * @param {Number} total 获取个数,默认整个棋盘需要的棋子数

   * @returns {Array} 源数据

   */

  getRandomData: function(total) {

   total = total || this.cols * this.rows;

   var halfTotal = total/2;

   var pieces = [];

   for(var i = 0; i < halfTotal; i++) {

    //保证每个元素都是成双的

    var num = Math.floor(Math.random() * 45);

    pieces.push(num);

    pieces.push(num);

   }

   return pieces;

  },

  

  /**

   * 随机排序算法

   * @returns {number} -1或1

   */

  randomSort: function() {

   return Math.random() > 0.5 ? -1 : 1;

  },

  

  /**

   * 开始计时

   * @param {Number} total 总时间,单位秒

   * @param {Number} interval 间隔时间

   */

  startTime: function(total, interval) {

   interval = interval || 1000;

   var self = this;

   var $bar = $('.time-line').find('.bar');

   var remain = total;

   this.reset();

   clearInterval(timer);

   $('.remain-time').html(total);

   $bar.css('background-color', '#40b60f');

   timer = setInterval(function() {

    if(remain < 0.1) {

     clearInterval(timer);

     self.fail();

     return;

    }

    remain = remain-interval/1000;

    $bar.css('width', remain*100/total + '%');

    if(remain*100/total > 25 && remain*100/total < 50) {

     $bar.css('background-color', 'orange');

    }else if(remain*100/total <= 25){

     $bar.css('background-color', 'red');

    }

    $('.remain-time').html(Math.round(remain));

   },interval)

  },

  

  /**

   * 处理游戏逻辑

   * @param {Object} el 需要处理的元素

   */

  dealGame: function(el) {

   var x = pointOne.x * 1;

   var y = pointOne.y * 1;

   var m = pointTwo.x * 1;

   var n = pointTwo.y * 1;

   var self = this;

   if(clickTimes > 2) return;

   this.dealSelectStatus(el);

  

   //点击同一个点

   if(x == m && y == n) {

    self.showError();

    return;

   }

  

   if(pointTwo.x > 0 || pointTwo.y > 0) {

    if(self.isOk(x, y, m, n)) {

     self.showRight();

    }else {

     self.showError();

    }

   }

  },

  

  /**

   * 连线没有折点的处理

   * @param {Number} x 第一个点的横坐标

   * @param {Number} y 第一个点的纵坐标

   * @param {Number} m 第二个点的横坐标

   * @param {Number} n 第二个点的纵坐标

   * @returns {Boolean} 是否可以连通

   */

  noFoldPoint: function(x, y, m, n) {

  

   if(this.isOneLine(x, y, m, n)) {

    if(this.dealOneLine(x, y, m, n)) {

// console.log('同行或同列');

     return this.isSamePic();

    }

   }

  

   return false;

  },

  

  /**

   * 处理在一条线上的情况

   * @param {Number} x 第一个点的横坐标

   * @param {Number} y 第一个点的纵坐标

   * @param {Number} m 第二个点的横坐标

   * @param {Number} n 第二个点的纵坐标

   * @returns {boolean} 是否可以连通

   */

  dealOneLine: function(x, y, m, n) {

   var $gameBoard = $('.game-board');

   var currentOnePos = $gameBoard.find('.current-one').data('pos');

   var currentTwoPos = $gameBoard.find('.current-two').data('pos');

   var minX = Math.min(x, m);

   var maxX = Math.max(x, m);

   var minY = Math.min(y, n);

   var maxY = Math.max(y, n);

   var isSuccess = true;

   if(x == m) {

    for(var b = minY; b <= maxY; b++) {

     var pos = x + '_' + b;

     var $item = $gameBoard.find('.pos'+ pos);

     var status = $item.data('status');

     if(status == 1 && pos != currentOnePos && pos != currentTwoPos) {

      isSuccess = false;

      break;

     }

    }

   }else if(y == n) {

    for(var a = minX; a <= maxX; a++) {

     var pos = a + '_' + y;

     var $item = $gameBoard.find('.pos'+ pos);

     var status = $item.data('status');

     if(status == 1 && pos != currentOnePos && pos != currentTwoPos) {

      isSuccess = false;

      break;

     }

    }

   }

  

   return isSuccess;

  },

  

  /**

   * 处理一个折点的情况

   * @param {Number} x 第一个点的横坐标

   * @param {Number} y 第一个点的纵坐标

   * @param {Number} m 第二个点的横坐标

   * @param {Number} n 第二个点的纵坐标

   * @returns {Boolean} 是否可以连通

   */

  oneFoldPoint: function(x, y, m, n) {

   //两种情况

   if(this.dealOneLine(x, y, x, n) && this.dealOneLine(x, n, m, n)) {

// console.log('纵向一个折点');

    return this.isSamePic();

   }else if(this.dealOneLine( m, y, m, n) && this.dealOneLine( x, y, m, y)) {

// console.log('横向一个折点');

    return this.isSamePic();

   }

   return false;

  },

  

  /**

   * 处理两个折点的情况

   * @param {Number} x 第一个点的横坐标

   * @param {Number} y 第一个点的纵坐标

   * @param {Number} m 第二个点的横坐标

   * @param {Number} n 第二个点的纵坐标

   * @returns {boolean} 是否可以连通

   */

  twoFoldPoint: function(x, y, m, n) {

   if(this.deepSeArch(x, y, m, n, 'right')

    || this.deepSearch(x, y, m, n, 'down')

    || this.deepSearch(x, y, m, n, 'left')

    || this.deepSearch(x, y, m, n, 'up')) {

// console.log('两个折点');

    return true;

   }

   return false;

  },

  

  /**

   * 深度搜索

   * @param {Number} x 第一个点的横坐标

   * @param {Number} y 第一个点的纵坐标

   * @param {Number} m 第二个点的横坐标

   * @param {Number} n 第二个点的纵坐标

   * @param {String} direction 搜索方向

   * @returns {Boolean} 是否可以连通

   */

  deepSearch: function(x, y, m, n, direction) {

   switch (direction) {

    case 'up':

     for(var i = y - 1; i >= 0; i--) {

      if(!this.isHasPic(x, i)) {

       var result = this.oneFoldPoint(x, i, m, n);

       if(!result) continue;

       return result;

      }else {

       return false;

      }

     }

    case 'down':

     for(var i = y + 1; i <= this.rows + 1; i++) {

      if(!this.isHasPic(x, i)) {

       var result = this.oneFoldPoint(x, i, m, n);

       if(!result) continue;

       return result;

      }else {

       return false;

      }

     }

    case 'left':

     for(var i = x - 1; i >= 0; i--) {

      if(!this.isHasPic(i, y)) {

       var result = this.oneFoldPoint(i, y, m, n);

       if(!result) continue;

       return result;

      }else {

       return false;

      }

     }

    case 'right':

     for(var i = x + 1; i <= this.cols + 1; i++) {

      if(!this.isHasPic(i, y)) {

       var result = this.oneFoldPoint(i, y, m, n);

       if(!result) continue;

       return result;

      }else {

       return false;

      }

     }

   }

  },

  

  /**

   * 检测是否存在棋子

   * @param {Number} x 横坐标

   * @param {Number} y 纵坐标

   * @returns {boolean} 是否存在

   */

  isHasPic: function(x, y) {

   var status = $('.game-board').find('.pos' + x + '_' + y).data('status');

   return status == 1 ? true : false;

  },

  

  /**

   * 检测两点是否同行或同列

   * @param {Number} x 第一个点的横坐标

   * @param {Number} y 第一个点的纵坐标

   * @param {Number} m 第二个点的横坐标

   * @param {Number} n 第二个点的纵坐标

   * @returns {boolean} 是否同行或同列

   */

  isOneLine: function(x, y, m, n) {

   if(x == m || y == n){

    return true;

   }

   return false;

  },

  

  /**

   * 检测选中两点是否相同棋子

   * @returns {boolean}

   */

  isSamePic: function() {

   var $gameBoard = $('.game-board');

   var $currentOne = $gameBoard.find('.current-one');

   var $currentTwo = $gameBoard.find('.current-two');

  

   if($currentOne.data('pic') == $currentTwo.data('pic')) {

    return true;

   }else {

    return false;

   }

  },

  

  /**

   * 检测两点是否可以连通

   * @param {Number} x 第一个点的横坐标

   * @param {Number} y 第一个点的纵坐标

   * @param {Number} m 第二个点的横坐标

   * @param {Number} n 第二个点的纵坐标

   * @returns {boolean}

   */

  isOk: function(x, y, m, n) {

   if(this.noFoldPoint(x, y, m, n) || this.oneFoldPoint(x, y, m, n) || this.twoFoldPoint(x, y, m, n)) {

    return true;

   }

   return false;

  },

  

  /**

   * 处理选中状态

   * @param {Object} el 选中元素

   */

  dealSelectStatus: function(el) {

   $(el).addClass('selected');

  },

  

  //提示功能

  hints: function() {

   var self = this;

   var switchFlag = false;

   var $items = $('.game-board').find('.item');

   $items.each(function(i, sourceitem) {

    var $sourceItem = $(sourceItem);

    var $remainItems = $sourceItem.siblings('.item');

    var sourcePos = $sourceItem.data('pos').split('_');

    $remainItems.each(function(i, item) {

     var $targetItem = $(item);

     var targetPos = $targetItem.data('pos').split('_');

     $sourceItem.addClass('current-one');

     $targetItem.addClass('current-two');

     if(self.isSamePic()) {

      pointOne = {

       x: sourcePos[0],

       y: sourcePos[1]

      };

      pointTwo = {

       x: targetPos[0],

       y: targetPos[1]

      };

      if(self.isOk(pointOne.x, pointOne.y, pointTwo.x, pointTwo.y)) {

       $targetItem.addClass('tip');

       $sourceItem.addClass('tip');

       self.reset();

       switchFlag = true;

       $sourceItem.removeClass('current-one');

       $targetItem.removeClass('current-two');

       return false;

      }

     }

     $sourceItem.removeClass('current-one');

     $targetItem.removeClass('current-two');

    });

  

    if(switchFlag) return false;

   });

   //没有可以提示的情况下,重新排序

   if(!switchFlag) {

    self.rebuildGameBoard();

    self.hints();

   }

  },

  

  //可正确连线

  showRight: function() {

   var self = this;

   var $gameBoard = $('.game-board');

   var $currentOne = $gameBoard.find('.current-one');

   var $currentTwo = $gameBoard.find('.current-two');

   var posOne = $currentOne.data('pos');

   var posTwo = $currentTwo.data('pos');

   $currentOne.addClass('remove').data('status', 0);

   $currentTwo.addClass('remove').data('status', 0);

   setTimeout(function() {

    $currentOne.removeClass().addClass('item-remove').addClass('pos'+posOne);

    $currentTwo.removeClass().addClass('item-remove').addClass('pos'+posTwo);

    self.reset();

    self.checkSuccess();

   }, 300);

  },

  

  //不可正确连线

  showError: function() {

   var self = this;

   var $gameBoard = $('.game-board');

   var $currentOne = $gameBoard.find('.current-one');

   var $currentTwo = $gameBoard.find('.current-two');

   $currentOne.addClass('error');

   $currentTwo.addClass('error');

   setTimeout(function() {

    $currentOne.removeClass('error').removeClass('current-one').removeClass('selected').remove('tip');

    $currentTwo.removeClass('error').removeClass('current-two').removeClass('selected').remove('tip');

    self.reset();

   }, 300);

  },

  

  //检测是否过关

  checkSuccess: function() {

   var $item = $('.game-board').find('p').filter('.item');

   if(!$item[0]) {

    clearInterval(timer);

    this.win();

   }

  },

  

  //过关成功通知

  win: function() {

            var self = this;

   var total = this.total;

            var newTotal = 0;

            clearInterval(timer);

   if(total > 100) {

                this.showMsg('成功提示', '看来你很厉害,要不要再来一局!点击确定减少10秒钟');

                newTotal = total - 10;

   }else if(total > 50) {

                this.showMsg('成功提示', '果然不同反响!点击确定减少5秒钟');

                newTotal = total - 5;

   }else if(total > 10){

                this.showMsg('成功提示', '你要超神啊!点击确定减少1秒钟');

                newTotal = total - 1;

   }

  

            $('.sure-BTn').off('click').on('click', function(e) {

                e.preventDefault();

                self.init(true, newTotal);

             levelSum++;

                self.hideMsg();

            });

  

            $('.unsure-btn').off('click').on('click', function(e) {

                e.preventDefault();

                self.hideMsg();

            });

  },

  

  //过关失败通知

  fail:function () {

            var self = this;

            this.showMsg('失败提示', '不要气馁,点击确定重新开始,点击取消关闭');

            $('.sure-btn').off('click').on('click', function(e) {

                e.preventDefault();

                $('.restart').trigger('click');

             levelSum = 1;

                self.hideMsg();

            });

  

            $('.unsure-btn').off('click').on('click', function(e) {

                e.preventDefault();

                self.hideMsg();

                $('.item').off('click').on('click', function() {

                    e.preventDefault();

                    self.showMsg('温馨提示', '您可以点击确定重新开始按钮');

                });

            });

  },

  

  //设置关数

  setLevel: function(level) {

   $('.level').find('.level-num').html(level);

  },

  

  /**

   * 显示提示信息

   * @param {String} title 标题

   * @param {String} msg 信息内容

   */

        showMsg: function(title, msg) {

            $('.panel-title').html(title);

            $('.panel-msg').html(msg);

            $('.mask').show();

            $('.panel').show();

        },

  

  //隐藏提示信息

        hideMsg: function() {

            $('.mask').hide();

            $('.panel').hide();

         this.setLevel(levelSum);

        },

  

  //重置坐标、点击状态

  reset: function() {

   pointOne.x = pointOne.y = pointTwo.x = pointTwo.y = 0;

   clickTimes = 0;

  }

 });

  

 window.LinkGame = LinkGame;

})();

    

觉得可用,就经常来吧! 脚本宝典 欢迎评论哦! js脚本,巧夺天工,精雕玉琢。小宝典献丑了!

脚本宝典总结

以上是脚本宝典为你收集整理的javascript代码实例教程-javascrpit开发连连看记录-小游戏全部内容,希望文章能够帮你解决javascript代码实例教程-javascrpit开发连连看记录-小游戏所遇到的问题。

如果觉得脚本宝典网站内容还不错,欢迎将脚本宝典推荐好友。

本图文内容来源于网友网络收集整理提供,作为学习参考使用,版权属于原作者。
如您有任何意见或建议可联系处理。小编QQ:384754419,请注明来意。