初夏创意投稿大赛 | 合成大冰棍

529 阅读2分钟

我正在参加「初夏创意投稿大赛」详情请看:初夏创意投稿大赛

序言

夏天到啦!不如来玩合成大冰棍,清爽加倍,快乐加倍!

设计思路

 我打算做的是类似于消消乐 + 2048 那种,找到两个相同的元素,点击两个相同的元素就可以合成另一个 level 更高的元素。也就是 1 + 1 = 2... ,最后算到最大的一个数就算游戏成功。

  1. 整个设计是 5*5 的格子(当然也可以更多)
  2. 游戏开始之前,每一个格子随机生成一个背景图片(待匹配的元素)
  3. 如果点击了两个相同的元素,后一个点击的元素会合成成 level 更高的元素,前一个元素会再次随机生成背景图片
  4. 如果合成的元素是最高等级的(大冰棍),游戏成功 ps:我选择了 16 张图片,19 张图片可以随机生成, 1016 张图片只能通过合成

代码实现

创建格子

鱿鱼容器内部全是格子,所以直接使用 grid 布局

<div class="summmer_wrapper">
	<div class="eliminate_wrapper"></div>
</div>
.eliminate_wrapper {
	display: grid;
	grid-template-columns: repeat(5, 120px);
	grid-template-rows: repeat(5, 120px);
	grid-row-gap: 10px;
	grid-column-gap: 10px;
}

一开始无脑冲,直接 html 拉满,但是因为我的格子有 25 个,总不能一个个写到 25 吧这也太拉了

<div class="eliminate_wrapper">
	<div id="xxx_1"><div>... ...</div></div>
</div>

然后想到动态创建元素, 但是如果多次使用 appendChild,会造成大量的回流,所以想到了碎片节点

const eliminate = document.getElementsByClassName('eliminate_wrapper')[0];
for (let i = 0; i < 25; i++) {
	let elem = document.createElement('div');
	elem.id = `eliminate_${i + 1}`;
	oFrag.appendChild(elem);
}
eliminate.appendChild(oFrag);

创建完格子之后给每一个格子加上随机背景(待消除的元素)

//生成从minNum到maxNum的随机数
function randomNum(minNum, maxNum) {
	return parseInt(Math.random() * (maxNum - minNum + 1) + minNum, 10);
}
for (let i = 0; i < eliminate.children.length; i++) {
  // 生成1~9的随机图片
	let n = randomNum(1, 9);
	eliminate.children[i].style.backgroundImage = `url('${imgs[n - 1]}')`;
	eliminate.children[i].style.backgroundRepeat = 'no-repeat';
	eliminate.children[i].style.backgroundSize = '100%';
}

然后随便加点绿绿蓝蓝的背景色,显得非常的解暑有没有!

image.png

如何选中元素 - 事件代理

一开始想着给每个元素加点击事件,但是如果使用循环绑定,就会非常消耗新能,而且在后面动态添加无法执行,所以使用事件代理

是不是很久没有用原生了!来复习一下事件代理吧!

事件代理:不亲自绑定事件,委托给父级,再通过寻找事件源去处理有(多个元素需要绑定事件的时候,建议使用事件委托

eliminate.onclick = e => {
	let tar = e.target || e.srcElement;
	// dosomething
};

核心逻辑

  1. 创建一个数组来保存选中的元素,点击选中元素,就把元素 push 进数组
  2. 如果两次点击 id 相同的元素,认为是取消选中
  3. 如果数组中两个元素 id 不相等且背景相等则匹配成功,否则匹配失败
  4. 数组中两个元素匹配成功,arr[1]的元素的背景替换成更高 level 的背景,随机生成 arr[0]的元素的背景
  5. 如果 arr[1]的背景是最高等级的背景,游戏成功,显示成功动画,否则清空数组
let selectedPair = [];
eliminate.onclick = e => {
	let tar = e.target || e.srcElement;
	if (tar === selectedPair[0] && selectedPair.length === 1) {
		selectedPair[0].className = '';
		selectedPair = [];
		return;
	}
	if (
		tar.id.indexOf('eliminate') !== -1 &&
		selectedPair.indexOf(tar) === -1 &&
		selectedPair.length < 2
	) {
		selectedPair.push(tar);
		tar.className = 'choose';
	}
	if (selectedPair.length === 2) {
		if (selectedPair[0].style.backgroundImage === selectedPair[1].style.backgroundImage) {
			let addImg = parseInt(selectedPair[1].style.backgroundImage.split('ice-cream-img/')[1][0]);
			if (addImg <= 15) {
				selectedPair[1].style.backgroundImage = `url('../big-ice-cream/ice-cream-img/${
					addImg + 1
				}.png')`;
				selectedPair[0].style.backgroundImage = `url('${imgs[randomNum(1, 9) - 1]}')`;
				selectedPair[0].style.backgroundRepeat = selectedPair[1].style.backgroundRepeat =
					'no-repeat';
			}
			if (addImg >= 15) {
				selectedPair[1].className += ' success';
				restart.style.display = 'block';
			} else {
				selectedPair[0].className = selectedPair[1].className = '';
				selectedPair = [];
			}
		} else {
			selectedPair[1].className = '';
			selectedPair.pop();
		}
	}
};

挑战成功

合成大冰棍之后,弹出成功按钮,并加上一些动画,不然太丑了
再加上游戏说明,完成

image.png

马上耍一把看看!

游戏地址

代码地址