微信小程序 实现拼图功能

微信小程序 实现拼图

效果示例

微信小程序 碎片拼图

功能描述

在微信小程序中,实现一个简单的拼图小游戏。用户需要将四张碎片图片拖动到目标图片的正确位置,具体功能如下:

拖动功能:

用户可以通过手指拖动碎片图片,自由移动到目标图片的任意位置。

位置匹配:

如果碎片被拖动到正确的位置(即与目标图片的预定区域完全重叠或匹配),碎片会自动吸附到目标图片的指定位置,并显示为已完成。

如果碎片被拖动到错误的位置(未能与目标区域匹配),碎片会自动返回到初始位置。

完成检测:

当所有碎片都被正确放置后,触发完成拼图的效果(如显示完整图片、播放动画或提示成功信息)。

代码示例

  • html

    <view class="container"> <view class="puzzle-box"> <view class="puzzle-cell" wx:for="{{puzzleCells}}" wx:key="id" id="{{item.id}}" data-id="{{item.id}}"> <image src="{{item.image}}" class="target-image"></image> </view> </view>
    复制代码
    <!-- 下方的碎片 --> <!-- 添加 data-index 以传递碎片的索引 -->
    <view class="pieces">
      <view class="piece" wx:for="{{pieces}}" wx:key="id" 
        id="{{item.id}}" 
        style="left: {{item.left}}px; top: {{item.top}}px;" 
        data-id="{{item.id}}" 
        data-index="{{index}}"  
        bindtouchstart="onTouchStart" 
        bindtouchmove="onTouchMove" 
        bindtouchend="onTouchEnd"
        wx:if="{{!item.hidden}}"> <!-- 只有当 hidden 为 false 时才显示碎片 -->
        <image src="{{item.image}}"></image>
      </view>
    </view>
    </view>
  • css

    /* pages/cssCase/puzzle1/index.wxss */
    .container {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    height: 100%;
    }

    .puzzle-box {
    margin: 20rpx;
    border: 1px solid #ccc;
    display: flex;
    align-items: center;
    justify-content: center;
    flex-wrap: wrap;
    padding: 20rpx;
    box-sizing: border-box;
    }

    .puzzle-cell {
    width: 300rpx;
    height: 300rpx;
    border: 1rpx solid #ccc;
    position: relative;
    }
    .target-image {
    width: 300rpx;
    height: 300rpx;
    }

    .pieces {
    display: flex;
    justify-content: space-between;
    width: 100%;
    padding: 0 10rpx;
    }

    .piece {
    width: 150rpx;
    height: 150rpx;
    position: absolute;
    }

    .piece image {
    width: 100%;
    height: 100%;
    }

  • js

    // pages/cssCase/puzzle1/index.js
    Page({
    data: {
    puzzleCells: [
    { id: 'cell-1', image: '', correctPieceId: 'piece-1' },
    { id: 'cell-2', image: '', correctPieceId: 'piece-2' },
    { id: 'cell-3', image: '', correctPieceId: 'piece-3' },
    { id: 'cell-4', image: '', correctPieceId: 'piece-4' },
    ],
    pieces: [
    { id: 'piece-1', image: 'https://static.sprucesmart.com/activity/shandong/jigsawPuzzle20250109/ce1.jpeg', left: 10, top: 380, originalLeft: 10, originalTop: 380, hidden: false },
    { id: 'piece-2', image: 'https://static.sprucesmart.com/activity/shandong/jigsawPuzzle20250109/ce2.jpeg', left: 120, top: 380, originalLeft: 120, originalTop: 380, hidden: false },
    { id: 'piece-3', image: 'https://static.sprucesmart.com/activity/shandong/jigsawPuzzle20250109/ce3.jpeg', left: 210, top: 380, originalLeft: 210, originalTop: 380, hidden: false },
    { id: 'piece-4', image: 'https://static.sprucesmart.com/activity/shandong/jigsawPuzzle20250109/ce4.jpeg', left: 300, top: 380, originalLeft: 300, originalTop: 380, hidden: false },
    ],
    draggingPiece: null,
    draggingPieceIndex: null, // 用于记录当前拖拽的碎片在 pieces 中的索引
    },

    复制代码
    onTouchStart(e) {
      const { id, index } = e.currentTarget.dataset;
      this.setData({
        draggingPiece: id,
        draggingPieceIndex: index,
      });
    },
    
    onTouchMove(e) {
      const { pageX, pageY } = e.touches[0];
      const updatedPieces = this.data.pieces.map((piece, index) => {
        if (index === this.data.draggingPieceIndex) {
          return { ...piece, left: pageX - 75, top: pageY - 75 }; // 让碎片跟随手指移动
        }
        return piece;
      });
      this.setData({ pieces: updatedPieces });
    },
    
    onTouchEnd(e) {
      const { draggingPiece, draggingPieceIndex } = this.data;
      if (!draggingPiece) return;
    
      const query = wx.createSelectorQuery();
      this.data.puzzleCells.forEach((cell) => {
        query.select(`#${cell.id}`).boundingClientRect();
      });
      query.select(`#${draggingPiece}`).boundingClientRect();
    
      query.exec((res) => {
        const cellRects = res.slice(0, this.data.puzzleCells.length);
        const pieceRect = res[res.length - 1];
    
        let placed = false;
        cellRects.forEach((cellRect, index) => {
          const cell = this.data.puzzleCells[index];
          if (cell.correctPieceId === draggingPiece && this.checkOverlap(cellRect, pieceRect)) {
            placed = true;
            this.updatePuzzleCellImage(index, this.data.pieces[draggingPieceIndex].image);
            this.hidePiece(draggingPieceIndex);
            this.updatePiecePosition(draggingPieceIndex, cellRect.left, cellRect.top);
          }
        });
    
        if (!placed) {
          this.resetPiecePosition(draggingPieceIndex);
        }
    
        this.setData({ draggingPiece: null });
    
        // 检查是否完成拼图
        this.checkCompletion();
      });
    },
    
    checkOverlap(box1, box2) {
      return (
        box1.left < box2.left + box2.width &&
        box1.left + box1.width > box2.left &&
        box1.top < box2.top + box2.height &&
        box1.top + box1.height > box2.top
      );
    },
    
    updatePuzzleCellImage(cellIndex, image) {
      const updatedCells = [...this.data.puzzleCells];
      updatedCells[cellIndex].image = image;
      this.setData({ puzzleCells: updatedCells });
    },
    
    hidePiece(pieceIndex) {
      const updatedPieces = this.data.pieces.map((piece, index) => {
        if (index === pieceIndex) {
          return { ...piece, hidden: true }; // 设置碎片为隐藏
        }
        return piece;
      });
      this.setData({ pieces: updatedPieces });
    },
    
    updatePiecePosition(pieceIndex, left, top) {
      const updatedPieces = this.data.pieces.map((piece, index) => {
        if (index === pieceIndex) {
          return { ...piece, left, top };
        }
        return piece;
      });
      this.setData({ pieces: updatedPieces });
    },
    
    resetPiecePosition(pieceIndex) {
      const updatedPieces = this.data.pieces.map((piece, index) => {
        if (index === pieceIndex) {
          return { ...piece, left: piece.originalLeft, top: piece.originalTop };
        }
        return piece;
      });
      this.setData({ pieces: updatedPieces });
    },
    
    // 检查拼图是否完成
    checkCompletion() {
      const allPiecesPlaced = this.data.pieces.every((piece) => piece.hidden);
      if (allPiecesPlaced) {
        wx.showToast({
          title: '拼图完成!',
          icon: 'success',
          duration: 2000,
        });
      }
    },

    });

相关推荐
musk12126 分钟前
electron 打包太大 试试 tauri , tauri 安装打包demo
前端·electron·tauri
翻滚吧键盘35 分钟前
js代码09
开发语言·javascript·ecmascript
万少1 小时前
第五款 HarmonyOS 上架作品 奇趣故事匣 来了
前端·harmonyos·客户端
OpenGL1 小时前
Android targetSdkVersion升级至35(Android15)相关问题
前端
rzl021 小时前
java web5(黑马)
java·开发语言·前端
Amy.Wang1 小时前
前端如何实现电子签名
前端·javascript·html5
海天胜景1 小时前
vue3 el-table 行筛选 设置为单选
javascript·vue.js·elementui
今天又在摸鱼2 小时前
Vue3-组件化-Vue核心思想之一
前端·javascript·vue.js
蓝婷儿2 小时前
每天一个前端小知识 Day 21 - 浏览器兼容性与 Polyfill 策略
前端
百锦再2 小时前
Vue中对象赋值问题:对象引用被保留,仅部分属性被覆盖
前端·javascript·vue.js·vue·web·reactive·ref