美文网首页
canvas小游戏-贪吃蛇

canvas小游戏-贪吃蛇

作者: 你怀中的猫 | 来源:发表于2022-05-28 16:18 被阅读0次

使用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);
}


相关文章

  • canvas小游戏-贪吃蛇

    使用canvas完成贪吃蛇小游戏 可以设置速度 可以设置有墙或无墙状态 可以修改蛇身的皮肤image.png ht...

  • HTML5新增API

    Canvas 画布 canvas用途 游戏 小游戏 图表 报表 如 Charts插件 炫酷效果 banner 模...

  • canvas简单入门(1)

    Canvas 画布 canvas用途 游戏 小游戏 图表 报表 如 Charts插件 炫酷效果 banner 模...

  • canvas的简单使用

    Canvas 画布 canvas用途 游戏 小游戏 图表 报表 如 Charts插件 炫酷效果 banner 模...

  • canvas基础

    Canvas 画布基础 canvas用途 游戏 小游戏 图表 报表 如 Charts插件 炫酷效果 banner...

  • canvas— —刮刮乐

    今天,结合上一篇文章的抽奖小游戏,用canvas来写一个小游戏——刮刮乐。首先,用canvas做一个画布,宽高各为...

  • 游戏 & Github Page

    1. snakewizard.github.io 贪吃蛇小游戏 2. mattbasile.github.io 龙...

  • 好玩的Canvas射箭小游戏

    Canvas射箭小游戏 body{ margin:0; background:#2...

  • 《极限贪吃蛇》

    贪吃蛇是一款非常有趣的小游戏。 益智有好玩,等你来体验

  • “贪吃蛇🐍”的一生

    前段时间,出于无聊,下载了“贪吃蛇”这个游戏,原本以为这样的小游戏没啥意思,没想到居然上头了。 “贪吃蛇”这个游戏...

网友评论

      本文标题:canvas小游戏-贪吃蛇

      本文链接:https://www.haomeiwen.com/subject/vpiiprtx.html