微信小程序 实现拼图功能

微信小程序 实现拼图

效果示例

微信小程序 碎片拼图

功能描述

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

拖动功能:

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

位置匹配:

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

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

完成检测:

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

代码示例

  • 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,
        });
      }
    },
    

    });

相关推荐
哟哟耶耶20 分钟前
improve-gantt-elastic(vue2中甘特图实现与引入)
前端·甘特图
maply37 分钟前
npm 方式安装Pyodide 详解
前端·python·npm·node.js·pyodide
千禧年@43 分钟前
html辅助标签与样式表
前端·chrome·html
熊仔其人1 小时前
原生JS实现一个日期选择器(DatePicker)组件
javascript·html5
只会写Bug的程序员2 小时前
面试之《web安全问题》
javascript·web安全·面试
程序员猪佩琪2 小时前
软考架构师上岸,我用了这些方法
前端·后端·架构
@大迁世界2 小时前
利用 Tree Shaking 提升 React.js 性能
前端·javascript·react.js·前端框架·ecmascript
某公司摸鱼前端2 小时前
React 第三方状态管理库相关 -- Redux & MobX 篇
前端·javascript·react.js·mobx·redux
傻小胖2 小时前
react中hooks之useRef 用法总结
前端·javascript·react.js
夕水2 小时前
SCSS即将废弃`@import`,以前的`@import`该何去何从?
前端·scss