基于原生js,使用JavaScript完成消消乐的游戏

2 篇文章 0 订阅
2 篇文章 0 订阅

一、GIF图展示:

二、实现功能需要的js技术栈

        1.一维数组和二维数组

        2.使用js选择器选择DOM元素并操作DOM元素

        3.循环,函数,使用js修改DOM样式

三、实现思路

        1.棋盘的初始化

              定义一个容器作为棋盘,使用二维数组映射棋盘,再使用一个数组保存图片地址,二维数组的每个数由随机数产生,随机数的范围是0~存放图片数组的长度-1。然后通过初始化函数遍历所有格子,把格子里面的数字对应为图片数组,再通过操作DOM元素修改图片的地址渲染整个数组。

        初始化HTML代码

	<!-- 棋盘容器 -->
	<div id="game">

	</div>

       棋盘基本样式CSS

/* 消消乐容器宽高 */
#game {
	width: 500px;
	height: 500px;
	margin: 50px auto 0;
}

/* 消消乐每个格子 */
#game li {
	float: left;
	width: 46px;
	height: 46px;
	border: 2px solid skyblue;
	overflow: hidden;

}

        初始化棋盘部分代码

//创建一个二维数组作为棋盘的映射
var board = []
//判断当前所放容器能放几个图标
var container = document.querySelector("#game")
var containerWidth = container.offsetWidth
var containerHeight = container.offsetHeight
// ul的个数等于容器宽度等于二维数组的行
var countLine = containerHeight / 50
var countCol = containerWidth / 50
//图片列表(消除的元素)
var imgList = ["./img/1.png", "./img/2.png", "./img/3.png", "./img/4.png", "./img/5.png"]

//初始化数组 建立结构
for (let i = 0; i < countLine; i++) {
	var temp = []
	board.push(temp)
	for (var j = 0; j < countCol; j++) {
		board[i][j] = 0
	}
}


//渲染棋盘结构
for (let i = 0; i < board.length; i++) {
	var ul = document.createElement("ul")
    //ul对应二维数组的行 设置索引
	ul.setAttribute("index", i)
	for (let j = 0; j < board[0].length; j++) {
		var li = document.createElement("li")
        //ul对应二维数组的列
		li.setAttribute("index", j)
		var img = document.createElement("img")
		var ramdom = Math.floor(Math.random() * imgList.length)
		board[i][j] = ramdom

		li.appendChild(img)

		ul.appendChild(li)
	}
	container.appendChild(ul)
}

//更新棋盘逻辑(遍历棋盘数组)渲染格子内容
function updateBoard() {
	removeAroundMark()
	for (let i = 0; i < board.length; i++) {
		for (let j = 0; j < board[0].length; j++) {
			var img = document.querySelectorAll("#game ul")[i].children[j].children[0]
			img.style.animation = "none"
			if (img.className == "alreadySet") {
				var randomIndex = Math.floor(Math.random() * imgList.length)
				board[i][j] = randomIndex
				img.className = "notSet"
			}
			img.src = imgList[board[i][j]]
		}
	}
}
//调用渲染格子内容函数
updateBoard()

        2.点击消除逻辑

        给整个棋盘添加点击事件, 当点击棋盘的某个格子的时候,拿到此格子的元素,通过getAttribute()方法拿到该格子在棋盘的位置,也就是在棋盘上二维数组的位置。通过拿到该格子的坐标访问二维数组,进入判断函数:对其上下左右进行判断,如果y轴(上下)或者x轴(左右),有两个以及两个以上的数字,则把上下左右的相同数量送入消除函数。

        消除函数里面:拿到点击的坐标和相同的数量的个数,通过循环遍历,拿到这些要被消除的数组索引,并且在DOM棋盘上进行标记,再次进入判断函数,直到上下左右构不成消除的条件,最后更新棋盘,就完成了一个循环。

        JS部分代码

//判断点击天气上下是否为3个以及3个以上
function judgeY(x, y) {
	var top = x - 1
	var bottom = x + 1
	var countTop = 0
	var countBottom = 0
	// 寻找上面一共有几个并计数
	if (top >= 0) {
		while (board[x][y] == board[top][y]) {
			countTop++
			top--
			if (top < 0) {
				break
			}


		}
	}

	//寻找下面有几个并计数
	if (bottom < board.length) {
		while (board[x][y] == board[bottom][y]) {
			countBottom++
			bottom++
			if (bottom > board.length - 1) {
				break
			}
		}
	}
	//如果上面加上面相同的超过3个 则执行消除操作
	if (countBottom + countTop >= 2) {
		//消除
		removeItem("x", x, y, countTop, countBottom)
		return 1;
	}
}
//判断点击左右是否为3个或者三个以上
function judgeX(x, y) {

	var left = y - 1
	var right = y + 1
	var countLeft = 0
	var countRight = 0

	if (left >= 0) {
		while (board[x][y] == board[x][left]) {
			left--
			countLeft++
			if (left < 0) {
				break
			}

		}
	}
	if (right <= board[0].length) {
		while (board[x][y] == board[x][right]) {
			right++
			countRight++
			if (right > board[0].length) {
				break
			}
		}
	}
	if (countLeft + countRight >= 2) {
		//消除
		removeItem("y", x, y, countLeft, countRight)
		return 1;

	}

}
//消除函数
//判断消除的是横向还是纵向 
function removeItem(direction, x, y, min, max) {
	//纵向消除逻辑
	if (direction == "x") {
		console.log(x, y, min, max);
		for (let i = x - min; i <= x + max; i++) {
			var img = document.querySelectorAll("#game ul")[i].children[y].children[0]

			if (img.className == "alreadySet") {
				continue
			} else {
				img.className = "alreadySet"

				addTargetAnima(i, y)
				//再次判断要被消除的元素周围是否存在可消除条件
				rewriteYX(i, y)
			}



		}

	}
	//横向消除逻辑
	if (direction == "y") {
		for (let i = y - min; i <= y + max; i++) {
			//再次判断要被消除的元素周围是否存在可消除条件
			judgeY(x, i)
			var img = document.querySelectorAll("#game ul")[x].children[i].children[0]
			if (img.className == "alreadySet") {
				continue
			}
			img.className = "alreadySet"
			addTargetAnima(x, i)




		}
	}
}
//再次判断纵向消除时 左右消除的逻辑
function rewriteYX(x, y) {

	var left = y - 1
	var right = y + 1
	var countLeft = 0
	var countRight = 0

	if (left >= 0) {
		while (board[x][y] == board[x][left]) {
			left--
			countLeft++
			if (left < 0) {
				break
			}

		}
	}
	if (right <= board[0].length) {
		while (board[x][y] == board[x][right]) {
			right++
			countRight++
			if (right > board[0].length) {
				break
			}
		}
	}

	if (countLeft + countRight >= 2) {
		//消除
		for (let i = y - countLeft; i <= y + countRight; i++) {

			var img = document.querySelectorAll("#game ul")[x].children[i].children[0]
			if (img.className == "alreadySet") {
				continue
			} else {
				img.className = "alreadySet"
				addTargetAnima(x, i)

			}

		}

	}
}

        3.上下/左右交换

        判断逻辑

        点击棋盘的时候把点击的位置送到判断函数里面,如果判断函数有返回值则优先执行消除逻辑,否则执行交换逻辑。

        交换逻辑

        1.不能交换:

                首先把点击的第一个坐标的周围使用标记函数对齐周围进行标记,如果点击第二个位置的坐标没有此标记,则此次交换不成立,再判断此次交换以后是否能消除,如果不能消除,此次交换不成立 。

        2.可以交换:

                判断 为上下交换还是左右交换,进入对应的逻辑进行增加该方向消除动画,然后把交换以后的两个坐标放进判断函数进行消除。

        JS部分代码

//判断是否有上下左右属性如果有的话交换
		var res = document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]].getAttribute(
			"v-brother")

		if (res) {
			//再交换之前判断交换后是否能消除 如果交换后不能消除则不交换
			var one = [swapTemp[0][0], swapTemp[0][1]]
			var two = [swapTemp[1][0], swapTemp[1][1]]
			var temp = 0
			//交换二维数组
			temp = board[one[0]][one[1]]
			board[one[0]][one[1]] = board[two[0]][two[1]]
			board[two[0]][two[1]] = temp

			change = true
			if (!(judgeX(one[0], one[1]) || judgeY(one[0], one[1]) || judgeX(two[0], two[1]) || judgeY(two[0], two[
					1]))) {
				// 不能交换 清除高亮
				document.querySelectorAll("#game ul")[swapTemp[0][0]].children[swapTemp[0][1]].className = "none"
				document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]].className = "none"
				//不能交换就把交换的数组交换回来
				temp = board[one[0]][one[1]]
				board[one[0]][one[1]] = board[two[0]][two[1]]
				board[two[0]][two[1]] = temp

				swapTemp = []
				return 0;

			}

		}

		if (res) {
			//判断是上下还是左右
			if (swapTemp[0][0] == swapTemp[1][0]) {


				var imgLeft = document.querySelectorAll("#game ul")[swapTemp[0][0]].children[swapTemp[0][1]]
					.children[0]
				var imgRight = document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]]
					.children[0]
				imgLeft.style.animation = "none"
				imgRight.style.animation = "none"

				var tempSrc = imgLeft.src
				imgLeft.src = imgRight.src
				imgRight.src = tempSrc

				//交换图片
				var re = /\d.png/
				var imgLeftSrc = "./img/" + imgLeft.src.match(re)[0]
				var imgRightSrc = "./img/" + imgRight.src.match(re)[0]
				var indexL = imgList.indexOf(imgLeftSrc)
				var indexR = imgList.indexOf(imgRightSrc)


				//左右交换动画 并标记是左右动画 底下不在执行消除动画
				imgRight.setAttribute("animateType", "line")
				imgLeft.setAttribute("animateType", "line")
				//判断哪个是左
				var animateLeft;
				var animateRight;
				if (swapTemp[0][1] < swapTemp[1][1]) {
					animateRight = imgRight
					animateLeft = imgLeft

				} else {
					animateRight = imgLeft
					animateLeft = imgRight

				}
				animateLeft.style.animation = "lineLeft 0.5s normal linear"
				animateRight.style.animation = "lineRight 0.5s normal linear"




				board[swapTemp[0][0]][swapTemp[0][1]] = indexL
				board[swapTemp[1][0]][swapTemp[1][1]] = indexR

				console.log("左右交换");
				//交换完成以后送去消除
				judgeX(swapTemp[1][0], swapTemp[1][1])
				judgeX(swapTemp[0][0], swapTemp[0][1])
				judgeY(swapTemp[0][0], swapTemp[0][1])
				judgeY(swapTemp[1][0], swapTemp[1][1])

			} else {
				var imgTop = document.querySelectorAll("#game ul")[swapTemp[0][0]].children[swapTemp[0][1]]
					.children[0]
				var imgBottom = document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]]
					.children[0]
				imgTop.style.animation = "none"
				imgBottom.style.animation = "none"
				var tempSrc = imgTop.src
				imgTop.src = imgBottom.src
				imgBottom.src = tempSrc


				var re = /\d.png/
				var imgTopSrc = "./img/" + imgTop.src.match(re)[0]
				var imgBottomSrc = "./img/" + imgBottom.src.match(re)[0]
				var indexT = imgList.indexOf(imgTopSrc)
				var indexB = imgList.indexOf(imgBottomSrc)


				//列交换动画
				var animateTop;
				var animateBottom;
				if (swapTemp[0][0] < swapTemp[1][0]) {
					animateTop = imgTop
					animateBottom = imgBottom


				} else {
					animateTop = imgBottom
					animateBottom = imgTop


				}
				animateTop.style.animation = "colTop 0.5s normal linear"
				animateBottom.style.animation = "colBottom 0.5s normal linear"
				board[swapTemp[0][0]][swapTemp[0][1]] = indexT
				board[swapTemp[1][0]][swapTemp[1][1]] = indexB
				judgeX(swapTemp[1][0], swapTemp[1][1])
				judgeX(swapTemp[0][0], swapTemp[0][1])
				judgeY(swapTemp[0][0], swapTemp[0][1])
				judgeY(swapTemp[1][0], swapTemp[1][1])

			}
		}
		//交换完把高亮样式删除
		document.querySelectorAll("#game ul")[swapTemp[0][0]].children[swapTemp[0][1]].className = "none"
		document.querySelectorAll("#game ul")[swapTemp[1][0]].children[swapTemp[1][1]].className = "none"
		//删除所有标记
		removeAroundMark()
		swapTemp = []

//标记周围
function markAround(x, y, top, bottom, left, right) {
	document.querySelectorAll("#game ul")[x].children[y].setAttribute("v-brother", "brother")
	if (top >= 0) {
		document.querySelectorAll("#game ul")[top].children[y].setAttribute("v-brother", "brother")

	}
	if (bottom < board.length) {
		document.querySelectorAll("#game ul")[bottom].children[y].setAttribute("v-brother", "brother")
	}
	if (left >= 0) {
		document.querySelectorAll("#game ul")[x].children[left].setAttribute("v-brother", "brother")
	}
	if (right < board.length) {
		document.querySelectorAll("#game ul")[x].children[right].setAttribute("v-brother", "brother")
	}
}
//清楚周围标记
function removeAroundMark() {
	for (let i = 0; i < board.length; i++) {
		for (var j = 0; j < board[0].length; j++) {
			document.querySelectorAll("#game ul")[i].children[j].removeAttribute("v-brother")
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

晚安778

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值