微信小程序?qū)崿F(xiàn)的數(shù)字滑塊拼圖效果
微信小程序?qū)崿F(xiàn)的數(shù)字滑塊拼圖
【注】本文章只是記錄下實(shí)現(xiàn)的過程,個(gè)人喜好,無技術(shù)指導(dǎo)傾向,感興趣的小伙伴可以繼續(xù)往下看下實(shí)現(xiàn)過程,
總體實(shí)現(xiàn)效果如下圖,第一個(gè)界面是拼圖初始界面,第二個(gè)是拼圖過程界面
游戲玩法介紹:
滑塊拼圖(Slider Puzzle)是一種經(jīng)典的智力游戲,通常由一個(gè)3x3或更大的格子組成,其中一個(gè)格子為空,玩家通過滑動(dòng)拼圖塊來達(dá)到特定的圖案或順序。
按鈕介紹
“開始/暫停” 按鈕
初次進(jìn)入頁(yè)面,需要點(diǎn)擊開始按鈕,才能進(jìn)行游戲,第一次點(diǎn)擊后,屏幕上面的計(jì)時(shí)器會(huì)開始計(jì)時(shí),再次點(diǎn)擊暫停按鈕,計(jì)時(shí)停止,游戲界面鎖定
“重置”按鈕
將正在進(jìn)行中的游戲進(jìn)行還原初始化,重新開始
代碼實(shí)現(xiàn)
代碼整體目錄結(jié)構(gòu)如下:
├── app.js ├── app.json ├── app.wxss ├── pages │ ├── index │ │ ├── index.js │ │ ├── index.json │ │ ├── index.wxml │ │ └── index.wxss ├── project.config.json ├── project.private.config.json ├── sitemap.json └── utils └── util.js
感興趣的小伙伴可以下載看下
源碼下載:https://gitee.com/ZYHHYZ/slider_puzzles
app.json
該文件僅僅是定義了一個(gè)導(dǎo)航條名稱為 滑塊拼圖
{ "pages": [ "pages/index/index" ], "window": { "backgroundTextStyle": "light", "navigationBarBackgroundColor": "#fff", "navigationBarTitleText": "滑塊拼圖", "navigationBarTextStyle": "black" } }
page
page文件夾 只包含 一個(gè)index頁(yè)面
index頁(yè)面
index.wxml
代碼如下
<view class="container"> <!-- 計(jì)時(shí)器 --> <view class="timer-row"> <view class="timer-text timer-text-m">{{ timerM }}</view> <view class="timer-sp timer-text-sp">:</view> <view class="timer-text timer-text-s">{{ timerS }}</view> <view class="timer-sp timer-text-sp">:</view> <view class="timer-text timer-text-ms">{{ timerMs }}</view> </view> <!-- 滑塊 --> <view class="puzzle-container"> <block wx:for="{{tiles}}" wx:key="*this"> <view class="puzzle-tile" bind:tap="onclickEvent" bindtouchstart="touchStart" bindtouchmove="touchMove" bindtouchend="touchEnd" data-index="{{index}}"> {{item}} </view> </block> </view> <!-- 按鈕區(qū) --> <view class="button-container"> <button class="start-button" bindtap="toggleTimer">開始/停止</button> <button class="restart-button" bindtap="restartPuzzle">重置</button> </view> </view>
index.js
Page({ data: { successTiles: [1, 2, 3, 4, 5, 6, 7, 8, ''], tiles: [1, 2, 3, 4, 5, 6, 7, 8, ''], emptyIndex: 8, selector: { x: 0, y: 0, index: 0 }, isGameing: false, timer: '00:00:00', timerM: '00', timerS: '00', timerMs: '00', timerRunning: false, timerInterval: null }, onLoad: function () { }, touchStart: function (e) { // console.log("移動(dòng)開始", e.currentTarget.dataset) if(!this.data.timerRunning){ console.log("請(qǐng)點(diǎn)擊 開始按鈕") return } const touch = e.touches[0]; let index = e.currentTarget.dataset.index; let xy = this.getXY(index, 3) // console.log(xy) this.setData({ startX: touch.clientX, startY: touch.clientY, selector: xy }); }, touchMove: function (e) { // console.log("移動(dòng)進(jìn)行中", e) const touch = e.touches[0]; this.setData({ moveX: touch.clientX, moveY: touch.clientY, }); }, touchEnd: function (e) { // console.log("移動(dòng)結(jié)束", e) const endX = this.data.moveX; const endY = this.data.moveY; const startX = this.data.startX; const startY = this.data.startY; const deltaX = endX - startX; const deltaY = endY - startY; // console.log("deltaX ", deltaX," deltaY ", deltaY) if (Math.abs(deltaX) > Math.abs(deltaY)) { // 水平滑動(dòng) if (deltaX > 30) { // 向右滑動(dòng) // console.log("→") this.slideTiles('right'); } else if (deltaX < -30) { // 向左滑動(dòng) // console.log("←") this.slideTiles('left'); } } else { // 垂直滑動(dòng) if (deltaY > 30) { // 向下滑動(dòng) // console.log("↓") this.slideTiles('down'); } else if (deltaY < -30) { // 向上滑動(dòng) // console.log("↑") this.slideTiles('up'); } } }, slideTiles: function (direction) { // 根據(jù)方向交換空白塊和相鄰塊 // 這里需要添加實(shí)際的交換邏輯,確??瞻讐K可以移動(dòng) // 例如,你可以在這里交換兩個(gè)塊的位置,但要確??瞻讐K可以移動(dòng) // 以下是一個(gè)簡(jiǎn)單的示例,實(shí)際邏輯會(huì)更復(fù)雜 let newTiles = this.data.tiles.slice(); let emptyIndex = this.data.emptyIndex; let selector = this.data.selector; emptyIndex = selector.index console.log(selector, direction) switch (direction) { case 'right': if (emptyIndex % 3 < 2) { // 判斷相鄰的要移動(dòng)的是否為空白塊 if (newTiles[emptyIndex + 1] != '') { console.log("不能移動(dòng)", direction) return } [newTiles[emptyIndex], newTiles[emptyIndex + 1]] = [newTiles[emptyIndex + 1], newTiles[emptyIndex]]; this.setData({ tiles: newTiles, emptyIndex: emptyIndex + 1 }); } break; case 'left': if (emptyIndex % 3 > 0) { if (newTiles[emptyIndex - 1] != '') { console.log("不能移動(dòng)", direction) return } [newTiles[emptyIndex], newTiles[emptyIndex - 1]] = [newTiles[emptyIndex - 1], newTiles[emptyIndex]]; this.setData({ tiles: newTiles, emptyIndex: emptyIndex - 1 }); } break; case 'up': if (emptyIndex >= 3) { if (newTiles[emptyIndex - 3] != '') { console.log("不能移動(dòng)", direction) return } [newTiles[emptyIndex], newTiles[emptyIndex - 3]] = [newTiles[emptyIndex - 3], newTiles[emptyIndex]]; this.setData({ tiles: newTiles, emptyIndex: emptyIndex - 3 }); } break; case 'down': if (emptyIndex < 6) { if (newTiles[emptyIndex + 3] != '') { console.log("不能移動(dòng)", direction) return } [newTiles[emptyIndex], newTiles[emptyIndex + 3]] = [newTiles[emptyIndex + 3], newTiles[emptyIndex]]; this.setData({ tiles: newTiles, emptyIndex: emptyIndex + 3 }); } break; } this.isSuccess() }, isSuccess: function () { let ti = this.data.tiles let su = this.data.successTiles console.log(su == ti) let ti_str = ti.join(',') let su_str = su.join(',') // console.log(ti_str == su_str) // console.log("isSuccess", ti, ti_str, su_str) if (ti_str == su_str) { this.stopTimer(); wx.showToast({ title: '操作成功', icon: 'success', duration: 2000 }); } }, shuffleArray: function (array) { for (let i = array.length - 1; i > 0; i--) { // 生成一個(gè)隨機(jī)索引從 0 到 i const j = Math.floor(Math.random() * (i + 1)); // 交換元素 [array[i], array[j]] = [array[j], array[i]]; } return array; }, onclickEvent: function (e) { if(!this.data.isGameing){ console.log("請(qǐng)點(diǎn)擊 開始按鈕") return } let index = e.currentTarget.dataset.index; let newTiles = this.data.tiles.slice(); let tiles = this.data.tiles let currentTile = tiles[index] if (currentTile == "") { // console.log("不能移動(dòng)") return } let upIndex, downIndex, leftIndex, rightIndex = null; // 查詢 上下左右的索引 let xy = this.getXY(index, 3) let selector = this.data.selector; let emptyIndex = selector.index // 可以向右移動(dòng) if (emptyIndex % 3 < 2) { if (newTiles[emptyIndex + 1] == '') { [newTiles[emptyIndex], newTiles[emptyIndex + 1]] = [newTiles[emptyIndex + 1], newTiles[emptyIndex]]; this.setData({ tiles: newTiles, emptyIndex: emptyIndex + 1 }); } } // 可以向左運(yùn)動(dòng) if (emptyIndex % 3 > 0) { if (newTiles[emptyIndex - 1] == '') { [newTiles[emptyIndex], newTiles[emptyIndex - 1]] = [newTiles[emptyIndex - 1], newTiles[emptyIndex]]; this.setData({ tiles: newTiles, emptyIndex: emptyIndex - 1 }); } } // 可以向上運(yùn)動(dòng) if (emptyIndex >= 3) { if (newTiles[emptyIndex - 3] == '') { [newTiles[emptyIndex], newTiles[emptyIndex - 3]] = [newTiles[emptyIndex - 3], newTiles[emptyIndex]]; this.setData({ tiles: newTiles, emptyIndex: emptyIndex - 3 }); } } // 向下運(yùn)動(dòng) if (emptyIndex < 6) { if (newTiles[emptyIndex + 3] == '') { [newTiles[emptyIndex], newTiles[emptyIndex + 3]] = [newTiles[emptyIndex + 3], newTiles[emptyIndex]]; this.setData({ tiles: newTiles, emptyIndex: emptyIndex + 3 }); } } console.log("點(diǎn)擊事件", xy, ) }, getXY: function (index, num) { let x = Math.floor(index / num) + 1 let y = index % num + 1 return { x, y, index } }, startTimer: function () { if (!this.data.timerRunning) { let tiles = this.data.tiles let isGameing = this.data.isGameing if (!this.data.isGameing) { // 游戲未開始 ,打亂順序 tiles = this.shuffleArray(tiles) isGameing = true } this.setData({ tiles: tiles, timerRunning: true, isGameing: isGameing }); this.data.timerInterval = setInterval(() => { let timers = this.data.timer.split(":") let m = Number(timers[0]) let s = Number(timers[1]) let ms = Number(timers[2]) if (ms < 99) { ms += 1 } else { ms = 0 if (s < 59) { s = s + 1 } else { s = 0 m += 1 } } let timestr = `${this.formatNumber(m,2)}:${this.formatNumber(s,2)}:${this.formatNumber(ms,2)}` console.log("--------", timers, timestr) this.setData({ timer: timestr, timerM:this.formatNumber(m,2), timerS:this.formatNumber(s,2), timerMs:this.formatNumber(ms,2) }); }, 10); } }, stopTimer: function () { if (this.data.timerRunning) { this.setData({ timerRunning: false }); clearInterval(this.data.timerInterval); } }, toggleTimer: function () { if (this.data.timerRunning) { this.stopTimer(); } else { this.startTimer(); } }, restartPuzzle:function(){ // let tiles = this.data.tiles // tiles = this.shuffleArray(tiles) this.stopTimer() this.setData({ successTiles: [1, 2, 3, 4, 5, 6, 7, 8, ''], tiles: [1, 2, 3, 4, 5, 6, 7, 8, ''], emptyIndex: 8, selector: { x: 0, y: 0, index: 0 }, isGameing: false, timer: '00:00:00', timerM: '00', timerS: '00', timerMs: '00', timerRunning: false, timerInterval: null }) // this.startTimer() }, formatNumber: function (num, length) { return num.toString().padStart(length, '0'); }, });
index.wxss
.container { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; background-color: #fffaf0; font-family: 'Comic Sans MS', cursive, sans-serif; } .timer-row { display: flex; align-items: center; margin-bottom: 100px; animation: blink 2s infinite; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border: 1px solid #ffb6c1; border-radius: 15px; padding: 15px; } .timer-text { width: 90px; height: 100px; background-color: #ffcccc; display: flex; justify-content: center; align-items: center; font-size: 64px; /* 增大字體大小 */ font-weight: bold; /* 加粗字體 */ cursor: pointer; position: relative; overflow: hidden; transition: transform 0.3s ease; /* border-radius: 5px; */ color: #ffffff; /* 粉色調(diào)字體 */ } .timer-sp { width: 10px; height: 100px; background-color: #ffcccc; display: flex; justify-content: center; align-items: center; font-size: 64px; /* 增大字體大小 */ font-weight: bold; /* 加粗字體 */ position: relative; color: #ffffff; /* 粉色調(diào)字體 */ } @keyframes blink { 0% { opacity: 1; } 50% { opacity: 0.5; } 100% { opacity: 1; } } /* */ .button-container { display: flex; justify-content: space-between; /* 使按鈕分布在容器的兩端 */ width: 100%; /* 容器寬度為100% */ margin-top: 50px; /* 與拼圖塊之間添加一些間距 */ } .start-button { background-color: hsl(0, 100%, 90%); color: #cf77a3; width: 110px; border: 1px solid #ffb6c1; padding: 5px 10px; border-radius: 5px; font-size: 18px; font-weight: bolder; cursor: pointer; } .restart-button { background-color: #ffcccc; color: #cf77a3; border: 1px solid #ffb6c1; padding: 5px 10px; width: 110px; border-radius: 5px; font-size: 18px; font-weight: bold; cursor: pointer; } /* 滑塊樣式 */ .puzzle-container { margin-top: -50px; display: grid; grid-template-columns: repeat(3, 100px); grid-gap: 10px; perspective: 1000px; } .puzzle-tile { width: 100px; height: 100px; background-color: #ffcccc; display: flex; justify-content: center; align-items: center; font-size: 32px; font-weight: bold; cursor: pointer; position: relative; overflow: hidden; border: 1px solid #ffb6c1; transition: transform 0.3s ease; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border-radius: 5px; color: #ff69b4; } .puzzle-tile { width: 100px; height: 100px; background-color: #ffcccc; display: flex; justify-content: center; align-items: center; font-size: 64px; /* 增大字體大小 */ font-weight: bold; /* 加粗字體 */ cursor: pointer; position: relative; overflow: hidden; border: 1px solid #ffb6c1; transition: transform 0.3s ease; box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); border-radius: 5px; color: #ffffff; /* 粉色調(diào)字體 */ } /* 當(dāng)拼圖塊被點(diǎn)擊時(shí),添加一些動(dòng)畫效果 */ .puzzle-tile:active { transform: scale(0.5); }
到此這篇關(guān)于微信小程序?qū)崿F(xiàn)的數(shù)字滑塊拼圖的文章就介紹到這了,更多相關(guān)微信小程序數(shù)字滑塊內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 微信小程序?qū)崿F(xiàn)帶滑塊的進(jìn)度條
- 微信小程序?qū)崿F(xiàn)滑塊驗(yàn)證
- 微信小程序?qū)崿F(xiàn)登陸注冊(cè)滑塊驗(yàn)證
- 微信小程序滑塊驗(yàn)證實(shí)現(xiàn)方法
- 微信小程序swiper-dot中的點(diǎn)如何改成滑塊詳解
- 微信小程序12行js代碼自己寫個(gè)滑塊功能(推薦)
- 微信小程序之導(dǎo)航滑塊視圖容器功能的實(shí)現(xiàn)代碼(簡(jiǎn)單兩步)
- 微信小程序?qū)崿F(xiàn)帶刻度尺滑塊功能
- 微信小程序 開發(fā)之滑塊視圖容器(swiper)詳解及實(shí)例代碼
- 微信小程序?qū)崿F(xiàn)滑動(dòng)驗(yàn)證拼圖
- 微信小程序?qū)崿F(xiàn)拼圖游戲
- 微信小程序?qū)崿F(xiàn)拼圖小游戲
相關(guān)文章
Js表格萬(wàn)條數(shù)據(jù)瞬間加載實(shí)現(xiàn)代碼
一條數(shù)據(jù)創(chuàng)建一行,如果數(shù)量大的時(shí)候,一次性要加載完數(shù)據(jù)的話,瀏覽器就會(huì)卡上半天,下面有個(gè)不錯(cuò)的方法,大家可以參考下2014-02-02webuploader實(shí)現(xiàn)上傳圖片到服務(wù)器功能
這篇文章主要為大家詳細(xì)介紹了webuploader實(shí)現(xiàn)上傳圖片到服務(wù)器功能,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-08-08基于Html+CSS+JS實(shí)現(xiàn)手動(dòng)放煙花效果
這篇文章主要介紹了利用Html+CSS+JavaScript實(shí)現(xiàn)的放煙花效果,文中一共實(shí)現(xiàn)了兩種方式:手動(dòng)和自動(dòng),文中的示例代碼講解詳細(xì),感興趣的可以試一試2022-01-01JS實(shí)現(xiàn)的添加彈出層并完成鎖屏操作示例
這篇文章主要介紹了JS實(shí)現(xiàn)的添加彈出層并完成鎖屏操作,涉及JS針對(duì)頁(yè)面元素與樣式動(dòng)態(tài)操作相關(guān)技巧,需要的朋友可以參考下2017-04-04javascript的動(dòng)態(tài)加載、緩存、更新以及復(fù)用(一)
在做OA、MIS、ERP等信息管理類的項(xiàng)目,經(jīng)常會(huì)遇到引用很多js文件,這就需要用到動(dòng)態(tài)加載、緩存、更新以及復(fù)用等技術(shù),下面我們來討論下2014-06-06