【十字绣】传统手艺-微信小程序开发流程详解

还记得小时候看过母亲的十字绣吗,易学易懂,就是用专用的绣线和十字格布,通过平面坐标计找出位置,对照专用的图案进行刺绣,可作出心中所想的画,奈何所需材料成本不小,这里用小程序简单模拟十字绣,喜欢的话可用它练习一下。

打开微信开发工具,选择小程序,创建一个项目,
新建小程序

例如项目名称为miniprogram-cross-sitich,然后选择以下,再确定创建

  • AppID 使用测试号
  • 不使用云服务
  • JavaScript - 基础模板

游戏页面

小程序创建好后,找到文件pages/index/index.js,这是第一个页面的逻辑文件,

找到里面的方法onLoad(),在里面添加如下代码,可自动进到游戏页面

wx.navigateTo({
  url: '/pages/game/game',
})

页面布局

创建一个游戏页面,文件在pages/game/game.wxml

页面布局参照HTML网页的vue组件化布局,做好的页面运行显示效果图如下
在这里插入图片描述

布局中用到了一个canvas和用作背景显示的image组件,
还有颜色盒,可以左右拖动选择更多颜色,
还有底部的四个按钮,可清空,缩放网格,预览效果

游戏逻辑

接下来,在文件pages/game/game.wxml中写代码,实现游戏逻辑

初始化

实现的前提是做好初始化处理,把需要用到的全局变量,设置到data中,以便后面能读取和重新赋值

data:{
	bgImg:'',
    colorList:['F08784','EB3324','774342','8E403A','3A0603','9FFCFD','73FBFD','3282F6','0023F5','00129A','16417C','000C7B','FFFE91','FFFD55','F09B59','F08650','784315','817F26','7E84F7','732BF5','3580BB','00023D','58135E','3A083E','A1FB8E','A1FA4F','75F94D','75FA61','75FA8D','818049','EF88BE','EE8AF8','EA3FF7','EA3680','7F82BB','75163F','377D22','377E47','367E7F','507F80','183E0C','173F3F','741B7C','39107B','000000','808080','C0C0C0','FFFFFF'].map(color=>'#'+color),
    scale:1.0,
    colorCurrent:0
}
  • colorList就是颜色盒的数组数据,可选择的颜色都在这里定义;
  • colorCurrent指定数组中的其中的一个颜色值,选定笔色;
  • scale就是画布中的初始缩放尺寸,值1.0是表示原始大小;

获取画布

当页面加载完成时,会调用其中的onReady()事件,

在这里写代码,获取到布局文件中的canvas组件

wx.createSelectorQuery().select('#canv').fields({
  size:true, node:true
},res=>{
  //...省略了
  const ctx = res.node.getContext('2d');
  this.canvasData = {
    ctx,
    canvas:res.node,
    width:ctx.canvas.width,
    height:ctx.canvas.height
  };
  this.initCanvas();
}).exec()

传入的ctx就是画布的context对象,可用来绘制,
调用的initCanvas()是初始化方法,这里将继续处理,绘制网格

绘制网格

方法initCanvas()是把所有网格数据建出来,用灰白色区分不同位置的格子,

类似于PS软件中的透明背景图,代码如下

// 获取屏幕宽度和像素比
const { windowWidth, pixelRatio } = wx.getSystemInfoSync();
// 获取画布宽高
const { width, height } = this.canvasData;
// 算出格子大小,列和行
const size = Math.floor(windowWidth/pixelRatio/16);
const cols = Math.floor(width/size);
const rows = Math.floor(height/size);
// 算出内边距
const paddingH = (width-cols*size)*0.5;
const paddingV = (height-rows*size)*0.5;
// 定义网格数组
const grids = [];
for(let r=0; r<rows; r++){
  for(let c=0; c<cols; c++){
    let g = {
      left: c*size+paddingH,
      top: r*size+paddingV,
      //...省略了
    };
    // 将一个格子数据添加到数组中
    grids.push(g);
  }
}
// 设置网格数据,将上面定义的数据暂存起来
this.gridsData = {
  grids,
  //...省略了
  positon: {
    //...画布位置
  }
};
this.redrawGrils();

其中redrawGrils()就是绘制所有网格的方法,用canvas组件的context对象去绘制grids

实现操作

网格画出来后,接下来处理用户的操作

触摸事件

当用户手指触摸到页面布局中画布canvas区域时,画布会调用三个不同的事件,

分别是触摸的开始,移动,结束事件,分别做一下处理,

触摸开始事件

会调用onTouchStart(e)方法,代码如下

const touch = e.touches[0];
//记录触摸开始时的点
this.downPositon = touch;
//重置清除 触摸结束时的点
this.upPosition = undefined;
触摸移动事件

调用onTouchMove(e)方法,代码如下

const touch = e.touches[0];
const { downPositon } = this;
const { scale } = this.data;
this.upPosition = touch;
// 计算触摸结束到开始时的相对位置
let offsetPositon = {
  left: touch.x - downPositon.x,
  top: touch.y - downPositon.y
};
// 重新绘制所有网格
this.redrawGrils(scale, offsetPositon);

触摸移动时,就可以拖动画布,
调用方法redrawGrils(scale, offsetPositon),传入的第二个参数可以改变画布的位置,然后重新绘制网格和涂点位置

触摸结束事件

调用方法onTouchEnd(),代码如下

const { downPositon, upPosition } = this;
// 当触摸结束时,判断结束点可区分是否移动过
if (upPosition) {
  //省略了...
  let offsetPositon = {
	//省略了...
  };
  //如果移动了,就更新一下拖动画布后的位置
  this.gridsData.positon.left+=offsetPositon.left;
  this.gridsData.positon.top+=offsetPositon.top;
  return;
}

// 执行到这里时,以下就是对点击操作处理
const { grids, size } = this.gridsData;
const { scale, colorList, colorCurrent } = this.data;
// 触摸按下时的开始点
let touch = downPositon;
// 根据缩放和位置,找出格子
let s = size*scale;
// 偏移一半格子的距离
let offset = s*0.5;
let left = touch.x-offset;
let top = touch.y-offset;
let grid = grids.find(grid=>grid.left<=left && grid.left+s>left && grid.top<=top && grid.top+s>top);
//判断是否碰到格子,没有就返回
if(grid==undefined) return;
//省略了...
//判断是否涂点过(刺绣)
if(grid.flag) {
	//擦除涂点
  grid.flag = false;
  this.drawFlag(grid);
}else{
	//涂点
  grid.color = colorList[colorCurrent];
  grid.flag = true;
  this.drawFlag(grid);
}

其中drawFlag(grid)就是绘制格子方法,绘制交叉的涂点

选择颜色

这里实现选择颜色盒的颜色,很简单,

选择其中一个颜色格子时,会调用方法onClickColor(e),代码如下

const { index } = e.currentTarget.dataset;
// 更新指向颜色数组中的索引(游标)
this.setData({
  colorCurrent: index
})
放大和缩小

由于是在手机屏幕上操作,当显示的网格过小,手指会点不准的,

需要点击放大按钮,放大网格,这样就点得准,方便涂点,

点击按钮会调用方法onClickKey(e),代码如下

switch(e.currentTarget.dataset.key){
  case 'preview':// 预览
    this.saveImage();
    break;
  case 'amplify':// 放大
    this.amplifyGrids();
    break;
  case 'reduce':// 缩小
    this.reduceGrids();
    break;
  case 'clear':// 清空
    wx.showModal({
      title: '系统提示',
      content: '确定要清空吗?',
      complete: (res) => {
    	//...
        if (res.confirm) {
          this.resetGridData()
        }
      }
    });
    break;
}

页面中的底部四个按钮都是调用方法onClickKey(e),传入不同的参数,
例如,点击放大按钮时,调用方法传入参数amplify
再选择调用方法amplifyGrids()进行放大处理

放大的方法,就是调用了redrawGrils(scale),实现缩放,代码如下

let { scale } = this.data;
//放大
scale+=0.1;
//省略了...
//重新绘制网格,传入缩放比例
this.redrawGrils(scale);

有没有看出来,很多地方都调用了方法redrawGrils(scale)重绘网格,
这个方法实现了缩放和平移,是稍微复杂一点,不到60行代码,不多吧

缩小的方法,调用reduceGrids()后,也是调用了redrawGrils(scale)

缩小的代码同上面的一样,只是其中改成了scale-=0.1

预览图片

点击预览按钮,调用方法saveImage()这里会先进行预览,

图片看着没问题的话,长按图片就可以保存和分享,如下是代码

const { canvas, ctx } = this.canvasData;
//省略了...
//重新绘制网格,这里添加白色背景
this.redrawGrils(1, undefined, '#ffffff');
//生成图片地址
const imgSrc = canvas.toDataURL();
//省略了...
//再重新绘制一下 恢复原来的画面
this.redrawGrils(scale);
//开启预览
wx.previewImage({
  urls: [imgSrc],
  showmenu: true, // 长按图片可保存
  success:()=>{
  }
});

调用系统的wx.previewImage()方法,可以轻松实现预览和保存,分享图片

运行测试

讲到这里,这一个项目基本上就能完成,可以运行测试,

如想看项目源码,请点击这里查看,在资源一栏(手机上看可能找不到哦,请用电脑浏览器上看),找到其中的 十字绣 小程序项目源码 ,请放心下载,感谢支持。

如遇到什么问题可以留言,作者看到会回复的,

最后,看一下运行效果,动图如下,作者亲自做的,好看吗
请添加图片描述

十字绣-龙猫

试试绣出《梦里花》
唯一纯白的茉莉花,盛开在琥珀色月牙…

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TA远方

谢谢!收到你的爱╮(╯▽╰)╭

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值