文档章节

最近学习到H5的canvas,一时兴起写了个经典的“贪吃蛇”小游戏

xiwanglr
 xiwanglr
发布于 2017/07/31 17:57
字数 1226
阅读 41
收藏 1
  1.     要完成这个游戏,首先要了解蛇是由一个一个的点组成的,然后这个点要有位置、颜色,关键的还要有下一个点的基本位置信息,不然怎么知道这个点的下一个运动位置呢。上代码:
    class Dot {
    		constructor(x,y,color){
    			this.color = color
    			this.x = x
    			this.y = y
    			this.next = null
    
    			ctx.fillStyle = this.color
    			ctx.beginPath()
    			ctx.arc(x,y,5,0,2*Math.PI)
    			ctx.fill()
    		}
    		reDraw() {
    			ctx.fillStyle = this.color
    			ctx.beginPath()
    			ctx.arc(this.x,this.y,5,0,2*Math.PI)
    			ctx.fill()
    		}
    
    	}

    reDraw()方法就是对这个点的重画,点位置移动后重新画上去。

  2. 随机点的生成。随机点的位置其实也不是随机的,最基本的它不能超出画布范围,还有重要的一点就是它的位置必须是蛇可以经过的地方,可能说的不是很明白。但是大家应该都能明白..比如上边的代码设置的点的半径为5px,所以这个随机点的x、y都必须是5的整数倍,不然的话蛇就可能不会和随机点正面相撞,也就是虽然相遇了,但不在一条直线上。代码:
     

    //生成随机点
    	function randomDot () {
    		let x = parseInt(Math.random()*10 + 1) * (width-100)/10
    		let y = parseInt(Math.random()*10 + 1) * (height-100)/10
    		//判断点不在snake上,如果存在,重新生成
    		for(let dot of snake){
    			if(dot.x == x && dot.y == y){
    				return randomDot()
    			}
    		}
    		return new Dot(x,y,'white')
    	}

     

  3. 碰撞的判断。我判断碰撞就是简单的比较一下蛇头的x、y坐标和随机点的坐标是否一致

  4. 方向的控制。这个我想大家都会就不多说了:
     

    window.onkeydown = function(eve){
    		switch(eve.keyCode){
            case 38:
                dir = 'up'
                break;
            case 40:
                dir = 'down'
                break;
            case 37:
                dir = 'left'
                break;
            case 39:
                dir = 'right'
                break;
        	}
    	}

     

  5. 最后一步就是贪吃蛇的移动(画布刷新)、判断碰撞、长大、游戏失败等等的逻辑了。
    通过setInterval来刷新画布,贪吃蛇使用一个存储‘点’的数组来表示,最后一个元素作为蛇头,通过点的next属性来判断每一个点下次的位置。需要注意的是蛇头的next为空,需要根据运动方向计算出来:nextDot(dot)。把点的x、y重新赋值,以及点的next信息重新赋值以后,调用reDraw()方法重新在画布上画出来就可以了。
    代码:

  6. let time = 500
    	let refresh =  setInterval(()=>updateCanvas(),time)
    
    	function updateCanvas(){
    		ctx.clearRect(0,0,width,height)
    		currentDot.reDraw()
    
    		let dot = snake[snake.length - 1]
    		snake[snake.length - 1] = nextDot(dot)
    		//非末尾元素
    		for(let i = 0; i < snake.length-1; i++){
    			let next = snake[i].next
    			let sNext = snake[i+1]
    			snake[i] = new Dot(next.x,next.y,'red')
    			if(sNext.next == null){
    				snake[i].next = new Dot(dot.x,dot.y,'red')
    			}else{
    				snake[i].next = new Dot(sNext.next.x,sNext.next.y,'red')
    			}
    			snake[i].reDraw()
    		}
    
    		if(dot.x < 0 || dot.y < 0 || dot.x > width || dot.y > height){
    			clearInterval(refresh)
    			alert("游戏结束...")
    		}
    
    		if(dot.x == currentDot.x && dot.y == currentDot.y){
    			score += 5
    			document.getElementById('score').innerHTML = score
    			dot.next = currentDot
    			dot.color = 'red'
    			snake.push(currentDot)
    			currentDot = randomDot()
    			//吃到一个点,速度变快
    			clearInterval(refresh)
    			time = time - 50
    			if(time <= 50) time  = 50
    			refresh = setInterval(()=>updateCanvas(),time)
    		}
    		dot.reDraw()
    	}

    下面是完整的代码:
     

    <!DOCTYPE html>
    <html>
    <head>
    	<title>贪吃蛇</title>
    </head>
    <body>
    <div style="width: 1030px">
    	<canvas id="canvas" width="900" height="500" style="background-color: #2a8e2a;float: left;"></canvas>
    	<div style="float: right;">得分:<h5 id="score" style="display: inline;">0</h5></div>
    	<div style="float: right;"><button onclick="stopOrRun(this)">暂停</button>&nbsp;&nbsp;&nbsp;</div>
    	<div><button onclick="speedUp()">加速</button> <button onclick="speedDown()">减速</button></div>
    </div>
    </body>
    <script type="text/javascript">
    	let ctx = document.getElementById('canvas').getContext('2d')
    	let width = 900
    	let height = 500
    	let score = 0
    	let isRun = true
    	class Dot {
    		constructor(x,y,color){
    			this.color = color
    			this.x = x
    			this.y = y
    			this.next = null
    
    			ctx.fillStyle = this.color
    			ctx.beginPath()
    			ctx.arc(x,y,5,0,2*Math.PI)
    			ctx.fill()
    		}
    		reDraw() {
    			ctx.fillStyle = this.color
    			ctx.beginPath()
    			ctx.arc(this.x,this.y,5,0,2*Math.PI)
    			ctx.fill()
    		}
    
    	}
    	let dir = 'right'
    	//初始化snake
    	let snake = new Array()
    	let len = 5
    	for(let i = 1; i <= len; i++){
    		let nextDot = null
    		if(i < len) nextDot = new Dot(10 * (i+1),50,'red')
    		let dot = new Dot(10 * i,50,'red')
    		if(i === len) dot.color = 'white'
    		dot.next = nextDot
    		snake.push(dot)
    	}
    
    	let currentDot = randomDot()
    
    	
    	//生成随机点
    	function randomDot () {
    		let x = parseInt(Math.random()*10 + 1) * (width-100)/10
    		let y = parseInt(Math.random()*10 + 1) * (height-100)/10
    		//判断点不在snake上,如果存在,重新生成
    		for(let dot of snake){
    			if(dot.x == x && dot.y == y){
    				return randomDot()
    			}
    		}
    		return new Dot(x,y,'white')
    	}
    
    
    	let time = 500
    	let refresh =  setInterval(()=>updateCanvas(),time)
    
    	function updateCanvas(){
    		ctx.clearRect(0,0,width,height)
    		currentDot.reDraw()
    
    		let dot = snake[snake.length - 1]
    		snake[snake.length - 1] = nextDot(dot)
    		//非末尾元素
    		for(let i = 0; i < snake.length-1; i++){
    			let next = snake[i].next
    			let sNext = snake[i+1]
    			snake[i] = new Dot(next.x,next.y,'red')
    			if(sNext.next == null){
    				snake[i].next = new Dot(dot.x,dot.y,'red')
    			}else{
    				snake[i].next = new Dot(sNext.next.x,sNext.next.y,'red')
    			}
    			snake[i].reDraw()
    		}
    
    		if(dot.x < 0 || dot.y < 0 || dot.x > width || dot.y > height){
    			clearInterval(refresh)
    			alert("游戏结束...")
    		}
    
    		if(dot.x == currentDot.x && dot.y == currentDot.y){
    			score += 5
    			document.getElementById('score').innerHTML = score
    			dot.next = currentDot
    			dot.color = 'red'
    			snake.push(currentDot)
    			currentDot = randomDot()
    			//吃到一个点,速度变快
    			clearInterval(refresh)
    			time = time - 50
    			if(time <= 50) time  = 50
    			refresh = setInterval(()=>updateCanvas(),time)
    		}
    		dot.reDraw()
    	}
    
    
    	function nextDot(dot){
    		switch(dir){
    			case 'right':
    				dot.x = dot.x + 10
    				break;
    			case 'left':
    				dot.x = dot.x - 10
    				break;
    			case 'up':
    				dot.y = dot.y - 10
    				break;
    			case 'down':
    				dot.y = dot.y + 10
    				break;
    		}
    		return dot
    	}
    
    	window.onkeydown = function(eve){
    		switch(eve.keyCode){
            case 38:
                dir = 'up'
                break;
            case 40:
                dir = 'down'
                break;
            case 37:
                dir = 'left'
                break;
            case 39:
                dir = 'right'
                break;
        	}
    	}
    
    	function stopOrRun (obj) {
    		if(isRun){
    			obj.innerHTML = '运行'
    			clearInterval(refresh)
    			isRun = false
    		}else{
    			obj.innerHTML = '暂停'
    			refresh = setInterval(()=>updateCanvas(),time)
    			isRun = true
    		}
    	}
    
    	function speedUp() {
    		time -= 10
    		clearInterval(refresh)
    		if(time <= 50) time  = 50
    		refresh = setInterval(()=>updateCanvas(),time)
    	}
    	function speedDown() {
    		time += 10
    		clearInterval(refresh)
    		if(time <= 50) time  = 50
    		refresh = setInterval(()=>updateCanvas(),time)
    	}
    </script>
    </html>

     

  7. over。

© 著作权归作者所有

xiwanglr

xiwanglr

粉丝 0
博文 18
码字总数 5447
作品 0
普陀
高级程序员
私信 提问
加载中

评论(1)

xiwanglr
xiwanglr 博主
👍
在pcDuino上摇杆控制贪吃蛇游戏

最近一直在玩pcDuino,苦恼于各种程序。。。好吧,玩玩趣味性的游戏我觉的是个不错的想法,可是pcDuino上貌似还没有可玩的小游戏,试试移植一个?犹豫片刻决定动手,首先就想到经典游戏贪吃蛇...

pc朵拉
2013/07/01
1K
2
在 Linux 终端中玩贪吃蛇

有了这个 20 世纪 70 年代的经典重制游戏,Python 将不再是你在 Linux 终端能发现的唯一的“蛇”。 欢迎回到 Linux 命令行玩具日历。如果这是你第一次访问该系列,你可能会问什么是命令行玩具...

作者: Jason Baker
01/12
0
0
【C/C++】10分钟教你用C++写一个贪吃蛇附带AI功能(附源代码详解和下载)

C++编写贪吃蛇小游戏快速入门 刚学完C++。一时兴起,就花几天时间手动做了个贪吃蛇,后来觉得不过瘾,于是又加入了AI功能。希望大家Enjoy It. 效果图示 AI模式演示 整体规划+原理 大体上可以...

短短的路走走停停
2018/07/29
0
0
做游戏,学编程(C语言) 9 贪吃蛇

这个案例给出了14级同学大一时实现的贪吃蛇小游戏,分步骤代码、游戏素材可以从百度云盘下载:http://pan.baidu.com/s/1c1lYKQ 首先可以打开Exefinal目录下的Exefinal.dsw工程文件,编译运行...

童晶
2017/02/03
0
0
在源码上玩贪吃蛇,程序员式快乐!

贪吃蛇确实经典又耐玩,并且可以说是已经被玩出了花来,变种繁多。 上月初我们刚报道过作为愚人节彩蛋的谷歌地图版贪吃蛇,还有前不久以 Web 浏览器的网址栏作为游戏界面的 URL 贪吃蛇,最近...

xplanet
05/01
2.4K
4

没有更多内容

加载失败,请刷新页面

加载更多

【0918】正则介绍_grep

【0918】正则介绍_grep 9.1 正则介绍_grep上 9.2 grep中 9.3 grep下 一、正则介绍 正则是一串有规律的字符串,它使用单个字符串来描述或匹配一系列符合某个语法规则的字符串。 二、grep工具 ...

飞翔的竹蜻蜓
27分钟前
4
0
为什么要在网站中应用CDN加速?

1. 网页加载速度更快 在网站中使用CDN技术最直接的一个好处就是它可以加快网页的加载速度。首先,CDN加速的内容分发是基于服务器缓存的,由于CDN中缓存了不少数据,它能够给用户提供更快的页...

云漫网络Ruan
今天
8
0
亚玛芬体育(Amer Sports)和信必优正式启动合作开发Movesense创新

亚玛芬体育和信必优正式启动合作开发Movesense创新,作为亚玛芬体育的完美技术搭档,信必优利用Movesense传感器技术为第三方开发移动应用和服务。 Movesense基于传感器技术和开放的API,测量...

symbiochina88
今天
4
0
创龙TI AM437x ARM Cortex-A9 + Xilinx Spartan-6 FPGA核心板规格书

SOM-TL437xF是一款广州创龙基于TI AM437x ARM Cortex-A9 + Xilinx Spartan-6 FPGA芯片设计的核心板,采用沉金无铅工艺的10层板设计,适用于高速数据采集和处理系统、汽车导航、工业自动化等领...

Tronlong创龙
今天
5
0
好程序员Java学习路线分享MyBatis之线程优化

  好程序员Java学习路线分享MyBatis之线程优化,我们的项目存在大量用户同时访问的情况,那么就会出现大量线程并发访问数据库,这样会带来线程同步问题,本章我们将讨论MyBatis的线程同步问...

好程序员官方
今天
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部