程序员最近都爱上了这个网站  程序员们快来瞅瞅吧!  it98k网:it98k.com

本站消息

站长简介/公众号

  出租广告位,需要合作请联系站长


+关注
已关注

分类  

暂无分类

标签  

暂无标签

日期归档  

2023-06(4)

javascript(html5 canvas)做的拼图游戏,简单易懂

发布于2021-03-13 19:22     阅读(892)     评论(0)     点赞(29)     收藏(5)


趁着摸鱼的时间,写了个拼图小游戏,操作简单、提神醒脑

效果图(最后的完成了好像被遮住了,哈哈)

实现思路

  1. 用到canvas的drawImage方法,使用8个参数的方式来将大图片切成一张张的小图,同时将每个小图片存储到对应的数组中。
  2. 在切图的同时用两个数组keys和orig_keys存取小图的下标,9张小图的话(keys就输数字0-8的数组)。
  3. 点击开始按钮的时候keys随机排序,然后从小图片数组中去获取对应的图片对象,更新其显示位置,这样就可以打乱图片了。
  4. 选择一个小图片(再次点击此图片会取消当前选择状态),再选择另一个图片将会互相交换位置。
  5. 每次交换位置后会对数组keys和orig_keys进行比较,如果两个数组结构一样,则表示拼图完成。

drawImage使用

可以看这篇文章

 

编写ImageDraw构造函数

  1. //图片对象ImageDraw构造函数
  2. function ImageDraw(o,obj){
  3. this.id='',
  4. this.image=0,//图片对象(必填)
  5. this.sx=0,//图片切片开始x位置(显示整个图片的时候不需要填)
  6. this.sy=0,//图片切片开始y位置(显示整个图片的时候不需要填)
  7. this.sWidth=0, //图片切片开始宽度(显示整个图片的时候不需要填)
  8. this.sHeight=0,//图片切片开始高度(显示整个图片的时候不需要填)
  9. this.dx=0, //图片目标x位置(必填)
  10. this.dy=0, //图片目标y位置(必填)
  11. this.dWidth=0,//图片目标显示宽度(宽度不缩放时不必填)
  12. this.dHeight=0//图片目标高度高度(高度不缩放时不必填)
  13. this.init(o,obj);
  14. }
  15. ImageDraw.prototype.init=function(o,obj){
  16. this.lol=obj;
  17. for(var key in o){
  18. this[key]=o[key];
  19. }
  20. return this;
  21. }
  22. ImageDraw.prototype.render=function(context){
  23. draw(context,this);
  24. function draw(context,obj) {
  25. var ctx=context;
  26. ctx.save();
  27. if(!obj.image || getType(obj.dx)=='undefined' || getType(obj.dy)=='undefined'){
  28. throw new Error("绘制图片缺失参数");
  29. return;
  30. }
  31. ctx.translate(obj.dx,obj.dy);
  32. if(getType(obj.sx)!='undefined' && getType(obj.sy)!='undefined' && obj.sWidth && obj.sHeight && obj.dWidth && obj.dHeight){
  33. //裁剪图片,显示时候有缩放
  34. ctx.drawImage(obj.image, obj.sx, obj.sy, obj.sWidth, obj.sHeight, 0, 0, obj.dWidth, obj.dHeight);
  35. }else if(obj.dWidth && obj.dHeight){
  36. ctx.drawImage(obj.image, 0, 0, obj.dWidth, obj.dHeight);//原始图片,显示时候有缩放
  37. }else{
  38. ctx.drawImage(obj.image,0, 0);//原始图片,显示时候无缩放
  39. }
  40. ctx.restore();
  41. }
  42. }
  43. ImageDraw.prototype.isPoint=function(pos){
  44. //鼠标位置的x、y要分别大于dx、dy 且x、y要分别小于 dx+dWidth、dy+dHeight
  45. if(pos.x>this.dx && pos.y>this.dy && pos.x<this.dx+this.dWidth && pos.y<this.dy+this.dHeight ){//表示处于当前图片对象范围内
  46. return true;
  47. }
  48. return false;
  49. }

对图片进行切片

  1. 用大图片的长除以列数、用大图片的宽除以行数,分别得到小图片的长和宽;
  2. 用双循环初始化小图片
  3. keys存储key和posArr数组存取dx、dy(打乱的时候要用)
  1. //对图片进行切片
  2. Jigsaw.prototype.sliceImage=function(){
  3. var imgObj = this.imgObj;
  4. var img,image,key=this.imageIndex,renderArr=this.renderArr;
  5. var countX=this.countX,countY=this.countY;
  6. image=imgObj[key];
  7. var disX = this.w/countX,//小图片的宽
  8. disY = this.h/countY;//小图片的高
  9. //相关数组清空处理
  10. renderArr.length=0;
  11. this.orig_keys.length=0;
  12. this.keys.length=0;
  13. this.posArr.length=0;
  14. //初始化小图片对象
  15. var x=y=n=0;
  16. for(var i=0;i<countX;i++){
  17. x = i*disX;
  18. for(var j=0;j<countY;j++){
  19. y = j*disY;
  20. img = new ImageDraw({image:image,sx:x,sy:y,sWidth:disX,sHeight:disY, dx:x, dy:y ,dWidth:disX,dHeight:disY},this);
  21. renderArr.push(img);
  22. img.key=n;//设置key值
  23. img.keyPos=n;//设置所处于的位置
  24. this.orig_keys.push(n);
  25. this.keys.push(n);
  26. this.posArr.push({x:x,y:y})
  27. n++;
  28. }
  29. }
  30. }

随机排序

  1. this.keys.sort(function(a,b){//随机排序
  2. return Math.random()>0.5?1:-1;
  3. })
  1. 打乱前keys是这样:[0, 1, 2, 3, 4, 5, 6, 7, 8]
  2. 打乱后keys是这样的 : [5, 0, 7, 1, 4, 8, 6, 2, 3]
  3. 循环小图片对象的时候下标是0,1,2这样开始的,那第一次取到的key是keys数组的第一个元素5
  4. 用5再去posArr取到第6个元素posArr[5],并把这个元素的dx,dy设置给当前下标为0的小图片,其他一样道理,这样就打乱了图片。
  1. var key,pos;
  2. //排序后重新更改位置,达到打乱图片的效果
  3. _.each(this.renderArr,function(item,index){
  4. if(item){
  5. key = that.keys[index];
  6. pos = that.posArr[key];
  7. //改变dx,dy既可
  8. item.dx=pos.x;
  9. item.dy=pos.y;
  10. item.image=that.imgObj[that.imageIndex];
  11. item.key=key;
  12. item.keyPos=index;
  13. }
  14. });

看一下效果吧

给canvas添加点击事件,并给每个小图片增加判断,如果点击了当前小图片则增加一个边框,表示选中

Rect构造函数

  1. function Rect(o){
  2. this.x=0,//x坐标
  3. this.y=0,//y坐标
  4. this.width=100,//宽
  5. this.height=40,//高
  6. this.thin=true,//线段薄一点
  7. this.init(o);
  8. }
  9. Rect.prototype.init=function(o){
  10. for(var key in o){
  11. this[key]=o[key];
  12. }
  13. }
  14. Rect.prototype.render=function(context){
  15. this.ctx=context;
  16. innerRender(this);
  17. function innerRender(obj){
  18. var ctx=obj.ctx;
  19. ctx.save()
  20. ctx.beginPath();
  21. ctx.translate(obj.x,obj.y);
  22. if(obj.lineWidth){
  23. ctx.lineWidth=obj.lineWidth;
  24. }
  25. if(obj.thin){
  26. ctx.translate(0.5,0.5);
  27. }
  28. ctx.rect(0,0,obj.width,obj.height);
  29. if(obj.fill){//是否填充
  30. obj.fillStyle?(ctx.fillStyle=obj.fillStyle):null;
  31. ctx.fill();
  32. }
  33. if(obj.stroke){//是否描边
  34. obj.strokeStyle?(ctx.strokeStyle=obj.strokeStyle):null;
  35. ctx.stroke();
  36. }
  37. ctx.restore();
  38. }
  39. return this;
  40. }

点击后代码

  1. //表示第一次选中
  2. item.selected=true;
  3. //添加一个边框用来指示被选择
  4. var rect = new Rect({
  5. x:item.dx,
  6. y:item.dy,
  7. width:item.dWidth,
  8. height:item.dHeight,
  9. stroke:true,
  10. strokeStyle:'skyblue'
  11. })
  12. rect.img=item;
  13. this.renderRectArr.push(rect);

此时效果

选中另一个图片后交换位置

  1. 清空选择状态及指示框
  2. 交换两个小图片对象的pos和key值
  3. 交换他们在keys数组中的值
  4. 判断此时keys与orig_keys是否一致,如果一致则表示完成
  1. var itemSelected = this.renderRectArr[0].img;
  2. //将已选择的dx、dy拷贝给x、y
  3. var x = itemSelected.dx,y=itemSelected.dy;
  4. //进行位置交换
  5. itemSelected.dx=item.dx,itemSelected.dy=item.dy,
  6. item.dx=x,item.dy=y;
  7. //清空选择状态及指示框
  8. itemSelected.selected=false;
  9. this.renderRectArr.length=0;
  10. //位置的交换
  11. var from_pos = itemSelected.keyPos;
  12. var from_key = itemSelected.key;
  13. var target_pos = item.keyPos;
  14. var target_key = item.key;
  15. itemSelected.pos=target_pos;
  16. itemSelected.key=target_key;
  17. item.pos=from_pos;
  18. item.key=from_key;
  19. //交换他们在this.keys中的位置
  20. this.keys.splice(from_pos,1,target_key);
  21. this.keys.splice(target_pos,1,from_key);
  22. //如果相等表示已经找好了
  23. if(this.diff(this.orig_keys,this.keys)){//每次交换完成以后都要进行一次判断,看是否完成拼图
  24. setTimeout(function(){
  25. alert("恭喜你已完成!");
  26. console.log('完成了');
  27. },0)
  28. }

最后、加上图片更换和难度系数的代码就完成了

  1. var box = document.getElementById('box');
  2. var start = document.getElementById('start');
  3. jigsaw.init(box,start);
  4. function up(type){
  5. var el = document.getElementById("difficulty_"+type);
  6. if(el){
  7. var val=el.value;
  8. if(val<10){
  9. val++;
  10. el.value=val;
  11. if(type='col'){
  12. jigsaw.countY=val;
  13. }else{
  14. jigsaw.countX=val;
  15. }
  16. }
  17. }
  18. }
  19. function down(type){
  20. var el = document.getElementById("difficulty_"+type);
  21. if(el){
  22. var val=el.value;
  23. if(val>3){
  24. val--;
  25. el.value=val;
  26. if(type='col'){
  27. jigsaw.countY=val;
  28. }else{
  29. jigsaw.countX=val;
  30. }
  31. }
  32. }
  33. }
  34. var index=1;
  35. var small_img =document.getElementsByClassName("small_img")[0];
  36. document.getElementById("next").onclick=function(){
  37. var src = small_img.src;
  38. var reg = /(\d+)\.jpeg$/;
  39. var arr = reg.exec(src);
  40. if(arr.length>1){
  41. index = ++arr[1];
  42. if(index>16){
  43. index=1;
  44. }
  45. jigsaw.imageIndex=index;
  46. jigsaw.draw();
  47. }
  48. small_img.src='./images/'+index+'.jpeg';
  49. }

 

全部代码下载,无需积分

兄弟们给个三连吧,谢谢拉!!




所属网站分类: 技术文章 > 博客

作者:程序员的人生

链接:http://www.qianduanheidong.com/blog/article/35789/ebef83b0c6f72269fa17/

来源:前端黑洞网

任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任

29 0
收藏该文
已收藏

评论内容:(最多支持255个字符)