拼拼乐小游戏开发(VUE版本)
深秋的某一天,在地铁上面刷着手机,看到徐小夕的公众号推送的一篇文章,介绍的是一个移动端端的拼图小游戏,于是自己尝试着识别二维码完了下,感觉还挺有意思的.周末抽空研究了一下,看了下这个小游戏有哪些功能.问了下原作者,他用的是原生JS写的一版.自己本身在学习使用VUE开发项目,于是便萌发了用VUE尝试改版一下.正好可以学习学习一下.于是看了下游戏的大体效果,决定尝试用VUE改写一版玩一下,说干就干.也欢迎有兴趣,有想法的小伙伴可以一起讨论.
下面列一下用到的一些知识点:
- 洗牌算法
- CSS3动画切换(图片切割样式定位)
- 用FileReader API实现本地预览文件
- 用Canvas生成海报
- webpack打包(不同难度等级切换样式问题)
零零碎碎的花了2~3个周末的时间,然后部署了下页面.虽然存在一些问题,代码也比较粗糙.但是还是实现了自己想要的效果.
大致的实现思路可以参考趣谈前端
公众号里面的文章,教你用200行代码写一个爱豆拼拼乐H5小游戏(附源码).这里我对这个游戏VUE实现了相关的功能.而且还增加了一些自己的想法.
主要有相邻元素才可以挪动
和难度等级
选择,发版的是两个不同的版本.当然在实现的过程中也遇到了一些问题.不过经过自己的折腾还是基本实现出来自己想要的效果啦.
先来看看大致的实现功能模块:
具体实现:
1.根据选择的难度等级生成n*n的矩阵图切割图片
// 生成n维矩阵
generateMatrix(n, dx, dy) {
var arr = [],
index = 0;
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
arr.push({ x: j * dx, y: i * dy, index: index });
index++;
}
}
return arr;
}
2.数组乱序(重新排列)
upsetArr(arr) {
return arr.sort(function() {
return Math.random() > 0.5 ? -1 : 1;
});
}
3.点击高亮并且切换对应的位置(当前点击的和你要交换的)
// 点击高亮并且切换对应位置 (想办法交换对应索引位置的x,y值即可)
changePositon(e, item) {
//点击小图片切换位置方法
let reg = /active/g;
this.boxArractivelass = item;
let pieces = document.querySelectorAll(".piece");
if (!this.wall) {
this.wall = 1;
this.prevEl = e.target;
for (var i = 0, len = pieces.length; i < len; i++) {
// 使用replace为了避免元素后期加入其他类名
pieces[i].className = pieces[i].className.replace(" active", "");
}
!reg.test(this.className) && (this.className += " active");
} else {
this.wall = 0;
var prevIndex = +this.prevEl.getAttribute("index"),
curIndex = +e.target.getAttribute("index");
// 置换数组
this.swap(this.pool, prevIndex, curIndex);
this.prevEl.style.transform =
"translate(" +
this.pool[prevIndex].x +
"vw," +
this.pool[prevIndex].y +
"vh" +
")";
e.target.style.transform =
"translate(" +
this.pool[curIndex].x +
"vw," +
this.pool[curIndex].y +
"vh" +
")";
// 清除样式
this.boxArractivelass = -1;
// 校验是否成功
if (this.isTestSuccess(this.pool)) {
clearInterval(this.timer);
this.startDx -= 100;
this.issuccess = true;
this.transformX(this.$refs.wrap, this.startDx + "vw");
}
}
}
4.点击交换图片的位置
// 置换数组(对应索引的x,y值进行交换)
swap(arr, indexA, indexB) {
// ES6的解耦交换方式: [arr[index], arr[n]] = [arr[n], arr[index]];
[arr[indexA], arr[indexB]] = [arr[indexB], arr[indexA]];
},
5.检验是否成功方法:
//对比数组中的每一个值是否与之前的值相等
isTestSuccess(arr) {
return arr.every(function(item, i) {
return item.index === i;
});
}
在实现的过程中,遇到一个印象比较深的问题就是,当在第一个页面选择简单
等级,然后点击开始游戏,然后返回重新选择中级
等级,由于样式加载顺序,导致页面展示的还是之前简单
等级的页面样式.
之前出现这种问题的原因是由于,我这边是通过判断选择等级,然后import引入不同的样式文件导致的.
例如:实现的思路判断:
if(this.gradeSelected==3) {
import('../assets/style/default.css');
} else if(this.gradeSelected===4){
import('../assets/style/middle.css');
} else if(this.gradeSelected===5) {
import('../assets/style/senior.css');
}
后来重新换了一种思路,直接写了一个方法,本地存储选中的等级,用来设置选中不同难度等级的样式文件.然后动态的插入到head标签中.
// 引入设置和获取本地存储的挑战等级标识
import localStorage from "./storage";
const skin = {};
let getSkinStyle = (skin) => {
if (!skin) {
return "";
}
if (skin === 'three') {
return `简单等级的样式文件`
} else if(skin==='four') {
return `中等等级的样式文件`
} else if(skin==='five') {
return `高级等级的样式文件`
}
let setSkinStyle = (skin) => {
let styleText = getSkinStyle(skin);
let oldStyle = document.getElementById("skin");
const style = document.createElement("style");
style.id = "skin";
style.type = "text/css";
style.innerHTML = styleText;
oldStyle ? document.head.replaceChild(style, oldStyle) : document.head.appendChild(style);
};
// 设置不同等级图片切割样式
skin[localStorage.getSkin()] && setSkinStyle(skin[localStorage.getSkin()]);
export { skin, setSkinStyle }
至此,现在不同等级的选择切换,再也不会造成选择等级与图片分割界面样式不符啦.也可以愉快的玩耍啦.
当然代码还是比较粗糙,也存在一些问题的.还有就是不同版本的手机也没有经过兼容性测试,代码都在一个页面,也没有进行合理的组件拆分等等.
以上游戏纯属娱乐,有兴趣的小伙伴也欢迎交流,有什么问题也可以一起探讨,源码地址也放到了我的Github
上面,欢迎大家一起交流探讨,共同进步.