思路:
-
上傳一張自己的本地的圖片
-
將圖片分割成若干行若干列
+ 給每一個小格子,添加上自己的索引
+ 把索引存入一個數(shù)組中,方便最后判斷是否完成
-
分割的每一個小格子上都顯示完整圖片對應(yīng)的一部分
-
點擊開始游戲按鈕,打亂圖片的位置
+ 創(chuàng)建一個新數(shù)組敬肚,將原數(shù)組打亂之后存到新數(shù)組中
+ 讓每一個小格子根據(jù)打亂后的數(shù)組進行定位
-
點擊兩個不同的小格,讓其交換位置。
+ 小格子位置交換完成后郁妈,需要將打亂的數(shù)組對應(yīng)的兩個值也交換位置。
-
判斷交換后的亂序數(shù)組和原來的數(shù)組是否相等认臊,如果相等即表示游戲完成圃庭。
難點:
-
如何上傳本地圖片讓其顯示的
-
如何將一張圖片切割成多個小格子
-
如果根據(jù)亂序的數(shù)組來計算當前的行數(shù)和列數(shù)
解決辦法:
-
針對于如何上傳一張本體圖片,看之前的一篇關(guān)于瀏覽器如何在頁面上顯示準備上傳的圖片的問題失晴,下面是傳送門剧腻。
+ <a target = "_blank" href="http://www.reibang.com/p/9e4a1ee03089">關(guān)于瀏覽器如何在頁面上顯示準備上傳的圖片的問題</a>
-
針對如何切割一張圖片的問題,事實上也并不能說是切割涂屁,且聽我細細道來书在。
+ 首先我們利用兩個for循環(huán),外層代表行數(shù)拆又,里面代表列數(shù)儒旬,然后動態(tài)創(chuàng)建div來表示每一個小方格。
+ 然后我們分隔好了小方格帖族,我們也知道小方格的寬和高栈源,并且知道每行每列各有多少個小方格。
+ 之后我們給每一個小方格都設(shè)置一個`background-image`屬性竖般,讓每一個方格都有一個完整的圖甚垦。所以說這里并不是一張背景圖,而是有多少個小方格就有多少張圖片。
+ 再之后根據(jù)行數(shù)和列數(shù)的數(shù)量來設(shè)置`background-size`艰亮,比如只有一個格子闭翩,`background-size`的值就是 100% ,同理迄埃,兩個值就是200%
+ 最后根據(jù)當前第幾行疗韵,第幾列,每一個小格子的寬度和高度來計算出偏移量侄非,即left值和top值蕉汪。再利用`background-position`來進行定位即可實現(xiàn)。
-
針對根據(jù)亂序數(shù)組來計算當前的行數(shù)和列數(shù)彩库。這里其實也并不難肤无,只是我個人卡在這里卡了一會兒。骇钦。宛渐。。
+ 首先我們的亂序數(shù)組是根據(jù)原來的數(shù)組打亂順序而來眯搭,所以里面的數(shù)值除了順序應(yīng)該就是一樣的窥翩。
+ 當我們點擊圖片的時候能夠獲取到圖片所在的div的索引。
+ 因為原數(shù)組是按照0,1,2,3,4.....這樣排列的鳞仙,所以這個索引在亂序數(shù)組中對應(yīng)的值就是打亂后的圖片是從0開始數(shù)的第多少張圖片寇蚊。
+ 知道了這張圖片此時是屬于第幾張,我們就能根據(jù)這個值來計算出這張圖片此時對應(yīng)的行數(shù)和列數(shù)棍好。
- 當前是第幾張圖片 / 一行多少列 然后取整 就是當前屬于第幾行
- 當前是第幾張圖片 % 一行多少列 然后取余 就是當前屬于第幾列
這里我用一張動圖來表示如果切割圖片的
注意點:
-
打亂索引 的時候要注意仗岸,由于打亂的數(shù)組可能跟原數(shù)組還是一樣,所以需要控制一下借笙。
-
上傳的本地的圖片不要太大扒怖,不然讀取的速度那還真有點慢。业稼。盗痒。
-
上傳的圖片需要是個正方形的,實在沒有正方向的話低散,高度大于寬度的圖片也行俯邓,無非是下半部分被干掉了。熔号。
-
因為個人比較懶稽鞭。很多地方?jīng)]有寫兼容,所以打開小游戲請使用chrome瀏覽器
我們來看看關(guān)鍵代碼
-
HTML部分
<!-- 獲取圖片 -->
<input type="file" id="file">
<!-- 字體圖標 -->
<div id="btn">
<i class="iconfont icon-xiangji2"></i>
</div>
<div id="gameArea">
<!-- 游戲開始按鈕 -->
<div id="gameStart">點擊開始</div>
<!-- 圖片存放的區(qū)域 -->
<div id="imgArea"></div>
</div>
-
CSS部分
css部分真沒啥好說的引镊,有興趣的話大家下載源碼朦蕴,一看就知道了
-
JS部分
- 切割圖片
// 切割圖片 imgSplit:function(){ // 清空圖片存放區(qū)域 this.imgArea.innerHTML = ''; // 用來存方動態(tài)創(chuàng)建的div元素 var _cell = ''; // 行數(shù) for (var i = 0, l =this.leverArr[0]; i<l ;i++) { // 列數(shù) for (var j = 0,l =this.leverArr[1]; j<l ;j++) { // 給每張圖片一個索引值 // 索引遞增規(guī)則為 從左到右 從上到下 this.imgOrigArr.push(i*this.leverArr[0] + j); // 創(chuàng)建div _cell = document.createElement('div'); // 給div添加id _cell.className = "imgCell"; // 給每張一個索引吃嘿,方便后面點擊的時候進行判斷 _cell.index = i*this.leverArr[0] + j; // 給div添加樣式 _cell.style.width = this.cellWidth+'px'; _cell.style.height = this.cellHeight+'px'; _cell.style.left = j*this.cellWidth+'px'; _cell.style.top = i*this.cellHeight + 'px'; _cell.style.backgroundImage= "url("+this.imgUrl+")"; // 這里因為100%就讓背景圖的大小等于了一個小格子的大小 // 而我們只需要原始圖的一部分,并不是想縮小原圖 // 所以根據(jù)小格子的個數(shù)來放大圖片 _cell.style.backgroundSize = this.leverArr[1]+'00%'; // 移動背景圖梦重,行成最后切成的一塊塊的效果 _cell.style.backgroundPosition = (-j)*this.cellWidth + 'px ' + (-i)*this.cellHeight+'px'; // 讓背景圖從邊框開始平鋪 _cell.style.backgroundOrigin = "border-box"; this.imgArea.appendChild(_cell); } } // 獲取小格子的dom元素 this.imgCells = document.querySelectorAll('.imgCell'); //將選擇圖片的按鈕移動到可視區(qū)域外 this.btnObj.style.left= -this.btnObj.offsetWidth+'px'; // 將圖片移入可視區(qū)域 // this.gameAreaObj.style.background = 'url('+this.imgUrl +')'; this.gameAreaObj.style.left = '50%'; this.gameAreaObj.style.transform= 'translate(-50%,-50%)'; // 使按鈕綁定事件,點擊按鈕開始整個游戲 this.gameStartBtnObj.onclick = this.clickHandle(); }
- 打亂圖片索引
// 打亂圖片索引 randomArr:function(){ // 清空亂序數(shù)組 this.imgRandomArr = []; // 判斷原來的數(shù)組是否和亂序數(shù)組一樣 var _flag = true; // 遍歷原始索引 for(var i=0,l=this.imgOrigArr.length;i<l;i++){ // 獲取從0到數(shù)組長度之間的一個索引值 var order = Math.floor(Math.random()*this.imgOrigArr.length); // 如果亂序數(shù)組中沒有值就直接添加 // 否則就在這個亂序數(shù)組中找對應(yīng)的隨機數(shù)的索引亮瓷,找不到就添加,找到就繼續(xù)隨機 if(this.imgRandomArr.length>0){ while(this.imgRandomArr.indexOf(order) >-1){ order = Math.floor(Math.random()*this.imgOrigArr.length); } } this.imgRandomArr.push(order); } // 判斷亂序數(shù)組和原始數(shù)組是否一樣 if(this.imgRandomArr.length === this.imgOrigArr.length){ // 遍歷數(shù)組 for(var i=0,l=this.imgOrigArr.length;i<l;i++){ if(this.imgRandomArr[i] != this.imgOrigArr[i]){ _flag = false; break; }else{ _flag = true; } } }else{ _flag = true; } // 返回值為true的話 就代表原始數(shù)組和亂序數(shù)組一致琴拧,重新打亂數(shù)組 if(_flag){ this.randomArr(); } }
- 交換兩次點擊的圖片位置
// 交換兩次點擊的圖片位置 cellExchange:function(from,to){ // 因為圖片此時的排序是根據(jù) 以圖片的索引值為索引 // 在亂序的數(shù)組中根據(jù)相對應(yīng)的索引取出的值作為當前圖片的排序位置的 // 因此根據(jù)from to這兩個值作為索引,就能在亂序數(shù)組中得到當前圖片是第幾張 // 求出from的圖片 是第幾行第幾列 // 當前是第幾張圖片 / 一行多少列 然后取整 就是當前屬于第幾行 var _fromRow = Math.floor(this.imgRandomArr[from] / this.leverArr[1]); // 當前是第幾張圖片 % 一行多少列 然后取余 就是當前屬于第幾列 var _fromCol = this.imgRandomArr[from] % this.leverArr[1]; // 求出to的圖片 是第幾張第幾列 var _toRow = Math.floor(this.imgRandomArr[to] / this.leverArr[1]); var _toCol = this.imgRandomArr[to] % this.leverArr[1]; // 移動兩張圖片 this.imgCells[from].style.left = _toCol*this.cellWidth + 'px'; this.imgCells[from].style.top = _toRow*this.cellHeight + 'px'; this.imgCells[to].style.left = _fromCol*this.cellWidth + 'px'; this.imgCells[to].style.top = _fromRow*this.cellHeight + 'px'; // 將亂序數(shù)組中的兩個值交換位置 // 定義一個臨時變量來實現(xiàn)交換順序 var _temp = this.imgRandomArr[from]; this.imgRandomArr[from] = this.imgRandomArr[to]; this.imgRandomArr[to] = _temp; //如果亂序數(shù)組和原數(shù)組一致嘱支,則表示拼圖已完成 if(this.imgOrigArr.toString() === this.imgRandomArr.toString()){ // 調(diào)用成功方法 this.success(); } }
源碼保存在了<a target = "_blank" >github</a>上蚓胸,有愛點擊github自取。
在線地址可以直接測試使用除师,<a target = "_blank" >拼圖小游戲</a>←點擊跳轉(zhuǎn)即可
總結(jié):
- 最近不知道怎么了沛膳,老是不在狀態(tài),腦袋反應(yīng)比較慢汛聚,一個簡單問題總是要想好久锹安。感覺整個人都魔怔了。倚舀。叹哭。。
- 本來我是想自動獲取圖片寬高來切成行列的痕貌,不過行數(shù)列數(shù)不相等的話风罩,好像有點麻煩。而且不是正方形也不好看啊舵稠。想了想還是不弄了超升。。想興趣的朋友自己弄弄吧哺徊。室琢。
- 順便一提,上面的動圖所用到的圖片唉工,畫師是P站的 METO@三日目東ミ24a