欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Vue实现拼图小游戏

程序员文章站 2022-07-13 08:27:56
...

需要的主要参数
Vue实现拼图小游戏
App.vue

<template>
    <div>
        <!-- 子组件通过自己触发next事件与父组件进行通信 -->  
        <d-puzzle v-bind="puzzleConfig[level]" @next = "handleNext"></d-puzzle>
    </div>
</template>
<script>
import DPuzzle from './Puzzle'
export default {
    components:{
        DPuzzle
    },
    data() {
        return {
            level : 0,  //难易程度
            puzzleConfig :[
                {row: 3, col: 3, img: './image/0.jpg'},
                {row: 4, col: 4, img: './image/1.jpg'},
                {row: 5, col: 5, img: './image/2.jpg'},
                {row: 6, col: 6, img: './image/3.jpg'},
                {row: 8, col: 8, img: './image/4.jpg'},
            ]
        }
    },
    methods:{
        // 父组件监听到当前事件成功,通过handleNext控制关卡
        handleNext(){
            this.level ++;
            if(this.level == this.puzzleConfig.length){
                const answerFlag = window.confirm('已经是最后一关了,是否重新开始?');
                if(answerFlag){
                    this.level = 0;
                }
            }
            // console.log('next');
            
        }
    }
}
</script>

Puzzle.vue

<template>
    <div class="puzzle" :style="{width : width + 'px', height : height + 'px'}">
        <div
        class="puzzle__block"
         v-for="(item, index) in blockPoints"
         :key="item.id"
         :style="{
             width: blockWidth + 'px',
             height: blockHeight + 'px',
             left: item.x + 'px',
             top: item.y + 'px',
             backgroundImage:`url(${img})`,
             backgroundPosition:`-${correctPoints[index].x}px  -${correctPoints[index].y}px`,
             opacity:index === blockPoints.length - 1 && 0
         }"
         @click="handleClick"
         :ref="index === blockPoints.length - 1 ? 'empty' : 'block'"
         :data-correctX = "correctPoints[index].x"
         :data-correctY = "correctPoints[index].y"
        >

        </div>
    </div>
</template>
<script>
export default {
    props: {
        width: {
            type: Number,
            default: 500
        },
        height: {
             type: Number,
            default: 500
        },
        row: {
            type: Number,
            default: 3
        },
        col: {
            type: Number,
            default: 3
        },
        img: {
            type: String,
            required: true
        }
    },
    computed: {
        //小块的宽度
        blockWidth (){
            return this.width / this.col;
        },
        //小块的高度
        blockHeight (){
            return this.height / this.row;
        },
        //
        correctPoints(){
            const { row,blockWidth, blockHeight } = this;
            const arr = [];
            for(let i = 0; i < row; i++){
                for(let j = 0; j < row; j++){
                    arr.push({
                        x : j * blockWidth,
                        y: i * blockHeight,
                        id: new Date().getTime() + Math.random() *100
                    })
                }   
            }
            return arr;
        },
        blockPoints (){
          const points = this.correctPoints;
          const length = points.length;
          const lastEle = points[length - 1];
          const newArr = [...points];
          newArr.length = length - 1;
          newArr.sort(() => Math.random() -0.5);
          newArr.push(lastEle);
          return newArr;
         }
    },
    methods: {
        handleClick(e){
            const blockDom = e.target;
            const emptyDom = this.$refs.empty[0];
            if(!this.isAdjacent(blockDom,emptyDom)){
                return;
            }
            const {left , top} = blockDom.style;
            blockDom.style.left = emptyDom.style.left;
            blockDom.style.top = emptyDom.style.top;
            emptyDom.style.left = left;
            emptyDom.style.top = top;
            const winFlag = this.checkWin();
            if(winFlag){
                // console.log('success'); 
                this.winGame(emptyDom);
            }
     },
     //判断是否可以满足交换条件
     isAdjacent(blockDom,emptyDom){
         const {left:domLeft, top:domTop, width, height } = blockDom.style;
         const {left:emptyLeft, top: emptyTop} = emptyDom.style;
         const xDis = Math.floor(Math.abs(parseFloat(domLeft) - parseFloat(emptyLeft)));
         const yDis = Math.floor(Math.abs(parseFloat(domTop) - parseFloat(emptyTop)));
         const flag = (domLeft === emptyLeft && yDis ===parseInt(height)) 
                              || (domTop === emptyTop && xDis === parseInt(width));
         return flag;   
     },
    //  判断成功,每一个小块的现坐标和原坐标都相等
     checkWin() {
         const blockDomArr = this.$refs.block;
         return blockDomArr.every(dom => {
                const {left:domLeft, top:domTop} = dom.style;
                const {correctx:correctX, correcty:correctY} = dom.dataset;
                const  flag =  parseInt(domLeft) === parseInt(correctX) && parseInt(domTop) === parseInt(correctY); 
                // console.log(flag);
                return flag;
            })
        },
        //拼图成功
        winGame(emptyDom) {
            setTimeout(()=>{
                alert('you are so great!');
                emptyDom.style.opacity = 1;
                setTimeout(() => {
                     this.goToNextLevel();
                },300)
            },300)
        },
        //进入下一关
        goToNextLevel(){
            console.log('aaa');
            const answerFlag = window.confirm('继续下一关?');
            if(answerFlag){
                this.$emit('next');
            }
        }
    }
}
</script>
<style>
    .puzzle{
        border:1px solid black;
        position: relative;
    }
    .puzzle__block{
        box-sizing: border-box;
        background-color: red;
        position: absolute;
        border: 1px solid white;
        transition: all .3s;
    }
</style>

效果图:

Vue实现拼图小游戏
Vue实现拼图小游戏
Vue实现拼图小游戏

相关标签: Vue