html5+js+css开发贪吃蛇

本文介绍了一个基于HTML5 Canvas的贪吃蛇游戏实现方案。通过JavaScript编程,详细讲解了游戏的初始化设置、蛇的绘制与移动逻辑、食物生成机制、碰撞检测及用户交互等内容。
<!doctype html>
<html>
 <head>
  <meta charset="UTF-8">
  <meta name="Keywords" content="">
  <meta name="Description" content="">
  <title>̰贪吃蛇</title>
  <style type="text/css">
	*{
		margin:0;
		padding:0;
	}
	body{
		background:url(img/bg.jpg);
		background-size:cover;/*屏幕自适应*/
	}
	#box{
		width:600px;
		margin:20px auto;
	}
	#canvas{
		border:3px solid #4a4a4a;
	}
	#btn a{
		width:100px;
		height:26px;
		display:inline-block;
		text-decoration:none;
		background:#338328;
		text-align:center;
		padding:10px;
		border-radius:10px;
		line-height:26px;
		color:#000;
		font-weight:600;
	}
	#btn a:hover{
		color:#fff;
	}
	#score_one{
		color:#fff;
		text-align:center;
		font-weight:600;
		font-size:20px;
	}
  </style>
 </head>
 <body>
	<div id="box">
		<div id="score_one">
			得分:<span id="score"></span>
		</div>
		<canvas id="canvas" width="600" height="600"></canvas>
		<div id="btn">
			<a href="javascript:void(0);" onclick="btnStart();">开始游戏</a>
			<a href="javascript:void(0);" onclick="reStart();">重新游戏</a>
		</div>
		<audio src="mp3/bg.mp3" loop id="beginmusic"></audio>
		<audio src="mp3/eat.mp3" id="bomb"></audio>
		<audio src="mp3/over.mp3" id="over"></audio>
	</div>
	
	<script type="text/javascript">
		function $(id){
			return document.getElementById(id);
		}
		
		//获取画布对象
		var canvas = $("canvas");
		var beginmusic = $("beginmusic");
		var bomb = $("bomb");
		var over = $("over");
		var score = $("score");
		score.innerText="0";
		//获取上下文
		var ctx = canvas.getContext("2d");
		//蛇身长4格
		var snakeCount = 4;
		var snakes = [];
		var foodX = 0;
		var foodY = 0;
		var timer = null;
		var toGo = 3;// 1 左 2 上 3 右 4 下
		
		//绘画
		function draw(){
			var s=600;
			for(var i=0;i<s;i+=40){
				ctx.strokeStyle="#4a4a4a";
				ctx.moveTo(0,i+40);
				ctx.lineTo(600,i+40);
				ctx.moveTo(i+40,0);
				ctx.lineTo(i+40,600);
				ctx.stroke();
			}
			//画蛇
			for(var i=0;i<snakes.length;i++){
				//重启绘画
				ctx.beginPath();
				ctx.fillRect(snakes[i].x,snakes[i].y,40,40);
				ctx.strokeStyle="#4a4a4a";
				ctx.moveTo(snakes[i].x,snakes[i].y);// 0  0
				ctx.lineTo(snakes[i].x+40,snakes[i].y);// 40 0
				ctx.lineTo(snakes[i].x+40,snakes[i].y+40);// 40 40
				ctx.lineTo(snakes[i].x,snakes[i].y+40);// 0 40
				ctx.lineTo(snakes[i].x,snakes[i].y);// 0 0
				ctx.stroke();
			}
			ctx.fillRect(foodX,foodY,40,40);
		}
		
		//定义蛇的位置
		function start(){
			for(var i=0;i<snakeCount;i++){
				snakes[i]={x:i*40,y:0};
			}
			addFood();
			draw();
		}

		//添加食物
		function addFood(){
			foodX = Math.floor(Math.random()*15)*40;
			foodY = Math.floor(Math.random()*15)*40;
		}

		//蛇移动
		function move(){
			switch(toGo){
				case 1:
					//给数组添加新的元素
					snakes.push({x:snakes[snakeCount-1].x-40,y:snakes[snakeCount-1].y});//左
					break;
				case 2:
					//给数组添加新的元素
					snakes.push({x:snakes[snakeCount-1].x,y:snakes[snakeCount-1].y-40});//上
					break;
				case 3:
					//给数组添加新的元素
					snakes.push({x:snakes[snakeCount-1].x+40,y:snakes[snakeCount-1].y});//右
					break;
				case 4:
					//给数组添加新的元素
					snakes.push({x:snakes[snakeCount-1].x,y:snakes[snakeCount-1].y+40});//下
					break;
			}
			
			//删除数组的第一个元素
			snakes.shift();
			ctx.clearRect(0,0,600,600);
			isEat();
			isDead();
			draw();
		}
		
		//键盘方向键控制蛇的走向
		function keyDown(e){
			switch(e.keyCode){
				case 37://左
					toGo = 1;
					break;
				case 38:
					toGo = 2;
					break;
				case 39:
					toGo = 3;
					break;
				case 40:
					toGo = 4;
					break;
			}
		};

		//蛇吃东西
		function isEat(){
			if(snakes[snakeCount-1].x == foodX && snakes[snakeCount-1].y == foodY){
				snakeCount++;
				addFood();
				snakes.unshift({x:-40,y:-40});
				score.innerText = parseInt(score.innerText)+50;
				bomb.play();
			}
		};
		
		//规则限制
		function isDead(){
			//边界判断
			if(snakes[snakes.length-1].x>560 || snakes[snakes.length-1].y>560 || snakes[snakes.length-1].x<0 || snakes[snakes.length-1].y<0){
				beginmusic.pause();
				over.play();
				alert("你为啥这么想不开呢?");
				window.location.reload();
			}

			//判断自身,蛇不能碰到蛇身
			for(var i=0;i<snakes.length-1;i++){
				if(snakes[snakes.length-1].x == snakes[i].x && snakes[snakes.length-1].y == snakes[i].y){
					beginmusic.pause();
					over.play();
					alert("你何必为难自己呢?");
					window.location.reload();
				}
			}
		}

		//开始游戏
		function btnStart(){
			beginmusic.play();
			timer = setInterval(move,150);
			document.onkeydown = function(e){
				e = e || window.event;
				keyDown(e);
			}
		}
		
		//重新游戏
		function reStart(){
			window.location.reload();
		}
		

		window.onload = function(){
			start();
		}

	</script>
 </body>
</html>

实现移动,吃食变长游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。[3] 二、“贪吃蛇”游戏的发展编辑 改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难,游戏制作的精细度画面的质量也随着版本的提高而不断提高,且有单人及团队联机对战版本陆续推出。 参考资料游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。[3] 二、“贪吃蛇”游戏的发展编辑 改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难,游戏制作的精细度画面的质量也随着版本的提高而不断提高,且有单人及团队联机对战版本陆续推出。 游戏把子上下左右控制蛇的方向,寻找吃的东西,每吃一口就能得到一定的积分,而且蛇的身子会越吃越长,身子越长玩的难度就越大,不能碰墙,不能咬到自己的身体,更不能咬自己的尾巴,等到了一定的分数,就能过关,然后继续玩下一关。[3] 二、“贪吃蛇”游戏的发展编辑 改变此款游戏的特别多。比如在蛋的方面,可能放上带道具的蛋,使蛇吃完后具有保护,穿墙等特种功能,而且难度逐渐变难,游戏制作的精细度画面的质量也随着版本的提高而不断提高,且有单人及团队联机对战版本陆续推出。
<think> 我们被要求用HTMLCSSJavaScript实现贪吃蛇游戏,并且用户提供了两个引用作为参考。我们将结合这两个引用,并补充完整代码。 引用[1]提供了基本的HTML结构部分JavaScript代码,但CSSJavaScript不完整。 引用[2]提供了一段关于方向控制的代码片段。 因此,我们将完成一个完整的贪吃蛇游戏,包括以下部分: 1. HTML结构:包含标题、分数显示画布。 2. CSS样式:居中显示,设置字体等。 3. JavaScript:实现游戏逻辑,包括蛇的移动、食物生成、碰撞检测键盘控制。 我们将按照以下步骤实现: HTML部分: - 使用canvas元素绘制游戏区域。 CSS部分: - 设置页面居中,字体等。 JavaScript部分: - 定义常量:画布大小、网格大小等。 - 初始化蛇食物的位置。 - 绘制蛇食物的函数。 - 移动蛇的函数,并检测是否吃到食物或碰撞。 - 键盘事件监听,改变蛇的方向。 - 游戏循环,使用setInterval定期更新。 注意:引用[2]中提到了方向控制的限制,即蛇不能立即反向移动。 下面给出完整代码: </think> # HTML+CSS+JavaScript实现贪吃蛇游戏 我将为您创建一个完整、美观且可直接运行的贪吃蛇游戏。这个实现使用了Canvas绘制游戏区域,并添加了现代化的UI设计。 ```html <!DOCTYPE html> <html lang="zh-CN"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>贪吃蛇游戏</title> <style> * { margin: 0; padding: 0; box-sizing: border-box; font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; } body { display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(135deg, #1a2a6c, #b21f1f, #1a2a6c); background-size: 400% 400%; animation: gradientBG 15s ease infinite; overflow: hidden; padding: 20px; } @keyframes gradientBG { 0% { background-position: 0% 50%; } 50% { background-position: 100% 50%; } 100% { background-position: 0% 50%; } } .game-container { width: 100%; max-width: 800px; display: flex; flex-direction: column; gap: 20px; } header { text-align: center; color: white; padding: 15px; background: rgba(0, 0, 0, 0.7); border-radius: 15px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); backdrop-filter: blur(10px); } h1 { font-size: 2.8rem; margin-bottom: 10px; text-shadow: 0 0 10px rgba(255, 255, 255, 0.5); background: linear-gradient(to right, #ff9966, #ff5e62); -webkit-background-clip: text; background-clip: text; color: transparent; } .game-stats { display: flex; justify-content: space-between; align-items: center; background: rgba(0, 0, 0, 0.7); border-radius: 15px; padding: 15px 25px; color: white; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); backdrop-filter: blur(10px); } .stat-box { display: flex; flex-direction: column; align-items: center; } .stat-label { font-size: 1rem; color: #aaa; margin-bottom: 5px; } .stat-value { font-size: 1.8rem; font-weight: bold; color: #4caf50; } .game-area { display: flex; flex-direction: column; gap: 20px; } .canvas-container { position: relative; background: rgba(0, 0, 0, 0.8); border-radius: 15px; overflow: hidden; box-shadow: 0 15px 35px rgba(0, 0, 0, 0.5); padding: 5px; } canvas { display: block; margin: 0 auto; background: #0d1b2a; border-radius: 10px; } .controls { display: flex; justify-content: center; gap: 15px; } button { padding: 12px 25px; font-size: 1.1rem; font-weight: bold; background: linear-gradient(135deg, #4caf50, #2e7d32); border: none; border-radius: 50px; color: white; cursor: pointer; transition: all 0.3s ease; box-shadow: 0 5px 15px rgba(0, 0, 0, 0.3); } button:hover { transform: translateY(-3px); box-shadow: 0 8px 20px rgba(0, 0, 0, 0.4); background: linear-gradient(135deg, #66bb6a, #388e3c); } button:active { transform: translateY(1px); } .restart-btn { background: linear-gradient(135deg, #ff5722, #e64a19); } .restart-btn:hover { background: linear-gradient(135deg, #ff7043, #f4511e); } .directions { display: grid; grid-template-columns: repeat(4, 1fr); gap: 15px; margin-top: 10px; } .dir-key { display: flex; justify-content: center; align-items: center; height: 50px; background: rgba(255, 255, 255, 0.1); border-radius: 10px; font-weight: bold; color: white; font-size: 1.5rem; } .instructions { background: rgba(0, 0, 0, 0.7); border-radius: 15px; padding: 20px; color: #ddd; line-height: 1.6; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); backdrop-filter: blur(10px); } .instructions h2 { color: #4caf50; margin-bottom: 15px; font-size: 1.5rem; } .instructions ul { padding-left: 25px; } .instructions li { margin-bottom: 8px; } .game-over { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0, 0, 0, 0.85); display: flex; flex-direction: column; justify-content: center; align-items: center; color: white; border-radius: 10px; z-index: 10; display: none; } .game-over h2 { font-size: 3rem; margin-bottom: 20px; color: #ff5252; } .final-score { font-size: 2rem; margin-bottom: 30px; } .game-over button { font-size: 1.4rem; padding: 15px 40px; } @media (max-width: 600px) { h1 { font-size: 2rem; } .game-stats { flex-direction: column; gap: 15px; } .directions { grid-template-columns: repeat(2, 1fr); } } </style> </head> <body> <div class="game-container"> <header> <h1>贪吃蛇游戏</h1> <p>经典的贪吃蛇游戏 - 用方向键控制蛇的移动</p> </header> <div class="game-stats"> <div class="stat-box"> <span class="stat-label">分数</span> <span class="stat-value" id="score">0</span> </div> <div class="stat-box"> <span class="stat-label">长度</span> <span class="stat-value" id="length">1</span> </div> <div class="stat-box"> <span class="stat-label">速度</span> <span class="stat-value" id="speed">100</span> </div> <div class="stat-box"> <span class="stat-label">食物</span> <span class="stat-value" id="food">0</span> </div> </div> <div class="game-area"> <div class="canvas-container"> <canvas id="game-board" width="400" height="400"></canvas> <div class="game-over" id="game-over"> <h2>游戏结束!</h2> <div class="final-score">最终得分: <span id="final-score">0</span></div> <button id="restart-btn">重新开始</button> </div> </div> <div class="controls"> <button id="start-btn">开始游戏</button> <button id="pause-btn">暂停</button> <button class="restart-btn" id="new-game-btn">新游戏</button> </div> <div class="directions"> <div class="dir-key">←</div> <div class="dir-key">→</div> <div class="dir-key">↑</div> <div class="dir-key">↓</div> </div> </div> <div class="instructions"> <h2>游戏说明</h2> <ul> <li>使用键盘方向键控制蛇的移动方向</li> <li>吃到红色食物可以增加蛇的长度得分</li> <li>每吃到5个食物,游戏速度会增加</li> <li>撞到墙壁或自己的身体会导致游戏结束</li> <li>蛇可以穿过边界(从一边出来从另一边进入)</li> </ul> </div> </div> <script> document.addEventListener('DOMContentLoaded', () => { // 游戏常量 const GRID_SIZE = 20; const TILE_COUNT = 20; const CANVAS_SIZE = GRID_SIZE * TILE_COUNT; // DOM 元素 const canvas = document.getElementById('game-board'); const ctx = canvas.getContext('2d'); const scoreElement = document.getElementById('score'); const lengthElement = document.getElementById('length'); const speedElement = document.getElementById('speed'); const foodElement = document.getElementById('food'); const finalScoreElement = document.getElementById('final-score'); const gameOverScreen = document.getElementById('game-over'); const startBtn = document.getElementById('start-btn'); const pauseBtn = document.getElementById('pause-btn'); const newGameBtn = document.getElementById('new-game-btn'); const restartBtn = document.getElementById('restart-btn'); // 游戏状态 let snake = [{x: 10, y: 10}]; let food = generateFood(); let direction = {x: 0, y: 0}; let score = 0; let foodEaten = 0; let gameSpeed = 100; let lastRenderTime = 0; let gameRunning = false; let gamePaused = false; // 设置画布尺寸 canvas.width = CANVAS_SIZE; canvas.height = CANVAS_SIZE; // 生成食物位置 function generateFood() { while (true) { const foodPos = { x: Math.floor(Math.random() * TILE_COUNT), y: Math.floor(Math.random() * TILE_COUNT) }; // 确保食物不会出现在蛇身上 if (!snake.some(segment => segment.x === foodPos.x && segment.y === foodPos.y)) { return foodPos; } } } // 绘制游戏场景 function draw() { // 清除画布 ctx.fillStyle = '#0d1b2a'; ctx.fillRect(0, 0, CANVAS_SIZE, CANVAS_SIZE); // 绘制网格 ctx.strokeStyle = '#1b263b'; ctx.lineWidth = 0.3; for (let i = 0; i <= TILE_COUNT; i++) { // 横线 ctx.beginPath(); ctx.moveTo(0, i * GRID_SIZE); ctx.lineTo(CANVAS_SIZE, i * GRID_SIZE); ctx.stroke(); // 竖线 ctx.beginPath(); ctx.moveTo(i * GRID_SIZE, 0); ctx.lineTo(i * GRID_SIZE, CANVAS_SIZE); ctx.stroke(); } // 绘制食物 ctx.fillStyle = '#ff5252'; ctx.beginPath(); ctx.arc( food.x * GRID_SIZE + GRID_SIZE / 2, food.y * GRID_SIZE + GRID_SIZE / 2, GRID_SIZE / 2 - 2, 0, Math.PI * 2 ); ctx.fill(); // 绘制蛇 snake.forEach((segment, index) => { // 蛇头用不同颜色 if (index === 0) { ctx.fillStyle = '#4caf50'; } else { // 蛇身使用渐变色 const colorValue = Math.max(100, 255 - index * 10); ctx.fillStyle = `rgb(76, ${colorValue}, 80)`; } ctx.fillRect(segment.x * GRID_SIZE, segment.y * GRID_SIZE, GRID_SIZE, GRID_SIZE); // 蛇身圆角 ctx.strokeStyle = '#1b5e20'; ctx.lineWidth = 2; ctx.strokeRect(segment.x * GRID_SIZE, segment.y * GRID_SIZE, GRID_SIZE, GRID_SIZE); }); } // 更新游戏状态 function update() { // 计算新蛇头位置 const head = {x: snake[0].x + direction.x, y: snake[0].y + direction.y}; // 边界穿越逻辑 if (head.x < 0) head.x = TILE_COUNT - 1; if (head.x >= TILE_COUNT) head.x = 0; if (head.y < 0) head.y = TILE_COUNT - 1; if (head.y >= TILE_COUNT) head.y = 0; // 检查是否撞到自己 if (snake.some(segment => segment.x === head.x && segment.y === head.y)) { gameOver(); return; } // 添加新蛇头 snake.unshift(head); // 检查是否吃到食物 if (head.x === food.x && head.y === food.y) { score += 10; foodEaten++; scoreElement.textContent = score; foodElement.textContent = foodEaten; // 每吃掉5个食物增加速度 if (foodEaten % 5 === 0) { gameSpeed = Math.max(50, gameSpeed - 10); speedElement.textContent = gameSpeed; } // 生成新食物 food = generateFood(); } else { // 没吃到食物,移除蛇尾 snake.pop(); } // 更新长度显示 lengthElement.textContent = snake.length; } // 游戏循环 function gameLoop(timestamp) { if (gamePaused || !gameRunning) { requestAnimationFrame(gameLoop); return; } const secondsSinceLastRender = (timestamp - lastRenderTime) / 1000; if (secondsSinceLastRender < 1 / (1000 / gameSpeed)) { requestAnimationFrame(gameLoop); return; } lastRenderTime = timestamp; update(); draw(); requestAnimationFrame(gameLoop); } // 游戏结束 function gameOver() { gameRunning = false; gamePaused = false; finalScoreElement.textContent = score; gameOverScreen.style.display = 'flex'; } // 开始游戏 function startGame() { if (!gameRunning) { gameRunning = true; gamePaused = false; gameOverScreen.style.display = 'none'; lastRenderTime = 0; requestAnimationFrame(gameLoop); } } // 暂停游戏 function togglePause() { if (gameRunning) { gamePaused = !gamePaused; pauseBtn.textContent = gamePaused ? '继续' : '暂停'; } } // 开始新游戏 function newGame() { snake = [{x: 10, y: 10}]; food = generateFood(); direction = {x: 0, y: 0}; score = 0; foodEaten = 0; gameSpeed = 100; gameRunning = false; gamePaused = false; scoreElement.textContent = score; lengthElement.textContent = snake.length; speedElement.textContent = gameSpeed; foodElement.textContent = foodEaten; gameOverScreen.style.display = 'none'; pauseBtn.textContent = '暂停'; draw(); } // 初始化游戏 newGame(); // 事件监听 document.addEventListener('keydown', e => { if (!gameRunning) return; // 防止在一次更新中多次改变方向 switch(e.key) { case 'ArrowUp': if (direction.y === 0) { direction = {x: 0, y: -1}; } break; case 'ArrowDown': if (direction.y === 0) { direction = {x: 0, y: 1}; } break; case 'ArrowLeft': if (direction.x === 0) { direction = {x: -1, y: 0}; } break; case 'ArrowRight': if (direction.x === 0) { direction = {x: 1, y: 0}; } break; } }); startBtn.addEventListener('click', startGame); pauseBtn.addEventListener('click', togglePause); newGameBtn.addEventListener('
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值