python拼图游戏代码的理解_有意思的JS(1)拼图游戏 玩法介绍及其代码实现
我是你们的索儿呀,很幸运我的文章能与你相见,愿萌新能直观的感受到Javascript的趣味性,愿有一定基础者有所收获,愿大佬不吝赐教
拼图游戏是一张图片分为若干块,打乱次序,将其中一块变为空白块,其只能与相邻块互换,发挥你的聪明才智来将其复原
而我本篇文章的目的是,介绍拼图游戏的玩法、技巧,使用JavaScript语言实现拼图游戏
就算是萌新,也是可以阅读前半篇文章的,若能勾起你的兴趣将整篇文章看完那就更棒了
效果展览
- 原图、2 × 2、3 × 3、6 × 6
- 甚至还可以4 × 3、3 × 6
- 图片也是可以更换的,其原图、4 × 4
游戏玩法及技巧
既然决定写这篇文章,我花了一个上午研究拼图游戏,也某度、某乎查看了一些技巧,遂整体成文
本人建议,先到文末将核心代码下载下来,边玩边看玩法技巧,食用更佳
如果你是萌新,推荐使用百度网盘下载代码、查看运行哟
下载到电脑上后,只需要鼠标左键双击game.html文件,即可用浏览器打开,可以尝试玩一下哟(图片尺寸较大,缩放页面视觉效果更佳)
查看代码,就使用编辑器(或者电脑自带的记事本:鼠标右键该文件,打开方式,记事本)打开script文件夹下的game.js文件,就可以开始玩了(重新开一局也很简单:刷新页面)
若拼图是完全随机排序的,不一定可以复原, 拼图的复原在于旋转,旋转是受限制的(可以这么理解:把复原好的任意阶拼图,任意互换两块的位置,都不可能复原)
- 2 × 2 比如下图是复原不了的:
- 3 × 3 是拼图游戏的基础,因为它大概率可以复原(只有一种情况是无法复原的,后文会讲到);可以引申为一句话,无论是?× ?的拼图,只要包含3 × 3,就可以简化为3 × 3的拼图
只要会复原3 × 3,就可以玩转拼图游戏了(若它能够复原)
以可复原为基础,
拼图游戏有什么技巧吗?www.zhihu.com
给的复原3 × 3技巧,我发现非常好用:
- 复原顺序分为两种:纵向和横向 假设以一列一列的方式复原
- 准则一:当你复原一列的时候,你的眼中只有这一列的块,其他列都不属于你的考虑范围
- 准则二:当你复原完一列的时候,就再不要管它,不要动它,把它给忘掉。
- 注意:不要被伪复原迷惑(复原每一列的时候,一定也要遵循从上往下或从下往上一块块复原,不连贯就是伪复原)
除了以上技巧,还要会借位技巧(你就已经是拼图大神了)
我将情况尽量简化,来讲解借位技巧,给下图(1、4、7已经排好了,这一列不看了):
而且上图恰好是伪复原,2、8看似复原了,实际上这样想会进入死胡同的,实际上只复原了2或8
我就以2复原了作为基础,来讲解怎么将第二列(2、5、8)复原: 先将2、5复原(不用思考就做得到),
此时摆在我们面前的问题是,如何将8复原,此处需要借位技巧了
先将2移到上图3处,5移到上图2处(眼中只做到这两步即可)
然后就是最后一个难点了,将8移到上图6处,空白格再移回上图空白格处
接位的目标已达成,将空白格上移、右移,第二列复原完成
于是,你发现了一个问题...嘿嘿...我给的这个3 × 3 拼图是不可能复原的
部分JS知识点陈列
为了阅读的流畅性,我先陈列一些后文我将用到的JS函数、dom元素的玩法(大致瞟一眼,留个印象就好了,阅读到后面可以返回来看)
一:dom元素的玩法
- document.getElementById("id名") 通过id获取对应id的元素
- document.createElement("元素名") 创建一个dom元素对象(此时不影响文本结构)
- this关键字在事件处理程序中指代当前发生的事件元素
- dom.style.样式名 = 值 设置该dom元素的行内样式
- dom.appendChild(dom元素) 在某个元素末尾加入一个子元素
- dom.onclick() = function(){函数体} 为dom元素注册点击事件,当鼠标在页面上点击该dom元素时,执行函数体内容
二:JS函数
- push() 可向数组的末尾添加一个或多个元素,并返回新的长度
- parseInt(浮点数) 返回整数,即将浮点数的小数点即其后的数去掉
- Math.floor(数) 向下取整,比如12.1~12.9都返回12
- Math.random() 返回介于 0 ~ 1 之间的一个随机数(包括0,不包括1)
- Math.abs(数) 返回该数的绝对值
- 数组.find() 为数组中的每个元素都调用一次函数执行:当数组中的元素在测试条件时返回 true 时, find() 返回符合条件的元素,之后的值不会再调用执行函数。
- 数组.filter() 创建一个新的数组,新数组中的元素是通过调用数组中的每个元素并检查,返回满足条件的元素到新数组中
- 数组.forEach() 用于调用数组的每个元素,并将元素传递给回调函数。
个人所虑,必有不足。若有疑问,欢迎在评论区提问。
思路及代码实现
若你对于JavaScript才初窥门径,我建议你使用电脑下载代码(文末提供的核心代码),然后配合本篇文章食用更佳
我先以 3 × 3 的九宫格来讲解拼图游戏的思路,实际上我提供的代码是很灵活的,可以更换图片和改变分割方式
补充一嘴:本人没有对打乱拼图的算法做逻辑处理,显示出来的拼图不一定可以复原哦~~
html代码只需要一行即可:
<div id="game"></div>
其余内容皆由JavaScript完成
一:游戏整体配置
此时,摆在我们眼前的有两种做法: 1. div中放九个img作为拼图块(这个做法太死板了,若我要改变图片、分割方式,改动起来会非常麻烦琐碎) 2. div只需要一个背景图片,里面生成九个div作为拼图块,即将其分割为3 × 3 的九宫格(将图片看作spirit图,然后配合background-position属性即可做到)
- 根据图片的分辨率( 900 × 900 ),确定
<div id="game"></div>
的宽高 - 拼图游戏( 3 × 3 ),确定每一行、每一列有多少个拼图块
- 图片路径,相对的是页面路径
以上三个方面的配置是最基本的,可以通过更改以上配置来更改拼图游戏的图片或者分割方式
/*** 游戏配置*/
var config = {dom: document.getElementById("game"), //游戏的dom对象width: 900,height: 900,rows: 3, //行数cols: 3, //列数url: "img/Ahri.png", //图片路径
};
- 每一块拼图块的宽高取决于
<div id="game"></div>
的宽高和行列数 - 拼图块的数量取决于div的行列数
//每一个拼图块的宽高
config.blockWidth = config.width / config.cols;
config.blockHeight = config.height / config.rows;//拼图块的数量
config.blockNumber = config.rows * config.cols;
二:初始化游戏
1. 初始化游戏面板 - config.dom获取的是<div id="game"></div>
的dom对象 - 然后使用这个dom对象设置其css属性(宽高、边框) - 为什么要设置为相对定位呢?因为拼图游戏中的拼图是可以移动的,它们的位置需要使用绝对定位
/*** 初始化游戏容器*/
function initGameDom(){config.dom.style.width = config.width + "px";config.dom.style.height = config.height + "px";config.dom.style.border = "2px solid #ccc";config.dom.style.position = "relative";
}
2. 初始化拼图块
一个拼图块就是一个div,
需要在<div id="game"></div>
中创建九个div(都设置为绝对定位),
此时需要一个数组,数组的每一项是一个对象,存放每一个div(拼图块)的信息
//存放拼图块信息
var blocks = [];
- i 对应行号,j 对应列号,left、top为定位元素
- left = j × blockWidth
- top = i × blockHeight
此时,<div id="game"></div>
中的九个div(拼图块)的位置就安排好了
/*** 初始化拼图块的数组*/
function initBlocks(){for(var i = 0; i < config.rows; i++){for(var j = 0; j < config.cols; j++){var isVisible = true;if(i === config.rows-1 && j === config.cols-1){isVisible = false;}blocks.push(new Block(j * config.blockWidth, i * config.blockHeight, isVisible));}}
}
同时,每个div(拼图块)对应的正确的背景图片的位置correctBgX、correctBgY与left、top其实是一一对应的 - correctBgX = -left; - correctBgY = -top;
Block构造函数有三个参数:; 以下函数的第三个参数isVisible控制拼图块是否可见(最后一个拼图块是不可见的)
关键参数为前两个参数:定位元素left、right,
在构造函数Block中先生成div的dom元素,然后定义其必须要的属性:width、height、border、background、position,
box-sizing: border-box
决定div的宽高包括边框的宽度,这样不会影响到页面布局 cursor: pointer
鼠标移动到该标签上时变为手指 transition : .5s
css属性变化的时候,在0.5秒内完成(达到拼图块交互时的拖拽效果)
/*** 拼图块的构造函数* @param {*} left * @param {*} top * @param {*} isVisible 是否可见*/
function Block(left, top, isVisible){this.left = left;this.top = top;this.correctBgX = -this.left;this.correctBgY = -this.top;this.isVisible = isVisible;//是否可见this.dom = document.createElement("div");this.dom.style.width = config.blockWidth + "px";this.dom.style.height = config.blockHeight + "px";this.dom.style.boxSizing = "border-box";this.dom.style.border = "2px solid #fff";this.dom.style.background = 'url("'+ config.url + '") ' + this.correctBgX + "px " + this.correctBgY + "px";this.dom.style.cursor = "pointer";this.dom.style.transition = ".5s";//css属性变化的时候,在0.5秒内完成if(!isVisible){this.dom.style.display = "none";}this.dom.style.position = "absolute";/*** 根据当前的left、top,显示div的位置*/this.show = function(){this.dom.style.left = this.left + "px";this.dom.style.top = this.top + "px";}this.show();config.dom.appendChild(this.dom);
}
此时,拼图的大概样子是做出来了
3. 打乱拼图块
将存放拼图块的数组blocks重新排序,需要循环数组重新给其left、top值赋值,
最后一个拼图块是空白的,它的位置是确定的(不参与重新洗牌)
/*** 给blocks数组从新排序*/
function shuffle(){for(var i = 0; i < blocks.length-1; i++){//随机产生一个下标var index = getRandom(0, blocks.length-2);//交换left、topexchangeBlock(blocks[i], blocks[index]); }
}/*** 生成[min, max]范围内的随机数* @param {*} min * @param {*} max */
function getRandom(min, max){return Math.floor(Math.random() * (max +1 -min) + min);
}/*** 交换两个拼图块的top、left,并在页面上重新显示* 参数都为拼图块对象* @param {*} x * @param {*} y */
function exchangeBlock(x, y){//交换leftvar temp = x.left;x.left = y.left;y.left = temp;//交换topvar temp = x.top;x.top = y.top;y.top = temp;//在页面重新显示x.show();y.show();
}
4. 给拼图块注册点击事件
交换看的见的拼图块与空白拼图块的坐标位置,
并且它们必须要挨着一起 - 同一行,它们的left的差值的绝对值,等于拼图块的宽度 - 同一列,它们的top的差值的绝对值,等于拼图块的高度
/*** 给拼图块注册点击事件*/
function regEvent(){//找到空白拼图块var inVisibleBlock = blocks.find(function(b){return !b.isVisible;});blocks.forEach(function(b){b.dom.onclick = function(){if((isEqual(b.top, inVisibleBlock.top) && isEqual(Math.abs(b.left - inVisibleBlock.left), config.blockWidth))||(isEqual(b.left, inVisibleBlock.left) &&isEqual(Math.abs(b.top - inVisibleBlock.top), config.blockHeight))){//交换看的见的拼图块与空白拼图块的坐标位置exchangeBlock(b, inVisibleBlock);//游戏结束判定此处有一个函数}}});
}
/*** 避免小数的不精确,将两数化整比较* @param {*} x * @param {*} y */
function isEqual(x, y){return parseInt(x) === parseInt(y);
}
5. 游戏结束判定
关键:判断每一个拼图块是否都在正确的位置上
/*** 游戏结束判定*/
function isWin(){//过滤不在正确位置上的拼图块var mistakenBlocks = blocks.filter(function(b){return !(isEqual(b.left, -b.correctBgX) && isEqual(b.top, -b.correctBgY));});if(mistakenBlocks.length === 0){//游戏结束blocks.forEach(function(b){b.dom.style.border = "none";b.dom.style.display = "block";//将最后一个拼图块也显示在页面上});}
}
此时还没有完成哦~
拼图完成后,要将每一个拼图块设置为都不能点击,有兴趣的可以阅读文末提供的完整核心代码哟
代码获取
拼图游戏的完整核心代码,有两个方式获取
所谓核心代码,即本篇文章带你实现的拼图游戏的完整代码,没有加入许许多多花里胡哨的东西,以免文章无法连贯讲解
- 百度网盘
文件夹链接:https://pan.baidu.com/s/1bFiosDk2uXjvOHuVYsI2IQ
提取码:r1ua
压缩包链接:https://pan.baidu.com/s/1nvYilW7vYErJZWQzXER6DQ
提取码:zr7k
2. github:https://github.com/Zhangguohao666/demo-front-end/tree/master/jigsaw
拼图游戏的完整提高版代码,未完待续...
python拼图游戏代码的理解_有意思的JS(1)拼图游戏 玩法介绍及其代码实现相关推荐
- 拼图游戏 玩法介绍及其代码实现(有意思的JS 一)
我是你们的索儿呀,很幸运我的文章能与你相见 愿萌新能直观的感受到Javascript的趣味性,愿有一定基础者有所收获,愿大佬不吝赐教 拼图游戏是一张图片分为若干块,打乱次序,将其中一块变为空白块,其只 ...
- 决斗小游戏代码html,《游戏王:决斗链接》的基础玩法介绍
<游戏王:决斗链接>是konami于2016年发行的<YU-GI-OH Duel Links>的国服,同时也是在手机应用市场下载量位于卡牌游戏榜首,是全世界最火的游戏王网络游戏 ...
- 15数字华容道解法 图解_数字华容道解法图解 数字华容道玩法介绍
数字华容道,一款全新的经典的益智类型数字APP.目的是用最少的步数,*短时间将棋盘上的数字方块,按照从左到右,从上到下的顺序重新排列整齐.以往华容道游戏基于三国背景,需将棋子移动到出口.现在以数字为形 ...
- 美团小游戏守卫羊村玩法介绍和游戏漏洞
序言 这款游戏是一个解压小游戏,是我在闲暇时发现的,然后就使用它来度过无聊的碎片化时间.这是一款传统的塔防类游戏,建议大家可以试试,玩法有很多种,当然它的游戏优化还是不太行,建议多优化优化. 玩法介绍 ...
- 手机计算机怎么玩24点游戏,计算器游戏怎么玩_计算器游戏新手玩法介绍_快吧手游...
计算器游戏怎么玩,新手前期玩法介绍,计算器游戏是怎么操作的,新手要怎么操作上手,想必很玩家也是十分的想知道吧,下面快吧小编带来了这篇攻略,希望能帮助大家,赶紧去看看吧. 计算器游戏怎么玩? 计算器游戏 ...
- 鸿蒙符碎片什么游戏,武林外传手游鸿蒙鼎怎么玩_武林外传手游鸿蒙鼎玩法介绍_游戏吧...
武林外传手游中有很多的小伙伴们对鸿蒙鼎还不是很了解,下面游戏吧小编为大家带来武林外传手游鸿蒙鼎玩法介绍,感兴趣的小伙伴们快来一起了解一下吧! 武林外传手游鸿蒙鼎玩法介绍 鸿蒙鼎为合成分解系统,解决客官 ...
- Java小游戏流光之刃_战刃流光之地副本如何玩 副本玩法介绍
战刃流光之地副本如何玩 副本玩法介绍 战刃流光之地副本如何玩呢?下面我就来大家介绍副本的玩法,还不知道如何打这个副本的玩家可不要错过了哦. 当玩家将等级提升至40级时,可通过日常副本"流光之 ...
- 明日之后怎么跳过实名认证_明日之后新手教程能不能跳过 明日之后新手教程玩法介绍...
明日之后新手教程能不能跳过,明日之后游戏萌新注册账号后都会经历一段新手教程玩法才能正式体验游戏,不少小伙伴都最少花费30-50分钟才能完成,许多玩家都很好奇新手教程玩法能不能跳过,下面小编给大家带来明 ...
- 手机计算机怎么玩24点游戏,计算器游戏怎么玩 新手前期玩法介绍
类型:休闲益智大小:30.7M语言:中文 评分:10.0 标签: 立即下载 计算器游戏怎么玩,新手前期玩法介绍,计算器游戏是怎么操作的,新手要怎么操作上手,想必很玩家也是十分的想知道吧,下面西西带来了 ...
最新文章
- 如何用openvr api打开vive前置摄像头
- iOS app 企业内部发布及HTTPS服务器配置
- [渝粤教育] 东南大学 工程热力学 参考 资料
- Number.isInteger()
- d3 v5 api Axes
- Nginx学习总结(12)——Nginx各项配置总结
- Linux 命令 之 【stat】 查看文件状态。 (包括修改时间)
- java调用自身_Java有趣的自己调用自己
- 地区picker 各选择器,优劣分析
- Ubuntu 16.04虚拟环境virtualenv搭建
- 基于tensorflow的RBF神经网络案例
- SAP 金税解决方案
- vscode远程连接虚拟机/云服务器
- 颜值为王 美图M8成京东618新机好评榜最大黑马
- 龙之谷服务器仓库在哪个位置,全区全服版本更新至Ver.190
- Unity3D空战游戏模板 Air Warfare Pro
- 彩虹登录聚合中转API程序网站源码「免授权」
- Ubuntu 下同局域网主机访问Tomcat 服务器
- 汽车零部件-线控底盘
- 练习三:利用条件语句实现计数分频时序电路
热门文章
- java spi与api,SPI和API之间的区别?
- python函数封装总结_python 笔记 之 函数封装成类
- 【OpenStack】【Rocky】安装Rocky之前的先决条件包
- 【英语学习】【WOTD】ratiocination 释义/词源/示例
- C#下实现的基础K-MEANS多维聚类
- nginx反向代理配置去除前缀
- uml类图工具_三款超级轻量化制图工具!每个不超过2MB,堪称神器!
- 11月16日云栖精选夜读:阿里云 oss JavaScript客户端签名文件上传 vue2.0
- 火狐浏览器快捷键大全
- 【转】Linux下的多线程编程背景知识