篇文章给大家带来的内容是关于使用javascript中canvas实现拼图小游戏 ,有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助。
如果您想要综合使用javascript中canvas、原生拖拽、本地存储等多种技术完成一个有趣的项目,那么这篇文章将非常适合您
该项目中的拼图小游戏使用javascript原创,相比于网站上类似的功能,它使用到的技术点更先进丰富,功能更强大,还包含程序开发中更多先进的思想理念,从该项目中您将能学到:
项目源码-github
下面是游戏界面的示例图:
根据游戏界面图我们可以将完成这么一个小游戏分为以下几步来实现:
从以上对小游戏制作过程的分析来看,第4步是程序功能实现的重点和难点,在以上的每个步骤中都有很多小细节需要注意和探讨,下面我就详细分析一下每个步骤的实现细节,说的不好的地方,欢迎大家留言指正。
3.1 图片内容读取和加载
在游戏开发第1步中,我们将图片拖拽到指定区域后,程序是怎样得到图片内容信息的呢?fileReader对象又是怎样将图片信息转化为base64字符串内容的?Image对象拿到图片的base64内容之后,又是怎样初始化加载的?带着这些疑问,我们来研究一下实现项目中实现了第一步的关键代码。
var droptarget=document.getElementById("droptarget"),
output=document.getElementById("ul1"),
thumbImg=document.getElementById("thumbimg");
//此处省略相关代码........
function handleEvent(event) {
var info="",
reader=new FileReader(),
files, i, len;
EventUtil.preventDefault(event);
localStorage.clear();
if (event.type=="drop") {
files=event.dataTransfer.files;
len=files.length;
if (!/image/.test(files[0].type)) {
alert('请上传图片类型的文件');
}
if (len > 1) {
alert('上传图片数量不能大于1');
}
var canvas=document.createElement('canvas');
var context=canvas.getContext('2d');
var img=new Image(), //原图
thumbimg=new Image(); //等比缩放后的缩略图
reader.readAsDataURL(files[0]);
reader.onload=function (e) {
img.src=e.target.result;
}
//图片对象加载完毕后,对图片进行等比缩放处理。缩放后最大宽度为三百像素
img.onload=function () {
var targetWidth, targetHeight;
targetWidth=this.width > 300 ? 300 : this.width;
targetHeight=targetWidth / this.width * this.height;
canvas.width=targetWidth;
canvas.height=targetHeight;
context.clearRect(0, 0, targetWidth, targetHeight);
context.drawImage(img, 0, 0, targetWidth, targetHeight);
var tmpSrc=canvas.toDataURL("image/jpeg");
//在本地存储完整的缩略图源
localStorage.setItem('FullImage', tmpSrc);
thumbimg.src=tmpSrc;
}
//此处省略相关代码......
EventUtil.addHandler(droptarget, "dragenter", handleEvent);
EventUtil.addHandler(droptarget, "dragover", handleEvent);
EventUtil.addHandler(droptarget, "drop", handleEvent);
}
这段代码的思路就是首先获得拖拽区域目标对象droptarget,为droptarget注册拖拽监听事件。代码中用到的EventUtil是我封装的一个对元素添加事件、事件对象的兼容处理等常用功能的简单对象,下面是其添加注册事件的简单简单代码,其中还有很多其他的封装,读者可自行查阅,功能比较简单。
var EventUtil={
addHandler: function(element, type, handler){
if (element.addEventListener){
element.addEventListener(type, handler, false);
} else if (element.attachEvent){
element.attachEvent("on" + type, handler);
} else {
element["on" + type]=handler;
}
},
//此处省略代......
}
当用户将图片文件拖放到区域目标对象droptarget时,droptarget的事件对象通过event.dataTransfer.files获取到文件信息,对文件进行过滤(限制只能为图片内容,并且最多只能有一张图片)。拿到文件内容以后,使用FileReader对象reader读取文件内容,使用其readAsDataURL方法读取到图片的base64内容,赋值给Image对象img的src属性,就可以等到img对象初始化加载完毕,使canvas对img进行下一步的处理了。这里有一个重点的地方需要说明:一定要等img加载完成后,再使用canvas进行下一步的处理,不然可能会出现图片损坏的情况。原因是:当img的src属性读取图片文件的base64内容时,可能还没有将内容加载到内存中时,canvas就开始处理图片(此时的图片是不完整的)。所以我们可以看到canvas对图片的处理是放在img.onload方法中进行的,程序后边还会有这种情况,之后就不再赘述了。
3.2 图片等比缩放和本地存储
在第一步中我们完成了对拖拽文件的内容读取,并将其成功加载到了Image对象img中。接下来我们使用canvas对图片进行等比缩放,对图片进行等比缩放,我们采取的策略是限制图片的最大宽度为300像素,我们再来看一下这部分代码吧:
img.onload=function () {
var targetWidth, targetHeight;
targetWidth=this.width > 300 ? 300 : this.width;
targetHeight=targetWidth / this.width * this.height;
canvas.width=targetWidth;
canvas.height=targetHeight;
context.clearRect(0, 0, targetWidth, targetHeight);
context.drawImage(img, 0, 0, targetWidth, targetHeight);
var tmpSrc=canvas.toDataURL("image/jpeg");
//在本地存储完整的缩略图源
localStorage.setItem('FullImage', tmpSrc);
thumbimg.src=tmpSrc;
}
确定了缩放后的宽度targetWidth和高度targetHeight之后,我们使用canvas的drawImage方法对图像进行压缩,在这之前我们最好先使用画布的clearRect对画布进行一次清理。对图片等比缩放以后,使用canvas的toDataURL方法,获取到缩放图的base64内容,赋给新的缩放图Image对象thumbimg的src属性,待缩放图加载完毕,进行下一步的切割处理。缩放图的base64内容使用localStorage存储,键名为"FullImage"。浏览器的本地存储localStorage是硬存储,在浏览器刷新之后内容不会丢失,这样我们就可以在游戏过程中保持数据状态,这点稍后再详细讲解,我们需要知道的是localStorage是有大小限制的,最大为5M。这也是为什么我们先对图片进行压缩,减少存储数据大小,保存缩放图base64内容的原因。关于开发过程中存储哪些内容,下一小节会配有图例详细说明。
3.3 缩略图切割
生成缩略图之后要做的工作就是对缩略图进行切割了,同样的也是使用canvas的drawImage方法,而且相应的处理必须放在缩略图加载完成之后(即thumbimg.onload)进行处理,原因前面我们已经说过。下面我们再来详细分析一下源代码吧:
thumbimg.onload=function () {
//每一个切片的宽高[切割成3*4格式]
var sliceWidth, sliceHeight, sliceBase64, n=0, outputElement='',
sliceWidth=this.width / 3,
sliceHeight=this.height / 4,
sliceElements=[];
canvas.width=sliceWidth;
canvas.height=sliceHeight;
for (var j=0; j < 4; j++) {
for (var i=0; i < 3; i++) {
context.clearRect(0, 0, sliceWidth, sliceHeight);
context.drawImage(thumbimg, sliceWidth * i, sliceHeight * j, sliceWidth, sliceHeight, 0, 0, sliceWidth, sliceHeight);
sliceBase64=canvas.toDataURL("image/jpeg");
localStorage.setItem('slice' + n, sliceBase64);
//为了防止图片三像素问题发生,请为图片属性添加 display:block
newElement="<li name=\"" + n + "\" style=\"margin:3px;\"><img src=\"" + sliceBase64 + "\" style=\"display:block;\"></li>";
//根据随机数打乱图片顺序
(Math.random() > 0.5) ? sliceElements.push(newElement) : sliceElements.unshift(newElement);
n++;
}
}
//拼接元素
for (var k=0, len=sliceElements.length; k < len; k++) {
outputElement +=sliceElements[k];
}
localStorage.setItem('imageWidth', this.width + 18);
localStorage.setItem('imageHeight', this.height + 18);
output.style.width=this.width + 18 + 'px';
output.style.height=this.height + 18 + 'px';
(output.innerHTML=outputElement) && beginGamesInit();
droptarget.remove();
}
上面的代码对于大家来说不难理解,就是将缩略图分割成12个切片,这里我给大家解释一下几个容易困惑的地方:
for (var j=0; j < 4; j++) {
for (var i=0; i < 3; i++) {
//此处省略逻辑代码
}
}
这个问题大家仔细想一想就明白了,我们将图片进行切割的时候,要记录下来每一个图片切片的原有顺序。在程序中我们使用 n 来表示图片切片的原有顺序,而且这个n记录在了每一个图片切片的元素的name属性中。在后续的游戏过程中我们可以使用元素的getAttribute('name')方法取出 n 的值,来判断图片切片是否都被拖动到了正确的位置,以此来判断游戏是否结束,现在讲起这个问题可能还会有些迷惑,我们后边还会再详细探讨,我给出一张图帮助大家理解图片切片位置序号信息n:
序号n从零开始是为了和javascript中的getElementsByTagName()选择的子元素坐标保持一致。
(Math.random() > 0.5) ? sliceElements.push(newElement) : sliceElements.unshift(newElement);
我们知道Math.random()生成一个[0, 1)之间的数,所以再canvas将缩略图裁切成切片以后,根据这些切片生成的web节点顺序是打乱的。打乱顺序以后重新组装节点:
//拼接元素
for (var k=0, len=sliceElements.length; k < len; k++) {
outputElement +=sliceElements[k];
}
然后再将节点添加到web页面中,也就自然而然出现了图片切片被打乱的样子了。
下面的一行代码,虽然简单,但是用的非常巧妙:
(output.innerHTML=outputElement) && beginGamesInit();
有开发经验的同学都知道 && 和 || 是短路运算符,代码中的含义是:只有当切片元素节点都添加到
WEB页面之后,才会初始化为这些节点绑定事件。
3.4 本地信息存储
代码中多次用到了本地存储,下面我们来详细解释一下本游戏开发过程中都有哪些信息需要存储,为什么要存储?下面是我给出的需要存储的信息图示例(从浏览器控制台获取):
浏览器本地存储localStorage使用key:value形式存储,从图中我们看到我们本次存储的内容有:
保存FullImage缩略图的信息是当游戏结束后显示源缩略图时,根据FullImage中的内容展示图片。而imageWidth,imageHeight,slice*,nodePos是为了防止浏览器刷新导致数据丢失所做的存储,当刷新页面的时候,浏览器会根据本地存储的数据加载没有完成的游戏内容。其中nodePos是在为缩略图切片发生拖动时存入本地存储的,并且它随着切片位置的变化而变化,也就是它追踪着游戏的状态,我们在接下来的代码功能展示中会再次说到它。
3.5 拖拽事件注册和监控
接下来我们要做的事才是游戏中最重要的部分,还是先来分析一下代码,首先是事件注册前的初始化工作:
//游戏开始初始化
function beginGamesInit() {
aLi=output.getElementsByTagName("li");
for (var i=0; i < aLi.length; i++) {
var t=aLi[i].offsetTop;
var l=aLi[i].offsetLeft;
aLi[i].style.top=t + "px";
aLi[i].style.left=l + "px";
aPos[i]={left: l, top: t};
aLi[i].index=i;
//将位置信息记录下来
nodePos.push(aLi[i].getAttribute('name'));
}
for (var i=0; i < aLi.length; i++) {
aLi[i].style.position="absolute";
aLi[i].style.margin=0;
setDrag(aLi[i]);
}
}
可以看到这部分初始化绑定事件代码所做的事情是:记录每一个图片切片对象的位置坐标相关信息记录到对象属性中,并为每一个对象都注册拖拽事件,对象的集合由aLi数组统一管理。这里值得一提的是图片切片的位置信息index记录的是切片现在所处的位置,而我们前边所提到的图片切片name属性所保存的信息n则是图片切片原本应该所处的位置,在游戏还没有结束之前,它们不一定相等。待所有的图片切片name属性所保存的值和其属性index都相等时,游戏才算结束(因为用户已经正确完成了图片的拼接),下面的代码就是用来判断游戏状态是否结束的,看起来更直观一些:
//判断游戏是否结束
function gameIsEnd() {
for (var i=0, len=aLi.length; i < len; i++) {
if (aLi[i].getAttribute('name') !=aLi[i].index) {
return false;
}
}
//后续处理代码省略......
}
下面我们还是详细说一说拖拽交换代码相关逻辑吧,拖拽交换的代码如下图所示:
//拖拽
function setDrag(obj) {
obj.onmouseover=function () {
obj.style.cursor="move";
console.log(obj.index);
}
obj.onmousedown=function (event) {
var scrollTop=document.documentElement.scrollTop || document.body.scrollTop;
var scrollLeft=document.documentElement.scrollLeft || document.body.scrollLeft;
obj.style.zIndex=minZindex++;
//当鼠标按下时计算鼠标与拖拽对象的距离
disX=event.clientX + scrollLeft - obj.offsetLeft;
disY=event.clientY + scrollTop - obj.offsetTop;
document.onmousemove=function (event) {
//当鼠标拖动时计算p的位置
var l=event.clientX - disX + scrollLeft;
var t=event.clientY - disY + scrollTop;
obj.style.left=l + "px";
obj.style.top=t + "px";
for (var i=0; i < aLi.length; i++) {
aLi[i].className="";
}
var oNear=findMin(obj);
if (oNear) {
oNear.className="active";
}
}
document.onmouseup=function () {
document.onmousemove=null; //当鼠标弹起时移出移动事件
document.onmouseup=null; //移出up事件,清空内存
//检测是否普碰上,在交换位置
var oNear=findMin(obj);
if (oNear) {
oNear.className="";
oNear.style.zIndex=minZindex++;
obj.style.zIndex=minZindex++;
startMove(oNear, aPos[obj.index]);
startMove(obj, aPos[oNear.index], function () {
gameIsEnd();
});
//交换index
var t=oNear.index;
oNear.index=obj.index;
obj.index=t;
//交换本次存储中的位置信息
var tmp=nodePos[oNear.index];
nodePos[oNear.index]=nodePos[obj.index];
nodePos[obj.index]=tmp;
localStorage.setItem('nodePos', nodePos);
} else {
startMove(obj, aPos[obj.index]);
}
}
clearInterval(obj.timer);
return false;//低版本出现禁止符号
}
}
这段代码所实现的功能是这样子的:拖动一个图片切片,当它与其它的图片切片有碰撞重叠的时候,就和与其左上角距离最近的一个图片切片交换位置,并交换其位置信息index,更新本地存储信息中的nodePos。移动完成之后判断游戏是否结束,若没有,则期待下一次用户的拖拽交换。
下面我来解释一下这段代码中比较难理解的几个点:
//碰撞检测
function colTest(obj1, obj2) {
var t1=obj1.offsetTop;
var r1=obj1.offsetWidth + obj1.offsetLeft;
var b1=obj1.offsetHeight + obj1.offsetTop;
var l1=obj1.offsetLeft;
var t2=obj2.offsetTop;
var r2=obj2.offsetWidth + obj2.offsetLeft;
var b2=obj2.offsetHeight + obj2.offsetTop;
var l2=obj2.offsetLeft;
`if (t1 > b2 || r1 < l2 || b1 < t2 || l1 > r2)` {
return false;
} else {
return true;
}
}
这段代码看似信息量很少,其实也很好理解,判断两个图片切片是否发生碰撞,只要将它们没有发生碰撞的情形排除掉就可以了。这有点类似与逻辑中的非是即否,两个切片又确实只可能存在两种情况:碰撞、不碰撞。图中的这段代码是判断不碰撞的情况:if (t1 > b2 || r1 < l2 || b1 < t2 || l1 > r2),返回false, else 返回true。
2.碰撞检测完成了之后,图片切片之间又是怎样寻找左上角定点距离最近的元素呢?
代码是这个样子的:
//勾股定理求距离(左上角的距离)
function getDis(obj1, obj2) {
var a=obj1.offsetLeft - obj2.offsetLeft;
var b=obj1.offsetTop - obj2.offsetTop;
return Math.sqrt(Math.pow(a, 2) + Math.pow(b, 2));
}
//找到距离最近的
function findMin(obj) {
var minDis=999999999;
var minIndex=-1;
for (var i=0; i < aLi.length; i++) {
if (obj==aLi[i]) continue;
if (colTest(obj, aLi[i])) {
var dis=getDis(obj, aLi[i]);
if (dis < minDis) {
minDis=dis;
minIndex=i;
}
}
}
if (minIndex==-1) {
return null;
} else {
return aLi[minIndex];
}
}
因为都是矩形区块,所以计算左上角的距离使用勾股定理,这点相信大家都能明白。查找距离最近的元素原理也很简单,就是遍历所有已经碰撞的元素,然后比较根据勾股定理计算出来的最小值,返回元素就可以了。代码中也是使用了比较通用的方法,先声明一个很大的值最为最小值,当有碰撞元素比其小时,再将更小的值最为最小值,遍历完成后,返回最小值的元素就可以了。
答案是回调函数,图片切片交换函数通过回调函数来判断游戏是否已经结束,游戏是否结束的判断函数前面我们已经说过。图片切片交换函数就是通过添加gameIsEnd作为回调函数,这样在每次图片切片移动交换完成之后,就判断一下游戏是否结束。图片切片的交换函数还是比较复杂的,有兴趣的同学可以研究一下,下面是其实现代码,大家重点理解其中添加了回调函数监控游戏是否结束就好了。
//通过class获取元素
function getClass(cls){
var ret=[];
var els=document.getElementsByTagName("*");
for (var i=0; i < els.length; i++){
//判断els[i]中是否存在cls这个className;.indexOf("cls")判断cls存在的下标,如果下标>=0则存在;
if(els[i].className===cls || els[i].className.indexOf("cls")>=0 || els[i].className.indexOf(" cls")>=0 || els[i].className.indexOf(" cls ")>0){
ret.push(els[i]);
}
}
return ret;
}
function getStyle(obj,attr){//解决JS兼容问题获取正确的属性值
return obj.currentStyle?obj.currentStyle[attr]:getComputedStyle(obj,false)[attr];
}
function gameEnd() {
alert('游戏结束!');
}
function startMove(obj,json,fun){
clearInterval(obj.timer);
obj.timer=setInterval(function(){
var isStop=true;
for(var attr in json){
var iCur=0;
//判断运动的是不是透明度值
if(attr=="opacity"){
iCur=parseInt(parseFloat(getStyle(obj,attr))*100);
}else{
iCur=parseInt(getStyle(obj,attr));
}
var ispeed=(json[attr]-iCur)/8;
//运动速度如果大于0则向下取整,如果小于0想上取整;
ispeed=ispeed>0?Math.ceil(ispeed):Math.floor(ispeed);
//判断所有运动是否全部完成
if(iCur!=json[attr]){
isStop=false;
}
//运动开始
if(attr=="opacity"){
obj.style.filter="alpha:(opacity:"+(json[attr]+ispeed)+")";
obj.style.opacity=(json[attr]+ispeed)/100;
}else{
obj.style[attr]=iCur+ispeed+"px";
}
}
//判断是否全部完成
if(isStop){
clearInterval(obj.timer);
if(fun){
fun();
}
}
},30);
}
4.1 游戏中值得完善的功能
我认为该游戏中值得优化的地方有两个:
这些功能感兴趣的小伙伴可以尝试一下。
相关推荐:
用javascript实现web拼图游戏
H5的canvas实现贪吃蛇小游戏
以上就是使用javascript中canvas实现拼图小游戏的详细内容,更多请关注其它相关文章!
更多技巧请《转发 + 关注》哦!
Canvas是一个矩形区域的画布,可以用JavaScript在上面绘画;
我们今天的目标是使用HTML5画布技术制作一款拼图小游戏,要求将图像划分为3*3的9块方块并打乱排序,用户可以移动方块拼成完整图片。
效果如下所示:
<div id="container">
<!--页面标题-->
<h3>HTML5画布综合项目之拼图游戏</h3>
<!--水平线-->
<hr />
<!--游戏内容-->
<!--游戏时间-->
<div id="timeBox">
共计时间:<span id="time">00:00:00</span>
</div>
<!--游戏画布-->
<canvas id="myCanvas" width="300" height="300" style="border:1px solid">
对不起,您的浏览器不支持HTML5画布API。
</canvas>
<!--游戏按钮-->
<div>
<button onclick="restartGame()">
重新开始
</button>
</div>
</div>
效果如下所示:
我们可以看到页面的大致结构是已经显现出来了,就是骨架已经搭建好了,现在我们要使用css强化样式;
整体背景设置
body {
background-color: silver;/*设置页面背景颜色为银色*/
}
游戏界面样式设置
#container {
background-color: white;
width: 600px;
margin: auto;
padding: 20px;
text-align: center;
box-shadow: 10px 10px 15px black;
}
游戏时间面板样式设置
#timeBox {
margin: 10px 0;
font-size: 18px;
}
游戏按钮样式设置
button {
width: 200px;
height: 50px;
margin: 10px 0;
border: 0;
outline: none;
font-size: 25px;
font-weight: bold;
color: white;
background-color: lightcoral;
}
鼠标悬浮时的按钮样式设置
button:hover {
background-color: coral;
}
设置好界面整体样式之后我们得到完整的界面,如下所示:
可以看到整体的静态界面已经搭建出来了
目标对象的获取
var c=document.getElementById('myCanvas'); //获取画布对象
var ctx=c.getContext('2d'); //获取2D的context对象
声明拼图的图片素材来源
var img=new Image();
img.src="image/pintu.jpg";
img.onload=function() { //当图片加载完毕时
generateNum(); //打乱拼图的位置
drawCanvas(); //在画布上绘制拼图
}
定义初始方块位置
var num=[[00, 01, 02], [10, 11, 12], [20, 21, 22]];
打乱拼图的位置
function generateNum() { //循环50次进行拼图打乱
for (var i=0; i < 50; i++) {
//随机抽取其中一个数据
var i1=Math.round(Math.random() * 2);
var j1=Math.round(Math.random() * 2);
//再随机抽取其中一个数据
var i2=Math.round(Math.random() * 2);
var j2=Math.round(Math.random() * 2);
//对调它们的位置
var temp=num[i1][j1];
num[i1][j1]=num[i2][j2];
num[i2][j2]=temp;
}
}
绘制拼图
自定义名称的drawCanvas()方法用于在画布上绘制乱序后的图片;
function drawCanvas() {
//清空画布
ctx.clearRect(0, 0, 300, 300);
//使用双重for循环绘制3x3的拼图
for (var i=0; i < 3; i++) {
for (var j=0; j < 3; j++) {
if (num[i][j] !=22) {
//获取数值的十位数,即第几行
var row=parseInt(num[i][j] / 10);
//获取数组的个位数,即第几列
var col=num[i][j] % 10;
//在画布的相关位置上绘图
ctx.drawImage(img, col * w, row * w, w, w, j * w, i * w, w, w); // w:300 / 3=100(小图宽度)
}
}
}
}
如下所示:
监听鼠标监听事件
c.onmousedown=function(e) {
var bound=c.getBoundingClientRect(); //获取画布边界
var x=e.pageX - bound.left; //获取鼠标在画布上的坐标位置(x,y)
var y=e.pageY - bound.top;
var row=parseInt(y / w); //将x和y换算成几行几列
var col=parseInt(x / w);
if (num[row][col] !=22) { //如果当前点击的不是空白区域
detectBox(row, col); //移动点击的方块
drawCanvas(); //重新绘制画布
var isWin=checkWin(); //检查游戏是否成功
if (isWin) { //如果游戏成功
clearInterval(timer); //清除计时器
ctx.drawImage(img, 0, 0); //绘制完整图片
ctx.font="bold 68px serif"; //设置字体为加粗、68号字,serif
ctx.fillStyle="red"; //设置填充色为红色
ctx.fillText("游戏成功!", 20, 150); //显示提示语句
}
}
}
点击方块移动
function detectBox(i, j) {
//如果点击的方块不在最上面一行
if (i > 0) {
//检测空白区域是否在当前方块的正上方
if (num[i-1][j]==22) {
//交换空白区域与当前方块的位置
num[i-1][j]=num[i][j];
num[i][j]=22;
return;
}
}
//如果点击的方块不在最下面一行
if (i < 2) {
//检测空白区域是否在当前方块的正下方
if (num[i+1][j]==22) {
//交换空白区域与当前方块的位置
num[i+1][j]=num[i][j];
num[i][j]=22;
return;
}
}
//如果点击的方块不在最左边一列
if (j > 0) {
//检测空白区域是否在当前方块的左边
if (num[i][j - 1]==22) {
//交换空白区域与当前方块的位置
num[i][j - 1]=num[i][j];
num[i][j]=22;
return;
}
}
//如果点击的方块不在最右边一列
if (j < 2) {
//检测空白区域是否在当前方块的右边
if (num[i][j + 1]==22) {
//交换空白区域与当前方块的位置
num[i][j + 1]=num[i][j];
num[i][j]=22;
return;
}
}
}
游戏成功判定与显示效果的实现
function restartGame() {
clearInterval(timer); //清除计时器
s=0; //时间清零
m=0;
h=0;
getCurrentTime(); //重新显示时间
timer=setInterval("getCurrentTime()", 1000);
generateNum(); //重新打乱拼图顺序
drawCanvas(); //绘制拼图
}
静态效果如上所示,至于游戏成功这里伙计们可以自行操作;
本次案例我们使用HTML5的新特性canvas画布标签打造了简单的9宫格拼图游戏,总体来说没有特别的复杂,主要是图片的分割方块移动事件的绑定,以及重新游戏的初始化操作,明确了游戏逻辑之后其实代码的编写其实不难。感兴趣的小伙伴可以去尝试一下。
TML5 CSS3 3D魔方拼图在线益智小游戏网页开发。一款基于HTML5和CSS3的3D立方体拼图应用,一共有8个小立方体组成的3D拼图,我们可以点击立方体或者方向键完成拼图,同时我们也可以让立方体保持旋转。采用响应式设计,自适应手机移动端,用户体验友好。
ps:推荐一下我的微细公众号:webqiand,学习前端有不懂的(学习方法,学习路线,如何学习有效率的问题)可以关一下,公众号有不错的学习教程,开发工具、电子书籍分享。
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <title>HTML5 CSS3 3D魔方拼图在线益智小游戏网页开发</title> <meta name="keywords" content="HTML5,CSS3,3D魔方,拼图,在线益智小游戏,网页开发" /> <meta name="description" content="HTML5 CSS3 3D魔方拼图在线益智小游戏网页开发。一款基于HTML5和CSS3的3D立方体拼图应用,一共有8个小立方体组成的3D拼图,我们可以点击立方体或者方向键完成拼图,同时我们也可以让立方体保持旋转。采用响应式设计,自适应手机移动端,用户体验友好。" /> <link rel='stylesheet prefetch' href='https://fonts.googleapis.com/icon?family=Material+Icons'> <link rel="stylesheet" href="css/style.css"> </head> <body> <div class="body-wrapper"> <div class="cubetwo-help-component"> <div class="cubetwo-row"> <div class="cubetwo-device-info"> <i class="material-icons"> touch_app </i> <div> tap or swipe with fingers </div> </div> <div class="cubetwo-device-info"> <i class="material-icons"> mouse </i> <div> click or swipe with mouse </div> </div> <div class="cubetwo-device-info cubetwo-device-info--keyboard"> <i class="material-icons"> keyboard </i> <div> keyboard keys </div> <div class="cubetwo-device-info-groups"> <div class="cubetwo-device-info-group"> <div> <i class="material-icons"> keyboard_tab </i> <i class="material-icons"> keyboard_arrow_up </i> </div> <div> <i class="material-icons"> keyboard_arrow_left </i> <i class="material-icons"> keyboard_arrow_down </i> <i class="material-icons"> keyboard_arrow_right </i> </div> </div> <div class="cubetwo-device-info-group"> <div> <span> q </span> <span> w </span> <span> e </span> </div> <div> <span> a </span> <span> s </span> <span> d </span> </div> <div> <span> x </span> <span> y </span> <span> z </span> </div> </div> </div> </div> </div> <a href="https://github.com/kunukn/cube-two" target="_blank" class="cubetwo-github-link"> github project </a> </div> <div class="cubetwo-menu-component"> <div class="cubetwo-row"> <button class="cubetwo-js cubetwo-btn cubetwo-btn-scramble"> scramble </button> <button class="cubetwo-js cubetwo-btn cubetwo-btn-spin"> spin </button> <button class="cubetwo-js cubetwo-btn cubetwo-btn-solve"> solve </button> </div> </div> <div class="cubetwo-component" id="cubetwo-component-1"> <div class="cubetwo-rotation-view"> <div class="cubetwo-cube-group cubetwo-cube-group--1"> <div class="cubetwo-cube-1" tabindex="0" data-type="cubetwo"> <div class="cubetwo-cube" data-type="cubetwo-display" data-index="1"> <div data-type="front"> <div> front </div> </div> <div data-type="up"> <div> up </div> </div> <div data-type="right"> <div> right </div> </div> <div data-type="back"> <div> back </div> </div> <div data-type="down"> <div> down </div> </div> <div data-type="left"> <div> left </div> </div> </div> <div class="cubetwo-cube" data-type="cubetwo-touch"> <div data-type="front"> touch front </div> <div data-type="up"> touch up </div> <div data-type="left"> touch left </div> </div> </div> <div class="cubetwo-cube-2" tabindex="0" data-type="cubetwo"> <div class="cubetwo-cube" data-type="cubetwo-display" data-index="2"> <div data-type="front"> <div> front </div> </div> <div data-type="up"> <div> up </div> </div> <div data-type="right"> <div> right </div> </div> <div data-type="back"> <div> back </div> </div> <div data-type="down"> <div> down </div> </div> <div data-type="left"> <div> left </div> </div> </div> <div class="cubetwo-cube" data-type="cubetwo-touch"> <div data-type="front"> touch front </div> <div data-type="up"> touch up </div> <div data-type="right"> touch right </div> </div> </div>
需要这个项目css、js代码、图片的可以找我免费领取。如果大家不怕麻烦可以关注我后私信我“前端学习资料”几个字 找我领取 24小时在线!
*请认真填写需求信息,我们会在24小时内与您取得联系。