首页 > 程序开发 > web前端 > HTML/CSS >

HTML5+Canvas贪吃蛇

2016-10-03

最近前端以及JavaScript很火,再加上上课web的需要,感觉是时候系统的学学HTML5了,之前和同学合作用html5的canvas开发了一个贪吃蛇改进版的小游戏,很有趣,当时的核心代码是同学敲得,而我也在忙别的事情一直没有回过头来研究一下。

最近前端以及JavaScript很火,再加上上课web的需要,感觉是时候系统的学学HTML5了,之前和同学合作用html5的canvas开发了一个贪吃蛇改进版的小游戏,很有趣,当时的核心代码是同学敲得,而我也在忙别的事情一直没有回过头来研究一下。好在快一年的时间了,自己也学了很多种UI的皮毛,见得多了,再看canvas感觉就是只要有文档就能直接用了。

这里分享一下开发的过程吧。

效果图。

  

\

  

\

还有穿墙功能。

  

\

前置技能

使用canvas。

所需工具以及前置技能:支持HTML5的浏览器,html+css, javascript,Jquery

canva是HTML5中新特性的一种,直接可以进行绘图,和其他UI差别不大。

布局

首先,我们写个index.html,并进行简单的布局及样式。

设置整个画布为720 x 480 的大小。每个蛇身、食物的半径为12,所以一行能放720 / 24 = 30个,每列能放 480 / 24 = 20个元素




//简单的布局
canvas not supported Score //得分 Level //关卡
//引入jquery

主逻辑

然后我们编写主逻辑。

首先获取Canvas对象,然后设置网页的键盘监听器(接受上下左右的按键),接着通过Jquery获取StartGame这个按钮的事件。

在引入Jquery的代码下面插入一段JS脚本。

<script type="text/javascript">
         var canvas = document.getElementById(&#39;canvas1&#39;); //获取canvas画布
         var ctxt = canvas.getContext(&#39;2d&#39;); //以后就用ctxt来在canvas画布上绘画
         document.addEventListener(&#39;keydown&#39;,keyDownCheck,false); //设置键盘按下的监听事件,通过keyDownCheck这个函数处理,
        $("#startGame").click(function(){
            beginGame(1); // 通过beginGame(1)这个函数来开始游戏,1代表了开始的关卡
        });
    </script>

好,这样我们游戏的外部框架出来了,接着我们往里深入,来实现贪吃蛇的主体逻辑。

Snake类

首先,我们先创建一个Snake的类,JavaScript的类用function就可以实现。

贪吃蛇需要有身子,身子由什么组成呢? 因为是2D游戏,所以由一个个相连的二位坐标点组成。

到这里我们想到,蛇身由点组成,那么食物也可由点组成,于是这里我们把点写成一个类,num属性代表食物的得分。

function Pos(x,y,num = 2){
  this.x = x;
  this.y = y;
  this.num = num;
}
this.body = [new Pos(20,15), new Pos(21,15),new Pos(22,15),
  new Pos(23,15), new Pos(24,15),new Pos(25,15)]; //定义蛇身,从20 ~ 25相邻的一串点

当然食物(障碍物)obstacle,我们也用一样的方法定义了。

function Obstacle(){
  this.body = [new Pos(0,0),new Pos(0,1),new Pos(1,0)
  ,new Pos(1,1),new Pos(29,19),new Pos(10,10),new Pos(11,11)];
}

有了蛇身,还要定义蛇当前行进的方向。

这里我们规定 1 ,2 ,3 ,4 分别为上下左右

  this.dir = 3; // 初始向左

有了身子方向,接着我们要想怎么去移动move。

这里提供一个思路。

首先,我们通过蛇头,和方向判断出蛇下一步要走的那个点的坐标。我们记做head,记录下这一坐标。然后从蛇尾遍历到蛇头,每一个的坐标赋值为其前一个位置的坐标,而蛇头就用head进行赋值,这样就能实现移动了。

当然,有了head我们还能做更多的事,判断head所在位置是不是墙,是不是蛇身,是不是食物,我们就能实现判断是否游戏结束,以及得分情况了。

this.move = function(level){
    var isEat = false;
    var head;
    if(this.dir == 1)
        head = new Pos(this.body[0].x,this.body[0].y-1);
    else if(this.dir == 2)
        head = new Pos(this.body[0].x,this.body[0].y+1);
    else if(this.dir == 3)
        head = new Pos(this.body[0].x-1,this.body[0].y);
    else if(this.dir == 4)
        head = new Pos(this.body[0].x+1,this.body[0].y);
    //判定是否死亡
    if(level == 1){ //可以穿墙 ,这里设置第一关可以穿越围墙到另一面
      if(head.x < 0) head.x = 29;
      if(head.x > 29) head.x = 0;
      if(head.y < 0) head.y = 19;
      if(head.y > 19) head.y = 0;
    }
    else if (head.x <0 || head.x > 29 || head.y < 0 || head.y > 20) //碰到边界
      this.dead = true;
    if(!this.dead){ //吃到自身
      for(i=0;i=0;i--){
          if(i == 0)
            this.body[i].x = head.x , this.body[i].y = head.y;
          else
            this.body[i].x = this.body[i-1].x,this.body[i].y = this.body[i-1].y;
        }
/*  另一种移动方法     this.body.splice(0,0,head); // 吃掉头
          this.body.pop(); // 删除尾部 ,这样就移动了!*/
     }

生成食物

吃到食物之后,为了让游戏进行下去,我们还要不断地生成食物。

直接用Math.Random()函数生成待生成食物的x,y坐标,然后判断是否当前坐标已经被占用,如果占用就再生成一次。

   if(isEat){ // 添加食物
        var isOcupy = false;
        var tmp;
        do{
          isOcupy = false;
          tmp = createObstacle();
          for(i=0;i
function createObstacle(){
  var tmp = new Pos(Math.floor(Math.random()*30), Math.floor(Math.random()*20));
  tmp.num = Math.random() < 0.1 ? 4: 2; // 出现4和2的比例 1 : 9
  return tmp;
}

这样,整体的游戏逻辑算是基本实现了。

接下啦完成剩余的工作。

接受键盘数据

主要是上下左右,除了方向键,还增添了wasd,同时保证了按相反的方向无效,因为贪吃蛇不会直接回头走。

function keyDownCheck(){
  var e=event||window.event||arguments.callee.caller.arguments[0]; //各种兼容下获取event
 // alert(e.keyCode);
  if(e.keyCode == 87 || e.keyCode == 38){ // up
    if(snake.dir == 2)
      return;
    snake.dir = 1;
  }
  else if(e.keyCode == 83 || e.keyCode == 40){ // down
    if(snake.dir == 1)
      return;
    snake.dir = 2;
  }
  else if(e.keyCode == 65 || e.keyCode == 37){ // left
    if(snake.dir == 4)
      return;
    snake.dir = 3;
  }
  else if(e.keyCode == 68 || e.keyCode == 39){ //right
    if(snake.dir == 3)
      return;
    snake.dir = 4;
  }
}


主体循环以及绘图

2D游戏应该都是这样,游戏数据不停的的变化,界面也在不停的刷新。我们用setInterval来设立一个定时器,每隔一段时间刷新一下屏幕。再刷新的同时执行snake的move函数,这样就能让贪吃蛇不停的往前走了。当然最重要的,是要让这个后台数据变化在屏幕上显示出来。这里就用到了canvas的绘图技术了。

首先是开始游戏的函数。

function beginGame(level){
  if(gameTimer)
  clearInterval(gameTimer); //清空计时器
  snake = new Snake(); //为贪吃蛇申请对象
  obstacle = new Obstacle(); //为障碍物申请对象
  gameTimer = setInterval(function(){ //设置定时器
    snake.move(level);
    draw(level); //绘图函数。
    $("#score").val(snake.score); //更新成绩
    $("#level").val(level);  
  },gameSpeed[level-1]);
}
var gameSpeed = [240,210,180,150]; // 游戏速度

接着draw函数。

function draw(level){
// 画布大小 720 x 480, 每个元素半径12
// X = 0 ~ 29 , Y = 0 ~ 19
  ctxt.clearRect(0,0,canvas.width,canvas.height); //清空我们的画布
  ctxt.beginPath();  //开始画
  ctxt.rect(0,0,canvas.width,canvas.height);
  ctxt.fillStyle = "black";
  ctxt.closePath();
  ctxt.fill(); //填充

  for(i=0;i

GameOver函数。

function GameOver(){
  alert(&#39;GameOver!&#39;); 
  clearInterval(gameTimer); //为了保险,清空一下计数器
  $("#score").val(0); //得分置为0
  $("#level").val(1); //关卡置为1
  snake.body = null; //蛇身置为空
}

接下来大家还可以为这个游戏加上音效,背景音乐,或者改造成其他版本的贪吃蛇,例如2048版贪吃蛇,相信如果你仔细学习了这个代码,扩充下去不难做到。大笑

这个项目我已经放到了github上,欢迎fork

https://github.com/chaiwenjun000/webSnake


相关文章
最新文章
热点推荐