▓▓▓▓▓▓ 大致介绍

  看了一个实现网页版2048小游戏的视频,觉得能做出自己以前喜欢玩的小游戏很有意思便自己动手试了试,真正的验证了这句话-不要以为你以为的就是你以为的,看视频时觉得看懂了,会写了,但是自己实现起来会遇到各种问题。比如,在最后判断游戏是否结束的时候,我写的语句语法是对的,但就是不执行。最后通过对视频源码的分析对比,发现原作者写的一个setTimeout定时器有额外的意思,本来我以为它就是简单的一个延时动画,其实他是在等待另外一个函数执行完毕。-_-||。最后还是很高兴能写出来,也改进了一些源代码的不足。

  jQuery在这个游戏中的应用并不多,如果对其中的jQuery语法有疑问,可以参考我写的jQuery学习之路(持续更新),里面有讲解

  预览:2048网页版

  这篇博客并不是详细的讲解,只是大致介绍函数的作用,其中实现的细节注释中有解释,网上的这个源码有点乱,如果想看比较整齐的源码或者视频的可以QQ联系我(免费)(找共同学习的伙伴)

▓▓▓▓▓▓ 思路

  这个小游戏可以抽象化分为3层(我觉得这样能更好理解)

    ◆最底下的一层是基本的样式(可见的)

    ◆中间的层是最主要的,是一个4x4的二维数组,游戏中我们都是对这个二维数组进行操作(不可见的)

    ◆最上面的一层也是一个4x4的二维数组,它只是根据第二层数组的每个数显示样式(可见的)

  我们通过最底下的一层显示最基本的16个小方格,通过键盘的按键或者手指在屏幕的滑动来操作中间层的数组,最后在通过最上面的一层显示出数字

▓▓▓▓▓▓ 基本结构与样式

  基本的结构和样式都挺简单,直接看代码

  结构:

  1. <div id="test2048">
  2. <div id="header">
  3. <h1>2048</h1>
  4. <a href="javascript:newgame()" >开始新的游戏</a>
  5. <p>分数:<span id="score">0</span></p>
  6. </div>
  7. <div id="container">
  8. <div class="cell" id="cell-0-0"></div>
  9. <div class="cell" id="cell-0-1"></div>
  10. <div class="cell" id="cell-0-2"></div>
  11. <div class="cell" id="cell-0-3"></div>
  12. <div class="cell" id="cell-1-0"></div>
  13. <div class="cell" id="cell-1-1"></div>
  14. <div class="cell" id="cell-1-2"></div>
  15. <div class="cell" id="cell-1-3"></div>
  16. <div class="cell" id="cell-2-0"></div>
  17. <div class="cell" id="cell-2-1"></div>
  18. <div class="cell" id="cell-2-2"></div>
  19. <div class="cell" id="cell-2-3"></div>
  20. <div class="cell" id="cell-3-0"></div>
  21. <div class="cell" id="cell-3-1"></div>
  22. <div class="cell" id="cell-3-2"></div>
  23. <div class="cell" id="cell-3-3"></div>
  24. </div>
  25. </div>

  

  样式:

  1. *{
  2. margin:;
  3. padding:;
  4. }
  5. #test2048{
  6. font-family: Arial;
  7. margin: 0 auto;
  8. text-align: center;
  9. }
  10. #header{
  11. margin: 20px;
  12. }
  13. #header a{
  14. font-family: Arial;
  15. text-decoration: none;
  16. display: block;
  17. color: white;
  18. margin: 20px auto;
  19. width: 125px;
  20. height: 35px;
  21. text-align: center;
  22. line-height: 40px;
  23. background-color: #8f7a66;
  24. border-radius: 10px;
  25. font-size: 15px;
  26. }
  27. #header p{
  28. font-family: Arial;
  29. font-size: 20px;
  30. }
  31. #container{
  32. width: 460px;
  33. height: 460px;
  34. background-color: #bbada0;
  35. margin: 0 auto;
  36. border-radius: 10px;
  37. position: relative;
  38. padding: 20px;
  39. }
  40. .cell{
  41. width: 100px;
  42. height: 100px;
  43. border-radius: 6px;
  44. background-color: #ccc0b3;
  45. position: absolute;
  46. }

CSS样式

  从CSS样式可以看出,我们并没有对每个格子的位置进行设置,因为如果用CSS给每个格子设置样式代码量太大,而且他们的位置有一定的规律,所以我们可以用js循环来完成每个格子样式的设置

  代码:

  1. // 初始化棋盘格
  2. function initialize(){
  3. for(var i=0;i<4;i++){
  4. for(var j=0;j<4;j++){
  5. // 设置棋盘格的位置
  6. var everyCell = $('#cell-'+ i +'-'+ j);
  7. everyCell.css({top:getPos(i),left:getPos(j)});
  8. }
  9. }
  10. }
  1. // 获取位置
  2. function getPos(num){
  3. return 20 + num*120;
  4. }

  这样我们的第一层就好了

  效果:

  现在构造第二层,即构建一个4x4的值全部为0的数组,由于在构造第二层时,有两层循环,所以我们可以在构造第一层时也能构造第二层

  第三层是用js生成16个格子,它和第一层的16个格子一一对应

  代码:

  1. // 数字格
  2. function numFormat(){
  3. for(var i=0;i<4;i++){
  4. for(var j=0;j<4;j++){
  5. $('#container').append('<div class="number" id="number-'+ i +'-'+ j +'"></div>')
  6.  
  7. // 设置数字格的位置,样式
  8. var everyNumber = $('#number-'+ i +'-'+ j);
  9. if(checkerboard[i][j] == 0){
  10. everyNumber.css({
  11. width:'0px',
  12. height:'0px',
  13. top:getPos(i) + 50,
  14. left:getPos(j) + 50
  15. })
  16. }else{
  17. everyNumber.css({
  18. width:'100px',
  19. height:'100px',
  20. top:getPos(i),
  21. left:getPos(j),
  22. backgroundColor:getBackgroundColor(checkerboard[i][j]),
  23. color:getColor(checkerboard[i][j])
  24. });
  25. everyNumber.text(checkerboard[i][j]);
  26. }
  27. }
  28. }
  29. }
  1. // 获取相应数字的背景颜色
  2. function getBackgroundColor(number){
  3.  
  4. switch (number) {
  5. case 2:return "#eee4da";break;
  6. case 4:return "#ede0c8";break;
  7. case 8:return "#f2b179";break;
  8. case 16:return "#f59563";break;
  9. case 32:return "#f67c5f";break;
  10. case 64:return "#f65e3b";break;
  11. case 128:return "#edcf72";break;
  12. case 256:return "#edcc61";break;
  13. case 512:return "#9c0";break;
  14. case 1024:return "#33b5e5";break;
  15. case 2048:return "#09c";break;
  16. case 4096:return "#a6c";break;
  17. case 8192:return "#93c";break;
  18. }
  19. }
  1. // 设置相应数字的文字颜色
  2. function getColor(number){
  3. if (number <= 4) {
  4. return "#776e65"
  5. }
  6. return "white";
  7. }

▓▓▓▓▓▓ 初始化

  在每次游戏重新开始时,都会在随机的位置出现两个随机的数字,我们写一个在随机位置出现一个随机数的函数,只要调用两次就可以实现了

  代码:

  1. // 随机的在一个位置上产生一个数字
  2. function randomNum(){
  3. // 随机产生一个坐标值
  4. var randomX = Math.floor(Math.random() * 4);
  5. var randomY = Math.floor(Math.random() * 4);
  6.  
  7. // 随机产生一个数字(2或4)
  8. var randomValue = Math.random() > 0.5 ? 2 : 4;
  9.  
  10. // 在数字格不为0的地方生成一个随机数字
  11. while(true){
  12. if(checkerboard[randomX][randomY] == 0){
  13. break;
  14. }else{
  15.  
  16. var randomX = Math.floor(Math.random() * 4);
  17. var randomY = Math.floor(Math.random() * 4);
  18. }
  19. }
  20.  
  21. // 将随机产生的数字显示在随机的位置上
  22. checkerboard[randomX][randomY] = randomValue;
  23.  
  24. // 动画
  25. randomNumAnimate(randomX,randomY,randomValue);
  26. }
  1. // 随机产生数字的动画
  2. function randomNumAnimate(randomX,randomY,randomValue){
  3. var randomnum = $('#number-'+ randomX +'-'+ randomY);
  4. randomnum.css({
  5. backgroundColor:getBackgroundColor(randomValue),
  6. color:getColor(randomValue),
  7. })
  8. .text(randomValue)
  9. .animate({
  10. width:'100px',
  11. height:'100px',
  12. top:getPos(randomX),
  13. left:getPos(randomY)
  14. },50);
  15. }

▓▓▓▓▓▓ 基本操作

  我们通过switch循环,来根据用户不同的输入进行不同的操作

  代码:

  1. // 获取键盘事件,检测不同的按键进行不同的操作
  2. $(document).keydown(function(event){
  3. switch(event.keyCode){
  4. case 37://左
  5. if(canMoveLeft(checkerboard)){
  6. // 如果可以向左移动
  7.  
  8. MoveLeft();
  9. // 向左移动
  10.  
  11. setTimeout(function(){
  12. randomNum();
  13. },200);
  14. // 随机产生一个数字
  15. }
  16. break;
  17. case 38://上
  18. if(canMoveUp(checkerboard)){
  19. // 如果可以向上移动
  20.  
  21. MoveUp();
  22. // 向上移动
  23.  
  24. setTimeout(function(){
  25. randomNum();
  26. },200);
  27. // 随机产生一个数字
  28. }
  29. break;
  30. case 39://右
  31. if(canMoveRight(checkerboard)){
  32. // 如果可以向右移动
  33.  
  34. MoveRight();
  35. // 向右移动
  36.  
  37. setTimeout(function(){
  38. randomNum();
  39. },200);
  40. // 随机产生一个数字
  41. }
  42. break;
  43. case 40://下
  44. if(canMoveDown(checkerboard)){
  45. // 如果可以向下移动
  46.  
  47. MoveDown();
  48. // 向下移动
  49.  
  50. setTimeout(function(){
  51. randomNum();
  52. },200);
  53. // 随机产生一个数字
  54. }
  55. break;
  56. default:
  57. break;
  58. }
  59. });

  由于数字格的移动只有左、上、右、下四种方式,并且他们都是大同小异的,所以就拿向左移动为例,

  向左移动,我们首先需要判断它是否能向左移动,能向左移动有两种情况

    第一种:当前格子的左边的格子是空的即值为0

    第二种:当前格子的值和左边格子的值相同

  由于向左移动,所以第一列的格子不可能向左移动,所以不需要判断

  代码:

  1. // 判断是否可以向左移动
  2. function canMoveLeft(checkerboard){
  3. for(var i=0;i<4;i++){
  4. for(var j=1;j<4;j++){
  5. if(checkerboard[i][j] != 0){
  6. // 如果这个数字格它左边的数字格为空或者左边的数字格和它相等,则可以向左移动
  7. if(checkerboard[i][j-1] == 0 || checkerboard[i][j] == checkerboard[i][j-1]){
  8. return true;
  9. }
  10. }
  11. }
  12. }
  13. return false;
  14. }

  判断能否向左移动后,我们就要对可以移动的格子进行移动,这里需要特别注意,向哪个方向移动就要先从哪个方向开始判断

  代码:

  1. // 向左移动
  2. function MoveLeft(){
  3. for(var i=0;i<4;i++){
  4. for(var j=1;j<4;j++){
  5. if(checkerboard[i][j] != 0){
  6. for(var k=0;k<j;k++){
  7. if(checkerboard[i][k] == 0 && noMiddleNumRow(i,k,j,checkerboard)){
  8. moveAnimation(i,j,i,k);
  9. checkerboard[i][k] = checkerboard[i][j];
  10. checkerboard[i][j] = 0;
  11. }else if(checkerboard[i][k] == checkerboard[i][j] && noMiddleNumRow(i,k,j,checkerboard) && !hasConflicted[i][k]){
  12. moveAnimation(i,j,i,k);
  13. checkerboard[i][k] += checkerboard[i][j];
  14. checkerboard[i][j] = 0;
  15.  
  16. }
  17. }
  18. }
  19. }
  20. }
  21. // 设置刷新的时间是为了让运动的动画走完在进行更新数字格,否则数字格运动的动画将会被打断
  22. setTimeout(function(){
  23. numFormat();
  24. },200);
  25. }
  1. // 判断中间的数字格是否为0(行)
  2. function noMiddleNumRow(row,col1,col2,checkerboard){
  3. for(var i=col1+1;i<col2;i++){
  4. if(checkerboard[row][i] != 0){
  5. return false;
  6. }
  7. }
  8. return true;
  9. }

  将上、右、下四个方向写完以后,游戏基本的操作就已经完成了。

▓▓▓▓▓▓ 游戏分数和判断游戏结束

  游戏的分数是每个相加的数的和,所以我们在每个数相加的时候更新分数就可以了

  代码:

  1. // 更新分数
  2. score += checkerboard[k][j];
  3. updateScore(score);
  1. // 设置分数
  2. function updateScore(num){
  3. $('#score').text(num);
  4. }

  判断游戏是否结束很简单,用我们之前定义的方法就可以实现

  代码:

  1. // 判断游戏是否结束
  2. function wheGameOver(checkerboard){
  3. if(!canMoveLeft(checkerboard) && !canMoveUp(checkerboard) && !canMoveRight(checkerboard) && !canMoveDown(checkerboard) ){
  4. showGameOver();
  5. }
  6. }
  1. // 显示游戏结束
  2. function showGameOver(){
  3. $('#container').append("<div id='gameover'><p>最终得分</p><span>"+ score +"</span><a href='javascript:resert();'>重新开始游戏</a></div> ")
  4. }
  5.  
  6. // 重新开始游戏
  7. function resert(){
  8. $('#gameover').remove();
  9. newgame();
  10. }

▓▓▓▓▓▓ 最后优化

  1、游戏中会出现一次移动,一个数会被累加很多次

  在原游戏中,每个数在每次操作中只能累加一次,所以我们在定义一个4x4的值为false的数组,与中间层的数组一一对应,专门用来防止一个数的多次累加,如果是false则可以累加,并将值改为false,否则不可以累加

  2、结束死循环

  由于在设置随机数的时候用到了一个死循环,但是在游戏结束后,该循环还在,所以我们在死循环中在添加一个条件,如果游戏结束就跳出循环

  3、最后的结束游戏提示不执行

 

  1. case 37://左
  2. if(canMoveLeft(checkerboard)){
  3. // 如果可以向左移动
  4.  
  5. MoveLeft();
  6. // 向左移动
  7.  
  8. setTimeout(function(){
  9. wheGameOver(checkerboard)
  10. },300);
  11. // 判断游戏是否结束,这里设置延时是因为要等到随机产生数字后再进行判断,如果不加
  12. // 延时,则最后一次的判断因为canMoveLeft(checkerboard)为false就不会再执行了
  13.  
  14. setTimeout(function(){
  15. randomNum();
  16. },200);
  17. // 随机产生一个数字
  18. }
  19. break;

  从代码中可以看出,判断游戏是否结束是在随机产生一个数字前执行的,所以在判断游戏结束时,总是有一个空的格子,所以代码执行后认为游戏没有结束,但是当这个随机数字产生后,所有的格子不能移动,当我们按键时,if条件不通过,判断游戏是否结束的函数不能执行。所以我们要给判断游戏结束的函数设置定时器,让他在随机产生一个数字后再进行判断

  4、在移动端可以执行

  由于原作者没有写有关移动端的操作,所以我在网上找的判断移动端触屏手机滑动位置的代码,加入了游戏的事件就可以执行了

  1. //返回角度
  2. function GetSlideAngle(dx, dy) {
  3. return Math.atan2(dy, dx) * 180 / Math.PI;
  4. }
  5.  
  6. //根据起点和终点返回方向 1:向上,2:向下,3:向左,4:向右,0:未滑动
  7. function GetSlideDirection(startX, startY, endX, endY) {
  8. var dy = startY - endY;
  9. var dx = endX - startX;
  10. varresult = 0;
  11.  
  12. //如果滑动距离太短
  13. if(Math.abs(dx) < 2 && Math.abs(dy) < 2) {
  14. returnresult;
  15. }
  16.  
  17. var angle = GetSlideAngle(dx, dy);
  18. if(angle >= -45 && angle < 45) {
  19. result = 4;
  20. }else if (angle >= 45 && angle < 135) {
  21. result = 1;
  22. }else if (angle >= -135 && angle < -45) {
  23. result = 2;
  24. }
  25. else if ((angle >= 135 && angle <= 180) || (angle >= -180 && angle < -135)) {
  26. result = 3;
  27. }
  28.  
  29. return result;
  30. }
  31.  
  32. //滑动处理
  33. var startX, startY;
  34. document.addEventListener('touchstart',function (ev) {
  35. startX = ev.touches[0].pageX;
  36. startY = ev.touches[0].pageY;
  37. }, false);
  38. document.addEventListener('touchend',function (ev) {
  39. var endX, endY;
  40. endX = ev.changedTouches[0].pageX;
  41. endY = ev.changedTouches[0].pageY;
  42. var direction = GetSlideDirection(startX, startY, endX, endY);
  43. switch(direction) {
  44. case 0:
  45. //没滑动
  46. break;
  47. case 1:
  48. if(canMoveUp(checkerboard)){
  49. // 如果可以向上移动
  50.  
  51. MoveUp();
  52. // 向上移动
  53.  
  54. setTimeout(function(){
  55. wheGameOver(checkerboard)
  56. },300);
  57. // 判断游戏是否结束
  58.  
  59. setTimeout(function(){
  60. randomNum();
  61. },200);
  62. // 随机产生一个数字
  63. }
  64. break;
  65. case 2:
  66. if(canMoveDown(checkerboard)){
  67. // 如果可以向下移动
  68.  
  69. MoveDown();
  70. // 向下移动
  71.  
  72. setTimeout(function(){
  73. wheGameOver(checkerboard)
  74. },300);
  75. // 判断游戏是否结束
  76.  
  77. setTimeout(function(){
  78. randomNum();
  79. },200);
  80. // 随机产生一个数字
  81. }
  82. break;
  83. case 3:
  84. if(canMoveLeft(checkerboard)){
  85. // 如果可以向左移动
  86.  
  87. MoveLeft();
  88. // 向左移动
  89.  
  90. setTimeout(function(){
  91. wheGameOver(checkerboard)
  92. },300);
  93. // 判断游戏是否结束,这里设置延时是因为要等到随机产生数字后再进行判断,如果不加
  94. // 延时,则最后一次的判断因为canMoveLeft(checkerboard)为false就不会再执行了
  95.  
  96. setTimeout(function(){
  97. randomNum();
  98. },200);
  99. // 随机产生一个数字
  100. }
  101. break;
  102. case 4:
  103. if(canMoveRight(checkerboard)){
  104. // 如果可以向右移动
  105.  
  106. MoveRight();
  107. // 向右移动
  108.  
  109. setTimeout(function(){
  110. wheGameOver(checkerboard)
  111. },300);
  112. // 判断游戏是否结束
  113.  
  114. setTimeout(function(){
  115. randomNum();
  116. },200);
  117. // 随机产生一个数字
  118. }
  119. break;
  120. default:
  121. }
  122. }, false);

▓▓▓▓▓▓ 总结

  总体来说这个游戏实现起来并不是太难,就是许多小的操作集合起来

  如果想看视频或者源码请QQ联系我

jQuery实践-网页版2048小游戏的更多相关文章

  1. c#撸的控制台版2048小游戏

    1.分析 最近心血来潮,突然想写一个2048小游戏.于是搜索了一个在线2048玩玩,熟悉熟悉规则. 只谈核心规则:(以左移为例) 1.1合并 以行为单位,忽略0位,每列依次向左进行合并,且每列只能合并 ...

  2. jQuery网页版五子棋小游戏源码下载

    体验效果:http://hovertree.com/texiao/game/4/ 网页五子棋源代码: <!DOCTYPE html> <html> <head> & ...

  3. 基于jQuery的2048小游戏设计(网页版)

    上周模仿一个2048小游戏,总结一下自己在编写代码的时候遇到的一些坑. 游戏规则:省略,我想大部分人都玩过,不写了 源码地址:https://github.com/xinhua6/2048game.g ...

  4. js、jQuery实现2048小游戏

    2048小游戏 一.游戏简介:  2048是一款休闲益智类的数字叠加小游戏 二. 游戏玩法: 在4*4的16宫格中,您可以选择上.下.左.右四个方向进行操作,数字会按方向移动,相邻的两个数字相同就会合 ...

  5. 2048小游戏代码解析 C语言版

    2048小游戏,也算是风靡一时的益智游戏.其背后实现的逻辑比较简单,代码量不算多,而且趣味性强,适合作为有语言基础的童鞋来加强编程训练.本篇分析2048小游戏的C语言实现代码. 前言 游戏截图:  游 ...

  6. .NET手撸2048小游戏

    .NET手撸2048小游戏 2048是一款益智小游戏,得益于其规则简单,又和2的倍数有关,因此广为人知,特别是广受程序员的喜爱. 本文将再次使用我自制的"准游戏引擎"FlysEng ...

  7. Swift实战之2048小游戏

    上周在图书馆借了一本Swift语言实战入门,入个门玩一玩^_^正好这本书的后面有一个2048小游戏的实例,笔者跟着实战了一把. 差不多一周的时间,到今天,游戏的基本功能已基本实现,细节我已不打算继续完 ...

  8. 如何在CentOS上安装一个2048小游戏

    如何在centos上安装一个2048小游戏 最近在学习CentOS系统,就琢磨着玩点什么,然后我看到有人在玩2048小游戏,所有我就在想,为啥不装一个2048小游戏搞一下嘞,于是乎,我就开始工作啦 由 ...

  9. C# 开发2048小游戏

    这应该是几个月前,闲的手痒,敲了一上午代码搞出来的,随之就把它丢弃了,当时让别人玩过,提过几条更改建议,但是时至今日,我也没有进行过优化和更改(本人只会作案,不会收场,嘎嘎),下面的建议要给代码爱好的 ...

随机推荐

  1. Windows 7上执行Cake 报错原因是Powershell 版本问题

    在Windows 7 SP1 电脑上执行Cake的的例子 http://cakebuild.net/docs/tutorials/getting-started ,运行./Build.ps1 报下面的 ...

  2. CSS Position 定位属性

    本篇文章主要介绍元素的Position属性,此属性可以设置元素在页面的定位方式. 目录 1. 介绍 position:介绍position的值以及辅助属性. 2. position 定位方式:介绍po ...

  3. webapp应用--模拟电子书翻页效果

    前言: 现在移动互联网发展火热,手机上网的用户越来越多,甚至大有超过pc访问的趋势.所以,用web程序做出仿原生效果的移动应用,也变得越来越流行了.这种程序也就是我们常说的单页应用程序,它也有一个英文 ...

  4. jQuery.Ajax IE8 无效(CORS)

    今天在开发的时候,遇到一个问题,$.get()在 IE8 浏览器不起作用,但 Chrome,Firefox 却是可以的,网上资料很多,最后发现是 IE8 默认不支持 CORS 请求,需要手动开启下: ...

  5. ZKWeb网页框架1.4正式发布

    本次更新的内容有 添加更快的批量操作函数 添加IDatabaseContext.FastBatchSave 添加IDatabaseContext.FastBatchDelete 注意这些函数不会触发注 ...

  6. js闭包 和 prototype

    function test(){ var p=200; function q(){ return p++; } return q; } var s = test(); alert(s()); aler ...

  7. 程序员必须要知道的Hadoop的一些事实

    程序员必须要知道的Hadoop的一些事实.现如今,Apache Hadoop已经无人不知无人不晓.当年雅虎搜索工程师Doug Cutting开发出这个用以创建分布式计算机环境的开源软...... 1: ...

  8. __Block与__Weak区别

    一.__block理解: Blocks可以访问局部变量,但是不能修改, 声明block的时候实际上是把当时的临时变量又复制了一份, 在block里即使修改了这些复制的变量,也不影响外面的原始变量.即所 ...

  9. Hyper-V上运行的Linux虚拟机验证是否安装了集成服务

    Hyper-V上运行的Linux虚拟机验证是否安装了集成服务 ps aux|grep "hv"root       311  0.0  0.0      0     0 ?     ...

  10. 认识ASP.NET 5项目结构和项目文件xproj

    ASP.NET 5 在项目结构上做了很大的改变,我们以前熟悉的目录结构与项目文件内容都不太一样了,本篇文章带大家了解 ASP.NET 5 到底跟以前有哪些不一样的地方. 我们先用 Visual Stu ...