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();</pre>
本文由用戶 程序猿123 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!