您现在的位置是:网站首页> 编程资料编程资料

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
                
                

-六神源码网