| 注册
请输入搜索内容

热门搜索

Java Linux MySQL PHP JavaScript Hibernate jQuery Nginx
程序猿123
10年前发布

JavaScript任意数量的拼图游戏

(function($) {      var puzzleConfig = {          sizeX: 3,          sizeY: 3      };         //全局常量      var Constants={          //每一片拼图透明度较低时候的透明度值          fadeOpacity: 0.8,          //放拼图元素的水平方向padding+border的合计值,用于载入拼图后控制容器尺寸          puzzleContainerExtra: 42      };         //图片相关变量      var puzzleImage=null,      imageURL="",      //图片上传标识,为true时表示相关设置合理,选择图片后将进入游戏      checkFlag=false,      imageWidth=0,      imageHeight=0;         //拼图相关变量      var puzzleWidth=0,      puzzleHeight=0,      puzzleItemWidth=0,      puzzleItemHeight=0,      puzzleSizeX=0,      puzzleSizeY=0,      //拼图数目      puzzleNumber=0,      //计数器,计算从开始到完成游戏用的步数      moveStepCount=0,      //拼图步数以及是否完成的提示文字      puzzleNote=null,      //保存每一片拼图的正确的坐标值的数组      validPosArrayX=[],      validPosArrayY=[],      //保存每一片拼图的数组,索引顺序和正确的拼图顺序相同      puzzleArray = [],      //整个拼图元素本身      puzzle=null,      //最终放置该拼图的父元素节点      puzzleSetElem=null;         //初始第一步,读取拼图设置和图片源,包括对填写内容的验证*/      var puzzleConfigSet = function() {          //类名常量          var sizeInputClassName = "size_input",              noteWarnClassName = "note_warn",              currentProgressClassName = "current_progress",              validImageSuffix = ".jpg|.jpeg|.gif|.bmp|.png";             //放置拼图的由外层变量保存的元素          puzzleSetElem=$ ("puzzleSet");             //取得对应元素          var sizeXElem = $("sizeX"),              sizeYElem = $("sizeY"),              sizeSetNote = $("sizeSetNote"),              uploadBtn = $("uploadBtn"),              fileImage = $("fileImage"),              uploadProgress = $("uploadProgress"),              currentProgress = uploadProgress.getFirst("." + currentProgressClassName),              uploadNote = $("uploadNote");             //拼图尺寸设定检查          var puzzleSizeCheck = function() {              var sizeX = sizeXElem.value,                  sizeY = sizeYElem.value,                  numberReg = /^\d{1,2}$/;              if (numberReg.test(sizeX) && numberReg.test(sizeY)) {                  if (sizeX >= 2 && sizeX <= 10 && sizeY >= 2 && sizeY <= 10) {                      puzzleConfig.sizeX = sizeX;                      puzzleConfig.sizeY = sizeY;                      checkFlag = true;                  } else {                      sizeSetNote.addClass(noteWarnClassName);                  }              } else {                  sizeSetNote.addClass(noteWarnClassName);              }          };             //图片尺寸检查          var imageCheck = function(image) {              var minWidth = 30,                  maxWidth = 850,                  minHeight = 30;              if (image.width >= 30 && image.width <= 850 && image.height > 30) {                  checkFlag = checkFlag && true;              } else {                  uploadNote.addClass(noteWarnClassName);                  checkFlag = false;              }          };             //图片格式检查          var formatCheck = function(image) {              var fileURL = fileImage.value.toLowerCase();              //获取文件拓展名              formatSuffix = fileURL.substring(fileURL.lastIndexOf("."));              if (formatSuffix&&validImageSuffix.contains(formatSuffix)) {                  //如果是正确格式的图片文件                  checkFlag = checkFlag && true;              } else {                  alert("请上传正确格式的图片文件(" + validImageSuffix + ")");                  checkFlag = false;              }          };             //拼图尺寸输入框的事件          $$("." + sizeInputClassName).addEvent("focus", function() {              sizeSetNote.removeClass(noteWarnClassName);          });             //读取选择上传的图片          puzzleImage = new Image();          puzzleImage.onload = function() {              imageCheck(puzzleImage);              if (checkFlag) {                  imageWidth = puzzleImage.width;                  //由于图片尺寸不一定能被拼图尺寸整除,因此做边缘裁剪                  while(imageWidth % puzzleConfig.sizeX != 0){                      imageWidth--;                  }                  imageHeight = puzzleImage.height;                  while(imageHeight % puzzleConfig.sizeY != 0){                      imageHeight--;                  }                  imageURL= puzzleImage.src;                  puzzleSetElem.empty();                  var containerWidth = imageWidth+Constants.puzzleContainerExtra,                  properContainerWidth = containerWidth>120?containerWidth:120;                  puzzleSetElem.getParent().setStyles({                      width: properContainerWidth                  });                  createPuzzle(); //创建拼图              }              else{                  //如果读取后图片尺寸不合适的话,重置图片上传                  uploadProgress.style.display = "none";                  currentProgress.setStyle("width", 0);                  uploadBtn.style.display = "";              }          };          if (typeof FileReader == "undefined") {              //如果是不支持File API的浏览器              fileImage.onchange = function() {                  puzzleSizeCheck();                  if (checkFlag) {                      formatCheck();                  }                  if (checkFlag) {                      puzzleImage.src =  fileImage.value;                  }              };          } else {              //如果支持File API,可以显示读取进度条              var imageReader = new FileReader();                 //对象URL(blob URL),经测试新版Chrome也支持window.URL              function createObjectURL(blob){                  if(window.URL){                      return window.URL.createObjectURL(blob);                  }else if(window.webkitURL){                      return window.webkitURL.createObjectURL(blob);                  }else{                      return null;                  }              }              //开始读取              imageReader.onloadstart = function() {                  puzzleSizeCheck();                  if(checkFlag){                      formatCheck();                  }                  if (checkFlag) {                      uploadBtn.style.display = "none";                      uploadProgress.style.display = "";                  }              };              //读取中              imageReader.onprogress = function(event) {                  if (checkFlag) {                      var percentage = 100 * parseInt(event.loaded / event.total) + "%";                      currentProgress.setStyle("width", percentage);                  }              };              imageReader.onload = function(event) {                  if (checkFlag) {                          //IE10也支持blob URL                          var url=createObjectURL(fileImage.files[0]);                          puzzleImage.src = url;                  }              };              fileImage.onchange = function() {                  imageReader.readAsDataURL(fileImage.files[0]);              };          }      };         //用于创建拼图      var createPuzzle = function() {              //classNameSet表示生成的元素的class名              var classNameSet = {                  listContainer: "puzzle_container",                  list: "puzzle_list",                  item: "puzzle_item"              };              //各类元素对应的基本样式              var puzzleStyle = {                  listContainer: {                      position: "relative",                      width: imageWidth,                      height: imageHeight,                      margin: "0 auto"                  },                  list: {                     },                  item: {                      position: "absolute"                  }              };              //计算得到每一块拼图的尺寸              puzzleSizeX = puzzleConfig.sizeX;              puzzleSizeY = puzzleConfig.sizeY;              puzzleWidth = imageWidth;              puzzleHeight = imageHeight;              puzzleItemWidth = puzzleWidth / puzzleSizeX;              puzzleItemHeight = puzzleHeight / puzzleSizeY;              puzzleNumber = puzzleSizeX * puzzleSizeY;                 //建立一个临时数组,用于生成随机顺序的拼图块              var randomOrderPuzzleArray=[];                 //创建元素              puzzle = elementsCreate();              showAnime();                 //创建整个拼图的dom,返回最外层的父级元素              function elementsCreate() {                  var listContainer = new Element("div");                  listContainer.addClass(classNameSet.listContainer);                  listContainer.setStyles(puzzleStyle.listContainer);                     var list = new Element("ul");                  list.addClass(classNameSet.list);                  list.setStyles(puzzleStyle.list);                     //先通过循环,创建每一个拼图块,并按正确顺序存入数组                  for(var i = 0, len = puzzleNumber; i < len; i++) {                      var item = new Element("li");                      //为每块拼图保存自身的正确索引                      var indexSet = i + 1;                      item.store("puzzleIndex", indexSet);                      item.addClass(classNameSet.item);                      //增加基本样式                      item.setStyles(puzzleStyle.item);                         //以正确顺序保存每一个拼图块到数组                      puzzleArray.push(item);                  }                     //建立一个正确顺序数组的副本                  var puzzleArrayClone=puzzleArray.clone();                     //再次通过循环,创建一个乱序的拼图数组,并把这个数组显示到页面中                  for (i = 0, len = puzzleNumber; i < len; i++) {                      var randomItem = puzzleArrayClone.getRandom();                      //为避免重复,需要把被取出来的元素在副本数组中删除                      puzzleArrayClone.erase(randomItem);                         //为每一块取出来的元素设置可变的位置索引                      var posIndex = i + 1;                      randomItem.posIndex = posIndex;                         //获取取出来的元素的正确索引,用于接下来计算拼图背景图位置                      var correctIndex = randomItem.retrieve("puzzleIndex");                         //计算位置                      var topSet = Math.floor((posIndex - 1) / puzzleSizeX) * puzzleItemHeight,                          leftSet = (posIndex - 1) % puzzleSizeX * puzzleItemWidth,                             //计算符合正确索引的背景图位置                          backgroundSetX = -(correctIndex - 1) % puzzleSizeX * puzzleItemWidth,                          backgroundSetY = -(Math.floor((correctIndex - 1) / puzzleSizeX) * puzzleItemHeight),                          backgroundString = "url(" + imageURL + ") " + backgroundSetX + "px " + backgroundSetY + "px " + "no-repeat";                         //添加关键样式                      randomItem.setStyles({                          width: Math.ceil(puzzleItemWidth),                          height: Math.ceil(puzzleItemHeight),                          background: backgroundString,                          left: leftSet,                          top: topSet,                          zIndex: posIndex                      });                         //生成合理的位置坐标数组                      validPosArrayX.push(leftSet);                      validPosArrayY.push(topSet);                         //存放乱序元素到乱序数组                      randomOrderPuzzleArray.push(randomItem);                  }                     //组合拼图的各个元素                  list.adopt(randomOrderPuzzleArray);                  listContainer.adopt(list);                     return listContainer;              }                 //为拼图的初始化创建动画              function showAnime(){                  //一些动画参数                  var timeSpace=50,                  //垂直移动的间距                  distance=30,                   //计数用                  count=0,                  timeFlag;                             //所有拼图先隐藏,透明度置为0                  for(var i=0,len=puzzleArray.length;i<len;i++){                      puzzleArray[i].setStyle("opacity",0);                  }                     //更新到页面dom中,准备开始动画                  puzzleSetElem.grab(puzzle);                     var enterFrameHandler=function(){                      var puzzleItem=randomOrderPuzzleArray[count++];                      var endTop=parseInt(puzzleItem.getStyle("top"));                      var startTop=endTop-distance;                         puzzleItem.set("morph",{                          transition: Fx.Transitions.Quad.easeOut                      });                      puzzleItem.morph({                          top:[startTop,endTop],                          opacity:Constants.fadeOpacity                      });                         if(count<puzzleNumber){                          //对最后一个拼图块的动画结束做侦听                          if(count==puzzleNumber-1){                              var lastMorph=puzzleItem.get("morph");                              var showAnimeEnd=function(){                                  lastMorph.removeEvent("complete",showAnimeEnd);                                  puzzleEventBind();                              }                              lastMorph.addEvent("complete",showAnimeEnd);                          }                          timeFlag=setTimeout(enterFrameHandler,timeSpace);                      }                  };                  timeFlag=setTimeout(enterFrameHandler,timeSpace);              }             };         //拼图的相关事件绑定,也是游戏的核心控制逻辑      var puzzleEventBind=function(){          //拼图游戏控制相关的变量          var selectedItem=null,          //当前选中的拼图位置索引          selectedIndex=0,          //用于保存当前鼠标正在拖动的拼图的zIndex值          selectedItemZIndex=0,          //每一次切换拼图位置的时候,都涉及到2块拼图,鼠标拖动的这块和交换位置的另外一块,这个就是另外一块          relatedItem=null,          //依照鼠标当前的位置,判断得到的目标索引,如果鼠标此时放开,就是说把选中的拼图移到现在鼠标所在的位置          targetIndexNew=0,          //通过new和old来区分鼠标从一个目标索引更换到另一个目标索引          targetIndexOld=0,          //判断是否进行一次拼图位置移动的逻辑值,只有当目标索引值有改变时,才允许进行拼图位置移动          isTargetIndexChanged=false,          //判断鼠标指针是否在拼图的区域之内          isInsidePuzzle=false,          //鼠标点击拼图的某一个点的时候,距离拼图的左上角定位点有的距离值          disX=0,          disY=0;             //计算获取整个拼图的左上角点的坐标          var puzzlePos=puzzle.getPosition();          var puzzlePosX=puzzlePos.x,          puzzlePosY=puzzlePos.y;             //重新设置每一个元素的动画速度          (function(){              for(var i=0,len=puzzleArray.length;i<len;i++){                  var puzzleItem=puzzleArray[i];                  puzzleItem.set("morph",{                      duration:250                  });              }          })();             //计数函数准备          var updateCount = (function(){              var stepCount = $("stepCount");              puzzleNote = stepCount.getParent();              return function(){                  stepCount.set("text", moveStepCount);              };          })();             //添加事件          puzzle.addEvent("mouseover",mouseOverHandler);          puzzle.addEvent("mouseout",mouseOutHandler);          puzzle.addEvent("mousedown",mouseDownHandler);          puzzle.addEvent("mouseup",mouseUpHandler);             //鼠标经过          function mouseOverHandler(event){              var target=event.target;              if(puzzleArray.contains(target)){                  target.setStyle("opacity",1);              }          }             //鼠标移出          function mouseOutHandler(event){              var target=event.target;              if(puzzleArray.contains(target)){                  target.setStyle("opacity",Constants.fadeOpacity);              }          }             //鼠标按下          function mouseDownHandler(event){              var target=event.target;              //race("[mouseDownHandler]selectedItem ="+selectedItem);              //如果当前没有其他目标选中,且鼠标选中的目标是拼图块              if(!selectedItem&&puzzleArray.contains(target)){                  if(target.getStyle("opacity")<1){                      target.setStyle("opacity",1);                  }                     //设置当前选中的目标及索引                  selectedItemZIndex=target.getStyle("zIndex");                  target.setStyle("zIndex",5000);                  selectedItem=target;                  selectedIndex=target.posIndex;                     //设置初始目标索引                  targetIndexNew=targetIndexOld=selectedIndex;                     //计算出鼠标点击的点和拼图左上角定位点的偏差距离                  var targetPos=target.getPosition();                  disX=event.page.x-targetPos.x;                  disY=event.page.y-targetPos.y;                     //增加鼠标移动的事件侦听,让拼图块跟随鼠标移动,并判断当前位置                  document.addEvent("mousemove",mouseMoveHandler);              }          }             //鼠标松开          function mouseUpHandler(event){              //如果有元素处于拖动状态,取消              if(selectedItem){                  selectedItem.setStyle("opacity",Constants.fadeOpacity);                  selectedItem.setStyle("zIndex",selectedItemZIndex);                  document.removeEvent("mousemove",mouseMoveHandler);                     //松开之后,根据目标索引和拖动元素的索引,移动拼图,并更新dom结构                  if(isInsidePuzzle){                      //如果目标索引是一块别的拼图                      if(targetIndexNew!=selectedIndex){                          puzzleItemMove(selectedItem,targetIndexNew,puzzleItemSwitch);                      }else{                          //还原回原来的位置                          puzzleItemMove(selectedItem,selectedIndex);                          selectedItem=null;                          relatedItem=null;                      }                  }else{                      //如果鼠标在拼图之外的区域松开,则被拖动的拼图还原回原来的位置                      puzzleItemMove(selectedItem,selectedIndex);                      selectedItem=null;                      relatedItem=null;                      targetIndexNew = targetIndexOld = selectedIndex;                  }              }          }             //鼠标移动          function mouseMoveHandler(event){              var mouseX=event.page.x,              mouseY=event.page.y;                 event.preventDefault();                 //设置选中元素的位置,跟随鼠标              selectedItem.setPosition({                  x:mouseX-disX-puzzlePosX,                  y:mouseY-disY-puzzlePosY              })                 //计算鼠标当前位置是否在拼图区域之内(拼图边缘也算在外)              isInsidePuzzle=(function(){                  if(mouseX<=puzzlePosX||mouseX-puzzlePosX>=puzzleWidth){                      return false;                  }                  if(mouseY<=puzzlePosY||mouseY-puzzlePosY>=puzzleHeight){                      return false;                  }                  return true;              })();                 //如果鼠标当前位置在拼图区域之内,再做目标索引计算              if(isInsidePuzzle){                  //race("[mouseMoveHandler]isInsidePuzzle = true");                     //计算目标索引,xIndex和yIndex分别表示当前位置所处的列序号和行序号                  var xIndex=Math.ceil((mouseX-puzzlePosX)/puzzleItemWidth),                  yIndex=Math.ceil((mouseY-puzzlePosY)/puzzleItemHeight);                  targetIndexNew=(yIndex-1)*puzzleSizeX+xIndex;                     if(targetIndexNew!=targetIndexOld){                      isTargetIndexChanged=true;                  }                  //只有当目标索引发生改变时,才移动拼图做示意                  if(isTargetIndexChanged){                      //如果上一个目标索引的拼图不是鼠标正在移动的这个,那么就需要恢复这张拼图的位置到它原来的地方                      if(targetIndexOld!=selectedIndex){                          var lastRelatedItemIndex=relatedItem.posIndex;                          puzzleItemMove(relatedItem,lastRelatedItemIndex);                      }                         //更新相关元素,取得拼图数组中posIndex等于当前的目标索引的元素                      relatedItem=puzzleArray.filter(function(item, index){                          return item.posIndex == targetIndexNew;                      })[0];                      //如果下一个目标索引,不是被拖走的拼图原来所在的位置,就移动新的目标索引的拼图到被拖走的拼图的位置                      if(targetIndexNew!=selectedIndex){                          puzzleItemMove(relatedItem,selectedIndex);                      }                         //重置目标索引改变的逻辑值                      isTargetIndexChanged=false;                         //更新上一个目标索引                      targetIndexOld=targetIndexNew;                  }              }else{                  //如果移到拼图区域之外,则考虑还原上一个目标索引的拼图                  if(targetIndexOld!=selectedIndex){                          var lastRelatedItemIndex=relatedItem.posIndex;                          puzzleItemMove(relatedItem,lastRelatedItemIndex);                  }                  //还原targetIndexOld的值,以处理移到拼图外的情况。                  targetIndexOld = selectedIndex;              }          }             //每一次拼图交换的功能实现的函数,更改对应元素的posIndex,并更改zIndex          function puzzleItemSwitch(){                 //交换元素的posIndex              selectedItem.posIndex=targetIndexNew;              relatedItem.posIndex=selectedIndex;                 //交换元素的zIndex,通过posIndex来赋值              selectedItem.setStyle("zIndex",selectedItem.posIndex);              relatedItem.setStyle("zIndex",relatedItem.posIndex);                 //清除对相关元素的引用              selectedItem=null;              relatedItem=null;                 //一次更换完成,计数器+1              moveStepCount++;              updateCount();                 //然后再判断拼图游戏是否完成              clearJudgement();          }             //每一块拼图在游戏中的移动函数          function puzzleItemMove(moveItem,moveToIndex,endFn){              var moveToX=validPosArrayX[moveToIndex-1],              moveToY=validPosArrayY[moveToIndex-1],              originZIndex=moveItem.posIndex;              moveItemMorph=moveItem.get("morph");              moveItemMorph.addEvent("start",moveStartHandler);              moveItemMorph.addEvent("complete",moveEndHandler);              moveItem.morph({                          left:moveToX,                          top:moveToY              });              function moveStartHandler(){                  moveItem.setStyle("zIndex",1000);              }              function moveEndHandler(){                  moveItemMorph.removeEvent("start",moveStartHandler);                  moveItemMorph.removeEvent("complete",moveEndHandler);                  moveItem.setStyle("zIndex",originZIndex);                     //结尾执行的函数,如果需要的话                  if(typeOf(endFn)=="function"){                      endFn();                  }              }          }             //完成拼图游戏的判定函数          function clearJudgement(){              //检查puzzleArray中的每一个元素的puzzleIndex和posIndex是否全部一致              var isGameClear=puzzleArray.every(function(item, index){                  var puzzleIndex=item.retrieve("puzzleIndex");                  return item.posIndex==puzzleIndex;              });                 if(isGameClear){                  clearShow();              }          }             //确定完成拼图游戏后,执行的函数          function clearShow(){               //清除所有事件侦听              puzzle.removeEvent("mouseover",mouseOverHandler);              puzzle.removeEvent("mouseout",mouseOutHandler);              puzzle.removeEvent("mousedown",mouseDownHandler);              puzzle.removeEvent("mouseup",mouseUpHandler);                 var clearAnimeFlag=null,              count=0;                 //按顺序点亮所有拼图的动画              var enterFrameHandler=function(){                  var item=puzzleArray[count++];                  item.fade(1);                  if(count<puzzleNumber){                      clearAnimeFlag=setTimeout(enterFrameHandler,50);                  }                   };                  clearAnimeFlag=setTimeout(enterFrameHandler,50);                             //游戏完成后的信息~❤              puzzleNote.set('html','Congratulations ! Your final step count is <em class="step_count">'+moveStepCount+'</em>.');          }      }         //创建全局变量puzzleGame      window.puzzleGame={};         //添加方法到全局变量puzzleGame中      puzzleGame.start = function() {          puzzleConfigSet();      };     })(document.id);     puzzleGame.start();