您现在的位置是:网站首页> 编程资料编程资料
JS实现羊了个羊小游戏实例_JavaScript_
2023-05-24
360人已围观
简介 JS实现羊了个羊小游戏实例_JavaScript_
引言
这两天火爆全场的《羊了个羊》游戏,相信大家都玩过了,那么在玩这个游戏的同时,我想大家都会好奇这个游戏的实现,本文就带大家使用css,html,js来实现一个动物版的游戏。
首先我用到了2个插件,第一个插件就是flexible.js,这个插件就是对不同设备设置根元素字体大小,也就是一个移动端的适配方案。
因为这里使用了rem布局,针对移动端做了自适应,所以这里选择采用rem布局方案。
rem布局方案
还有一个弹框插件,我很早自行实现的,就是popbox.js,关于这个插件,本文不打算讲解实现原理,只讲解一下使用原理:
popbox.js使用原理
ewConfirm({ title: "温馨提示", //弹框标题 content: "游戏结束,别灰心,你能行的!", //弹框内容 sureText: "重新开始", //确认按钮文本 isClickModal:false, //点击遮罩层是否关闭弹框 sure(context) { context.close(); //点击确认按钮执行的逻辑 },//点击确认的事件回调 })
引入了这个js之后,会在window对象上绑定一个ewConfirm方法,这个方法传入一个自定义对象,对象的属性有title,content,sureText,cancelText,cancel,sure,isClickModal
这几个属性,当然这里没有用到cancel按钮,所以不细讲。
正如注释所说,每个属性代表的意思,这里不做赘述。
html代码
羊了个羊《动物版》
可以看到html代码是什么都没有的,因为里面的DOM元素,我们都放在js代码里面动态生成了,所以script.js这里的代码是核心,这个后续会讲到,接下来看样式代码,也比较简单。
样式代码
* { margin: 0; padding: 0; box-sizing: border-box; } body, html { height: 100%; width: 100%; overflow: hidden; } body { background: url('https://www.eveningwater.com/my-web-projects/js/21/img/2.gif') no-repeat center / cover; display: flex; justify-content: center; align-items: center; } .ew-box { position: absolute; width: 8rem; height: 8rem; } .ew-box-item { width: 1.6rem; height: 1.6rem; border-radius: 4px; border: 1px solid #535455; background-position: center; background-size: cover; background-repeat: no-repeat; cursor: pointer; transition: all .4s cubic-bezier(0.075, 0.82, 0.165, 1); } .ew-collection { width: 8rem; height: 2.4rem; display: flex; align-items: center; justify-content: center; padding: 0 1rem; background: url('https://www.eveningwater.com/static/dist/20d6c430c2496590f224.jpg') no-repeat center/cover; position: fixed; margin: auto; overflow: auto; bottom: 10px; } .ew-collection > .ew-box-item { margin-right: 0.3rem; } .ew-left-source, .ew-right-source { width: 2.6rem; height: 1.2rem; position: absolute; top: 0; } .ew-left-source { left: 0; } .ew-right-source { right: 0; } .ew-shadow { box-shadow: 0 0 50px 10px #535455 inset; }
首先是通配选择器'*'代表匹配所有的元素,并且设置样式初始化,然后是html和body元素设置宽高为100%,并且隐藏溢出的内容,然后给body元素设置了一个背景图,并且body元素采用弹性盒子布局,水平垂直居中。
接下来是中间消除的盒子元素box,也很简单就是设置定位,和固定宽高为8rem。
接下来是box-item,代表每一个块元素,也就是消消乐的每一块元素,接着羊了个羊底部有一个存储选中块元素的收集盒子元素,也就是ew-collection,然后是左右的看不到层级的卡牌容器元素。
最后就是为了让块元素看起来有层叠效果而添加的阴影效果。
javascript代码
css核心代码也就比较简单,接下来我们来看javascript代码。
导入图片素材列表
在开始之前,我们需要先导入图片素材列表,这里如下:
const globalImageList = [ 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/1.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/2.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/3.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/4.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/5.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/6.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/7.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/8.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/9.jpg', 'https://www.eveningwater.com/my-web-projects/jQuery/7/img/10.jpg' ]
然后在onload也就是页面加载时调用我们封装好的Game类,将这个素材列表传入其中。如下:
window.onload = () => { const game = new Game(globalImageList); }
接下来,我们来看Game类的核心代码吧,首先定义这个类:
class Game { constructor(originSource, bindElement){ //核心代码 } }
这个类名有2个参数,第一个参数就是素材列表,第二个参数则是绑定的DOM元素,默认如果不传入的话,就绑定到document.body上。也因此,我们在构造函数里面初始化一些后续需要用到的变量。如下:
//constructor内部 this.doc = document; this.originSource = originSource; this.bindElement = bindElement || this.doc.body; // 存储随机打乱的元素 this.source = []; // 存储点击的元素 this.temp = {}; // dom元素 this.box = null; //存储消消乐块元素的容器盒子元素 this.leftSource = null; //左边素材容器元素 this.rightSource = null; //右边素材容器元素 this.collection = null; //收集素材的容器元素 // 需要调用bind方法修改this指向 this.init().then(this.startHandler.bind(this)); //startHandler为游戏开始的核心逻辑函数,init初始化方法
这里存储了document对象,存储了原始素材列表,以及绑定的dom元素,然后还定义了source用来存储被打乱后的素材列表,以及temp用来存储点击的元素,方便做消除,添加阴影这些操作。
还有四个变量,其实也就是存储dom元素的,如注释所述。
接下来init方法就是做初始化的一些操作,这个方法返回一个Promise所以才能调用then方法,然后startHandler是游戏开始的核心逻辑函数,这个后面会讲到,注意这里有一个有意思的点,那就是bind(this),因为在then方法内部的this并不是指Game这个实例,所以需要调用bind方法修改this绑定,接下来我们来看init方法做了什么。
init() { return new Promise(resolve => { const template = ``; const div = this.create('div'); this.bindElement.insertBefore(div, document.body.firstChild); this.createElement(div, template); div.remove(); resolve(); }) }
很显然这个方法如前所述返回了一个Promise,内部定义了template模板代码,也就是页面的结构,然后调用create方法创建一个容器元素,并且向body元素的首个子元素之前插入这个元素,然后在这个容器元素之前插入创建好的页面结构,删除这个容器元素,并且resolve出去,从而达到将页面元素添加到body元素内部。这里涉及到了两个工具函数,我们分别来看看它们,如下:
create(name) { return this.doc.createElement(name); }
create方法其实也就是调用createElement方法来创建一个DOM元素,this.doc指的就是document文件对象,也就是说,create方法只是document.createElement的一个封装而已。来看createElement方法。
createElement(el, str) { return el.insertAdjacentHTML('beforebegin', str); }
createElement方法传入2个参数,第一个参数是一个DOM元素,第二个参数是一个DOM元素字符串,表示在第一个DOM元素之前插入传入的模板元素。这个方法可以参考code-segment。
startHandler函数实现
init方法说白了就是动态创建元素的一个实现,接下来就是startHandler函数的实现。
startHandler() { this.box = this.$('#ew-box'); this.leftSource = this.$('#ew-left-source'); this.rightSource = this.$('#ew-right-source'); this.collection = this.$('#ew-collection'); this.resetHandler(); //后续还有逻辑 }
startHandler是核心实现,所以不可能只有上面那么点代码,但是我们要写一步步的拆分,以上的代码就做了2个逻辑,获取DOM元素和重置。这里涉及到了一个$方法,如下:
$(selector, el = this.doc) { return el.querySelector(selector); }
$方法传入2个参数,第一个参数为选择器,是一个字符串,第二个参数为DOM元素,实际上就是document.querySelector的一个封装。当然还有一个$$方法,类似,如下:
$$(selector, el = this.doc) { return el.querySelectorAll(selector); }
接下来是resetHandler方法,如下:
resetHandler() { this.box.innerHTML = ''; this.leftSource.innerHTML = ''; this.rightSource.innerHTML = ''; this.collection.innerHTML = ''; this.temp = {}; this.source = []; }
可以看到resetHandler方法确实是如其定义的那样,就是做重置的,我们要重置用到的数据以及DOM元素的子节点。
让我们继续,在startHandler也就是resetHandler方法的后面,添加这样的代码:
startHandler() { this.box = this.$('#ew-box'); this.leftSource = this.$('#ew-left-source'); this.rightSource = this.$('#ew-right-source'); this.collection = this.$('#ew-collection'); this.resetHandler(); for (let i = 0; i < 12; i++) { this.originSource.forEach((src, index) => { this.source.push({ src, index }) }) } this.source = this.randomList(this.source); //后续还有逻辑 }
可以看到这里实际上就是对素材数据做了一个添加和转换操作,randomList方法顾名思义,就是打乱素材列表的顺序。
randomList 工具方法
让我们来看这个工具方法的源码:
/** * 打乱顺序 * @param {*} arr * @returns */ randomList(arr) { const newArr = [...arr]; for (let i = newArr.length - 1; i >= 0; i--) { const index = Math.floor(Math.random() * i + 1); const next = newArr[index]; newArr[index] = newArr[i]; newArr[i] = next; } return newArr; }
这个函数的作用就是将素材列表随机打乱以达到随机的目的,接下来,让我们继续。
startHandler() { this.box = this.$('#ew-box'); this.leftSource = this.$('#ew-left-source'); this.rightSource = this.$('#ew-right-source'); this.collection = th
相关内容
- react Scheduler 实现示例教程_React_
- vue项目中vue-echarts讲解及常用图表实现方案(推荐)_vue.js_
- vue中设置echarts宽度自适应的代码步骤_vue.js_
- Vue中使用Echarts可视化图表宽度自适应的完美解决方案_vue.js_
- vue中的echarts实现宽度自适应的解决方案_vue.js_
- Vue3 封装 Element Plus Menu 无限级菜单组件功能的详细代码_vue.js_
- TypeScript数组的定义与使用详解_javascript技巧_
- vue项目打包后部署到服务器的详细步骤_vue.js_
- vue3动态修改打包后的请求路径的操作代码_vue.js_
- 解决vscode Better Comments插件在vue文件中不显示相对应的颜色的问题_vue.js_
点击排行
本栏推荐
