今天小編為大家帶來的是社區作者wuwhs的文章,讓我們一起來看看怎麼利用思否貓素材實現一個絲滑的華容道吧。
思否社區首屆「貓貓杯」線上代碼共創大賽日程已接近尾聲,各路大神狂拽炫酷的項目已經出爐了。奈何拖延症,我還在想「創意點」,同時考慮到實現周期要趕上 deadline,糾結之時,無意間在地鐵上瞟見有人在看《最強大腦》,靈光一現,對哦!記得有一期有個拼圖遊戲——數字華容道,自此賭王之子(何猷君)一戰成名。遊戲原理不難,益智又好玩。
將面板劃分 nxn 個方格,除了最後一格,每一個方格有一個滑塊;
考慮完全這次與思否貓主題結合,可以將滑塊編碼映射成背景圖片的局部編碼,這樣就變成了拼圖版數字華容道遊戲,奈斯,想法有了,現在就開擼。實現基礎布局
首先實現基本布局,這裡將 600px X 600px 面板平均劃分 3x3 方格。
<divclass="main"><sectionclass="content"><ulclass="row"v-for="rowinlevel":key="row":style="{width:`${appWidth}px`}"><liclass="col"v-for="colinlevel":key="col":style="{width:`${itemWidth}px`}"><divclass="item":style="{height:`${itemWidth}px`,}">{{row}}:{{col}}</div></li></ul></section></div>data(){return{appWidth:600,level:3,}},computed:{itemWidth(){returnthis.appWidth/this.level},},
可能我們會將大圖切圖然後填充,切成 3x3、4x4...,可以,但是不值得,太繁瑣了,後面還會有不同的圖片供選擇作為拼圖背景,工作量是成倍的。偷懶的是將背景圖片使用 CSS background-position進行定位https://developer.mozilla.org/zh-CN/docs/Web/CSS/background-position。
<divclass="item":style="{height:`${itemWidth}px`,backgroundPosition:getBgPos(row,col)}"></div>returnthis.appWidth/this.level},},
定位邏輯是,將第(row, col)位置的方格的背景圖從左上方平((col - 1)*width, (row - 1)*height)距離。比如第 2 行第 3 列的背景圖,往左移動 2 個方格寬度,往右移動 1 個方格高度。
//獲取背景圖片位置getBgPos(row,col){constw=this.itemWidthconst{level}=thisconstoffsetX=((col-1)%level)*wconstoffsetY=((row-1)%level)*wreturn`-${offsetX}px-${offsetY}px`},
.col.item{background-color:#99a9bf;background-repeat:no-repeat;background-image:url('./issue.png');overflow:hidden;}
這裡使用 Vue 實現,數據驅動視圖:響應式數據(數組)中兩個元素交換位置,對應的是視圖上的兩個方格位置交換。這裡我們只需交換背景圖位置信息來假裝元素移動了。
;[{index:0,//索引bgPos:'0px0px',//背景圖偏移量isSpace:false//是否是空白格},...{index:8,//索引bgPos:'-400px-400px',//背景圖偏移量isSpace:true//是否是空白格}]
其次,生成有序和亂序的數組,分別對應遊戲闖關成功狀態,和初始未開始狀態的視圖。在亂序數組的最後一項預留,作為相鄰滑塊交換空間,實現方式是複製一份有序數組(除去最後一項),然後插入一個空白項。其中空白項將背景圖片移出可視區即可。
//初始化init(){this.initOrigList()this.initMessList()},//初始化原始列表initOrigList(){const{level}=thisconstlist=[]for(leti=0;i<level;i++){for(letj=0;j<level;j++){list.push({index:i*level+j,bgPos:this.getBgPos(i+1,j+1),isSpace:false})}}this.origList=list},//初始化亂序列表initMessList(){//除去最後一項的列表打亂constlist=this.sufflex(this.origList.slice(0,-1))//最後一項設置為空白:背景圖片移出可視區this.messList=[...list,{index:Math.pow(this.level,2)-1,bgPos:`-${this.appWidth}px`,isSpace:true}]},
有序數組打亂這裡採用洗牌算法,原理很簡單:從末尾開始往前,前面隨機選取一個數與最後的數互換。
//洗牌算法sufflex(arr){constlen=arr.lengthconstcards=[...arr]letr=len-1while(r>=0){consti=Math.floor(Math.random()*(r+1));[cards[r],cards[i]]=[cards[i],cards[r]]r--}returncards},
其次,從生成布局上,每個方格的背景圖位置要與該亂序數組相關聯。
<divclass="item"@click="handleMove(row,col)":style="{height:`${itemWidth}px`,backgroundPosition:getMessBgPos(row,col),}"></div>
最後,在點擊某一項方格時,判斷它能不能移動,要看它的上下左右相鄰方格是否有空白格,有則與空白格交換位置,否則,不能移動。
//點擊單元項移動handleMove(row,col){consttargetPos=this.getNearbySpacePos(row-1,col-1)if(!targetPos.length)returnthis.changePos((row-1)*this.level+col-1,targetPos[0]*this.level+targetPos[1])},//獲取當前點擊模塊緊挨着的空白模塊位置//如果有則可以移動:當前模塊上下左右相鄰模塊有空白模塊則可以移動getNearbySpacePos(row,col){const{level,messList}=this//上if(row>0&&messList[(row-1)*level+col].isSpace)return[row-1,col]//下if(row<level-1&&messList[(row+1)*level+col].isSpace)return[row+1,col]//左if(col>0&&messList[row*level+col-1].isSpace)return[row,col-1]//右if(col<level-1&&messList[row*level+col+1].isSpace)return[row,col+1]return[]},//交換位置changePos(index,targetIndex){consttemp=this.messList[index]consttargetTemp=this.messList[targetIndex]this.$set(this.messList,targetIndex,temp)this.$set(this.messList,index,targetTemp)},
主體遊戲功能實現了,以上拓展功能的實現比較簡單,就不一一說明了,感興趣的可以點這裡https://github.com/wuwhs/szhrd-game查看代碼,或者直接點這裡https://wuwhs.gitee.io/demo/szhrd/在線體驗。

活動預告:ADM十周年來啦!
騰訊Light與你一起共赴「興」紀元~
ADM與「騰訊Light」進行可持續共創,在大會現場呈現為生物多樣性而打造的藝術裝置作品——《「我」的自然》。
作品由2019年環保藝術系列裝置《未來者》計劃發起人孫世偉先生設計製作,希望能給大家帶來關於生態保護的諸多思考。
地點:杭州杭氧街33號 武林之星博覽中心ADM MORE