原生JS实现拼图游戏

您所在的位置:网站首页 hkcha27q 原生JS实现拼图游戏

原生JS实现拼图游戏

2024-06-21 23:22| 来源: 网络整理| 查看: 265

前面的话

练习了10几个原生js小游戏的案例,刚开始是无从下手,而现在有了自己的思路,不再觉得那么的难了。总结起来,还是那句话,“好的代码是时间熬出来的,多练是硬道理!”,这篇文章来分析一下拼图游戏实现的过程。

在这里插入图片描述

整体思路

自己的理解画了一个思维导图,帮助分析。 在这里插入图片描述 效果图:

用面向对象的方式来写这个代码:

做准备工作: 1: 创建一个配置对象:

包括父盒子的宽高、需要的图片、以及划分的行列

var config = { // 大盒子的宽高 width: 500, height: 500, img: 'img/lol.png', gameDom: document.getElementById('game'), // 三行三列 row: 3, col: 3 }

2: 创建数据对象

包括小方块的数量、每个小方块的宽高

var computed = { num: config.col * config.row, // 小方块的数量 w: config.width / config.col, // 每个小方块的宽度 h: config.height / config.row // 每个小方块的高度 }

3:创建一个数组,存放所有的小方块对象

每个元素是一个对象,每个对象中记录了方块的最初的坐标、当前的坐标、dom元素、一些方法。

var squares = [];

静态布局

在方法setBlocks()中进行静态布局与动态交换。

1:创建一个数组存放每个小方块的正确的left值,top值

var points = getPointsArray();

这个数组由 getPointsArray() 来返回:

function getPointsArray() { var arr = []; for(var i = 0;i < computed.num ; i++){ arr.push ({ left: (i % config.col) * computed.w, top: parseInt(i / config.col) * computed.h }); } console.log(arr); return arr; }

2: 创建里一个数组,用来存放每个小方块交换之后当前的left值,与top值

首先复制points数组,这里的’…'是es6的语法,是扩展符,这里的作用就是用来复制points数组。

var shuffledPoints = [...points];

然后再打乱这个数组,通过将这个数组传入shuffle()方法中,进行洗牌打乱

shuffle(shuffledPoints); // 打乱每个小方块的位置

shuffle()方法:将前8个方块任意进行交换,每次刷新每个小方块的位置都不相同。

function shuffle(arr) { for(var i = 0; i < arr.length-1; i++){ var randomIndex = Math.floor(Math.random()* (arr.length -1)); var temp = arr[i]; arr[i] = arr[randomIndex]; arr[randomIndex] = temp; } }

3: 循环创建每一个小方块对象,包括对象的属性,方法

const es6语法 设置一个常量 ,point表示一个保存着每个小方块初始位置的left和top值的对象。

for(var i = 0; i < points.length; i++){ const point = points[i]; }

在for循环中创建每一个小方块对象:

var square = { left: point.left, top: point.top, curLeft: shuffledPoints[i].left, curTop: shuffledPoints[i].top, dom: document.createElement('div'), update() { this.dom.style.transition = 'all, .5s'; // 设置延迟 this.dom.style.left = this.curLeft + 'px';// 设置当前的位置 this.dom.style.top = this.curTop + 'px';// 当前高度 }, isEmpty: i === points.length -1, isCorrect() { return this.curTop === this.top && this.curLeft === this.left; } }

对象里面包括属性left/top(记录着初始的left、top值)、属性curleft/curtop(打乱之后的left、top值)、dom属性(创建一个div)、update方法(用来每一次交换或者初始化时更新小方块坐标)、属性isEmpty用来判断是不是空白格。isCorrect方法用来判断,交换位置之后当前状态的位置值是不是等于初始状态的值(作为游戏结束的依据)。

设置每一个小方块的样式:

square.dom.style.width = computed.w + "px";// 设置宽高 square.dom.style.height = computed.h + 'px'; square.dom.style.position = 'absolute'; square.dom.style.border = '1px solid #fff'; square.dom.style.boxSizing = 'border-box'; square.dom.style.background = `url("${config.img}")`;// 模板字符串 square.dom.style.cursor = 'pointer'; square.dom.style.backgroundPosition = -square.left + 'px ' + -square.top + 'px'; square.dom.block = square;

初始化更新以及将每个小方块对象保存到数组squares中

square.update(); // 初始化每个方块的位置 squares.push(square);// 将每个小方块对象存入数组中

此时可以渲染父盒子:

将最后一个方块空出,其余的小方块渲染到dom中

function generateGame() { config.gameDom.style.width = config.width + 'px'; config.gameDom.style.height = config.height + 'px'; config.gameDom.style.border = "2px solid #8c8c8c"; for(const item of squares) { if( !item.isEmpty){ config.gameDom.appendChild(item.dom); } } }

现在可以看到一个静态的效果图: 在这里插入图片描述

动态交换

当每个小方块被点击时,触发switchSquare函数,将被点击的方块传入到函数中。

square.dom.onclick = function() { switchSquare(this.block); }

switchSquare()方法:

先找到空白格的位置、再判断被点击的小方块是否与空白格相邻,最后再交换。

function switchSquare(block) { .... }

找到空白块

ES6的数组扩展语法:数组实例find方法:找到第一个符合条件的数组成员

var emptySquare = squares.find( function(index) { return index.isEmpty; });

判断是否相邻

只有小方块当前位置的left值 - 空白格当前位置的left值 与 小方块当前位置的top值 - 空白格当前位置的top值 的绝对值 为一个小方块的宽值时才会是相邻的。

if(Math.abs(block.curLeft - emptySquare.curLeft) + (Math.abs(block.curTop - emptySquare.curTop)) !== computed.w) { return; }

交换

var bLeft = block.curLeft;// 先保存当前被点击方块的位置 var bTop = block.curTop; block.curLeft = emptySquare.curLeft;// 再交换 block.curTop = emptySquare.curTop; emptySquare.curLeft = bLeft; emptySquare.curTop = bTop;

更新

更新点击方块与空白格的位置

block.update(); emptySquare.update();

判断游戏结束

if(isWin()) { setTimeout(()=>{ alert('游戏结束'); },500); }

isWin()方法: 当所有的方块的当前位置都等于初始位置的值时,代表拼图成功,游戏结束。

function isWin() { for( const s of squares) { if(!s.isCorrect()){ return false; } } return true; }

完整代码:

html部分:

js实现拼图游戏 #game{ position: relative; }

js部分

window.onload = function() { var config = { // 大盒子的宽高 width: 500, height: 500, img: 'img/lol.png', gameDom: document.getElementById('game'), // 三行三列 row: 3, col: 3 } // 数据对象 var computed = { num: config.col * config.row, // 小方块的数量 w: config.width / config.col, // 每个小方块的宽度 h: config.height / config.row // 每个小方块的高度 } // 装小方块对象的数组,每个元素是一个对象,每个对象中记录了方块的 // 最初的坐标、当前的坐标、dom元素、一些方法 var squares = []; setBlocks(); generateGame(); // 为全局变量blocks赋值 function generateGame() { config.gameDom.style.width = config.width + 'px'; config.gameDom.style.height = config.height + 'px'; config.gameDom.style.border = "2px solid #8c8c8c"; for(const item of squares) { if( !item.isEmpty){ config.gameDom.appendChild(item.dom); } } } function setBlocks() { var points = getPointsArray();// 返回的数组用来设置每个方块最初的位置 var shuffledPoints = [...points];// 复制points数组,用来存放变化后每个小方块的位置 shuffle(shuffledPoints); // 打乱每个小方块的位置 for(var i = 0; i < points.length; i++){ const point = points[i]; // 创建方块对象 var square = { left: point.left, top: point.top, curLeft: shuffledPoints[i].left, curTop: shuffledPoints[i].top, dom: document.createElement('div'), update() { this.dom.style.transition = 'all, .5s'; // 设置延迟 this.dom.style.left = this.curLeft + 'px';// 设置当前的位置 this.dom.style.top = this.curTop + 'px';// 当前高度 }, isEmpty: i === points.length -1, isCorrect() { return this.curTop === this.top && this.curLeft === this.left; } } square.dom.style.width = computed.w + "px";// 设置宽高 square.dom.style.height = computed.h + 'px'; square.dom.style.position = 'absolute'; square.dom.style.border = '1px solid #fff'; square.dom.style.boxSizing = 'border-box'; square.dom.style.background = `url("${config.img}")`;// 模板字符串 square.dom.style.cursor = 'pointer'; square.dom.style.backgroundPosition = -square.left + 'px ' + -square.top + 'px'; square.dom.block = square; //当小方块被点击时,如果与空白块相邻就交换位置 square.dom.onclick = function() { switchSquare(this.block); } square.update(); // 初始化每个方块的位置 squares.push(square);// 将每个小方块对象存入数组中 } } function switchSquare(block) { // 找到空白块 // ES6的数组扩展语法:数组实例find方法:找到第一个符合条件的数组成员 var emptySquare = squares.find( function(index) { return index.isEmpty; }); // 判断是否相邻 if(Math.abs(block.curLeft - emptySquare.curLeft) + (Math.abs(block.curTop - emptySquare.curTop)) !== computed.w) { return; } // 交换 var bLeft = block.curLeft;// 先保存当前被点击方块的位置 var bTop = block.curTop; block.curLeft = emptySquare.curLeft;// 再交换 block.curTop = emptySquare.curTop; emptySquare.curLeft = bLeft; emptySquare.curTop = bTop; // 更新点击方块与空白格的位置 block.update(); emptySquare.update(); // 判断游戏结束 if(isWin()) { setTimeout(()=>{ alert('游戏结束'); },500); } } function isWin() { for( const s of squares) { if(!s.isCorrect()){ return false; } } return true; } function shuffle(arr) { for(var i = 0; i < arr.length-1; i++){ var randomIndex = Math.floor(Math.random()* (arr.length -1)); var temp = arr[i]; arr[i] = arr[randomIndex]; arr[randomIndex] = temp; } } function getPointsArray() { var arr = []; for(var i = 0;i < computed.num ; i++){ arr.push ({ left: (i % config.col) * computed.w, top: parseInt(i / config.col) * computed.h }); } console.log(arr); return arr; } }


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3