查看: 228|回复: 9

[HTML5游戏教程] 使用HTML5做一个数独游戏教程

[复制链接]
发表于 2016-11-22 16:22:15 | 显示全部楼层 |阅读模式
数独是很好玩的游戏,之前我用jQuery做了一个数独游戏,因为用JavaScript来实现drag和drap非常麻烦,jQuery的UI提供了一套非常不错的drag和drap(以后就简称DnD算了),方便我们开发。现在HTML5支持原生的DnD了,那我们来学习下,并且将原先的数独游戏迁移到HTML5的DnD应用来。
d270c1071496b38ce2b8cb3e6e0c7e4a.jpg

先简单的了解下HTML5的DnD事件模型,事件发生在源元素(被拖动的元素)和目标元素(被进入的元素)上,为了简单的描述,我们将源元素称为src,目标元素叫des。


drag:src[拖动中]dragstart:src[开始拖动]
dragenter:des[进入目标]
dragover:des[在目标移动]
dragleave:des[离开目标]
drop:des[释放拖动]
dragend:src[拖动完成]


所有的事件我们知道肯定都应该给我们一个event对象,帮助我们获得一些信息或我们来设置一些信息,以上事件都可以得到一个event,如果我们的事件函数是function(e)那么,

e.dataTransfer.effectAllowed:只能在dragstart事件设置,值为以下之一:"none", "copy", "copyLink", "copyMove", "link", "linkMove", "move", "all", and "uninitialized";

e.dataTransfer.dropEffect:返回拖来的行为,对应上面的effectAllowed,值是:"none", "copy", "link", and "move";

e.target:可以得到当前事件的dom对象,比如你可以得到e.target.innerHTML,或者设置e.target.classList.add,或者e.target.classList.remove;

e.dataTransfer.setData(foramt,value):为拖动赋值,foramt的值是为了描述值的类型,一般有text/plain 和 text/uri-list;

e.dataTransfer.getData(foramt):获取被拖来的元素通过setData存储的值;

e.stopPropagation:阻止事件冒泡,这样可以防止子元素的拖动处理被带到父元素事件中(触发父元素事件),在IE中可以用e.cancelBubble = true;

e.preventDefault:阻止默认事件发生,也可以简单的写return false,在IE中可以用e.returnValue = false;

有了上面的基本概念,我们先做一个小小的模型,来测试几个技术要点:监视拖放事件,改变元素在拖放中的样式,传递值和检查值什么的
在body里面,我们声明了10个div元素,并且都标记允许拖放

  1. <font color="#2f4f4f"><body>  
  2.     <div style="width: 50px; height: 50px; background-color: Red;" draggable="true">  
  3.         1  
  4.     </div>  
  5.     <div style="width: 50px; height: 50px; background-color: Yellow;" draggable="true">  
  6.         2  
  7.     </div>  
  8.     <div style="width: 50px; height: 50px; background-color: Blue;" draggable="true">  
  9.         3  
  10.     </div>  
  11.     <div style="width: 50px; height: 50px; background-color: Lime;" draggable="true">  
  12.         4  
  13.     </div>  
  14.     <div style="width: 50px; height: 50px; background-color: Maroon;" draggable="true">  
  15.         5  
  16.     </div>  
  17.     <div style="width: 50px; height: 50px; background-color: Black;" draggable="true">  
  18.         6  
  19.     </div>  
  20.     <div style="width: 50px; height: 50px; background-color: Orange;" draggable="true">  
  21.         7  
  22.     </div>  
  23.     <div style="width: 50px; height: 50px; background-color: Olive;" draggable="true">  
  24.         8  
  25.     </div>  
  26.     <div style="width: 50px; height: 50px; background-color: Teal;" draggable="true">  
  27.         9  
  28.     </div>  
  29.     <div style="width: 50px; height: 50px; background-color: Green;" draggable="true">  
  30.         10  
  31.     </div>  
  32. </body>  </font>
复制代码
现在我们想做一个应用,只有相互有倍数关系的div之间才可用拖放。

首选,我们做一个用于输出调式的小工具代码

  1. <font color="#2f4f4f">$.log = function(msg) {  
  2.     console.log(msg);  
  3. }  </font>
复制代码
这个我们可以方便的$.log()输出,而不要写冗长的console.log了
第一步,编写dragStart事件函数
  1. <font color="#2f4f4f">function handleDragStart(e) {  
  2.     this.style.opacity = "0.5";  
  3.     e.dataTransfer.effectAllowed = "move";  
  4.     e.dataTransfer.setData("text/plain", this.innerHTML);  
  5.     //$.log(this.innerHTML);  
  6.     //$.log(e.target.innerHTML);  
  7.     //$.log(e.srcElement.innerHTML);  
  8.     [ ].forEach.call(document.querySelectorAll("div"),  
  9.     function(item) {  
  10.         var a = parseInt(e.target.innerHTML);  
  11.         var b = parseInt(item.innerHTML);  
  12.         if (a % b != 0 && b % a != 0) {  
  13.             item.style.opacity = "0.1";  
  14.   
  15.         }  
  16.     });  
  17. }  </font>
复制代码
以上的代码有几个要点

    1 .对事件来讲this、e.target和e.srcElement都是同一对象
    2 .在forEach中,this是指item,所以forEach中,我们要用e.target来引用


但是一测试我们就发现虽然元素可以拖拉,但并没有事件激活,那是应为我们没有为元素绑定事件,所以现在我们用addEventListener来将元素和事件绑定

  1. <font color="#2f4f4f">$(  
  2. function() {  
  3.     [ ].forEach.call(document.querySelectorAll("div"),  
  4. function(item) {  
  5.      item.addEventListener("dragstart", handleDragStart, false);   
  6. }  
  7. );  
  8. }  
  9. );  </font>
复制代码
现在我们可以看到,当任意元素拖动的时候,不和其元素有相互倍数的元素变了很淡了。

第二步,当我们拖放完成后,所有div恢复原先颜色,那自然是编写handleDragEnd
  1. <font color="#2f4f4f">function handleDragEnd(e) {  
  2.     if (e.preventDefault) {  
  3.         e.preventDefault(); //不要执行与事件关联的默认动作  
  4.     }  
  5.     [ ].forEach.call(document.querySelectorAll("div"),  
  6.     function(item) {  
  7.         item.style.opacity = "1";  
  8.     }  
  9.     );  
  10. }  </font>
复制代码
记得将上面的事件做绑定哦,应该类似以下代码
  1. <font color="#2f4f4f">$(  
  2. function() {  
  3.     [ ].forEach.call(document.querySelectorAll("div"),  
  4. function(item) {  
  5.      item.addEventListener("dragstart", handleDragStart, false);  
  6.      item.addEventListener("dragend", handleDragEnd, false);   
  7. }  
  8. );  
  9. }  
  10. );  </font>
复制代码
第三步,我们要通知那些互为倍数的元素允许我们做拖入操作

我们先需要为目标元素定义些事件函数
  1. <font color="#2f4f4f">function handleDragEnter(e) {  
  2.     $.log(e);  
  3. }  
  4.   
  5. function handleDragOver(e) {  
  6.     if (e.preventDefault) {  
  7.         e.preventDefault(); //不要执行与事件关联的默认动作  
  8.     }  
  9.     if (e.stopPropagation) {  
  10.         e.stopPropagation(); //停止事件的传播  
  11.     }  
  12.     $.log(e);  
  13.     return false;  
  14. }  
  15.   
  16.   
  17. function handleDragLeave(e) {  
  18.     $.log(e);  
  19. }  
  20.   
  21. function handleDrop(e) {  
  22.     if (e.preventDefault) {  
  23.         e.preventDefault(); //不要执行与事件关联的默认动作  
  24.     }  
  25.     if (e.stopPropagation) {  
  26.         e.stopPropagation(); //停止事件的传播  
  27.     }  
  28.     console.log(e);  
  29.     return false;  
  30. }  </font>
复制代码
注意我们使用了preventDefault和stopPropagation消除了浏览器默认的一些动作。
显然这些事件不是所有的元素都有的,只有互为倍数才有,所以我们要去修改handleDragStart函数了
修改后的代码大致如下:

  1. <font color="#2f4f4f">function handleDragStart(e) {  
  2.     this.style.opacity = "0.5";  
  3.     e.dataTransfer.effectAllowed = "move";  
  4.     e.dataTransfer.setData("text/plain", this.innerHTML);  
  5.     //$.log(this.innerHTML);  
  6.     //$.log(e.target.innerHTML);  
  7.     //$.log(e.srcElement.innerHTML);  
  8.     //$.log(this.innerHTML);  
  9.     [ ].forEach.call(document.querySelectorAll("div"),  
  10.     function(item) {  
  11.         var a = parseInt(e.target.innerHTML);  
  12.         var b = parseInt(item.innerHTML);  
  13.         if (a % b != 0 && b % a != 0) {  
  14.             item.style.opacity = "0.1";  
  15.         }  
  16.         else {  
  17.             item.addEventListener("dragover", handleDragOver, false);  
  18.             item.addEventListener("dragenter", handleDragEnter, false);  
  19.             item.addEventListener("dragleave", handleDragLeave, false);  
  20.             item.addEventListener("drop", handleDrop, false);  
  21.         }  
  22.     });  
  23. }  </font>
复制代码
现在你可以发现,当我们拖动互为倍数的元素是,视觉效果明显是允许拖入,否则就不允许了。当然记得在handleDragEnd函数中要恢复哦

  1. <font color="#2f4f4f">function handleDragEnd(e) {  
  2.     if (e.preventDefault) {  
  3.         e.preventDefault(); //不要执行与事件关联的默认动作  
  4.     }  
  5.     [ ].forEach.call(document.querySelectorAll("div"),  
  6.     function(item) {  
  7.         item.style.opacity = "1";  
  8.         item.removeEventListener("dragover", handleDragOver, false);  
  9.         item.removeEventListener("dragenter", handleDragEnter, false);  
  10.         item.removeEventListener("dragleave", handleDragLeave, false);  
  11.         item.removeEventListener("drop", handleDrop, false);  
  12.     }  
  13.     );  
  14. }  
  15. </font>
复制代码
第四步,当我们在可以放置的元素上结束拖放后,我们希望两个元素的值累计,并出现在被放置的元素里面,我们需要修改handleDrop函数

  1. <font color="#2f4f4f">function handleDrop(e) {  
  2.     if (e.preventDefault) {  
  3.         e.preventDefault(); //不要执行与事件关联的默认动作  
  4.     }  
  5.     if (e.stopPropagation) {  
  6.         e.stopPropagation(); //停止事件的传播  
  7.     }  
  8.     this.innerHTML = parseInt(this.innerHTML)+parseInt(e.dataTransfer.getData("text/plain"))  
  9.     console.log(e);  
  10.     return false;  
  11. }  </font>
复制代码

好了,到现在为止,准备知识都差不多了,而且作品我们也可以得意的玩玩,你可以发现div被累计都,再次拖拉的时候,是重新计算相互的倍数的,对不?

最后,我感觉黑色的字不好看,我们修改下初始化的函数

  1. <font color="#2f4f4f">$(  
  2. function() {  
  3.     [ ].forEach.call(document.querySelectorAll("div"),  
  4. function(item) {  
  5.     item.addEventListener("dragstart", handleDragStart, false);  
  6.     item.addEventListener("dragend", handleDragEnd, false);  
  7.     item.style.color = "White";  
  8. }  
  9. );  
  10. }  
  11. );  </font>
复制代码
  现在这个无聊的拖动作品,至少可以打发下你的时间,对不,欣赏下自己的作品吧,接下来,我们开始做正式做数独游戏了。
    第一步,我们先生成一个1-9的数字对象矩形,这个矩形可以拖动。
    先设计htmltag
  1. <font color="#2f4f4f"><ol id="numberBox" style="list-style-type: none; width: 90px; height: 90px;">  
  2. </ol></font>
复制代码
然后准备些样式
  1. <font color="#2f4f4f">#numberBox > li  
  2. {  
  3.     width: 30px;  
  4.     height: 25px;  
  5.     text-align: center;  
  6.     font-size: 20px;  
  7.     padding-top: 5px;  
  8.     float: left;  
  9.     color: White;  
  10. }  </font>
复制代码
最后是脚本

  1. <font color="#2f4f4f"> $(  
  2. function() {  
  3.     [{ number: 1, bgcolor: "#C71585" }, { number: 2, bgcolor: "#800080" }, { number: 3, bgcolor: "#B8860B" },  
  4.     { number: 4, bgcolor: "rgb(0,0,128)" }, { number: 5, bgcolor: "rgb(30,144,255)" },   
  5.     { number: 6, bgcolor: "rgb(255,165,0)" },  
  6.      { number: 7, bgcolor: "hsl(0,75%,50%)" }, { number: 8, bgcolor: "hsl(30,50%,50%)" },   
  7.      { number: 9, bgcolor: "hsl(120,75%,38%)"}].forEach(  
  8.      function(key, index) {  
  9.      $.log(key);  
  10.          var li = $("<li>").html(key.number).css("backgroundColor", key.bgcolor).attr("draggable","true");  
  11.          $.log(li);  
  12.          li[0].addEventListener("dragstart", function() {  
  13.          }, false);  
  14.          $("#numberBox").append(li);  
  15.      }  
  16.      );  
  17. }  
  18. );  </font>
复制代码
好,然后你运行下页面,可以看到一个九宫格,并且每一个格子都可以拖动。

    第二步,我们要类似的创建我们填数字得的区域了。
    首先还是htmlTag

  1. <font color="#2f4f4f"><ol id="player" style="list-style-type: none; width: 450px; height: 450px;">  
  2. </ol>  </font>
复制代码
然后是样式设定
  1. <font color="#2f4f4f">#player .default  
  2. {  
  3.     float: left;  
  4.     width: 48px;  
  5.     height: 33px;  
  6.     border: solid 1px rgb(0,0,0);  
  7.     font-size: 20px;  
  8.     padding-top: 15px;  
  9.     text-align: center;  
  10.     background-color: #B8860B;  
  11. }  
  12. #player .fix  
  13. {  
  14.     float: left;  
  15.     width: 48px;  
  16.     height: 33px;  
  17.     border: solid 1px rgb(0,0,0);  
  18.     font-size: 20px;  
  19.     padding-top: 15px;  
  20.     text-align: center;  
  21.     background-color: #FFFABC;  
  22. }  
  23. #player .ation  
  24. {  
  25.     float: left;  
  26.     width: 48px;  
  27.     height: 33px;  
  28.     border: solid 1px rgb(0,0,0);  
  29.     font-size: 20px;  
  30.     padding-top: 15px;  
  31.     text-align: center;  
  32.     background-color: #FFA07A;  
  33. }  </font>
复制代码
然后初始化这个区域。数独填字区域有的格子有值有的没有值,我用0表示没有值将来你可以填制,非0表示是固定区不可以改

  1. <font color="#2f4f4f"> $(  
  2. function() {  
  3.     "500000300090500400004000700051037289302080604008052137035000900609000823080023006".split("").forEach(  
  4.     function(item, index) {  
  5.         $.log(item);  
  6.         var li = $("<li>")  
  7.         if (item != "0") {  
  8.             li.addClass("fix");  
  9.             li[0].innerHTML = item;  
  10.         }  
  11.         else {  
  12.             li[0].classList.add("default");  
  13.             li[0].addEventListener("dragenter",  
  14.             function(e) {  
  15.                 $.log(e);  
  16.             }, false);  
  17.   
  18.             li[0].addEventListener("dragover",  
  19.             function(e) {  
  20.                 if (e.preventDefault) {  
  21.                     e.preventDefault(); //不要执行与事件关联的默认动作  
  22.                 }  
  23.                 if (e.stopPropagation) {  
  24.                     e.stopPropagation(); //停止事件的传播  
  25.                 }  
  26.                 $.log(e);  
  27.                 return false;  
  28.             }, false);  
  29.   
  30.             li[0].addEventListener("dragleave",  
  31.             function(e) {  
  32.             }, false);  
  33.   
  34.             li[0].addEventListener("drop",  
  35.             function(e) {  
  36.                 if (e.preventDefault) {  
  37.                     e.preventDefault(); //不要执行与事件关联的默认动作  
  38.                 }  
  39.                 if (e.stopPropagation) {  
  40.                     e.stopPropagation(); //停止事件的传播  
  41.                 }  
  42.   
  43.             }, false);  
  44.         }  
  45.         $("#player").append(li);  
  46.     }  
  47.     );  
  48. }  
  49. );  </font>
复制代码
现在你已经可以在页面上看到一个非常威武的“独”字了!

    第三步:我们拖动数字之后,希望可以填数字的区域有明显的颜色变化并给出提示,同时固定区域不可以拖进去,其他区域可以拖进去,并且拖动的时候要send值。
    有了前面的知识,我们马上知道去哪里改事件控制了:dragstart事件

  1. <font color="#2f4f4f"> $(  
  2. function() {  
  3.     [{ number: 1, bgcolor: "#C71585" }, { number: 2, bgcolor: "#800080" }, { number: 3, bgcolor: "#B8860B" },  
  4.     { number: 4, bgcolor: "rgb(0,0,128)" }, { number: 5, bgcolor: "rgb(30,144,255)" },  
  5.     { number: 6, bgcolor: "rgb(255,165,0)" },  
  6.      { number: 7, bgcolor: "hsl(0,75%,50%)" }, { number: 8, bgcolor: "hsl(30,50%,50%)" },  
  7.      { number: 9, bgcolor: "hsl(120,75%,38%)"}].forEach(  
  8.      function(key, index) {  
  9.          //$.log(key);  
  10.          var li = $("<li>").html(key.number).css("backgroundColor", key.bgcolor).attr("draggable", "true");  
  11.          //$.log(li);  
  12.          li[0].addEventListener("dragstart", function(e) {  
  13.              e.dataTransfer.effectAllowed = "copyMove";  
  14.              e.dataTransfer.setData("text/plain", this.innerHTML);  
  15.              $.log(this.innerHTML);  
  16.              [ ].forEach.call(document.querySelectorAll("#player .default"),  
  17.          function(item) {  
  18.              //$.log(item);  
  19.              item.classList.remove("default");  
  20.              item.classList.add("ation");  
  21.          });  
  22.          }, false);  
  23.   
  24.          li[0].addEventListener("dragend", function() {  
  25.              [ ].forEach.call(document.querySelectorAll("#player .ation"),  
  26.          function(item) {  
  27.              item.classList.remove("ation");  
  28.              item.classList.add("default");  
  29.          });  
  30.          }, false);  
  31.   
  32.          $("#numberBox").append(li);  
  33.      }  
  34.      );  
  35. }  
  36. );  </font>
复制代码
现在你可以测试下了,当你拖动数字的时候,有明显的颜色改变,并且不同的区域你的鼠标样式也不同哦。

    第四步,我们接受值,并且判断这个值是否存在行列冲突,如果冲突就提示,否则改写

  1. <font color="#2f4f4f">$(  
  2. function() {  
  3.     "500000300090500400004000700051037289302080604008052137035000900609000823080023006".split("").forEach(  
  4.     function(item, index) {  
  5.         $.log(item);  
  6.         var li = $("<li>")  
  7.         if (item != "0") {  
  8.             li.addClass("fix");  
  9.             li[0].innerHTML = item;  
  10.         }  
  11.         else {  
  12.             li[0].classList.add("default");  
  13.             li[0].addEventListener("dragenter",  
  14.             function(e) {  
  15.                 $.log(e);  
  16.             }, false);  
  17.   
  18.             li[0].addEventListener("dragover",  
  19.             function(e) {  
  20.                 if (e.preventDefault) {  
  21.                     e.preventDefault(); //不要执行与事件关联的默认动作  
  22.                 }  
  23.                 if (e.stopPropagation) {  
  24.                     e.stopPropagation(); //停止事件的传播  
  25.                 }  
  26.                 $.log(e);  
  27.                 return false;  
  28.             }, false);  
  29.   
  30.             li[0].addEventListener("dragleave",  
  31.             function(e) {  
  32.             }, false);  
  33.   
  34.             li[0].addEventListener("drop",  
  35.             function(e) {  
  36.                 if (e.preventDefault) {  
  37.                     e.preventDefault(); //不要执行与事件关联的默认动作  
  38.                 }  
  39.                 if (e.stopPropagation) {  
  40.                     e.stopPropagation(); //停止事件的传播  
  41.                 }  
  42.   
  43.                 var sendData = e.dataTransfer.getData("text/plain");  
  44.                 //获得#player>li矩阵数组  
  45.                 var matrix = Array.prototype.slice.call(document.querySelectorAll("#player>li"));   
  46.                 var currIndex = matrix.indexOf(this); //获得当前元素的位置  
  47.                 var rowIndex = currIndex - currIndex % 9; //行开始的位置  
  48.                 var colIndex = currIndex % 9//列开始的位置  
  49.                 for (var i = rowIndex; i < rowIndex + 9; i++) {  
  50.                     if (i != currIndex && matrix[i].innerHTML == sendData) {  
  51.                         alert("对不起行上有数据重复,请小心哦!亲");  
  52.                         return;  
  53.                     }  
  54.                 }  
  55.                 for (var i = colIndex; i < 81; i = i + 9) {  
  56.                     if (i != currIndex && matrix[i].innerHTML == sendData) {  
  57.                         alert("对不起列上有数据重复,请小心哦!亲");  
  58.                         return;  
  59.                     }  
  60.                 }  
  61.                 this.innerHTML = sendData;  
  62.   
  63.             }, false);  
  64.         }  
  65.         $("#player").append(li);  
  66.     }  
  67.     );  
  68. }  
  69. );  </font>
复制代码
游客,如果您要查看本帖隐藏内容请回复

回复

使用道具 举报

发表于 2016-11-22 23:26:31 | 显示全部楼层
新手过来学习,大家多多指教,,
回复 支持 反对

使用道具 举报

发表于 2016-12-3 10:59:59 | 显示全部楼层
有用~有用~有用~有用~
回复 支持 反对

使用道具 举报

发表于 2016-12-3 11:00:23 | 显示全部楼层
hhhhhhhhhh
回复 支持 反对

使用道具 举报

发表于 2016-12-5 17:00:13 | 显示全部楼层
6666666666666
回复 支持 反对

使用道具 举报

发表于 2016-12-6 14:29:41 | 显示全部楼层
耶耶耶耶耶耶耶耶
回复 支持 反对

使用道具 举报

发表于 2016-12-12 17:42:18 | 显示全部楼层
这个游戏也好玩,开发好
回复 支持 反对

使用道具 举报

发表于 2016-12-15 14:56:54 | 显示全部楼层
群组增加群二维码/设置聊天背景/消息免打扰/视频讲
回复 支持 反对

使用道具 举报

发表于 2017-1-10 14:34:53 | 显示全部楼层
还好吧,挺好的
回复 支持 反对

使用道具 举报

发表于 7 天前 | 显示全部楼层
有兴趣看看的哦
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

关闭

网站推荐上一条 /2 下一条

关注蚂蚁HTML5社区官方微信
关注蚂蚁HTML5社区官方微信

邮箱:Admin@zzfriend.com QQ:791577401 木子牛HTML5工作室 版权所有

© 2014-2016 MUZINIU Inc.小黑屋|手机版|Archiver|HANGNIU  

Powered by MuZiNiuX3.2( 豫ICP备12017936号 )

快速回复 返回顶部 返回列表
              

豫公网安备 41078102000103号