使用canvas完成贪吃蛇小游戏
- 可以设置速度
- 可以设置有墙或无墙状态
-
可以修改蛇身的皮肤
image.png
html代码
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>贪吃蛇</title>
<link rel="stylesheet" href="./index.css">
<script src="http://code.jquery.com/jquery-1.12.4.js"></script>
</head>
<body>
<div class="top">
<div class="left">Snake</div>
<div class="right">Score:<span class="score">0</span></div>
</div>
<canvas id="canvas"></canvas>
<!-- 开始游戏盒子 -->
<div class="begin">
<p>SNAKE</p>
<div class="start">start</div>
<br>
<div class="set">setting</div>
</div>
<!-- 设置盒子 -->
<div class="setBox">
<p>Settings</p>
<div class="start">start</div>
<div class="speed">Speed: <div class="slow">Slow</div>
<div class="normal">Normal</div>
<div class="fast">Fast</div>
</div>
<div class="wall">Wall: <div class="on">On</div>
<div class="off">Off</div>
</div>
</div>
<!-- 结束盒子 -->
<div class="end">
<p>Game Over</p>
<div class="endText">游戏结束</div>
<div class="start">start</div>
<br>
<div class="set">setting</div>
</div>
<audio id="audio"
src="https://dl.stream.qqmusic.qq.com/C400000uYx7S4VMZm0.m4a?guid=3943565997&vkey=D44390A154E3DC9A97128581F9652304787C70CB45A7C298ED80BB455C7C21128025EF7F3D3E2F134784118817FB0EE265DB174397269D32&uin=2497208832&fromtag=120002"></audio>
<audio src="./audio/game_over.mp3" id="audio1"></audio>
</body>
<script src="./index.js"></script>
</html>
CSS代码
@font-face {
font-family: 'VT323';
font-style: normal;
font-weight: 400;
src: url(https://fonts.gstatic.com/s/vt323/v17/pxiKyp0ihIEF2isfFJA.ttf) format('truetype');
}
* {
margin: 0px;
padding: 0px;
}
a {
text-decoration: none;
color: #000;
}
ul,
ol {
list-style-type: none;
}
table {
border-collapse: collapse;
}
input {
outline: none;
border-width: 1px;
}
textarea {
outline: none;
resize: none;
overflow: auto;
}
.clear {
clear: both;
}
.clear::after {
content: '';
clear: both;
}
body {
background-color: #000;
}
* {
color: #fff;
font-family: "VT323";
}
.top {
margin: 0 auto;
width: 340px;
overflow: hidden;
font-size: 26px;
padding-top: 10px;
margin-bottom: 20px;
}
.top .left {
float: left;
}
.top .right {
float: right;
}
body > div {
width: 340px;
margin: 0 auto;
}
#canvas {
border: 10px solid #fff;
display: block;
margin: 0 auto;
display: none;
}
.begin,
.end {
text-align: center;
}
.end{
display: none;
}
.begin > p,
.end > p {
text-align: center;
font-size: 50px;
padding-top: 30px;
animation: logo-ani 1000ms linear infinite;
margin-bottom: 20px;
}
.begin .start,
.end .start,
.begin .set,
.end .set {
font-size: 26px;
display: inline-block;
line-height: 40px;
cursor: pointer;
}
.begin .start::before,
.end .start::before,
.begin .set::before,
.end .set::before {
content: ">";
padding-right: 10px;
display: none;
}
.begin .start:hover::before,
.end .start:hover::before,
.begin .set:hover::before,
.end .set:hover::before {
display: inline-block;
}
.begin .endText,
.end .endText {
font-size: 30px;
}
@keyframes logo-ani {
50% {
transform: scale(1.3, 1.3);
}
100% {
transform: scale(1, 1);
}
}
.setBox {
text-align: center;
display: none;
}
.setBox > p {
text-align: center;
font-size: 50px;
padding-top: 30px;
margin-bottom: 20px;
}
.setBox .start {
font-size: 26px;
display: inline-block;
line-height: 40px;
cursor: pointer;
padding: 0px !important;
}
.setBox .start::before {
content: ">";
padding-right: 10px;
display: none;
}
.setBox .start:hover::before {
display: inline-block;
}
.setBox > div {
text-align: center;
font-size: 26px;
line-height: 30px;
padding: 5px 0;
}
.setBox > div > div {
display: inline-block;
cursor: pointer;
padding: 0 5px;
}
.setBox > div > .active {
background-color: #fff;
color: #000;
}
js代码
/*
键盘控制
上 下 左 右
*/
//设置画布的宽高
canvas.width = 640;
canvas.height = 640;
var ctx = canvas.getContext('2d');
//定义有没有墙
var hasWall = true;
//定义速度
var speed = 60;
//定义一个数组保存所有的格子
var arr = [];
//定义一个数组,保存蛇身所有的格子
var snake = [512, 513, 514, 515, 516, 517];
//声明一个变量 表示当前行进状态
var fx = 39; // 37 : 左 , 38 : 上 , 39 : 右 , 40 : 下
//定义一个变量,保存食物 的格子对象
var foods = null;
//定义一个变量,保存分数
var score = 0;
//定义一个蛇身渲染 和 键盘事件的开关
var flog = false;
//蛇头坐标
var gird = null;
//给设置墙的按钮绑定点击方法
$('.wall>div').click(function () {
var text = $(this).text();
// console.log(text);
switch (text) {
case 'On':
hasWall = true;
break;
case 'Off':
hasWall = false;
break;
}
// console.log(hasWall);
//点击添加calss名 并删除兄弟标签的class名
$(this).addClass('active').siblings().removeClass('active');
})
//模拟让 on 按钮被点击
$('.wall>div').eq(0).click();
//给设置速度的按钮绑定点击方法
$('.speed>div').click(function () {
var text = $(this).text();
// console.log(text);
switch (text) {
case 'Slow':
speed = 80;
break;
case 'Normal':
speed = 60;
break;
case 'Fast':
speed = 40;
break;
}
// console.log(hasWall);
//点击添加calss名 并删除兄弟标签的class名
$(this).addClass('active').siblings().removeClass('active');
console.log(speed);
})
//模拟让 on 按钮被点击
$('.speed>div').eq(1).click();
//给set按钮的点击方法 游戏设置按钮
$('.set').click(function () {
//关掉所有的盒子
$('.begin').hide();
$('.end').hide();
$('#canvas').hide();
//显示setBox盒子
$('.setBox').show();
})
//定义一个格子的类
function Rect(x, y, n,f) {
this.x = x;
this.y = y;
this.index = n;
// this.c = c || true; //默认为黑色 true 代表黑色 false代表白色
this.fx = f;
}
//添加一个绘制黑色格子的方法
Rect.prototype.drawB = function () {
ctx.beginPath();
ctx.fillStyle = 'block';
ctx.fillRect(this.x, this.y, 20, 20);
ctx.closePath();
ctx.stroke();
}
//添加一个绘制白色格子的方法
Rect.prototype.drawW = function () {
ctx.beginPath();
ctx.fillStyle = '#fff';
ctx.fillRect(this.x, this.y, 20, 20);
ctx.closePath();
ctx.stroke();
}
//添加一个绘制食物的方法
Rect.prototype.drawFood = function () {
ctx.beginPath();
ctx.arc(this.x + 10, this.y + 10, 10, 0, 360)
ctx.fillStyle = 'gold';
ctx.fill();
ctx.closePath();
ctx.stroke();
}
//添加绘制蛇身皮肤的方法
Rect.prototype.drawBody = function (img) {
var that = this;
img.onload = function () {
var deg = Math.PI / 180;
ctx.save();
switch (that.fx) {
case 37:
ctx.translate(that.x, that.y + 20);
ctx.rotate(270 * deg);
break;
case 38:
ctx.translate(that.x, that.y);
ctx.rotate(0);
break;
case 39:
ctx.translate(that.x + 20, that.y);
ctx.rotate(90 * deg);
break;
case 40:
ctx.translate(that.x + 20, that.y + 20);
ctx.rotate(180 * deg);
break;
}
ctx.drawImage(this, 0, 0, 20, 20);
ctx.restore();
}
}
//生成棋盘的方法
function createBox() {
var x = 0;
var y = 0;
arr = [];
for (var i = 0; i < 32 * 32; i++) {
var obj = new Rect(x, y, i, 39);
obj.drawB();
arr.push(obj);
x += 20;
if ((i + 1) % 32 == 0) {
y += 20;
x = 0;
}
}
//设置一下墙
if (hasWall) {
canvas.style.borderColor = '#fff';
} else {
canvas.style.borderColor = '#333';
}
}
//绘制蛇身的方法
function drawSnake() {
for (var i = 0; i < snake.length; i++) {
var a = snake[i];
// if(a == gird){
// arr[a].fx = fx;
// }
//蛇身皮肤
// if (i == snake.length - 1) {
// //执行画头部的方法
// var img = new Image();
// img.src = './img/1.png';
// arr[a].drawBody(img);
// } else if (i == 0) {
// //执行画尾部的方法
// var img = new Image();
// img.src = './img/3.png';
// arr[a].drawBody(img);
// } else {
// //执行画身体的的方法
// var img = new Image();
// img.src = './img/2.png';
// arr[a].drawBody(img);
// }
//正常小白快蛇身
arr[a].drawW();
}
//
flog = false;
}
//定义一个蛇身移动的方法
function move() {
var timer = setInterval(function () {
canvas.width = canvas.width;
//调用生成格子的方法
createBox();
//调用绘制蛇身的方法
drawSnake();
//绘制食物
arr[foods].drawFood();
//判断蛇是否吃到食物
// eat() 返回值 如果吃到食物返回true 如果没吃到返回false
if (!eat()) {
//删掉蛇身数组中的第一个元素
snake.shift();
}
//根据行进状态,改变蛇身数组
var num = null;
switch (fx) {
case 37://左
num = snake[snake.length - 1] - 1;
break;
case 38://上
num = snake[snake.length - 1] - 32;
break;
case 39://右
num = snake[snake.length - 1] + 1;
break;
case 40://下
num = snake[snake.length - 1] + 32;
break;
}
//碰撞判断
if (wall(num)) {
//判断有没有墙壁
if (hasWall) {
//有墙,撞上就结束游戏
clearInterval(timer)
// alert('游戏结束');
end('你个老六,你撞墙了!!!')
audio.pause();
audio1.play();
} else {
//无墙 撞上之后从反方向出现
var head = snake[snake.length - 1];
//右墙
if ((head + 1) % 32 == 0 && fx == 39) {
num = head - 31;
}
//左墙
if (head % 32 == 0 && fx == 37) {
num = head + 31;
}
//上墙
if (head < 32 && fx == 38) {
num = head + 31 * 32;
}
//下墙
if (head >= 32 * 31 && fx == 40) {
num = head - 31 * 32;
}
}
}
//判断是否咬到自己
if (eatSelf()) {
clearInterval(timer)
audio.pause();
audio1.play();
// alert('游戏结束');
end('你个老六,咬到自己了!!!')
}
snake.push(num);
// console.log(snake);
}, speed)
}
//定义 碰撞检测的方法
function wall(n) {
//上下墙的碰撞检测
if (n < 0 || n > (32 * 32 - 1)) {
return true; //撞到墙壁
}
//蛇头坐标
var head = snake[snake.length - 1];
//右墙的碰撞检测
if ((head + 1) % 32 == 0 && n == head + 1) {
return true;
}
//左边墙壁的碰撞检测
if (head % 32 == 0 && n == head - 1) {
return true;
}
}
//定义一个生成食物的方法
function food() {
var num = randNum(0, arr.length - 1);
if (snake.indexOf(num) == -1) {
// console.log(arr[num]);
return num;
} else {
return food();
}
}
//判断蛇吃食物
function eat() {
//获取蛇头
var head = snake[snake.length - 1];
if (head == foods) {
//蛇吃到食物
//重新生成食物
foods = food();
arr[foods].drawFood();
score++;
$('.score').text(score);
return true;
} else {
//没吃到
return false;
}
}
//判断蛇是否咬到自己
function eatSelf() {
var head = snake[snake.length - 1];
// console.log(snake);
//先将蛇头从 蛇身数组中去掉
snake.pop();
// console.log(snake);
if (snake.indexOf(head) == -1) {
snake.push(head);
return false;
} else {
//咬到自己
snake.push(head);
return true;
}
}
//给start按钮的点击方法 开始游戏按钮
$('.start').click(function () {
//关掉所有的盒子
$('.begin').hide();
$('.end').hide();
$('.setBox').hide();
//显示canvas盒子
$('#canvas').css('display', 'block');
audio.play();
audio1.pause();
//调用绘制蛇身的方法
// drawSnake()
//将蛇身初始化
snake = [512, 513, 514, 515, 516];
//清空画布
canvas.width = canvas.width;
//修改键值方向
fx = 39;
//清空分数
score = 0;
$('.score').text(score);
//调用生成格子的方法
createBox();
//生成食物
foods = food();
//绘制食物
arr[foods].drawFood();
move();
})
//键盘事件
window.onkeydown = function (e) {
var code = e.keyCode;
// 向哪一个方向行进时,不能向反方向移动
if (fx == 39 && code == 37) {
return;
}
if (fx == 37 && code == 39) {
return;
}
if (fx == 38 && code == 40) {
return;
}
if (fx == 40 && code == 38) {
return;
}
//蛇身渲染 和 键盘事件的开关
if (flog) {
return;
}
//如果不是这四个键,不执行
if (code == 37 || code == 38 || code == 39 || code == 40) {
gird = snake[snake.length - 1];
fx = code;
flog = true;
}
}
//游戏结束的方法
function end(t) {
//关掉所有的盒子
$('.begin').hide();
$('#canvas').hide();
$('.setBox').hide();
//显示end盒子
$('.end').show();
$('.endText').text(t)
}
//封装随机数
function randNum(min, max) {
return Math.floor(Math.random() * (max - min + 1) + min);
}
网友评论