vue3+uniapp在微信小程序实现一个2048小游戏

一、效果展示

二、代码

<template>
	<view class="page">
		<view class="top">
			<view class="score">
				得分:{{total}}
			</view>
			<view class="time">
				用时:{{allTime}}s
			</view>
		</view>
		<view class="center">
			<view class="mainBox">
				<view class="row" v-for="(row, rowIndex) in gameBoard" :key="rowIndex">
					<view class="cell" v-for="(cell, cellIndex) in row" :key="cellIndex">
						<!-- 	<view :class="cell!==0?'cellBox':''"> -->
						<view
							:class="cellIndex==newArr[0][1]&&rowIndex==newArr[0][0]||cellIndex==newArr[1][1]&&rowIndex==newArr[1][0]?'newBox':cell!==0?'cellBox':''">
							<view class="colorBox"
								:style="{backgroundColor:cell==2?'#ff3a3a':cell==4?'#ff9b29':cell==8?'#ebff31':cell==16?'#34ff31':cell==32?'#369083':cell==64?'#2e3cff':cell==128?'#c12fff':cell==256?'#ff77ed':cell==512?'#ffe9fe':cell==1024?'#fffcd4':cell==2048?'#04010b':''}">
								<text v-show=" cell!==0&&cell!==1">{{ cell }}</text>
							</view>

						</view>

					</view>
				</view>
			</view>
		</view>
		<view class="bottom">
			<view class="kaishi" v-show="gameStatus==false">
				<view class="flexBox"> <button @click="gameStart()"> 游戏开始</button></view>
			</view>
			<view class="jinxing" v-show="gameStatus==true">
				<view class="flexBox">
					<view class="gameOver">
						<view class="gameOverButton" @click="gameOver()">
							结束
						</view>
					</view>
					<view class="contorl">
						<view class="shang" @click="shang()">

						</view>
						<view class="xia" @click="xia()">

						</view>
						<view class="zuo" @click="zuo()">

						</view>
						<view class="you" @click="you()">

						</view>
					</view>

				</view>

			</view>
		</view>
	</view>
</template>

<script lang="ts" setup>
	import { ref } from 'vue'
	// 游戏状态
	const gameStatus = ref<boolean>(false);
	// 显示的数组
	let gameBoard = ref<number[][]>(Array.from({ length: 4 }, () => Array(4).fill(0)));
	// 新增的俩
	let newArr = ref<number[][]>(Array.from({ length: 2 }, () => Array(2).fill(null)))
	// 得分
	const total = ref<number>();
	// 用时
	const allTime = ref(0)
	const timer1 = ref()
	// 游戏开始
	const gameStart = () => {
		total.value = 0;
		allTime.value = 0
		gameStatus.value = true;
		gameBoard.value = numInit()
		timer1.value = setInterval(() => {
			allTime.value = allTime.value + 1;
		}, 1000)
	}
	// 游戏结束
	const gameOver = () => {
		gameStatus.value = false;
		clearInterval(timer1.value)
		timer1.value = null;
		newArr.value = Array.from({ length: 2 }, () => Array(2).fill(null));

	}
	// 获取随机数的函数
	const getRandomlet = (min, max) => {
		min = Math.ceil(min);
		max = Math.floor(max);
		return Math.floor(Math.random() * (max - min + 1)) + min;
	}
	// 随机初始化数值
	const numInit = () => {
		const array = Array.from({ length: 4 }, () => Array(4).fill(0));
		const positions = [];
		// 生成一个包含所有可能位置的数组  
		for (let i = 0; i < 4; i++) {
			for (let j = 0; j < 4; j++) {
				positions.push({ x: i, y: j });
			}
		}
		// 随机选择6个位置  
		const selectedPositions = [];
		for (let i = 0; i < 6; i++) {
			const randomIndex = getRandomlet(0, positions.length - 1);
			selectedPositions.push(positions[randomIndex]);
			positions.splice(randomIndex, 1); // 从数组中移除已选位置,避免重复选择  
		}
		// 设置前4个位置为2  
		for (let i = 0; i < 4; i++) {
			const position = selectedPositions[i];
			array[position.x][position.y] = 2;
		}
		// 对于剩下的2个位置,随机设置为4或8  
		for (let i = 4; i < 6; i++) {
			const position = selectedPositions[i];
			const randomValue = getRandomlet(1, 2) === 1 ? 4 : 8;
			array[position.x][position.y] = randomValue;
		}
		return array;
	}
	// 旋转数组
	const rotate90Clockwise = (matrix) => {
		const n = matrix.length;
		let rotatedMatrix = Array.from({ length: n }, () => []);

		// 顺时针旋转90度
		for (let i = 0; i < n; i++) {
			for (let j = 0; j < n; j++) {
				rotatedMatrix[j][n - i - 1] = matrix[i][j];
			}
		}

		return rotatedMatrix;
	}
	// 累计与填入
	const addNum = (arr) => {
		let copiedArray = JSON.parse(JSON.stringify(arr));
		let defen = 0;
		for (let i = 0; i < copiedArray.length; i++) {
			for (let j = 0; j < copiedArray[i].length; j++) {
				// 找到第一个不为0
				if (copiedArray[i][j] !== 0) {
					for (let p = 0; p < j; p++) {
						if (copiedArray[i][p] == copiedArray[i][j]) {
							copiedArray[i][p] = copiedArray[i][j] + copiedArray[i][p];
							defen = defen + copiedArray[i][p] / 2;
							copiedArray[i][j] = 0;
						}
						// 移动到第一个0
						if (copiedArray[i][p] == 0) {
							copiedArray[i][p] = copiedArray[i][j];
							copiedArray[i][j] = 0;
						}
					}
				}

			}
		}
		total.value = total.value + defen
		return copiedArray;
	}
	// 添加新数字
	const addRandomNumbersToZeros = (arr) => {
		let matrix = JSON.parse(JSON.stringify(arr));
		// 存储所有值为0的元素的坐标  
		let zeroIndices = [];

		// 遍历二维数组,找到值为0的元素的坐标  
		for (let i = 0; i < matrix.length; i++) {
			for (let j = 0; j < matrix[i].length; j++) {
				if (matrix[i][j] === 0) {
					zeroIndices.push([i, j]);
				}
			}
		}

		// 如果没有0,则无法添加数字  
		if (zeroIndices.length < 2) {
			gameOver()
			return;
		}

		// 从所有0的坐标中随机选择两个  
		let randomIndices = zeroIndices.sort(() => 0.5 - Math.random()).slice(0, 2);

		// 为这两个坐标对应的元素添加随机数字  
		let randomNumbers = [2, 4, 8];
		for (let index of randomIndices) {
			let [row, col] = index;
			let randomNumber = randomNumbers[Math.floor(Math.random() * randomNumbers.length)];
			matrix[row][col] = randomNumber;
		}
		newArr.value = randomIndices;
		return matrix;
	}

	// 移动
	const moveAndMerge = (dir) => {
		if (dir == 'shang') {
			gameBoard.value = addNum(gameBoard.value)
		}
		else if (dir == 'zuo') {
			let newArr = JSON.parse(JSON.stringify(gameBoard.value));
			newArr = rotate90Clockwise(addNum(rotate90Clockwise(rotate90Clockwise(rotate90Clockwise(newArr)))))
			gameBoard.value = newArr
		} else if (dir == 'you') {
			let newArr = JSON.parse(JSON.stringify(gameBoard.value));
			newArr = rotate90Clockwise(rotate90Clockwise(rotate90Clockwise(addNum(rotate90Clockwise(newArr)))))
			gameBoard.value = newArr
		} else if (dir == 'xia') {
			let newArr = JSON.parse(JSON.stringify(gameBoard.value));
			newArr = rotate90Clockwise(rotate90Clockwise(addNum(rotate90Clockwise(rotate90Clockwise(newArr)))))
			gameBoard.value = newArr
		}
		gameBoard.value = addRandomNumbersToZeros(gameBoard.value)
	}
	// 操作
	const shang = () => {
		moveAndMerge('shang')
	}
	const xia = () => {
		moveAndMerge('xia')
	}
	const zuo = () => {
		moveAndMerge('zuo')
	}
	const you = () => {
		moveAndMerge('you')
	}
</script>

<style lang="scss" scoped>
	.page {
		width: 100vw;
		overflow: hidden;
		height: 100vh;
		background-color: #c6ffe6;
		display: flex;
		flex-direction: column;
		font-family: cuteFont;

		.top {
			width: 80%;
			height: 20vw;
			display: flex;
			align-items: center;
			margin-left: 10%;
			font-size: 2rem;

			.score {
				flex: 1;

			}

			.time {
				flex: 1;

			}
		}

		.center {
			width: 100vw;
			height: 100vw;


			.mainBox {
				width: 80%;
				margin: 10% 10%;
				height: 80%;
				border-radius: 15px;
				display: flex;

				.row {
					flex: 1;
					display: flex;
					flex-direction: column;
				}

				.cell {
					flex: 1;
					border: 1px solid #ff80c2;
					background-color: #b5f2ff;
					display: flex;
					justify-content: center;
					align-items: center;
					color: #ffffff;
					font-size: 2rem;

					.newBox {
						width: 90%;
						height: 90%;
						background-color: #9d6fff;
						border-radius: 15px;
						display: flex;
						justify-content: center;
						align-items: center;
						animation: newBox 0.5s;
					}

					.cellBox {
						width: 90%;
						height: 90%;
						background-color: #9d6fff;
						border-radius: 15px;

					}

					.colorBox {
						width: 100%;
						border-radius: 15px;
						height: 100%;
						display: flex;
						justify-content: center;
						align-items: center;
					}
				}
			}
		}

		.bottom {
			flex: 1;
			position: relative;

			.kaishi {
				width: 100%;
				height: 100%;
				background-color: #86ff61;
				position: absolute;
				.flexBox {
					width: inherit;
					height: inherit;
					display: flex;
					justify-content: center;
					align-items: center;
				}
			}

			.jinxing {
				width: 100%;
				height: 100%;
				position: absolute;

				.flexBox {
					width: inherit;
					height: inherit;
					display: flex;
					flex-direction: row;

					.contorl {
						flex: 1;


						.shang {
							width: 40px;
							height: 40%;
							position: absolute;
							left: 50%;
							background-color: #ff0777;
							clip-path: polygon(0% 50%, 50% 0%, 100% 50%, 80% 50%, 80% 100%, 20% 100%, 20% 50%);
						}

						.shang:hover {
							border: 1px solid #3d37ff;
						}

						.xia {
							width: 40px;
							height: 40%;
							position: absolute;
							top: 50%;
							left: 50%;
							background-color: #ff0777;
							clip-path: polygon(20% 0%, 80% 0%, 80% 50%, 100% 50%, 50% 100%, 0% 50%, 20% 50%);
						}

						.xia:hover {
							border: 1px solid #3d37ff;
						}

						.zuo {
							width: 120px;
							height: 40px;
							position: absolute;
							top: calc(50% - 30px);
							left: calc(50% - 120px);
							background-color: #ff0777;
							clip-path: polygon(0% 50%, 50% 0%, 50% 20%, 100% 20%, 100% 80%, 50% 80%, 50% 100%);
						}

						.zuo:hover {
							border: 1px solid #3d37ff;
						}

						.you {
							width: 120px;
							height: 40px;
							position: absolute;
							top: calc(50% - 30px);
							left: calc(50% + 40px);
							background-color: #ff0777;
							clip-path: polygon(0% 20%, 50% 20%, 50% 0%, 100% 50%, 50% 100%, 50% 80%, 0% 80%);
						}

						.you:hover {
							border: 1px solid #3d37ff;
						}
					}

					.gameOver {
						.gameOverButton {
							width: 50px;
							height: 100%;
							font-size: 2rem;
							display: flex;
							justify-content: center;
							align-items: center;
							background-color: #fff;
							border-radius: 0 15px 0 0;
							border: 1px solid #a860ff;
						}

					}

				}

			}
		}
	}

	@keyframes newBox {
		0% {
			width: 0%;
			height: 0%;
		}

		100% {
			width: 90%;
			height: 90%;
		}
	}
</style>

三、体验地址

微信小程序搜索《静远的工具箱》:偶数求和那个功能

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/428890.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【代码随想录算法训练营Day34】860.柠檬水找零;406.根据身高重建队列;452.用最少数量的箭引爆气球

❇️Day 34 第八章 贪心算法 part04 ✴️今日任务 860.柠檬水找零406.根据身高重建队列452.用最少数量的箭引爆气球 ❇️860.柠檬水找零 本题看上好像挺难&#xff0c;其实挺简单的&#xff0c;大家先尝试自己做一做。题目链接&#xff1a;https://leetcode.cn/problems/lem…

python lambda表达式(匿名函数)

lambda 表达式 在Python中&#xff0c;匿名函数&#xff08;也称为lambda函数&#xff09;是一种简洁的方式来定义小函数&#xff0c;这些函数可以在需要的地方直接定义和使用&#xff0c;而不需要使用def关键字来定义一个具有名称的函数。 lambda 函数是一种小型、匿名的、内…

软件测试/测试开发|一文讲清楚你什么是测试用例

前言 对于一个测试工程师来说&#xff0c;测试用例的编写是一项必须掌握的能力&#xff0c;但有效的设计和熟练的编写确实一项十分复杂的技术。不仅需要掌握软件测试技术和流程&#xff0c;而且还要对整个软件不管从业务&#xff0c;还是对软件的设计&#xff0c;程序模块的结…

【Bugs】class path resource [xxx.xml] cannot be opened because it does not exist

报错&#xff1a; 关键报错信息&#xff1a; class path resource [scope.xml] cannot be opened because it does not exist完整报错信息&#xff1a; 2024-03-01 14:26:58 866 [main] DEBUG org.springframework.context.support.ClassPathXmlApplicationContext - Refres…

外部存储器接口(EMIF)

外部存储器接口&#xff08;EMIF&#xff09; 该设备支持双核架构&#xff1b;为了为每个CPU子系统提供一个专用的EMIF&#xff0c;该设备支持两个EMIF模块——EMIF1和EMIF2。两个模块完全相同&#xff0c;具有相同的功能集&#xff0c;但具有不同的地址/数据大小。EMIF1在CPU…

赋能中国制造,大道云行发布智能制造分布式存储解决方案

《中国制造2025》指出&#xff0c;“制造业是国民经济的主体&#xff0c;是立国之本、兴国之器、强国之基。” 智能制造引领产业提质增效 智能制造是一种利用先进的信息技术、自动化技术和智能技术来优化和升级制造业生产过程的方法。它将人工智能、大数据、物联网、机器学习等…

代码工具APEX的入门使用(未包含安装)

第一次使用APEX是2019年&#xff0c;这个技术成名已久只是我了解的比较晚。请看Oracle ACE的网站&#xff0c;这就是用APEX做的。实际上有一次我看O记的人操作他们的办公流程&#xff0c;都是用APEX做的。 那一年&#xff0c;我用APEX做了一个CMDB的管理系统。那时候还没有流行…

Docker实战——容器

目录 Docker 容器的基本概念与操作1.使用“docker create”创建容器。这里基于Nginx的镜像创建了一个容器&#xff0c;名字为mycontainer。2.使用“docker ps -a”命令查看所有的容器&#xff0c;这时的容器不一定是运行状态。3.使用 “docker start” 命令可以启动容器。4.使用…

如何创建测试计划?这些要考虑到

以下为作者观点&#xff1a; 创建一个彻底和有效的测试计划对软件测试的成功至关重要。它可以帮助识别过程中可能出现的潜在问题或问题。 什么是测试计划&#xff1f; 测试计划是一份文件&#xff0c;概述了软件测试过程的策略、目标、资源和时间表。测试计划通常包括一些细…

抖店0元入驻不交钱会怎么样?个人店和个体店的利弊分析,开店必看

我是王路飞。 现在的抖店是可以开通个人店的。 也就是不需要营业执照、直接使用个人身份证就可以在抖音开店&#xff0c;而且也不需要缴纳店铺保证金就能开店运营了。 但真实情况是怎么样的呢&#xff1f;新手0元入驻抖店不交这个保证金会怎么样呢&#xff1f; 今天给想在抖…

倒计时35天

小红的子序列权值和 (nowcoder.com) #include<bits/stdc.h> using namespace std; #define int long long const int N2e56; const int inf0x3f3f3f3f; const double piacos(-1.0); const int mod1e97; int c[1100][1100]; int a[1100],b[5]; void solve() {int n;cin>…

布隆过滤器到底是什么东西?它有什么用

一、问题解析 昨天&#xff0c;一个工作了 6 年的粉丝私聊我&#xff0c;说最近面试被问到布隆过滤器没回答出来。然后在网上找了一堆资料也没有说清楚&#xff0c;想让我帮他讲解一下&#xff0c;今天正好有空&#xff0c;给大家分享一下布隆过滤器。 在解释布隆过滤器之前&a…

openGauss学习笔记-235 openGauss性能调优-系统调优-资源负载管理-资源管理准备-创建资源池

文章目录 openGauss学习笔记-235 openGauss性能调优-系统调优-资源负载管理-资源管理准备-创建资源池235.1 背景信息235.2 前提条件235.3 操作过程235.3.1 创建资源池235.3.2 管理资源池235.3.3 删除资源池 235.4 查看资源池的信息 openGauss学习笔记-235 openGauss性能调优-系…

加密与安全_ 凯撒密码

文章目录 Pre概述Code 实现 凯撒密码字母频率分析攻击Code解密凯撒密码 小结 Pre PKI - 02 对称与非对称密钥算法 概述 凯撒密码是一种简单的替换加密技术&#xff0c;也称为移位密码。它是古典密码学中最早的密码之一&#xff0c;得名于古罗马军队领袖凯撒尤利乌斯&#xff…

express+mysql+vue,从零搭建一个商城管理系统7--token

提示&#xff1a;学习express&#xff0c;搭建管理系统 文章目录 前言一、安装jsonwebtoken二、新建config/jwt.js三、修改models/user.js四、修改routes下的user.js五、修改index.js六、Api新建user/queryUserList接口七、token验证失败示例总结 前言 需求&#xff1a;主要学习…

Python爬虫副业真的可行吗?

首先回答你&#xff0c;是可行的&#xff0c;python爬虫能当副业&#xff0c;副业的方式比较多&#xff0c;等下我会讲几种。 那学到哪个层次可以接单呢&#xff1f;主要看你是接什么样的单&#xff0c;爬一些资料&#xff0c;视频这种简单的学一两个月就没什么问题&#xff0…

(unity学习)一些效果的学习

一、学习视频 【Unity教程】零基础带你从小白到超神 二、效果实现 三、问题解决 Unity 点击UI与点击屏幕冲突的解决方案 关于unity UI界面操作与场景内操作不冲突问题

TCPDump 使用教程

每次服务器网络不通的时候&#xff0c;总会听到一个声音&#xff0c;你去抓包啊&#xff0c;那这里就来介绍下TCPDump&#xff0c;一款强大的网络分析工具&#xff0c;可以捕获网络上的数据包&#xff0c;并进行分析。这款工具在网络管理员和安全专家中非常受欢迎。 一、安装 …

进程间通信之消息队列及共享内存

1.IPC对象: 内存文件 1.ipcs 查看系统重的消息队列、共享内存、信号灯的信息 2.ipcrm 删除消息队列、共享内存、信号灯 ipcrm -Q/-M/-S key ipcrm -q/-m/-s 消息队列ID/共享内存ID/信号灯ID 消息队列&#xff1a; 3.操作流程: …

【论文阅读】High-Resolution Image Synthesis with Latent Diffusion Model

High-Resolution Image Synthesis with Latent Diffusion Model 引用&#xff1a; Rombach R, Blattmann A, Lorenz D, et al. High-resolution image synthesis with latent diffusion models[C]//Proceedings of the IEEE/CVF conference on computer vision and pattern re…