当前位置:   article > 正文

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

vue 小程序 游戏

一、效果展示

二、代码

  1. <template>
  2. <view class="page">
  3. <view class="top">
  4. <view class="score">
  5. 得分:{{total}}
  6. </view>
  7. <view class="time">
  8. 用时:{{allTime}}s
  9. </view>
  10. </view>
  11. <view class="center">
  12. <view class="mainBox">
  13. <view class="row" v-for="(row, rowIndex) in gameBoard" :key="rowIndex">
  14. <view class="cell" v-for="(cell, cellIndex) in row" :key="cellIndex">
  15. <!-- <view :class="cell!==0?'cellBox':''"> -->
  16. <view
  17. :class="cellIndex==newArr[0][1]&&rowIndex==newArr[0][0]||cellIndex==newArr[1][1]&&rowIndex==newArr[1][0]?'newBox':cell!==0?'cellBox':''">
  18. <view class="colorBox"
  19. :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':''}">
  20. <text v-show=" cell!==0&&cell!==1">{{ cell }}</text>
  21. </view>
  22. </view>
  23. </view>
  24. </view>
  25. </view>
  26. </view>
  27. <view class="bottom">
  28. <view class="kaishi" v-show="gameStatus==false">
  29. <view class="flexBox"> <button @click="gameStart()"> 游戏开始</button></view>
  30. </view>
  31. <view class="jinxing" v-show="gameStatus==true">
  32. <view class="flexBox">
  33. <view class="gameOver">
  34. <view class="gameOverButton" @click="gameOver()">
  35. 结束
  36. </view>
  37. </view>
  38. <view class="contorl">
  39. <view class="shang" @click="shang()">
  40. </view>
  41. <view class="xia" @click="xia()">
  42. </view>
  43. <view class="zuo" @click="zuo()">
  44. </view>
  45. <view class="you" @click="you()">
  46. </view>
  47. </view>
  48. </view>
  49. </view>
  50. </view>
  51. </view>
  52. </template>
  53. <script lang="ts" setup>
  54. import { ref } from 'vue'
  55. // 游戏状态
  56. const gameStatus = ref<boolean>(false);
  57. // 显示的数组
  58. let gameBoard = ref<number[][]>(Array.from({ length: 4 }, () => Array(4).fill(0)));
  59. // 新增的俩
  60. let newArr = ref<number[][]>(Array.from({ length: 2 }, () => Array(2).fill(null)))
  61. // 得分
  62. const total = ref<number>();
  63. // 用时
  64. const allTime = ref(0)
  65. const timer1 = ref()
  66. // 游戏开始
  67. const gameStart = () => {
  68. total.value = 0;
  69. allTime.value = 0
  70. gameStatus.value = true;
  71. gameBoard.value = numInit()
  72. timer1.value = setInterval(() => {
  73. allTime.value = allTime.value + 1;
  74. }, 1000)
  75. }
  76. // 游戏结束
  77. const gameOver = () => {
  78. gameStatus.value = false;
  79. clearInterval(timer1.value)
  80. timer1.value = null;
  81. newArr.value = Array.from({ length: 2 }, () => Array(2).fill(null));
  82. }
  83. // 获取随机数的函数
  84. const getRandomlet = (min, max) => {
  85. min = Math.ceil(min);
  86. max = Math.floor(max);
  87. return Math.floor(Math.random() * (max - min + 1)) + min;
  88. }
  89. // 随机初始化数值
  90. const numInit = () => {
  91. const array = Array.from({ length: 4 }, () => Array(4).fill(0));
  92. const positions = [];
  93. // 生成一个包含所有可能位置的数组
  94. for (let i = 0; i < 4; i++) {
  95. for (let j = 0; j < 4; j++) {
  96. positions.push({ x: i, y: j });
  97. }
  98. }
  99. // 随机选择6个位置
  100. const selectedPositions = [];
  101. for (let i = 0; i < 6; i++) {
  102. const randomIndex = getRandomlet(0, positions.length - 1);
  103. selectedPositions.push(positions[randomIndex]);
  104. positions.splice(randomIndex, 1); // 从数组中移除已选位置,避免重复选择
  105. }
  106. // 设置前4个位置为2
  107. for (let i = 0; i < 4; i++) {
  108. const position = selectedPositions[i];
  109. array[position.x][position.y] = 2;
  110. }
  111. // 对于剩下的2个位置,随机设置为4或8
  112. for (let i = 4; i < 6; i++) {
  113. const position = selectedPositions[i];
  114. const randomValue = getRandomlet(1, 2) === 1 ? 4 : 8;
  115. array[position.x][position.y] = randomValue;
  116. }
  117. return array;
  118. }
  119. // 旋转数组
  120. const rotate90Clockwise = (matrix) => {
  121. const n = matrix.length;
  122. let rotatedMatrix = Array.from({ length: n }, () => []);
  123. // 顺时针旋转90度
  124. for (let i = 0; i < n; i++) {
  125. for (let j = 0; j < n; j++) {
  126. rotatedMatrix[j][n - i - 1] = matrix[i][j];
  127. }
  128. }
  129. return rotatedMatrix;
  130. }
  131. // 累计与填入
  132. const addNum = (arr) => {
  133. let copiedArray = JSON.parse(JSON.stringify(arr));
  134. let defen = 0;
  135. for (let i = 0; i < copiedArray.length; i++) {
  136. for (let j = 0; j < copiedArray[i].length; j++) {
  137. // 找到第一个不为0
  138. if (copiedArray[i][j] !== 0) {
  139. for (let p = 0; p < j; p++) {
  140. if (copiedArray[i][p] == copiedArray[i][j]) {
  141. copiedArray[i][p] = copiedArray[i][j] + copiedArray[i][p];
  142. defen = defen + copiedArray[i][p] / 2;
  143. copiedArray[i][j] = 0;
  144. }
  145. // 移动到第一个0
  146. if (copiedArray[i][p] == 0) {
  147. copiedArray[i][p] = copiedArray[i][j];
  148. copiedArray[i][j] = 0;
  149. }
  150. }
  151. }
  152. }
  153. }
  154. total.value = total.value + defen
  155. return copiedArray;
  156. }
  157. // 添加新数字
  158. const addRandomNumbersToZeros = (arr) => {
  159. let matrix = JSON.parse(JSON.stringify(arr));
  160. // 存储所有值为0的元素的坐标
  161. let zeroIndices = [];
  162. // 遍历二维数组,找到值为0的元素的坐标
  163. for (let i = 0; i < matrix.length; i++) {
  164. for (let j = 0; j < matrix[i].length; j++) {
  165. if (matrix[i][j] === 0) {
  166. zeroIndices.push([i, j]);
  167. }
  168. }
  169. }
  170. // 如果没有0,则无法添加数字
  171. if (zeroIndices.length < 2) {
  172. gameOver()
  173. return;
  174. }
  175. // 从所有0的坐标中随机选择两个
  176. let randomIndices = zeroIndices.sort(() => 0.5 - Math.random()).slice(0, 2);
  177. // 为这两个坐标对应的元素添加随机数字
  178. let randomNumbers = [2, 4, 8];
  179. for (let index of randomIndices) {
  180. let [row, col] = index;
  181. let randomNumber = randomNumbers[Math.floor(Math.random() * randomNumbers.length)];
  182. matrix[row][col] = randomNumber;
  183. }
  184. newArr.value = randomIndices;
  185. return matrix;
  186. }
  187. // 移动
  188. const moveAndMerge = (dir) => {
  189. if (dir == 'shang') {
  190. gameBoard.value = addNum(gameBoard.value)
  191. }
  192. else if (dir == 'zuo') {
  193. let newArr = JSON.parse(JSON.stringify(gameBoard.value));
  194. newArr = rotate90Clockwise(addNum(rotate90Clockwise(rotate90Clockwise(rotate90Clockwise(newArr)))))
  195. gameBoard.value = newArr
  196. } else if (dir == 'you') {
  197. let newArr = JSON.parse(JSON.stringify(gameBoard.value));
  198. newArr = rotate90Clockwise(rotate90Clockwise(rotate90Clockwise(addNum(rotate90Clockwise(newArr)))))
  199. gameBoard.value = newArr
  200. } else if (dir == 'xia') {
  201. let newArr = JSON.parse(JSON.stringify(gameBoard.value));
  202. newArr = rotate90Clockwise(rotate90Clockwise(addNum(rotate90Clockwise(rotate90Clockwise(newArr)))))
  203. gameBoard.value = newArr
  204. }
  205. gameBoard.value = addRandomNumbersToZeros(gameBoard.value)
  206. }
  207. // 操作
  208. const shang = () => {
  209. moveAndMerge('shang')
  210. }
  211. const xia = () => {
  212. moveAndMerge('xia')
  213. }
  214. const zuo = () => {
  215. moveAndMerge('zuo')
  216. }
  217. const you = () => {
  218. moveAndMerge('you')
  219. }
  220. </script>
  221. <style lang="scss" scoped>
  222. .page {
  223. width: 100vw;
  224. overflow: hidden;
  225. height: 100vh;
  226. background-color: #c6ffe6;
  227. display: flex;
  228. flex-direction: column;
  229. font-family: cuteFont;
  230. .top {
  231. width: 80%;
  232. height: 20vw;
  233. display: flex;
  234. align-items: center;
  235. margin-left: 10%;
  236. font-size: 2rem;
  237. .score {
  238. flex: 1;
  239. }
  240. .time {
  241. flex: 1;
  242. }
  243. }
  244. .center {
  245. width: 100vw;
  246. height: 100vw;
  247. .mainBox {
  248. width: 80%;
  249. margin: 10% 10%;
  250. height: 80%;
  251. border-radius: 15px;
  252. display: flex;
  253. .row {
  254. flex: 1;
  255. display: flex;
  256. flex-direction: column;
  257. }
  258. .cell {
  259. flex: 1;
  260. border: 1px solid #ff80c2;
  261. background-color: #b5f2ff;
  262. display: flex;
  263. justify-content: center;
  264. align-items: center;
  265. color: #ffffff;
  266. font-size: 2rem;
  267. .newBox {
  268. width: 90%;
  269. height: 90%;
  270. background-color: #9d6fff;
  271. border-radius: 15px;
  272. display: flex;
  273. justify-content: center;
  274. align-items: center;
  275. animation: newBox 0.5s;
  276. }
  277. .cellBox {
  278. width: 90%;
  279. height: 90%;
  280. background-color: #9d6fff;
  281. border-radius: 15px;
  282. }
  283. .colorBox {
  284. width: 100%;
  285. border-radius: 15px;
  286. height: 100%;
  287. display: flex;
  288. justify-content: center;
  289. align-items: center;
  290. }
  291. }
  292. }
  293. }
  294. .bottom {
  295. flex: 1;
  296. position: relative;
  297. .kaishi {
  298. width: 100%;
  299. height: 100%;
  300. background-color: #86ff61;
  301. position: absolute;
  302. .flexBox {
  303. width: inherit;
  304. height: inherit;
  305. display: flex;
  306. justify-content: center;
  307. align-items: center;
  308. }
  309. }
  310. .jinxing {
  311. width: 100%;
  312. height: 100%;
  313. position: absolute;
  314. .flexBox {
  315. width: inherit;
  316. height: inherit;
  317. display: flex;
  318. flex-direction: row;
  319. .contorl {
  320. flex: 1;
  321. .shang {
  322. width: 40px;
  323. height: 40%;
  324. position: absolute;
  325. left: 50%;
  326. background-color: #ff0777;
  327. clip-path: polygon(0% 50%, 50% 0%, 100% 50%, 80% 50%, 80% 100%, 20% 100%, 20% 50%);
  328. }
  329. .shang:hover {
  330. border: 1px solid #3d37ff;
  331. }
  332. .xia {
  333. width: 40px;
  334. height: 40%;
  335. position: absolute;
  336. top: 50%;
  337. left: 50%;
  338. background-color: #ff0777;
  339. clip-path: polygon(20% 0%, 80% 0%, 80% 50%, 100% 50%, 50% 100%, 0% 50%, 20% 50%);
  340. }
  341. .xia:hover {
  342. border: 1px solid #3d37ff;
  343. }
  344. .zuo {
  345. width: 120px;
  346. height: 40px;
  347. position: absolute;
  348. top: calc(50% - 30px);
  349. left: calc(50% - 120px);
  350. background-color: #ff0777;
  351. clip-path: polygon(0% 50%, 50% 0%, 50% 20%, 100% 20%, 100% 80%, 50% 80%, 50% 100%);
  352. }
  353. .zuo:hover {
  354. border: 1px solid #3d37ff;
  355. }
  356. .you {
  357. width: 120px;
  358. height: 40px;
  359. position: absolute;
  360. top: calc(50% - 30px);
  361. left: calc(50% + 40px);
  362. background-color: #ff0777;
  363. clip-path: polygon(0% 20%, 50% 20%, 50% 0%, 100% 50%, 50% 100%, 50% 80%, 0% 80%);
  364. }
  365. .you:hover {
  366. border: 1px solid #3d37ff;
  367. }
  368. }
  369. .gameOver {
  370. .gameOverButton {
  371. width: 50px;
  372. height: 100%;
  373. font-size: 2rem;
  374. display: flex;
  375. justify-content: center;
  376. align-items: center;
  377. background-color: #fff;
  378. border-radius: 0 15px 0 0;
  379. border: 1px solid #a860ff;
  380. }
  381. }
  382. }
  383. }
  384. }
  385. }
  386. @keyframes newBox {
  387. 0% {
  388. width: 0%;
  389. height: 0%;
  390. }
  391. 100% {
  392. width: 90%;
  393. height: 90%;
  394. }
  395. }
  396. </style>

三、体验地址

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/214988
推荐阅读
相关标签
  

闽ICP备14008679号