zoukankan      html  css  js  c++  java
  • 小游戏之莫交叉

           做这个小游戏的灵感来源于...那时候在西永上班的几个同事,一个设计健哥,一个后台wei哥,另一个产品wei哥,再加上我这个前端,组成的一个开发小组,有一段时间我想自己写一个网络上比较火的贪吃蛇游戏耍,我就把想法和健哥讨论了下,结果不得了,估计大家工作都做得快(PS人事的艳姐看到这里莫敲我们脑壳,公司的事情点都没耽误:)),就七嘴八舌的一起讨论,就说要不然我们几个一起来开发一款益智游戏,当然我的贪吃蛇提议就肯定没被采纳,因为都感觉简单了,虽然我考虑的贪吃蛇并不是大众所认为的那样,最终应该是健哥提议的莫交叉这个游戏,我们找了几个网上的范本玩了玩,感觉还可以,就打算从这个游戏入手,想打下我们几个人的小游戏江山,我只能说终究我们还是太年轻了,虽然我最终把游戏原型做出来了,健哥把设计也画出来了,但是还是因为要做工作,慢慢的就不了了之,N年后的今天,我突然想到我最近看得最强大脑这个节目,上面就有很多这种类似的“小游戏”,早就手痒想盗版做几个了,不知怎么就联想到了当初做的那个莫交叉游戏,在N个云盘、服务器上翻箱倒柜,终于还找到了当初做的源码,自己也再拾掇拾掇,打算还是写个博客,纪念一下N年前那个夏天的idea。

           游戏的玩法,找了下百度,书名叫做“不交叉”,具体的解释链接是https://baike.baidu.com/item/%E4%B8%8D%E4%BA%A4%E5%8F%89/1581989?fr=aladdin,简单的说就是理清N个点之间的连线,除了点的交叉,没有线的交叉,随着初始点越来越多,线就越来越难理清楚,玩到后面还是有点烧脑,下面我们先来看下一个简单的起始面:

    现在我们初始是5个点,拖动每个点的时候,每个点相关联的线都会跟着移动,绿色的线是不交叉的,红色的线是因为有交叉,我们需要把所有的线都变成绿色就成功了,下面有个简单的动画演示效果

    可能大家看了这个动画,就感觉这个游戏很简单,是的,确实很简单,我曾经也这样天真的认为,那是因为我当时还没想清楚如果去开发这个游戏,其实最开始我觉得这个游戏可能有点难,我首先需要考虑3个问题:1、每个点都需要去连接线段,但是如何去连,可以看出有的点之间是没有连线的;2、点的移动是实时的,那么线的移动也是实时的,如何去考虑性能问题;3、根据第2点的问题,如何去判定游戏最终是成功的。当时我想如果把这3个问题解决了,应该就能考虑出代码思路了,然而还是too young了,我突然想到,点是随机生成,我怎么样才能知道哪些点之间要连线呢?突然就卡在这里了,不过考虑考虑,就在想,出这个游戏应该是要有解的吧(PS在写到这里的时候,突然冒出了一个想法,如果可以选择无解,那游戏的难度又会上一个台阶),那我为什么不先把正确的结果连接出来,然后再去随机移动初始点,再让用户去移动解答,这样就直接把思路理清楚了,至于第2点性能问题,貌似只能用Canvas了,所以就选择了createjs框架。

        其实整体的游戏核心代码很简洁,总共才300多行,而且都是纯前端代码,那时候为了快速出效果,后面也没维护,所以就没怎么写注释,将就着看。

     首先我们先定义画布(html):

    1 <div class="box">
    2     <canvas id="gameView" width="600" height="600" style="background-color:rgba(0,0,0,0.6)"></canvas>    
    3 </div>

     初始化系列参数(js):

     1 var stage = new createjs.Stage("gameView");
     2 createjs.Touch.enable(stage,true,false);
     3 var containerLine = new createjs.Container;
     4 var containerOther = new createjs.Container;
     5 stage.addChild(containerLine,containerOther);
     6 var arr = [];
     7 var lineArr = [];
     8 var indexArr = [];
     9 var jiaocha = false;
    10 var rightArr = [];
    11 var level = 5;

     重置方法:

     1 var restart = function(){
     2     containerLine.removeAllChildren()
     3     containerOther.removeAllChildren()
     4     arr = [];
     5     lineArr = [];
     6     indexArr = [];
     7     jiaocha = false;
     8     rightArr = [];
     9     start();
    10 }

     初始化界面上的点

     1             var start = function(){
     2                 for (var i =0;i<level;i++) {
     3                     var circle = new createjs.Shape();
     4                     circle.graphics.beginFill("green").drawCircle(0, 0, 10);
     5                     let w = Math.random()*bgW;
     6                     let h = Math.random()*bgH;
     7                     let x = w;
     8                     let y = h;
     9                     circle.x = x;
    10                     circle.y = y;
    11                     circle.index = i;
    12                     circle.addEvent(i);
    13                     containerOther.addChild(circle);
    14                     arr.push(circle)
    15                     
    16                     var point = {};
    17                     point.x = x;point.y = y;point.index = i;
    18                     rightArr.push(point);
    19                     
    20                     var text = new createjs.Text(i, "20px Arial", "#ff7700");
    21                     text.x = x;text.y = y;
    22                     text.textBaseline = "alphabetic";
    23                      containerOther.addChild(text)
    24                     stage.update();
    25                 }
    26                 drawLine1();
    27                 for(var j=0;j<level;j++){
    28                     randomLine();
    29                 }
    30                 drawLine2();
    31             }
    32             start();

      初始化方法里面的两个随机连线方法randomLine,drawLine1,drawLine2

     1             var randomLine = function(){
     2                 containerLine.removeAllChildren();
     3                 var rand = Math.floor(Math.random()*arr.length);
     4                 var x = Math.random()*bgW;
     5                 var y = Math.random()*bgH;
     6                 for(var i = 0;i<lineArr.length;i++){
     7                     var p3 = lineArr[i].p3;
     8                     var p4 = lineArr[i].p4;
     9                     if(rand == p3.index){
    10                         lineArr[i].p3.x = x;
    11                         lineArr[i].p3.y = y;
    12                     }
    13                     if(rand == p4.index){
    14                         lineArr[i].p4.x = x;
    15                         lineArr[i].p4.y = y;
    16                     }
    17                     
    18                 }
    19                 arr[rand].x = x;
    20                 arr[rand].y = y;
    21                 stage.update();
    22             }
     1             var drawLine1 = function(){
     2                 //在每个点的时候都要去找一下另外的匹配不交叉点
     3                 for(var i=0;i<arr.length;i++){
     4                     var p1 = {},p2 = {};
     5                     p1.x = arr[i].x,p1.y = arr[i].y,p1.index = arr[i].index;
     6                     
     7                     var count = Math.floor(Math.random()*level)+3;
     8                     for(let j=0;j<arr.length;j++){
     9                         if(i!=j){
    10                             p2.x = arr[j].x,p2.y = arr[j].y,p2.index = arr[j].index;
    11                             var result = checkLine(p1,p2,lineArr);
    12                             if(result == false){
    13                                 //先检查点有多少个了,多了就不画了
    14                                 let countP = checkPointCount(p1,p2);
    15                                 if(countP<=count)
    16                                 {
    17                                     var line = new createjs.Shape();
    18                                       line.graphics.setStrokeStyle(2).beginStroke("green");
    19                                       line.graphics.moveTo(p1.x, p1.y);
    20                                       line.graphics.lineTo(p2.x, p2.y);
    21                                       line.graphics.endStroke();
    22                                       containerLine.addChild(line);
    23                                       stage.update();
    24                                       var point = [];
    25                                       let p3={},p4={};
    26                                       p3.x = p1.x,p3.y = p1.y,p3.index = p1.index;
    27                                       p4.x = p2.x,p4.y = p2.y,p4.index = p2.index;
    28                                       point.p3 = p3;point.p4 = p4;
    29                                       lineArr.push(point)
    30                                       
    31                                       if(indexArr.indexOf(p1.index)==-1){
    32                                           indexArr.push(p1.index)
    33                                       }
    34                                       if(indexArr.indexOf(p2.index)==-1){
    35                                           indexArr.push(p2.index)
    36                                       }
    37                                 }
    38                             }
    39                         }
    40                     }
    41                     
    42                     var c = checkPointCount(p1,p2);
    43                     console.log(i,c)
    44                 }
    45             }
     1             var drawLine2 = function(){
     2                 jiaocha = false;
     3                 for(var i = 0;i<lineArr.length;i++){
     4                     var p1 = lineArr[i].p3;var p2 = lineArr[i].p4;
     5                     var result = false;
     6                     for(var j=0;j<lineArr.length;j++){
     7                         if(i!=j){
     8                             var p3 = lineArr[j].p3;var p4 = lineArr[j].p4;
     9                             if(checkCross(p1,p2,p3,p4)==true){
    10                                 if((p1.x == p3.x && p1.y == p3.y) || (p1.x == p4.x && p1.y == p4.y) || (p2.x == p3.x && p2.y == p3.y) || (p2.x == p4.x && p2.y == p4.y))
    11                                 {
    12                                     result = false;
    13                                 }
    14                                 else
    15                                 {
    16                                     result = true;
    17                                     jiaocha = true;
    18                                     break;
    19                                 }
    20                             }
    21                         }
    22                     }
    23                     var line = new createjs.Shape();
    24                     //要在这里判断每条线的交叉,然后再变颜色和做判断
    25                       line.graphics.setStrokeStyle(2).beginStroke(result==true?"red":"green");
    26                       line.graphics.moveTo(p1.x, p1.y);
    27                       line.graphics.lineTo(p2.x, p2.y);
    28                       line.graphics.endStroke();
    29                       containerLine.addChild(line);
    30                       stage.update();
    31                 }
    32                 if(jiaocha==false){
    33                     document.getElementsByClassName("over")[0].style.display = "block";
    34                 }
    35             }

    在drawLine1的时候还有一个检查点的方法checkPointCount

     1             var checkPointCount = function(p1,p2){
     2                 var count = 0;
     3                 for(var i = 0;i<lineArr.length;i++){
     4                     var p3 = lineArr[i].p3;
     5                     var p4 = lineArr[i].p4;
     6                     if(p1.index == p3.index || p1.index == p4.index || p2.index == p3.index || p2.index == p4.index){
     7                         count++;
     8                     }
     9                 }
    10                 return count;
    11             }

    当上面的完成后,就成了我们初始化的界面,level是初始的点,我也用来当成通关数,接下来就是移动点的操作了,给每一个点增加一个移动事件,并在每一个点移动的时候去调用drawLine2方法重绘每一条关联的线

     1             createjs.Shape.prototype.addEvent = function(count){
     2                 var _this = this;
     3                 this.addEventListener("mouseover",function(){
     4                     alert();
     5                 })
     6                 this.addEventListener("pressmove",function(_this){
     7                     if(jiaocha==false){
     8                         return;
     9                     }
    10                     var cir = _this.target;
    11                     var nowx = _this.stageX,nowy = _this.stageY;
    12                     cir.x = nowx;cir.y = nowy;
    13                     stage.update();
    14                     containerLine.removeAllChildren();
    15                     //这里要改变移动了点的信息
    16                     var index = _this.target.index;
    17                     for(var i = 0;i<lineArr.length;i++){
    18                         if(lineArr[i].p3.index == index){
    19                             lineArr[i].p3.x = nowx;lineArr[i].p3.y = nowy;
    20                         }
    21                         if(lineArr[i].p4.index == index){
    22                             lineArr[i].p4.x = nowx;lineArr[i].p4.y = nowy;
    23                         }
    24                     }
    25                     drawLine2()
    26                 })
    27             }

    在drawLine2方法里面有一个jiaocha变量,根据checkCross方法做一个判断所有lineArr数组里面的线是否有交汇,判断交汇方法如下:

     1             var checkCross = function(p1, p2, p3, p4) {
     2                 var v1 = {
     3                         x: p1.x - p3.x,
     4                         y: p1.y - p3.y
     5                     },
     6                     v2 = {
     7                         x: p2.x - p3.x,
     8                         y: p2.y - p3.y
     9                     },
    10                     v3 = {
    11                         x: p4.x - p3.x,
    12                         y: p4.y - p3.y
    13                     },
    14                     v = crossMul(v1, v3) * crossMul(v2, v3)
    15                 v1 = {
    16                     x: p3.x - p1.x,
    17                     y: p3.y - p1.y
    18                 }
    19                 v2 = {
    20                     x: p4.x - p1.x,
    21                     y: p4.y - p1.y
    22                 }
    23                 v3 = {
    24                     x: p2.x - p1.x,
    25                     y: p2.y - p1.y
    26                 }
    27                 var result = (v <= 0 && crossMul(v1, v3) * crossMul(v2, v3) <= 0) ? true : false;
    28                 if(result){
    29                     if((p1.x == p3.x && p1.y == p3.y) || (p1.x == p4.x && p1.y == p4.y) || (p2.x == p3.x && p2.y == p3.y) || (p2.x == p4.x && p2.y == p4.y))
    30                     {
    31                         result = false;
    32                     }
    33                     else
    34                     {
    35                         result = true;
    36                     }
    37                 }
    38                 return result;
    39             }

     1 var crossMul = function(v1, v2) { 2 return v1.x * v2.y - v1.y * v2.x; 3 } 

      到这里,整个游戏的思路就已经结束了,整体来说代码量不多,但是游戏是真的好玩,有兴趣的同学可以玩一下(在线地址:http://hudong.miaos.me/xxoo/ko_all.html),因为要涉及到很多点的操作,所以在PC上面操作体验会更好一些。另外目前的这种方法其实对于性能的问题并没有得到很好的解决,因为目前采用框架对于重绘是非常消耗资源,最后来一个30关的镇楼图吧,太烧脑了,目前我还没去研究最优解题的思路,后面哪天兴趣来了再去考虑。

    最后我觉得还是要把健哥的设计贴出来,做个纪念,虽然我们最终没能一起完成这个项目,但是我还是很欣赏你的设计的,不仅限于这个莫交叉:)

  • 相关阅读:
    把VB.NET代码转换为C#代码的方法
    离散数学 第二章 谓词逻辑 26 前束范式
    离散数学 第二章 谓词逻辑 27 谓词演算的推理理论
    asp.net中怎样用Javascript控制RequiredFieldValidator控件什么时候启用,什么时候不启用验证?
    离散数学中的IFF标记
    BIRT Overview
    离散数学 第二章 谓词逻辑 25 谓词演算的等价式和蕴涵式
    getRemoteAddr()和getRemoteHost()的区别
    scp 不用密码
    利用spring实现javamail功能
  • 原文地址:https://www.cnblogs.com/qinyulin/p/13496855.html
Copyright © 2011-2022 走看看