今天是2016年最后一天上班了。最近几天都比较休闲,有时间空闲下来写写文档之类的。

2016过得真是快。感觉没做什么就过去了。想到之前想坚持每个月写一写博客都没坚持到。希望2017年可以吧。

无聊之余,看到了之前写的一个拼图游戏。就发一发共享下。写了有1年了。有些地方写得不是很好。但也能用了。

先上图看效果:

完整的代码可以去 git下载:https://github.com/zhouxitian/puzzle.

这里主要说一下思路什么的。

1、写这个之前也去搜索过网上的一些类似的游戏。当感觉都没有自己想要的。主要是网上的插件有些兼容不太好,例如移动端没兼容等。其次就是游戏难度控制感觉不好,有时过于困难有时过于简单。

2、后来想想,还是自己动手写一个吧。这样比较符合自己想要的效果。

3、主要考虑的事情其实就是一个。怎么控制游戏难度。不会出现太容易活太难的情况,也不会出现完成不了的情况。

4、后来就想到了这个控制步数,来达到控制难度的方法。其实也很简单。就是难度为1。那么只要走1步就能完成游戏,难度为10。那么最少需要10步(难度控制在游戏总格数的一半比较好)。

5、知道这类游戏规律的人会觉得容易,但不会的人却总在兜圈。玩多了,自然会感觉容易些。

6、怎么控制步数来达到控制游戏难度这个效果呢。当时想的就是一个逆向思维。即 既然最后是要完成游戏,那么怎么 不一开始就当游戏是拼好的。然后根据难度随机走,尽量排除之前走过的,这样就能把游戏打乱。然后出来的结果能稳定的控制步数。

7、总结:有时想问题总钻牛角尖,还不如静下来。逆向思考一下问题,或许就会获得灵感。

为了方便,部分代码也发一发吧。完整的例子还是去git下:

 ;(function(window,undefined){
myPuzzle=function(opt){
var t=this;
t.options={
id:"game",
pic:"images/p1.jpg",//图片
x:4,//列
y:3,//行
hard:5,//最大难度最好不要大于总格数的一半
duration:100,//毫秒
startInit:null,//每次重新开始游戏时的回调(相当于初始化)
stepStart:null,//每步开始移动时的回调
finish:null,//游戏完成后的回调
stepEnd:null//每走一步后的回调
};
t.extend(t.options,opt);
t.container=t.getId(t.options.id);
t.length=t.options.x*t.options.y;
t.current={};//当前拖动的元素信息
t.move=true;//当前的移动对象是否li
t.isMove=false;//是否能移动
t.init();
}
myPuzzle.prototype={
init:function(){
var t=this;
t.createGrid();//排序
t.touch=new myTouch({//滑屏
wrapper:"#"+t.wid,
start:function(e){
e=e||window.event;
t.touchChild=e.target||e.srcElement;
t.move=true;
if(t.touchChild.nodeName.toLowerCase()!="li"){
t.move=false;
}
t.checkMove=false;//是否需要检查 是否能移动
t.isMove=false;//是否能移动
if(t.move){
t.touchChild.style.transitionDuration="0ms";
t.current.index=parseInt(t.touchChild.getAttribute("index"));
t.current.x=t.position[t.current.index].x*t.cWidth;
t.current.y=t.position[t.current.index].y*t.cHeight;
t.current._x=t.position[t.current.index]._x*t.cWidth;
t.current._y=t.position[t.current.index]._y*t.cHeight;
}
}
});
t.start();
t.touch.moveX=t.touch.moveY=function(){
if(t.move){
var _t=this,MoveXY=0;
if(!t.checkMove){//判断移动方向
if(_t.x){
if(_t.changeX<0){
t.direction="left";
}else if(_t.changeX>0){
t.direction="right";
}
MoveXY=_t.changeX;
}else if(_t.y){
if(_t.changeY<0){
t.direction="up";
}else if(_t.changeY>0){
t.direction="down";
}
MoveXY=_t.changeY;
}
t.isMove=t.canMove(t.position[t.current.index]._index,t.direction);
if(t.isMove){//能移动才触发 每步的开始回调
t.options.stepStart&&t.options.stepStart.call(t);
}
//console.log(t.position[t.index]);
//console.log(t.getRadomPosition(t.position[t.index]._index))
t.checkMove=true;
}else{//限制移动范围
if(_t.x){
if(t.direction=="left"){
MoveXY=_t.changeX<-t.cWidth?-t.cWidth:(_t.changeX>0?0:_t.changeX);
}else{
MoveXY=_t.changeX>t.cWidth?t.cWidth:(_t.changeX<0?0:_t.changeX);
}
}else if(_t.y){
if(t.direction=="up"){
MoveXY=_t.changeY<-t.cHeight?-t.cHeight:(_t.changeY>0?0:_t.changeY);
}else{
MoveXY=_t.changeY>t.cHeight?t.cHeight:(_t.changeY<0?0:_t.changeY);
}
}
}
if(t.isMove){
if(_t.x){
t.touchChild.style.cssText='transition-duration:0ms;-webkit-transition-duration:0ms;z-index:2;left:'+(t.current._x+MoveXY)+'px;top:'+t.current._y+'px;background-position: -'+t.current.x+'px -'+t.current.y+'px;';
}else if(_t.y){
t.touchChild.style.cssText='transition-duration:0ms;-webkit-transition-duration:0ms;z-index:2;left:'+t.current._x+'px;top:'+(t.current._y+MoveXY)+'px;background-position: -'+t.current.x+'px -'+t.current.y+'px;';
}
}
}
}
t.touch.endX=t.touch.endY=function(){
if(t.move&&t.isMove){
var _t=this,xy,_x=t.position[t.current.index]._x,_y=t.position[t.current.index]._y,_index=t.position[t.current.index]._index;
if(_t.x){
xy=t.position[t.index]._x*t.cWidth;
t.touchChild.style.cssText='transition-duration:'+t.options.duration+'ms;-webkit-transition-duration:'+t.options.duration+'ms;z-index:0;left:'+xy+'px;top:'+t.current._y+'px;background-position: -'+t.current.x+'px -'+t.current.y+'px;';
}else if(_t.y){
xy=t.position[t.index]._y*t.cHeight;
t.touchChild.style.cssText='transition-duration:'+t.options.duration+'ms;-webkit-transition-duration:'+t.options.duration+'ms;z-index:0;left:'+t.current._x+'px;top:'+xy+'px;background-position: -'+t.current.x+'px -'+t.current.y+'px;';
}
//交换坐标
t.position[t.current.index]._x=t.position[t.index]._x;
t.position[t.current.index]._y=t.position[t.index]._y;
t.position[t.current.index]._index=t.position[t.index]._index;
t.position[t.index]._x=_x;
t.position[t.index]._y=_y;
t.position[t.index]._index=_index;
var win=true;
for(var i=t.position.length;i--;){
if(t.position[i].index!=t.position[i]._index){
win=false;
break;
}
}
t.touch.moveing=true;
t.step++;
if(win){
setTimeout(function(){
t.removeClass(t.visible,"hidden");
t.options.finish&&t.options.finish.call(t);
},t.options.duration);
}else{
setTimeout(function(){
t.touch.moveing=false;
t.options.stepEnd&&t.options.stepEnd.call(t);
},t.options.duration);
}
}
}
},
start:function(){
var t=this;
t.position=new Array();//记录每个移动元素的坐标
t.positionM=new Array();//记录移动后的元素
t.step=0;//记录移动的步数
if(t.visible){
t.removeClass(t.visible,"hidden");
}
for(var i=0;i<t.length;i++){
var x=i%t.options.x;
var y=Math.floor(i/t.options.x);
t.position.push({index:i,x:x,y:y,_index:i,_x:x,_y:y});
t.positionM.push(i);
x=x*t.cWidth;
y=y*t.cHeight;
t.wrapper.children[i].style.cssText='left:'+x+'px;top:'+y+'px;transition-duration:0ms;-webkit-transition-duration:0ms;background-position: -'+x+'px -'+y+'px;';
}
t.setGrid();//抽空一格
t.upSet();//打乱
t.touch.moveing=false;
t.options.startInit&&t.options.startInit.call(t);
},
refresh:function(){
var t=this;
t.width=parseInt(t.getStyles(t.container,"width"));
t.height=parseInt(t.getStyles(t.container,"height"));
t.cWidth=t.width/t.options.x;
t.cHeight=t.height/t.options.y;
for(var i=t.length;i--;){
x=t.position[i].x*t.cWidth;//原始x坐标
y=t.position[i].y*t.cHeight;//原始y坐标
_x=t.position[i]._x*t.cWidth;//移动x坐标
_y=t.position[i]._y*t.cHeight;//移动y坐标
t.wrapper.children[i].style.cssText='left:'+_x+'px;top:'+_y+'px;background-position:-'+x+'px -'+y+'px;';
}
},
createGrid:function(){//排序
var t=this;
t.width=parseInt(t.getStyles(t.container,"width"));
t.height=parseInt(t.getStyles(t.container,"height"));
t.cWidth=t.width/t.options.x;
t.cHeight=t.height/t.options.y;
var position=t.getStyles(t.container,"position");
if(position=="static"){
t.container.style.position="relative";
}
var ul=document.createElement('ul');
var data=new Date().getTime();
t.wid="myPuzzle_"+data;
ul.setAttribute("id",t.wid);
var style={};
style['#'+t.wid]='position:absolute;width:100%;height:100%;left:0;top:0;user-select:none;-webkit-user-select:none;';
style['#'+t.wid+' li']='transition-property:left,top,opacity;transition-timing-function:linear;-webkit-transition-property:left,top,opacity;-webkit-transition-timing-function:linear;width:'+(100/t.options.x)+'%;height:'+(100/t.options.y)+'%;position:absolute;background-image:url('+t.options.pic+');background-repeat:no-repeat;background-size:'+t.options.x+'00% '+t.options.y+'00%;';
style['#'+t.wid+' li.hidden']='visibility:hidden;opacity:0;';
//style['#'+t.wid+' li.hidden']='opacity:0.5;';
t.setCss(t.container,style);
var html='';
for(var i=0;i<t.length;i++){
var x=i%t.options.x;
var y=Math.floor(i/t.options.x);
//t.position.push({index:i,x:x,y:y,_index:i,_x:x,_y:y});
//t.positionM.push(i);
x=x*t.cWidth;
y=y*t.cHeight;
html+='<li index='+i+'>'+i+'</li>';
}
ul.innerHTML=html;
t.container.appendChild(ul);
t.wrapper=t.getId(t.wid);
},
setGrid:function(){//随机空一格
var t=this;
var random=Math.round(Math.random()*(t.length-1));
t.visible=t.wrapper.children[random];
t.addClass(t.visible,"hidden");
t.index=random;
},
upSet:function(){//根据难度打乱排序
var t=this;
t.answer=new Array();//记录走法
var answer=new Array();//记录移动方向
for(var i=t.options.hard;i--;){
var moveObj=t.getRadomPosition(t.position[t.index]._index);//记录能移动的元素(下标,方向);
var random=Math.ceil(Math.random()*moveObj.length)-1;//在能移动的元素里随机一个移动
;(function(){//检查随机走向,修正使其不走重复的路径
var length=answer.length;
if(length>0){
length--;
//console.log("random:"+random);
if((moveObj[random].direction=="up"&&answer[length]=="down")||(moveObj[random].direction=="down"&&answer[length]=="up")||(moveObj[random].direction=="left"&&answer[length]=="right")||(moveObj[random].direction=="right"&&answer[length]=="left")){
//console.log("相邻方向相反:"+moveObj[random].direction,answer[length],random);
if(random<moveObj.length-1){
random++;
}else{
random=0;
}
//console.log("相邻方向相反:"+moveObj[random].direction,answer[length],random);
arguments.callee();
}else if(moveObj.length>2&&length>1&&((moveObj[random].direction=="up"&&answer[length-1]=="down")||(moveObj[random].direction=="down"&&answer[length-1]=="up")||(moveObj[random].direction=="left"&&answer[length-1]=="right")||(moveObj[random].direction=="right"&&answer[length-1]=="left"))){
//console.log(moveObj,answer)
for(var i=moveObj.length;i--;){
if(i!=random//不取当前的
&&!((moveObj[i].direction=="up"&&answer[length-1]=="down")||(moveObj[i].direction=="down"&&answer[length-1]=="up")||(moveObj[i].direction=="left"&&answer[length-1]=="right")||(moveObj[i].direction=="right"&&answer[length-1]=="left"))//随机方向对比上一个方向
&&!((moveObj[i].direction=="up"&&answer[length]=="down")||(moveObj[i].direction=="down"&&answer[length]=="up")||(moveObj[i].direction=="left"&&answer[length]=="right")||(moveObj[i].direction=="right"&&answer[length]=="left"))){//随机方向对比前一个方向
random=i;
//console.log("相隔方向相反:"+moveObj[random].direction,random);
break;
}
}
}
}
})();
t.touchChild=t.container.querySelectorAll("li")[moveObj[random].index];
//console.log(t.position[t.index].index+"换"+moveObj[random].index);
t.answer.push(moveObj[random].index);
answer.push(moveObj[random].direction);
t.current.x=t.position[moveObj[random].index].x*t.cWidth;
t.current.y=t.position[moveObj[random].index].y*t.cHeight;
t.current._x=t.position[moveObj[random].index]._x*t.cWidth;
t.current._y=t.position[moveObj[random].index]._y*t.cHeight; var xy,
_x=t.position[moveObj[random].index]._x,//临时保存需交换的坐标
_y=t.position[moveObj[random].index]._y,
_index=t.position[moveObj[random].index]._index; if(moveObj[random].direction=="right"||moveObj[random].direction=="left"){
xy=t.position[t.index]._x*t.cWidth;
t.touchChild.style.cssText='transition-duration:0ms;-webkit-transition-duration:0ms;z-index:0;left:'+xy+'px;top:'+t.current._y+'px;background-position: -'+t.current.x+'px -'+t.current.y+'px;';
}else{
xy=t.position[t.index]._y*t.cHeight;
t.touchChild.style.cssText='transition-duration:0ms;-webkit-transition-duration:0ms;z-index:0;left:'+t.current._x+'px;top:'+xy+'px;background-position: -'+t.current.x+'px -'+t.current.y+'px;';
}
//交换移动后的坐标
var aa=t.positionM[t.position[t.index]._index];
//console.log("空"+t.positionM[t.position[t.index]._index]+"换"+_index+","+_index+"换"+aa);
t.positionM[t.position[t.index]._index]=t.positionM[_index];
t.positionM[_index]=aa;
//交换坐标
t.position[moveObj[random].index]._x=t.position[t.index]._x;
t.position[moveObj[random].index]._y=t.position[t.index]._y;
t.position[moveObj[random].index]._index=t.position[t.index]._index;
t.position[t.index]._x=_x;
t.position[t.index]._y=_y;
t.position[t.index]._index=_index;
}
t.answer.reverse();//=t.reverse(t.answer,t.answer.length-1,"");
},
//递归反转数组(不改变原数组),arr数组;length数组长度;str:""(空字符串)
reverse:function(arr,length,str){
var t=this;
return length==0?str+arr[0]:(t.reverse(arr,length-1,str+arr[length]+"=>"));
},
/**返回所有能移动的坐标信息
***index:当前隐藏元素的下标
**/
getRadomPosition:function(index){
var t=this;
var arry=new Array();
if(t.position[index].y>0){
arry.push({index:t.positionM[index-t.options.x],direction:"down"});
}
if(t.position[index].x>0){
arry.push({index:t.positionM[index-1],direction:"right"});
}
if(t.position[index].x<t.options.x-1){
arry.push({index:t.positionM[index+1],direction:"left"});
}
if(t.position[index].y<t.options.y-1){
arry.push({index:t.positionM[index+t.options.x],direction:"up"});
}
return arry;
},
/**判断是否能移动
***index:移动对象的下标
***direction移动方向
**/
canMove:function(index,direction){
var t=this,_index=t.position[t.index]._index;
if((direction=="right"&&index==_index-1)||(direction=="left"&&index==_index+1)||(direction=="down"&&index==_index-t.options.x)||(direction=="up"&&index==_index+t.options.x)){
return true;
}
return false;
},
extend:function(target,source){//拷贝不引用,改变拷贝的数组不会改变原数组
var t=this;
for (var p in source){
if(t.getType(source[p])=="array"||t.getType(source[p])=="object"){
target[p]=t.getType(source[p])=="array"?[]:{};
arguments.callee(target[p],source[p]);
}else{
target[p] = source[p];
}
}
return target;
},
getType:function(o)
{
var _t;
return ((_t = typeof(o)) == "object" ? o==null && "null" || Object.prototype.toString.call(o).slice(8,-1):_t).toLowerCase();
},
getId:function(elemId){return document.getElementById(elemId);},
getStyles:function(obj,name){
if(window.getComputedStyle){
var getStyles;
if ( obj.ownerDocument.defaultView.opener ) {
var computed =obj.ownerDocument.defaultView.getComputedStyle( obj, null );
getStyles= computed.getPropertyValue(name)||computed[ name];
}else{
var computed =window.getComputedStyle( obj, null);
getStyles= computed.getPropertyValue(name)||computed[ name ];
}
}else{
getStyles=obj.currentStyle[name];
}
if(name=="width"){
var maxWidth=arguments.callee(obj,"max-width");
var pmaxWidth=parseFloat(maxWidth)||0;
var pgetStyles=parseFloat(getStyles)||0;
if(pmaxWidth&&(pgetStyles>pmaxWidth||!pgetStyles)){
getStyles=maxWidth;
}
}else if(name=="height"){
var maxHeight=arguments.callee(obj,"max-height");
var pmaxHeight=parseFloat(maxHeight)||0;
var pgetStyles=parseFloat(getStyles)||0;
if(pmaxHeight&&(pgetStyles>pmaxHeight||!pgetStyles)){
getStyles=maxHeight;
}
}
return getStyles;
},
setCss:function(obj,styleObj){
var cssCode = '';
if(document.createStyleSheet)//兼容ie8不能动态加载css
{
var sheet = document.createStyleSheet();
for (var c in styleObj){
this.insertCssRule(sheet,c,styleObj[c]);
}
}else{
for (var c in styleObj){
cssCode+=c+'{'+styleObj[c]+'}';
}
var styleElement = document.createElement('STYLE');
styleElement.type = 'text/css';
var innerHTML = document.createTextNode(cssCode);
styleElement.appendChild(innerHTML);
if(obj.hasChildNodes()){
obj.insertBefore(styleElement,obj.children[0]);
}else if(obj){
obj.appendChild(styleElement);
}else{
document.head.appendChild(styleElement);
}
}
},
insertCssRule:function(sheet,selectorText,cssText, position) {
position=position||0;
if (sheet.insertRule) {
sheet.insertRule(selectorText + "{" + cssText + "}", position);
} else if (sheet.addRule) {
sheet.addRule(selectorText, cssText, position);
}
},
addClass:function(o,cn){var re = new RegExp("(\\s*|^)"+cn+"\\b","g");o.className +=o.className?(re.test(o.className)?"":" "+ cn):cn;},
removeClass:function(o,cn){var re = new RegExp("(\\s*|^)"+cn+"\\b","g");var sName = o.className;o.className = sName.replace(re,"");}
}
})(window);

欢迎高手指教。虽然不经常上博客。偶然上来看看也会回复的。

最新文章

  1. python动态创建类的声明
  2. 配置nginx的图片服务器
  3. mysql 5.6 online ddl
  4. sqlserver linkserver
  5. 使用oss批量上传图片
  6. git 的记住用户名和密码和一些常用
  7. 基类中定义的虚函数在派生类中重新定义时,其函数原型,包括返回类型、函数名、参数个数、参数类型及参数的先后顺序,都必须与基类中的原型完全相同 but------&gt; 可以返回派生类对象的引用或指针
  8. jQuery事件控制点击内容下拉
  9. linux中去掉^M的方法
  10. Android Eclipse 安装教程 hosts替换
  11. P1036 选数 题解
  12. MT【1】终点在球面上的向量
  13. Scratch 3.0 版本比较
  14. SHELL 中的变量
  15. caffe fine tune 复制预训练model的参数和freeze指定层参数
  16. PIPESTATUS 对于ksh 无效
  17. ny710 外星人的供给站
  18. 为什么排版引擎解析 CSS 选择器时一定要从右往左解析?
  19. TDDL实践
  20. 使用intellij idea搭建MAVEN+SSM(Spring+SpringMVC+MyBatis)框架

热门文章

  1. 解迷宫的C++的未完善编程代码........请大神们帮忙改善下.........
  2. 最全面的常用正则表达式大全 zz
  3. Momentics创建Photon图形程序
  4. docker centos7 rabbitmq3.6.5
  5. git本地提交到远程仓库命令
  6. css的小技巧
  7. My Sql 中要Alter Table的同学请注意!!!
  8. setTimeout和setInterval的区别以及如何写出效率高的倒计时
  9. springMVC+mybatis+spring整合案例
  10. UITableView使用