当前位置: 首页 > news >正文

vue3 实现贪吃蛇 电脑版01

在这里插入图片描述

<template><div class="snake-game"><!-- 游戏标题和分数 --><div class="game-header"><h1>贪吃蛇</h1><div class="score-panel"><div class="current-score">分数: {{ currentScore }}</div><div class="high-score">最高分: {{ highScore }}</div></div></div><!-- 游戏区域 --><div class="game-area"><div class="game-board" :style="{ width: `${boardSize}px`, height: `${boardSize}px` }"><!-- 蛇身(绝对定位) --><divv-for="(segment, index) in snake":key="index"class="snake-segment":class="{ 'snake-head': index === 0 }":style="{left: `${segment.x * cellSize}px`,top: `${segment.y * cellSize}px`,width: `${cellSize}px`,height: `${cellSize}px`}"></div><!-- 食物(绝对定位,固定尺寸) --><divclass="food"v-if="food":style="{left: `${food.x * cellSize}px`,top: `${food.y * cellSize}px`,width: `${cellSize}px`,height: `${cellSize}px`}"></div><!-- 游戏开始界面 --><div class="game-start" v-if="!isPlaying && !gameOver"><button @click="startGame" class="start-btn">开始游戏</button></div><!-- 游戏结束界面 --><div class="game-over" v-if="gameOver"><h2>游戏结束</h2><p>最终得分: {{ currentScore }}</p><button @click="startGame" class="restart-btn">再来一局</button></div></div></div><!-- 虚拟方向按键 --><div class="control-pad" v-if="isPlaying || gameOver"><div class="control-row top-row"><buttonclass="control-btn up"@click="setDirection(0, -1)"@touchstart.prevent="setDirection(0, -1)"></button></div><div class="control-row middle-row"><buttonclass="control-btn left"@click="setDirection(-1, 0)"@touchstart.prevent="setDirection(-1, 0)"></button><buttonclass="control-btn down"@click="setDirection(0, 1)"@touchstart.prevent="setDirection(0, 1)"></button><buttonclass="control-btn right"@click="setDirection(1, 0)"@touchstart.prevent="setDirection(1, 0)"></button></div></div></div>
</template><script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue';// 游戏配置
const gridSize = 15; // 游戏网格大小(15x15)
const initialSpeed = 250; // 初始速度(毫秒)
const speedIncrease = 5; // 每吃一个食物加速的毫秒数// 响应式计算游戏板和单元格大小
const boardSize = computed(() => {return Math.min(window.innerWidth * 0.9, 400); // 游戏板大小
});
const cellSize = computed(() => {return boardSize.value / gridSize; // 每个单元格的像素大小(固定)
});// 游戏状态
const snake = ref([{ x: 7, y: 7 }]); // 蛇的初始位置(网格坐标)
const food = ref(null); // 食物位置(网格坐标)
const direction = ref({ x: 1, y: 0 }); // 当前方向(初始向右)
const nextDirection = ref({ ...direction.value }); // 下一次移动的方向
const currentScore = ref(0); // 当前分数
const highScore = ref(0); // 最高分
const isPlaying = ref(false); // 是否正在游戏中
const gameOver = ref(false); // 游戏是否结束
const gameInterval = ref(null); // 游戏循环计时器// 初始化游戏
const startGame = () => {// 重置游戏状态snake.value = [{ x: 7, y: 7 }];direction.value = { x: 1, y: 0 };nextDirection.value = { ...direction.value };currentScore.value = 0;gameOver.value = false;isPlaying.value = true;// 生成食物generateFood();// 开始游戏循环if (gameInterval.value) clearInterval(gameInterval.value);gameInterval.value = setInterval(moveSnake, initialSpeed);
};// 生成食物(固定在网格坐标上)
const generateFood = () => {let newFood;// 确保食物不会出现在蛇身上do {newFood = {x: Math.floor(Math.random() * gridSize), // 网格X坐标(0-14)y: Math.floor(Math.random() * gridSize)  // 网格Y坐标(0-14)};} while (snake.value.some(segment => segment.x === newFood.x && segment.y === newFood.y));food.value = newFood; // 食物坐标一旦生成,不会随蛇移动改变
};// 移动蛇(基于网格坐标计算)
const moveSnake = () => {if (!isPlaying.value) return;// 更新方向direction.value = { ...nextDirection.value };// 创建新头部(基于网格坐标计算)const head = {x: snake.value[0].x + direction.value.x,y: snake.value[0].y + direction.value.y};// 检查是否碰撞if (checkCollision(head)) {endGame();return;}// 将新头部添加到蛇身snake.value.unshift(head);// 检查是否吃到食物(基于网格坐标匹配)if (head.x === food.value.x && head.y === food.value.y) {currentScore.value += 10;if (currentScore.value > highScore.value) {highScore.value = currentScore.value;localStorage.setItem('snakeHighScore', highScore.value);}generateFood(); // 生成新食物(新的网格坐标)adjustSpeed();} else {snake.value.pop(); // 没吃到食物则移除尾部}
};// 检查碰撞
const checkCollision = (head) => {// 撞墙(超出网格范围)if (head.x < 0 || head.x >= gridSize || head.y < 0 || head.y >= gridSize) {return true;}// 撞到自己return snake.value.some((segment, index) => index !== 0 && segment.x === head.x && segment.y === head.y);
};// 调整游戏速度
const adjustSpeed = () => {if (gameInterval.value) {clearInterval(gameInterval.value);const newSpeed = Math.max(initialSpeed - (currentScore.value / 10) * speedIncrease, 100);gameInterval.value = setInterval(moveSnake, newSpeed);}
};// 结束游戏
const endGame = () => {isPlaying.value = false;gameOver.value = true;clearInterval(gameInterval.value);
};// 设置方向
const setDirection = (x, y) => {if ((direction.value.x === -x && direction.value.y === -y) || !isPlaying.value) {return;}nextDirection.value = { x, y };
};// 键盘控制(调试用)
const handleKeydown = (e) => {if (!isPlaying.value) return;switch(e.key) {case 'ArrowUp': setDirection(0, -1); break;case 'ArrowDown': setDirection(0, 1); break;case 'ArrowLeft': setDirection(-1, 0); break;case 'ArrowRight': setDirection(1, 0); break;}
};// 加载最高分
const loadHighScore = () => {const saved = localStorage.getItem('snakeHighScore');if (saved) highScore.value = parseInt(saved);
};// 生命周期
onMounted(() => {loadHighScore();window.addEventListener('keydown', handleKeydown);
});onUnmounted(() => {window.removeEventListener('keydown', handleKeydown);if (gameInterval.value) clearInterval(gameInterval.value);
});
</script><style scoped>
.snake-game {display: flex;flex-direction: column;align-items: center;min-height: 100vh;background-color: #f0f2f5;padding: 20px 10px;box-sizing: border-box;font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
}/* 游戏标题和分数 */
.game-header {width: 100%;max-width: 400px;margin-bottom: 20px;text-align: center;
}.game-header h1 {color: #1a1a1a;margin: 0 0 15px 0;font-size: 28px;
}.score-panel {display: flex;justify-content: space-around;background-color: white;padding: 12px;border-radius: 10px;box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1);
}.current-score, .high-score {font-size: 16px;font-weight: 500;color: #333;
}/* 游戏区域 */
.game-area {position: relative;margin-bottom: 30px;
}.game-board {position: relative; /* 作为蛇和食物的定位容器 */background-color: #e6f7ff;border: 2px solid #1890ff;border-radius: 8px;overflow: hidden;
}/* 蛇身和食物使用绝对定位 */
.snake-segment, .food {position: absolute;box-sizing: border-box;
}.snake-segment {background-color: #52c41a;border-radius: 4px;transition: all 0.1s ease;
}.snake-head {background-color: #2e7d32;border: 2px solid #1b5e20;
}.food {background-color: #ff4d4f;border-radius: 50%;box-shadow: 0 0 0 2px rgba(255, 77, 79, 0.5) inset;
}/* 游戏开始和结束界面 */
.game-start, .game-over {position: absolute;top: 0;left: 0;width: 100%;height: 100%;background-color: rgba(0, 0, 0, 0.7);display: flex;flex-direction: column;align-items: center;justify-content: center;border-radius: 6px;color: white;
}.game-over h2 {margin: 0 0 15px 0;font-size: 24px;
}.game-over p {margin: 0 0 20px 0;font-size: 18px;
}.start-btn, .restart-btn {background-color: #1890ff;color: white;border: none;border-radius: 6px;padding: 12px 24px;font-size: 16px;font-weight: 500;cursor: pointer;transition: background-color 0.2s;
}.start-btn:hover, .restart-btn:hover {background-color: #096dd9;
}.start-btn:active, .restart-btn:active {transform: scale(0.98);
}/* 虚拟方向按键 */
.control-pad {width: 240px;height: 200px;position: relative;margin-top: auto;margin-bottom: 20px;
}.control-row {display: flex;justify-content: center;
}.top-row {margin-bottom: 10px;
}.middle-row {gap: 10px;
}.control-btn {width: 70px;height: 70px;border-radius: 10px;background-color: #1890ff;color: white;border: none;font-size: 20px;font-weight: bold;box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);cursor: pointer;display: flex;align-items: center;justify-content: center;touch-action: manipulation;-webkit-tap-highlight-color: transparent;
}.control-btn:active {transform: scale(0.95);background-color: #096dd9;box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
}/* 适配小屏幕 */
@media (max-width: 360px) {.control-pad {width: 200px;height: 170px;}.control-btn {width: 60px;height: 60px;font-size: 18px;}.game-header h1 {font-size: 24px;}
}
</style>
http://www.dtcms.com/a/540126.html

相关文章:

  • 做网站带后台多少钱东莞做网站 动点官网
  • 郑州做网站建设wordpress数据控查看密码
  • 数据采集-BeautifulSoup库
  • 帝国cms的阅读量增加的api接口示例
  • RDF 实例
  • 面向对象编程:继承从理论到实战
  • 43-基于STM32的医用护理床设计与实现
  • 【经济方向专题会议】第二届经济数据分析与人工智能国际学术会议 (EDAI 2025)
  • Auto CAD二次开发——折线多段线
  • django做的购物网站海口网站建设优化案例
  • 一个密码破解器
  • 如何查看网站的建设者重庆建设部网站官网
  • Ansible 的条件语句与循环详解
  • 生产级 Ansible 部署全流程-nginx示例
  • Ansible Playbook 深度解析:自动化任务编排最佳实践
  • Ansible生产调优与故障排查全攻略
  • 【笔记】Podman Desktop 部署 开源数字人 HeyGem.ai
  • vue-day02
  • 青岛有哪些做网站的公司公司网页制作需要什么哪些材料
  • 建站公司用wordpress如何查看网站的建设方式
  • Leetcode 3727. Maximum Alternating Sum of Squares
  • rtp组播乱序三种策略模式选择(AI)
  • Docker基础 - 入门基础和Helloworld
  • 集群——GitLabJenkins部署
  • deepin 终端,但是版本是 deepin 15 的
  • 简单的分布式锁 SpringBoot Redisson‌
  • 如何建立一个视频网站网站域名权
  • 如何修改wordpress站名泰安网站建设哪家不错
  • 【Swift】LeetCode 73. 矩阵置零
  • 益和热力性能优化实践:从 SQL Server 到 TDengine 时序数据库,写入快 20 秒、查询提速 5 倍