Canvas制作经典贪吃蛇

效果展示

在这里插入图片描述
在这里插入图片描述

功能描述

  1. “上”“下”“左”“右”控制小蛇方向
  2. 按空格暂停
  3. 死亡后弹框,重新开始游戏
  4. 分数展示
  5. 按“ctrl”加速小蛇移动

然后是我个人开发这个小游戏时的大致步骤或者说思路

1、确定布局
2、绘制小蛇初始状态
3、实现小蛇移动
4、随机生成食物(并在食物位置不合理时重新绘制)
5、实现吃到食物,小蛇生长
6、判断小蛇死亡
7、死亡后弹框
8、实现重新开始游戏
9、添加规则说明
10、实现计分
11、实现暂停游戏
12、实现继续游戏

源代码

以下是源代码,也可以直接关注公众号 趣味代码爱好者 ,回复snake,获得打包好的完整项目,直接解压运行,省去黏贴复制,文件管理等繁琐步骤
后续也会在公众号中发布游戏开发的详细步骤以及更多有趣好玩的开源项目和IT技术!


index.html

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>webSnake</title>
    <link rel="stylesheet" type="text/css" href="css/common.css">
    <script type="text/javascript" src="js/js.js"></script>
</head>
<body onload="init()"> <!-- 每次加载页面时,调用init()函数 -->
     <table id="myTable">
        <tr>
            <td rowspan="3" colspan="2" class="Canvas">
                <canvas id="myCanvas" class="myCanvas" width="725px" height="600px">
                    您的浏览器不支持 HTML5 canvas 标签。
                </canvas>
            </td>
            <td class="rules">
                规则说明:<br/>
                (1)↑、↓、←、→控制小蛇方向<br/>
                (2)按空格暂停游戏<br/>
                (3)按ctrl加速<br/>
                (4)不要失去横冲直撞的勇气<br/>
            </td>
        </tr>
        <tr>
            <td  id="score" class="score">
                0
            </td>
        </tr>
        <tr>
            <td class="sourseCode">
                关注公众号获更多经典游戏源码及完整的游戏开发教程
                <img src="CodeCats.jpg">
            </td>
        </tr>
    </table>
    <div id="dialog" class="dialog">
        <div class="text">Game Over!</div>
        <button type="button" id="button" class="button" onclick="restart()">重开</button>
    </div>
</body>
</html>

js.js

var blockSize=25 //一个方块的边长为25
var width=29//地图的宽度为29*25px
var height=24//地图的宽度为24*25px
var direction=[[0,-1],[0,1],[-1,0],[1,0]]//对应上下左右 ,例如:"上"是横坐标不变,纵坐标减一即[0,-1]
var fX=0
var fY=0//食物的坐标
var score=0//分数
var interval=200//重绘小蛇的时间间隔
var id//setTimeout(fn,interval)返回值
var dir=3 //当前方向是右
var directX=direction[3][0] //横坐标增量
var directY=direction[3][1] //纵坐标增量
var flag=true //游戏暂停或继续的开关
//其中存储的是每个小方块的横纵坐标,如305,分别通过305/100和305%100获得实际坐标(3,5)
var snake=new Array()//蛇身
function init() {
    var canvas = document.getElementById("myCanvas");
    if (canvas.getContext) {
        //尽管ctx是在if语句中声明的,但if之外,也可以使用它,欲了解详情可学习“JavaScript 声明提升”
        var ctx = canvas.getContext("2d");
    }
    //初始化小蛇
    snake.push(101)//(1,1)
    snake.push(201)//(2,1)
    snake.push(301)//(3,1)
    drawSnake(ctx)//绘制小蛇
    generateFood(ctx)//绘制食物
    begin(ctx)
}

//开始游戏
function begin(ctx){
    //控制小蛇方向,游戏刚开始时,小蛇的默认方向向右
    document.onkeydown = keyDown;
    function keyDown(event){  // 方向键控制元素移动函数
        var event = event || window.event;  // 标准化事件对象
        switch(event.keyCode){  // 获取当前按下键盘键的编码   38  40   37  39
            case 38 :  // 按下上箭头键
                if(dir==1){//如果当前方向是"下",不允许向下改变方向,直接跳出
                    break;
                }
                directX=direction[0][0] //横坐标增量
                directY=direction[0][1] //纵坐标增量
                dir=0//当前方向
                break;
            case 40 :  // 按下下箭头键
                if(dir==0){
                    break;
                }
                directX=direction[1][0] //横坐标增量
                directY=direction[1][1] //纵坐标增量
                dir=1//当前方向
                break;
            case 37 :  // 按下左箭头键
                if(dir==3){
                    break;
                }
                directX=direction[2][0] //横坐标增量
                directY=direction[2][1] //纵坐标增量
                dir=2//当前方向
                break;
            case 39 :  // 按下右箭头键
                if(dir==2){
                    break;
                }
                directX=direction[3][0] //横坐标增量
                directY=direction[3][1] //纵坐标增量
                dir=3//当前方向
                break;
            case 17 : //按下ctrl键(加速)
                interval=50;
                break;
            case 32:  //按下空格(暂停)
                if(flag){
                    clearTimeout(id)
                    flag=!flag
                }else{
                    begin(ctx)
                    flag=!flag
                }
                
        }
        document.onkeyup = function(event){
            //当抬起ctrl时,恢复速度
            var event = event || window.event;  // 标准化事件对象
            if(event.keyCode==17){
                interval=200;
            }
        };
    }
    //实现小蛇移动
    /*小蛇的移动实际上是,尾部方块去掉,然后在小蛇方向上添加一个方块,作为蛇头
  而中间的其它方块并没有任何变化*/
    var fn=function(){
        clear(ctx);
        var newX=parseInt(snake[snake.length-1]/100)+directX;
        var newY=snake[snake.length-1]%100+directY;
        snake.push(newX*100+newY);//添加一个元素
        //每次移动后都检测小蛇有没有吃到食物
        if(!eaten(newX,newY)){
            //没吃到,所以要删除第一个元素,实现小蛇移动(不删除的话,就实现了小蛇生长)
            snake.shift();//删除第一个元素(即删除尾巴) 
        }else{
            //吃到了
            scoring()
            generateFood(ctx)
        }
        //每次移动后检查小蛇还活着吗
        if(isDead(newX,newY)){
            // alert("死了")
            over()
            return;
        }
        drawSnake(ctx);
        id=setTimeout(fn,interval);       
    }
    fn();
}

//随机生成食物
function generateFood(ctx){
    //随机生成食物的坐标
    var fu=function(){
        fX=Math.round(Math.random()*28);
        fY=Math.round(Math.random()*23);
        var flag=false
        for (var i = 0; i < snake.length; i++) {
            if(fX==parseInt(snake[i]/100)&&fY==snake[i]%100){
                // alert("发现生成的食物坐标与小蛇重合")
                flag=true
                break
            }     
        }
        if(!flag){
            //绘制食物
            ctx.fillStyle = "rgb(0,200,0)"; 
            ctx.fillRect (fX*blockSize,fY*blockSize , 25, 25);//填充颜色
            console.log(fX)
            console.log(fY)
        }else{
            //重新生成
            fu()
        }
    }
    fu()
}

//绘制小蛇
function drawSnake(ctx){
    for (i= 0; i <= snake.length-2; i++) {
        //绘制蛇身  
        var x=parseInt(snake[i]/100)*blockSize
        var y=snake[i]%100*blockSize
        ctx.fillStyle = "rgb(200,0,0)"; //蛇身是红色
        ctx.fillRect (x,y , 25, 25);//填充颜色
        ctx.strokeRect(x,y , 25, 25);
    }
    //绘制蛇头(snake数组的最后一个元素存储的是蛇头的坐标)
    x=parseInt(snake[snake.length-1]/100)
    y=snake[snake.length-1]%100
    ctx.fillStyle = "rgb(0,0,200)"; //蛇身是蓝色
    ctx.fillRect (x*blockSize,y*blockSize, 25, 25);//填充颜色
    ctx.strokeRect(x*blockSize,y*blockSize , 25, 25);
    //重绘食物,(因为在小蛇移动的实现过程中,活动区域被清空了)
    ctx.fillStyle = "rgb(0,200,0)"; 
    ctx.fillRect (fX*blockSize,fY*blockSize , 25, 25);//填充颜色
}

//清空屏幕
function clear(ctx) {
     ctx.clearRect(0,0,725,600)
}

//判断是否吃到食物
function eaten(x,y){
    if(x==fX&&y==fY){
        return true
    }else{
        return false
    }
}

//判断小蛇是否死亡
function isDead(x,y){
    //是否碰到墙壁
    if(x==-1||x==29||y==-1||y==24){
        return true;
    }
    //是否碰到身体
    for (var i = 0; i < snake.length-1; i++) {
        if(x==parseInt(snake[i]/100)&&y==snake[i]%100){
            return true;
        }
    }
    return false;
}

//死亡后调用over函数作为提示
function over(){
    //虚化背景
    var table=document.getElementById("myTable")
    table.style.opacity="0.6"
    //弹出提示框
    var dialog=document.getElementById("dialog")
    dialog.style.visibility="visible"
}

//重开游戏
function restart(){
    snake=new Array()//小蛇数据归零
    score=0//分数归零
    init()
    //将背景恢复
    var table=document.getElementById("myTable")
    table.style.opacity="1"
    //隐藏对话框
    var dialog=document.getElementById("dialog")
    dialog.style.visibility="hidden"
    //修改分数
    document.getElementById("score").innerHTML=score
}

//实现计分
function scoring(){
    score=score+1
    document.getElementById("score").innerHTML=score; // 改变内容
}

common.css

table, th, td{
	border: 1px solid black; /*边框设置*/
	padding: 0px;
}
table{
	position: absolute;
	margin: auto;/*实现居中效果*/
	background-color: #A7C942;/*背景颜色设置*/
	margin-left: 20%;
	margin-right: 20%; 
	z-index: 1;/*设置层级,实现div块重叠*/
}
.Canvas{
	width: 81%;
	height: 600px;
}
.myCanvas{
	width: 100%; 
	height: 100%;/*myCanvas充满整个Canvas*/
}
.dialog{
	position: absolute;
	background: white;
	width:20% ;
	height: 30%;
	margin-left: 35%;
	margin-top: 10%;
	border-radius: 5px;
	z-index: 2;/*层级*/
	visibility: hidden;
}
.dialog .text{
	position: absolute;
	text-align: center;
	line-height: 200px;
	width: 100%;
	height: 70%;
	font-size: 30px;
}
.button{
	position: absolute;
	width: 50px;
	height: 25px;
	border-radius: 5px;
	background: red;
	color: #fff;
	right: 5px;
	bottom: 5px;
	text-align: center;
}
.rules{
	height: 200px;
}
.score{
	text-align: center;
	height: 200px;
	font-size: 36px;
	color: red;
}
.sourseCode img{
	width: 70%;
	height: 70%;
	align-content: center;
}
  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值